[Solved] REST sensor for Jellyfin API json, working with arrays

Hello, I have been trying to build a RESTfull sensor for the Jellyfin API.
However, I have some trouble consuming it.

There are multiple states I am interested in knowing about in HA, so I’d like sensors to know when;

  • nothing is playing
  • a single user plays an item (user name and file name)
  • multiple users play items (user name and file name)

The response of the Jellyfin API call

  • when nothing is playing response is empty array:

[]

  • when one user is playing a file, response i:
[
    {
        "PlayState": {
            "PositionTicks": 1194405010,
            "CanSeek": true,
            "IsPaused": false,
            "IsMuted": false,
            "VolumeLevel": 70,
            "AudioStreamIndex": 1,
            "SubtitleStreamIndex": -1,
            "MediaSourceId": "72e99dc9b04b41d6ce6b5343be961a3c",
            "PlayMethod": "DirectPlay",
            "RepeatMode": "RepeatNone"
        },
        "AdditionalUsers": [],
        "Capabilities": {
            "PlayableMediaTypes": [
                "Audio",
                "Video"
            ],
            "SupportedCommands": [
                "MoveUp",
                "MoveDown",
                "MoveLeft",
                "MoveRight",
                "PageUp",
                "PageDown",
                "PreviousLetter",
                "NextLetter",
                "ToggleOsd",
                "ToggleContextMenu",
                "Select",
                "Back",
                "SendKey",
                "SendString",
                "GoHome",
                "GoToSettings",
                "VolumeUp",
                "VolumeDown",
                "Mute",
                "Unmute",
                "ToggleMute",
                "SetVolume",
                "SetAudioStreamIndex",
                "SetSubtitleStreamIndex",
                "DisplayContent",
                "GoToSearch",
                "DisplayMessage",
                "SetRepeatMode",
                "SetShuffleQueue",
                "ChannelUp",
                "ChannelDown",
                "PlayMediaSource",
                "PlayTrailers"
            ],
            "SupportsMediaControl": true,
            "SupportsContentUploading": false,
            "SupportsPersistentIdentifier": false,
            "SupportsSync": false
        },
        "RemoteEndPoint": "192.168.1.22",
        "PlayableMediaTypes": [
            "Audio",
            "Video"
        ],
        "Id": "ca2b2e75e8663e03f44e013db9dde2c6",
        "UserId": "1bbb895fdd65414faa68f54947e25e70",
        **"UserName": "sam",**
        **"Client": "Jellyfin Web",**
        "LastActivityDate": "2023-01-03T18:18:27.2549077Z",
        "LastPlaybackCheckIn": "2023-01-03T18:18:27.2549078Z",
        "DeviceName": "Edge Chromium",
        **"NowPlayingItem": {**
            **"Name": "Keeping the Peace",**
            "ServerId": "43ce93b98b93409dbe3e455b51bcd69f",
            "Id": "72e99dc9b04b41d6ce6b5343be961a3c",
            "DateCreated": "2022-08-30T01:25:08.6139961Z",
            "Container": "mkv,webm",
            "PremiereDate": "2016-11-11T00:00:00.0000000Z",
            "ExternalUrls": [],
            "Path": "/tv_shows/Shaun the Sheep/Season 5/Shaun.The.Sheep.S05E15.Keeping.The.Peace.720p.HDTV.x264-DEADPOOL[rarbg].mkv",
            "EnableMediaSourceDisplay": true,
            "ChannelId": null,
            "Overview": "After spending the night putting together the bed instead of sleeping in it, the farmer has a lie in and Bitzer is in charge of making sure his master's rest is uninterrupted.",
            "Taglines": [],
            "Genres": [],
            "RunTimeTicks": 4196900096,
            "ProductionYear": 2016,
            "IndexNumber": 15,
            "ParentIndexNumber": 5,
            "ProviderIds": {
                "Tvdb": "5544594",
                "sonarr": "2232"
            },
            "IsHD": true,
            "IsFolder": false,
            "ParentId": "47cbd030cd7c72344fa14be1df0a5663",
            "Type": "Episode",
            "Studios": [],
            "GenreItems": [],
            "ParentLogoItemId": "bc5b9f22c4d25fc70fb4b34a7782870e",
            "ParentBackdropItemId": "bc5b9f22c4d25fc70fb4b34a7782870e",
            "ParentBackdropImageTags": [
                "9395732216bb93e70f3bdb09bdd07ca8"
            ],
            "LocalTrailerCount": 0,
            "SeriesName": "Shaun the Sheep",
            "SeriesId": "bc5b9f22c4d25fc70fb4b34a7782870e",
            "SeasonId": "47cbd030cd7c72344fa14be1df0a5663",
            "SpecialFeatureCount": 0,
            "PrimaryImageAspectRatio": 1.7777777777777777,
            "SeriesPrimaryImageTag": "abe249fa5ce31052ae1b84c3a02b11cd",
            "SeasonName": "Season 5",
            "MediaStreams": [
                {
                    "": ""
                },
                {
                    "Codec": "aac",
                    "TimeBase": "1/1000",
                    "DisplayTitle": "AAC - Stereo - Default",
                    "IsInterlaced": false,
                    "ChannelLayout": "stereo",
                    "BitRate": 192000,
                    "Channels": 2,
                    "SampleRate": 48000,
                    "IsDefault": true,
                    "IsForced": false,
                    "Profile": "LC",
                    "Type": "Audio",
                    "Index": 1,
                    "IsExternal": false,
                    "IsTextSubtitleStream": false,
                    "SupportsExternalStream": false,
                    "Level": 0
                }
            ],
            "VideoType": "VideoFile",
            "ImageTags": {
                "Primary": "8892ba0ef1daccdeb8c50f3e03c58860"
            },
            "BackdropImageTags": [],
            "ParentLogoImageTag": "887f9a90b769cbbf45426ee5e55601bd",
            "ImageBlurHashes": {
                "Primary": {
                    "8892ba0ef1daccdeb8c50f3e03c58860": "[email protected]|sQn~fStTtmofoHWBbb",
                    "abe249fa5ce31052ae1b84c3a02b11cd": "dXH:jG.k%|%2x[nlRkxuu2VsXOtQ-:t7tQoy%MoNRRof"
                },
                "Logo": {
                    "887f9a90b769cbbf45426ee5e55601bd": "HCFPB0ay?a-:M|t7-:xu9Z~p-:oe-;xaoe%LofRj"
                },
                "Backdrop": {
                    "9395732216bb93e70f3bdb09bdd07ca8": "WRFr@KtOkW%KNFxutpIVM{WUWURkKUadsDWZjcxaKSj]oyoyWCa|"
                }
            },
            "SeriesStudio": "Netflix",
            "Chapters": [
                {
                    "StartPositionTicks": 0,
                    "Name": "Chapter 1",
                    "ImageDateModified": "0001-01-01T00:00:00.0000000Z"
                }
            ],
            "LocationType": "FileSystem",
            "MediaType": "Video",
            "Width": 1280,
            "Height": 720
        },
        "FullNowPlayingItem": {
            "Size": 75739504,
            "Container": "mkv,webm",
            "IsHD": true,
            "IsShortcut": false,
            "Width": 1280,
            "Height": 720,
            "ExtraIds": [],
            "DateLastSaved": "2022-10-20T21:32:39.039725Z",
            "RemoteTrailers": [],
            "SupportsExternalTransfer": false
        },
        "DeviceId": "7d8587e1-2d7d-4c2e-ba7b-4bfed6732e2d",
        "ApplicationVersion": "10.8.8",
        "IsActive": true,
        "SupportsMediaControl": true,
        "SupportsRemoteControl": true,
        "NowPlayingQueue": [
            {
                "Id": "72e99dc9b04b41d6ce6b5343be961a3c",
                "PlaylistItemId": "playlistItem0"
            },
            {
                "Id": "30c9f5900be30a356dfd0e9c27256695",
                "PlaylistItemId": "playlistItem1"
            }
        ],
        "NowPlayingQueueFullItems": [
            {
               "removed_for_brevity" : true
            }
        ],
        "HasCustomDeviceName": false,
        "PlaylistItemId": "playlistItem0",
        "ServerId": "43ce93b98b93409dbe3e455b51bcd69f",
        "SupportedCommands": [
            "MoveUp",
            "MoveDown",
            "MoveLeft",
            "MoveRight",
            "PageUp",
            "PageDown",
            "PreviousLetter",
            "NextLetter",
            "ToggleOsd",
            "ToggleContextMenu",
            "Select",
            "Back",
            "SendKey",
            "SendString",
            "GoHome",
            "GoToSettings",
            "VolumeUp",
            "VolumeDown",
            "Mute",
            "Unmute",
            "ToggleMute",
            "SetVolume",
            "SetAudioStreamIndex",
            "SetSubtitleStreamIndex",
            "DisplayContent",
            "GoToSearch",
            "DisplayMessage",
            "SetRepeatMode",
            "SetShuffleQueue",
            "ChannelUp",
            "ChannelDown",
            "PlayMediaSource",
            "PlayTrailers"
        ]
    }
]

I have tried the following syntax:

 - platform: rest
    name: DEBUG_1
    method: GET
    resource: https://192.168.1.41:8920/Sessions
    json_attributes_path: $..*
    json_attributes: 
      - name
      - NowPlayingItem
    verify_ssl: false
    headers:
        Authentication: !secret jellyfin_api_token
        
  - platform: rest
    name: DEBUG_2
    method: GET
    resource: https://192.168.1.41:8920/Sessions
   # json_attributes_path: $..NowPlayingItem.*
    verify_ssl: false
    value_template: "{{ value_json.NowPlayingItem.Name }}"
    headers:
        Accept: application/json
        Authentication: !secret jellyfin_api_token

  - platform: rest
    name: DEBUG_3
    method: GET
    resource: https://192.168.1.41:8920/Sessions
    json_attributes: 
      - NowPlayingItem
    verify_ssl: false
    headers:
        Authentication: !secret jellyfin_api_token

But I am not sure how to continue; I am not sure what sensor is actually want.
How would I build this ? Ideas / tips welcome.

note: i use hardcoded IP as resource, because a DNS resolve issue

I have found a workaround using command_line sensor

Jellyfin REST API sensor - Configuration - Home Assistant Community (home-assistant.io)

1 Like

This might help you. I use a rest sensor to get the dates of my bin collections, like so:-

- platform: rest
  name: bin_collection_restful
  resource: somewebsite
  timeout: 15
  scan_interval: 86400
  json_attributes:
    - label
    - Results
  value_template: 'OK'

Note the value template is irrelevant to me at this stage, its only when I build a template sensor from it that I extract what I need:-

- sensor:
    - name: "Bin Collection Address"
      unique_id: bin_collection_address
      state: "{{ states.sensor.bin_collection_restful.attributes['label'] }}"

- sensor:
    - name: "Recycling Collection Date"
      unique_id: recycling_collection_date
      state: >
        {% set recycling_date  = states.sensor.bin_collection_restful.attributes["Results"].split('<br/>')[1].split('</em>')[0] %}
        {{recycling_date}}

Thank you :slight_smile:

The problem was the data is variable; every connected clients gets a Session, but not all get a NowPlayingItem, and the NowPlayingItem. So we have 0:N of those. I wasn’t able to get all of them, I kept getting only the first result.
Now (not in this post) i need to go check in another node if it is a movie or a series name i need to get so i am just needing to make a nice template

Can you share your complete template? I would love to do exactly what you are doing

@Technologyman00
Over time i changed it a bit as it did not work for multiple states.

I am still not happy about having to input names manually, but hey it works and its not THAT dynamic.

You can duplicate the TV part sensor per user.

rest:
    -  resource: http://192.168.1.2:8096/Sessions?activeWithinSeconds=30   
       headers:
        Authorization: !secret jellyfin_api_token
       scan_interval: 30
       
       sensor:
         - name: "Jelly_active"
           value_template: "{{ value_json | selectattr('NowPlayingItem', 'defined') | list | length }}"
         
         - name: "Jelly_TV"
           value_template: >
             {% set user = value_json | selectattr('UserName', 'equalto', 'TV') | first %}
             {% if user is defined and user.NowPlayingItem is defined %}
               playing
             {% else %}
               not playing
             {% endif %}
           json_attributes_path: "$[?(@.UserName == 'TV' && @.NowPlayingItem)]..NowPlayingItem"
           json_attributes:
             - Name
             - SeriesName
1 Like