Files
mopidy-webhooks/mopidy_webhooks/frontend.py

137 lines
5.1 KiB
Python

import logging
import time
import json
from typing import Optional
import pykka
import requests
from mopidy.core import CoreListener
logger = logging.getLogger(__name__)
class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
def __init__(self, config, core):
super().__init__()
self.config = config
self.webhook_urls = []
self.last_start_time = None
def on_start(self):
self.webhook_urls = self.config["webhooks"]["urls"].split(",")
self.webhook_tokens = self.config["webhooks"]["tokens"].split(",")
logger.info(f"Parsing webhook URLs and tokens: {self.webhook_urls}")
def _build_post_data(self, track, time_position: Optional[int]=None) -> dict:
artists = ", ".join(sorted([a.name for a in track.artists]))
artists_list = [a for a in track.artists]
try:
musicbrainz_artist_id = artists_list[0].musicbrainz_id
except IndexError:
musicbrainz_artist_id = None
duration = track.length and track.length // 1000 or 0
album_name = ""
if track.album:
album_name = getattr(track.album, "name")
return {
"name": track.name,
"artist": artists,
"album": album_name,
"track_number": track.track_no,
"run_time_ticks": track.length,
"run_time": str(duration),
"playback_time_ticks": time_position,
"musicbrainz_track_id": track.musicbrainz_id if track.album else "",
"musicbrainz_album_id": track.album.musicbrainz_id if track.album else "",
"musicbrainz_artist_id": musicbrainz_artist_id,
"mopidy_uri": track.uri,
"primary_artist_mopidy_uri": artists_list[0].uri,
}
def _post_update_to_webhooks(self, post_data: dict, status: str):
post_data["status"] = status
for index, webhook_url in enumerate(self.webhook_urls):
token = ""
headers = {}
try:
token = self.webhook_tokens[index]
except IndexError:
logger.info(f"No token found for Webhook URL: {webhook_url}")
if token:
headers["Authorization"] = f"Token {token}"
response = requests.post(
webhook_url, json=json.dumps(post_data), headers=headers
)
logger.info(response)
def track_playback_started(self, tl_track):
track = tl_track.track
artists = ", ".join(sorted([a.name for a in track.artists]))
self.last_start_time = int(time.time())
logger.debug(f"Now playing track: {artists} - {track.name}")
post_data = self._build_post_data(tl_track.track, time_position=0)
# Build post data to send to urls
if not self.webhook_urls:
logger.info("No webhook URLS are configured ")
return
logger.info(f"Scrobbling via webhooks: {artists} - {track.name}")
self._post_update_to_webhooks(post_data, "started")
def track_playback_ended(self, tl_track, time_position):
track = tl_track.track
artists = ", ".join(sorted([a.name for a in track.artists]))
duration = track.length and track.length // 1000 or 0
time_position_sec = time_position // 1000
post_data = self._build_post_data(tl_track.track, time_position=time_position)
if time_position_sec < duration // 2 and time_position_sec < 240:
logger.debug(
"Track not played long enough to scrobble. (50% or 240s)"
)
return
if self.last_start_time is None:
self.last_start_time = int(time.time()) - duration
logger.info(
f"Scrobbling finished via webhooks: {artists} - {track.name}"
)
self._post_update_to_webhooks(post_data, "stopped")
def track_playback_paused(self, tl_track, time_position):
track = tl_track.track
artists = ", ".join(sorted([a.name for a in track.artists]))
duration = track.length and track.length // 1000 or 0
time_position_sec = time_position // 1000
post_data = self._build_post_data(tl_track.track, time_position=time_position)
if self.last_start_time is None:
self.last_start_time = int(time.time()) - duration
logger.info(
f"Scrobbling paused via webhooks: {artists} - {track.name}"
)
self._post_update_to_webhooks(post_data, "paused")
def track_playback_resumed(self, tl_track, time_position):
track = tl_track.track
artists = ", ".join(sorted([a.name for a in track.artists]))
self.last_start_time = int(time.time())
logger.debug(f"Now resuming track: {artists} - {track.name}")
post_data = self._build_post_data(tl_track.track, time_position=time_position)
# Build post data to send to urls
if not self.webhook_urls:
logger.info("No webhook URLS are configured ")
return
logger.info(f"Scrobbling via webhooks: {artists} - {track.name}")
self._post_update_to_webhooks(post_data, "resumed")