Continue audiobook from Music Assistant

Hi there, I have tried to find an answer to this myself, but I’ve not found anything, so if it’s obvious, I apologize.

I’m new to Home Assistant in general, so it’s possible my whole approach is wrong.

I’m trying to set up my Voice PE to accept the command “Read my book” and have it resume my most recent book on Music Assistant (backed by Audiobookshelf)

I should mention that I can play the audiobook through the Music Assistant web ui to the voice PE just fine

Here’s my automation so far:

alias: Read My Book
description: Continue the last played Audio book from Music Assistant
triggers:
  - trigger: conversation
    command: Read my book
conditions: []
actions:
  - action: music_assistant.get_library
    metadata: {}
    data:
      media_type: audiobook
      limit: 1
      order_by: last_played_desc
      config_entry_id: 01K7BQVKK6S2GKQK7MCF4EQFTH
    response_variable: continue_book
  - variables:
      book_uri: >-
        {{ continue_book['items'][0]['uri'] if continue_book and
        continue_book['items']|length > 0 else none }}
      trigger_device: "{{ trigger.device_id }}"
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ book_uri is not none }}"
        sequence:
          - action: music_assistant.play_media
            target:
              entity_id: |-
                {{ device_entities(trigger_device) 
                  | select('search', '^media_player\.') 
                  | list | first }}
            data:
              media_type: audiobook
              media_id: "{{ book_uri }}"
              enqueue: replace
    default:
      - action: assist_satellite.announce
        metadata: {}
        data:
          message: Couldn't find a book to play
          preannounce: true
        target:
          device_id: "{{ trigger_device }}"
mode: single

What’s working:

  • The automation is triggered
  • An audiobook is found
  • The play_media action is reached
  • The correct media_player entity is being returned (matches the MA web ui at least)

What’s not:

  • It’s just a random audio book, not the one listed under “Continue listening” in the web ui
  • It’s not playing. There’s no errors in the traces section for the automation, and the voice PE says “done” but then nothing happens

I’ve been banging my head against this for a couple hours now and I’m sure I’m just missing something simple.

Any help would be appreciated

Cheers

UPDATE: I’ve gotten playback to work. Turns out the media player associated with the trigger device ID is the wrong one to use. I don’t fully grok why, and I’m not certain this explanation is correct: there is another one created by the music assistant integration that should be used instead?

Getting this working required going to Settings > Devices & services > Music Assistant ( under integrations ) → For each entry, view entities, and select the media player entity → Settings → Use device area to ON

Then I changed the entity id selector to:

entity_id: |-
    {% set area = device_attr(trigger.device_id, 'area_id') %}
    {{ area_entities(area)
      | select('match', '^media_player\\.')
      | reject('search', 'voice_.*_media_player$')
      | select('search', 'home_assistant_.*_media_player$')
      | list | first }}

Now I just need it to select the correct audio book

1 Like

I’d still like to solve this properly, but in case someone else stumbles on to this, where I’ve landed is to just favorite the book I’m currently listening to, and have the automation search for that:

alias: Read My Book
description: Continue the last played Audio book from Music Assistant
triggers:
  - trigger: conversation
    command: Read my book
conditions: []
actions:
  - action: music_assistant.get_library
    metadata: {}
    data:
      media_type: audiobook
      limit: 1
      favorite: true
      config_entry_id: 01K7BQVKK6S2GKQK7MCF4EQFTH
    response_variable: continue_book
  - variables:
      book_uri: >-
        {{ continue_book['items'][0]['uri'] if continue_book and
        continue_book['items']|length > 0 else none }}
      trigger_device: "{{ trigger.device_id }}"
      media_player_entity: |-
        {% set area = device_attr(trigger.device_id, 'area_id') %}
        {{ area_entities(area)
          | select('match', '^media_player\\.')
          | reject('search', 'voice_.*_media_player$')
          | select('search', 'home_assistant_.*_media_player$')
          | list | first }}
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ book_uri is not none }}"
        sequence:
          - action: music_assistant.play_media
            target:
              entity_id: "{{ media_player_entity }}"
            data:
              media_type: audiobook
              media_id: "{{ book_uri }}"
              enqueue: replace
    default:
      - action: assist_satellite.announce
        metadata: {}
        data:
          message: Couldn't find a book to play
          preannounce: true
        target:
          device_id: "{{ trigger_device }}"
mode: single
1 Like

I’ve been looking at the same problem and have concluded, that the music assistant integration is broken for last_played and last_played_desc, at least with Audiobookshelf - thus I took a little detour and went directly against its API.

Prerequisite for this solution is, that you have enabled api access with the following in configuration.yaml

api:

Then, also in configuration.yaml create the following template for the http request against the Audiobookshelf API (generate an API key first)

get_last_played:
    url: "http://192.168.xxx.xxxx:PORT/api/me/items-in-progress?limit=1"
    headers:
      authorization: "Bearer yourAPIkey"

Once that has been set up you can use this automation and tune it to your needs:

alias: Resume Audiobook
description: ""
triggers:
  - trigger: conversation
    command:
      - Play audiobook
conditions: []
actions:
  - action: rest_command.get_last_played
    metadata: {}
    data: {}
    response_variable: continue_book
  - variables:
      book_id: |
        {% if continue_book.content.libraryItems | length > 0 %}
          {{ continue_book.content.libraryItems[0].id }}
        {% else %}
          none
        {% endif %}
      trigger_device: "{{ trigger.device_id }}"
      media_player_entity: |
        {{ (device_entities(trigger_device) 
        | select('search', '^media_player\.') 
        | first).replace('_media_player', '') }}
  - choose:
      - conditions:
          - condition: template
            value_template: "{{ book_id != 'none' }}"
        sequence:
          - action: music_assistant.play_media
            target:
              entity_id: "{{ media_player_entity }}"
            data:
              media_type: audiobook
              media_id: |
                audiobookshelf--YOURAUDIOBOOKSHELFINSTANCEID://audiobook/{{ book_id }}
    default:
      - action: assist_satellite.announce
        metadata: {}
        data:
          message: Couldn't find a book to play
          preannounce: true
        target:
          device_id: "{{ trigger_device }}"
mode: single

I haven’t really fine tuned it (how to handle more than one book being in the last played queue etc.), it is only a proof of concept, but it works and shows the principle of the thing.

You can find out the YOURAUDIOBOOKSHELFINSTANCEID part by going to music assistant, selecting any audiobook hosted on Audiobookshelf, then in then scrolling all the way down and expanding “Provider details”. There you should see the direct link to the item in audiobookshelf along with the audiobook’s uuid and the audiobookshelf instance id.