Ver código fonte

[videos] Add youtube scrobbling

Colin Powell 6 meses atrás
pai
commit
1b95706f70

+ 1 - 1
vrobbler/apps/scrobbles/models.py

@@ -1186,7 +1186,7 @@ class Scrobble(TimeStampedModel):
         profile = UserProfile.objects.filter(
             user_id=scrobble_data["user_id"]
         ).first()
-        if profile.ntfy_enabled and profile.ntfy_url:
+        if profile and profile.ntfy_enabled and profile.ntfy_url:
             # TODO allow prority and tags to be configured in the profile
             notify_str = f"{scrobble.media_obj}"
             if scrobble.log and scrobble.log.get("description"):

+ 44 - 0
vrobbler/apps/scrobbles/scrobblers.py

@@ -2,6 +2,7 @@ import logging
 import re
 from typing import Optional
 
+from datetime import datetime
 import pendulum
 import pytz
 from beers.models import Beer
@@ -133,6 +134,49 @@ def jellyfin_scrobble_media(
     )
 
 
+def web_scrobbler_scrobble_media(
+    post_data: dict, user_id: int
+) -> Optional[Scrobble]:
+    media_type = Scrobble.MediaType.VIDEO
+
+    event_name = post_data.get("eventName")
+    parsed = post_data.get("data").get("song").get("parsed")
+    processed = post_data.get("data").get("song").get("processed")
+    video, created = Video.objects.get_or_create(
+        video_type=Video.VideoType.YOUTUBE, 
+        youtube_url=parsed.get("originUrl"),
+    )
+    timestamp = datetime.utcfromtimestamp(
+        post_data.get("time", 0)/1000
+    ).replace(tzinfo=pytz.utc)
+
+    if created or event_name == "nowplaying":
+        video.run_time_seconds = 1800
+        processed = post_data.get("data").get("song").get("processed")
+        # TODO maybe artist could be the series?
+        video.title = " - ".join([processed.get("artist"), processed.get("track")])
+        video.save()
+        return video.scrobble_for_user(
+            user_id,
+            source="YouTube",
+            playback_position_seconds=0,
+            status=event_name,
+        )
+
+    scrobble = Scrobble.objects.filter(user_id=user_id, video=video, in_progress=True).first()
+    if not scrobble:
+        return video.scrobble_for_user(
+            user_id,
+            source="YouTube",
+            playback_position_seconds=0,
+            status=event_name,
+        )
+    if event_name == "paused":
+        scrobble.pause()
+    if event_name == "resumedplaying":
+        scrobble.resume()
+    return scrobble
+
 def manual_scrobble_video(imdb_id: str, user_id: int):
     if "tt" not in imdb_id:
         imdb_id = "tt" + imdb_id

+ 5 - 0
vrobbler/apps/scrobbles/urls.py

@@ -31,6 +31,11 @@ urlpatterns = [
         views.lastfm_import,
         name="lastfm-import",
     ),
+    path(
+        "webhook/web-scrobbler/",
+        views.web_scrobbler_webhook,
+        name="web-scrobbler-webhook",
+    ),
     path(
         "webhook/gps/",
         views.gps_webhook,

+ 23 - 0
vrobbler/apps/scrobbles/views.py

@@ -314,6 +314,29 @@ def lastfm_import(request):
 
     return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
 
+@csrf_exempt
+@permission_classes([IsAuthenticated])
+@api_view(["POST"])
+def web_scrobbler_webhook(request):
+    post_data = request.data
+    logger.info(
+        "[web_scrobbler_webhook] called",
+        extra={
+            "post_data": post_data,
+            "user_id": request.user.id,
+        },
+    )
+
+    scrobble = web_scrobbler_scrobble_media(post_data, request.user.id)
+
+    if not scrobble:
+        return Response({}, status=status.HTTP_400_BAD_REQUEST)
+
+    logger.info(
+        "[jellyfin_webhook] finished",
+        extra={"scrobble_id": scrobble.id},
+    )
+    return Response({"scrobble_id": scrobble.id}, status=status.HTTP_200_OK)
 
 @csrf_exempt
 @permission_classes([IsAuthenticated])

+ 33 - 0
vrobbler/apps/videos/migrations/0018_video_youtube_url_alter_video_video_type.py

@@ -0,0 +1,33 @@
+# Generated by Django 4.2.16 on 2024-11-06 03:07
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("videos", "0017_alter_video_video_type"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="video",
+            name="youtube_url",
+            field=models.CharField(blank=True, max_length=255, null=True),
+        ),
+        migrations.AlterField(
+            model_name="video",
+            name="video_type",
+            field=models.CharField(
+                choices=[
+                    ("U", "Unknown"),
+                    ("E", "TV Episode"),
+                    ("M", "Movie"),
+                    ("S", "Skate Video"),
+                    ("Y", "YouTube Video"),
+                ],
+                default="U",
+                max_length=1,
+            ),
+        ),
+    ]

+ 2 - 0
vrobbler/apps/videos/models.py

@@ -128,6 +128,7 @@ class Video(ScrobblableMixin):
         TV_EPISODE = "E", _("TV Episode")
         MOVIE = "M", _("Movie")
         SKATE_VIDEO = "S", _("Skate Video")
+        YOUTUBE = "Y", _("YouTube Video")
 
     video_type = models.CharField(
         max_length=1,
@@ -161,6 +162,7 @@ class Video(ScrobblableMixin):
     tvrage_id = models.CharField(max_length=20, **BNULL)
     tvdb_id = models.CharField(max_length=20, **BNULL)
     tmdb_id = models.CharField(max_length=20, **BNULL)
+    youtube_url = models.CharField(max_length=255, **BNULL)
     plot = models.TextField(**BNULL)
     year = models.IntegerField(**BNULL)