Audiobookshelf Integration

I feel like this shouldn’t be too difficult, particularly with the API being so well documented. I just don’t have the programming chops to do it. Anyone feel up to looking into it?

https://api.audiobookshelf.org/

Thanks

10 Likes

What would you expect it to do? Would it show sessions or library stats, and would it be connected to a particular user or all users?

1 Like

I would love to cast to a google device or wifi speaker.

2 Likes

I’d really love this as well.

It would be nice to be able to connect a user account and then use ha to direct that to media players around the house, just as with other media sources.

looks like someone started developing:

If the developer is reading this, where do you want to go with this integration?

I’d personally really like to see the bookshelf as media source, but even if I like collecting data, I can’t see any other interesting feature.
Of course this would have to work for non-admin users as well to somehow connect the HA user to the ABS user and track the progress.

2 Likes

I’ve added a combination of sensors that ultimately returns whether or not a user is listening to media from either AudioBookShelf or Spotify and the book/authur or track/artist currently playing. This is probably a really clunky way to do it, but it works. I don’t know what the real use case for it is, other than just fun. I did it so that my person cards on my dashboards could have headphones on and media info when they’re using either service. Again, not expressly useful, but fun. Code for sensors is below. Basically you create two rest sensors that pull data from ABS via api. One pulls the list of current online users, and the other pulls listening session data for all users. Then there’s a template sensor FOR EACH USER which parses the ABS information and determines if your chosen user is online and if they are, what they’re listening to. Last is another template sensor which checks the ABS template sensor and entities from the spotify integration, to determine if the user is actively listening to either. If the user is not listening at all, the sensor returns not listening. If the user is listening to either service, the sensor returns the appropriate media info.

  - platform: rest
    name: ABS Online Users
    resource: http://(ABS SERVER:PORT)/api/users/online?token=(ROOT USER API TOKEN)
    value_template: "{{ value_json.usersOnline | length }}"
    json_attributes:
      - usersOnline
    scan_interval: 15

#Rest sensor to get listenings sessions info for all users from ABS via api    
  - platform: rest
    name: ABS User Listening Sessions
    resource: http://(ABS SERVER:PORT)/api/users/(USER ID)/listening-sessions?token=(ROOT USER API TOKEN)
    value_template: "{{ value_json.sessions | length }}"
    json_attributes:
      - sessions
    scan_interval: 15
	
# Template sensor for ABS active listening session
    - name: "ABS user Active Session"
      state: >
          {% set user_id = '(USER ID)' %}
          {% set users_online = state_attr('sensor.abs_online_users', 'usersOnline') %}
          {% set sessions = state_attr('sensor.abs_user_listening_sessions', 'sessions') %}
          
          {% if users_online is not none and sessions is not none %}
            {% set user_online = users_online | selectattr('id', 'equalto', user_id) | list %}
            
            {% if user_online | length > 0 %}
              {% if sessions | length > 0 %}
                {% set session = sessions[0] %}
                
                {% if session.mediaMetadata and session.mediaMetadata.authors %}
                  📖 "{{ session.mediaMetadata.title }}" by {{ session.mediaMetadata.authors[0].name }}
                {% else %}
                  Active session with missing media metadata
                {% endif %}
              {% else %}
                No sessions found
              {% endif %}
            {% else %}
              Not Listening
            {% endif %}
          {% else %}
            No data
          {% endif %}
      unique_id: "abs_user_active_session"
	  
# Template sensor for name of media being played by user
    - name: "user Media Playing"
      state: >
          {% set abs_state = states('sensor.abs_user_active_session') %}
          {% set spotify_state = states('media_player.spotify_user') %}
          {% set spotify_title = state_attr('media_player.spotify_user', 'media_title') %}
          {% set spotify_artist = state_attr('media_player.spotify_user', 'media_artist') %}
          {% if abs_state != 'Not Listening' and abs_state != 'unknown' %}
             {{ abs_state }}
          {% elif spotify_state == 'playing' and spotify_title != none and spotify_artist != none %}
            🎵 {{ spotify_title }} - {{ spotify_artist }}
          {% else %}
            Not Listening
          {% endif %}
      unique_id: "user_media_playing"

Sorry for the poor quality gif conversion, but you get the idea.
personcard

1 Like

What would be amazing would be a media source component that connects to ABS, pulls in items from the library, allows you to play them, and syncs the listening progress with ABS.

I tried my hand at it, and got a proof of concept that could play an item. However, I’m totally stumped at how to do the progress part. It looks like you can only give HA the item to play but not where to start. I tried adding a timestamp to the URL (e.g. #t=206) which worked in the browser player, but not with Chromecast (which would be my use case). :frowning:

Besides the fact that I am a reformed developer and haven’t done hardcore coding in 5 years now. And even then, I was a Microsoft dev primarily. So I’m afraid creating an integration is likely beyond me.

Sharing in case it gives anyone who is better skilled inspiration. Otherwise, I may still tinker and if I come up with something worth sharing, I’ll do that.

1 Like

I had another couple of ideas, but I’ve hit dead ends and as hardheaded as I am, I still think I’m giving up this fight.

One idea: if the media source was completed, we could use an Event triggered automation to sync the progress. Like:

triggers:
  - trigger: event
    event_type: state_changed
conditions:
  - condition: template
    value_template: >-
      {{ trigger.event.data.entity_id.startswith('media_player.') and
      trigger.event.data.new_state.state == 'playing' and
      trigger.event.data.new_state.state != trigger.event.data.old_state.state
      }}
actions:
  - action: media_player.media_seek
    metadata: {}
    data:
      seek_position: 300
    target:
      entity_id: "{{trigger.event.data.entity_id}}"
mode: single

That does work. It needs to look up the seek_position value, but that’s probably doable.

However, next I tried a similar automation to obtain the progress for saving back to ABS. That is possible…but only if the playing media is paused. If you stop it or power off the media player, the progress does not get captured. That’s a pretty big limitation I don’t know how to get around.

I was having fantasies about being able to do something like this…which is almost possible but not quite. :frowning:

action: media_player.play_media
target:
  entity_id:
    - media_player.office_chromecast
data:
  media_content_id: media-source://audiobookshelf/podcasts/mypodcast/latest
  media_content_type: audio/mpeg

I would love an integration with audiobookshelf. To be able to track all books listened to (completed and in progress for each user), current play status, and Library metrics.
I will check out hass-audiobookself integration.