Org Web Adapter

pages/vrobbler.org

ID
89b6e1e6-411f-4a0b-bb6d-1944b3083372

Vrobbler

A basic webhook consumer for Jellyfin's media and Mopidy's music

Design

At it's most basic, Vrobbler presents a frontend for browing through peronal data related to "scrobbled" media, and a handful of endpoints for services to post data to the service for getting playback history into the database.

One of the design goals is to keep the layout of data super clear so it's possible to manipulate data via the database, not just the Django webapp that imports all of it.

Debugging info

#+begin_src python

import json

from flask import Flask, request

app = Flask(__name__)

@app.route("/webhook", methods=["POST", "GET"])

def webhook():

data_dict = json.loads(request.data.decode("utf-8"))

try:

run_time_ticks = data_dict["RunTimeTicks"]

play_back_ticks = data_dict["PlaybackPositionTicks"]

play_percent = int((play_back_ticks / run_time_ticks) * 100)

episode_num = data_dict["EpisodeNumber"]

season_num = data_dict["SeasonNumber"]

show_name = data_dict["SeriesName"]

app.logger.info(

f"You are {play_percent}% through an episode {episode_num} of season {season_num} of {show_name}"

)

except:

pass

return "Webhook received!"

app.run(host="0.0.0.0", port=8000, debug=True)

#+end_src

What Jellyfin dumps via the Webhook plugin

#+begin_src json

{

"ServerId": "2f31a8e3d3e9416a91df2ed5f0e9dfb2",

"ServerName": "jellyfin1",

"ServerVersion": "10.8.8",

"ServerUrl": "",

"NotificationType": "PlaybackStop",

"Timestamp": "2023-01-04T14:42:36.4243951-05:00",

"UtcTimestamp": "2023-01-04T19:42:36.4243987Z",

"Name": "Daybreak",

"Overview": "John Dutton, patriarch of a Montana ranching family and owner of the largest ranch in the U.S., fights to defend his land and his family from the modern-day forces that threaten his way of life; land developers, an Indian reservation and America\\u0027s first National Park.",

"Tagline": "",

"ItemId": "74eafb665657e902a34b4c78c779472b",

"ItemType": "Episode",

"RunTimeTicks": 55637880832,

"RunTime": "01:32:43",

"Year": 2018,

"SeriesName": "Yellowstone (2018)",

"SeasonNumber": 1,

"SeasonNumber00": "01",

"SeasonNumber000": "001",

"EpisodeNumber": 1,

"EpisodeNumber00": "01",

"EpisodeNumber000": "001",

"Provider_tvdb": "6507316",

"Provider_imdb": "tt7529124",

"Provider_tvrage": "785164",

"Video_0_Title": "720p H264 SDR",

"Video_0_Type": "Video",

"Video_0_Codec": "h264",

"Video_0_Profile": "Main",

"Video_0_Level": 31,

"Video_0_Height": 720,

"Video_0_Width": 1280,

"Video_0_AspectRatio": "2:1",

"Video_0_Interlaced": false,

"Video_0_FrameRate": 23.976025,

"Video_0_VideoRange": "SDR",

"Video_0_ColorSpace": "bt709",

"Video_0_ColorTransfer": "bt709",

"Video_0_ColorPrimaries": "bt709",

"Video_0_PixelFormat": "yuv420p",

"Video_0_RefFrames": 1,

"Audio_0_Title": "Stereo - English - AAC - Default",

"Audio_0_Type": "Audio",

"Audio_0_Language": "eng",

"Audio_0_Codec": "aac",

"Audio_0_Channels": 2,

"Audio_0_Bitrate": 192000,

"Audio_0_SampleRate": 48000,

"Audio_0_Default": true,

"Subtitle_0_Title": "English - ASS",

"Subtitle_0_Type": "Subtitle",

"Subtitle_0_Language": "eng",

"Subtitle_0_Codec": "ass",

"Subtitle_0_Default": false,

"Subtitle_0_Forced": false,

"Subtitle_0_External": false,

"PlaybackPositionTicks": 7820973099,

"PlaybackPosition": "00:13:02",

"MediaSourceId": "74eafb665657e902a34b4c78c779472b",

"IsPaused": false,

"IsAutomated": false,

"DeviceId": "TW96aWxsYS81LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTAuMTU7IHJ2OjEwNi4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEwNi4wfDE2NjgyMjI3MDAxODk1",

"DeviceName": "Firefox",

"ClientName": "Jellyfin Web",

"PlayedToCompletion": false,

"NotificationUsername": "secstate",

"UserId": "f78f0902128343e7957593c976636419"

}

#+end_src

#+begin_src json

{

"ServerId": "2f31a8e3d3e9416a91df2ed5f0e9dfb2",

"ServerName": "jellyfin1",

"ServerVersion": "10.8.8",

"ServerUrl": "",

"NotificationType": "PlaybackProgress",

"Timestamp": "2023-01-04T17:04:24.5253584-05:00",

"UtcTimestamp": "2023-01-04T22:04:24.5253596Z",

"Name": "That Darn Cat!",

"Overview": "A young woman suspects foul play when her cat comes home wearing a wristwatch. Convincing the FBI, though, and catching the bad guys is tougher than she imagined.",

"Tagline": "It takes a Siamese secret agent to unravel the PURR-fect crime!",

"ItemId": "77c6c3a53082a68896fb2823702314cf",

"ItemType": "Movie",

"RunTimeTicks": 69870510080,

"RunTime": "01:56:27",

"Year": 1965,

"Provider_tmdb": "20723",

"Provider_imdb": "tt0059793",

"Video_0_Title": "720p H264 SDR",

"Video_0_Type": "Video",

"Video_0_Codec": "h264",

"Video_0_Profile": "High",

"Video_0_Level": 41,

"Video_0_Height": 726,

"Video_0_Width": 1280,

"Video_0_AspectRatio": "16:9",

"Video_0_Interlaced": false,

"Video_0_FrameRate": 23.976025,

"Video_0_VideoRange": "SDR",

"Video_0_ColorSpace": "bt709",

"Video_0_ColorTransfer": "bt709",

"Video_0_ColorPrimaries": "bt709",

"Video_0_PixelFormat": "yuv420p",

"Video_0_RefFrames": 1,

"Audio_0_Title": "AAC - Stereo - Default",

"Audio_0_Type": "Audio",

"Audio_0_Language": "und",

"Audio_0_Codec": "aac",

"Audio_0_Channels": 2,

"Audio_0_Bitrate": 128459,

"Audio_0_SampleRate": 48000,

"Audio_0_Default": true,

"PlaybackPositionTicks": 32384675839,

"PlaybackPosition": "00:53:58",

"MediaSourceId": "77c6c3a53082a68896fb2823702314cf",

"IsPaused": false,

"IsAutomated": false,

"DeviceId": "TW96aWxsYS81LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTAuMTU7IHJ2OjEwNi4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzEwNi4wfDE2NjgyMjI3MDAxODk1",

"DeviceName": "Firefox",

"ClientName": "Jellyfin Web",

"NotificationUsername": "secstate",

"UserId": "f78f0902128343e7957593c976636419"

}

#+end_src