views.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import json
  2. import logging
  3. from datetime import datetime, timedelta
  4. from dateutil.parser import parse
  5. from django.conf import settings
  6. from django.db.models.fields import timezone
  7. from django.views.decorators.csrf import csrf_exempt
  8. from django.views.generic.list import ListView
  9. from rest_framework import status
  10. from rest_framework.decorators import api_view
  11. from rest_framework.response import Response
  12. from scrobbles.models import Scrobble
  13. from scrobbles.serializers import ScrobbleSerializer
  14. from videos.models import Series, Video
  15. logger = logging.getLogger(__name__)
  16. TRUTHY_VALUES = [
  17. 'true',
  18. '1',
  19. 't',
  20. 'y',
  21. 'yes',
  22. 'yeah',
  23. 'yup',
  24. 'certainly',
  25. 'uh-huh',
  26. ]
  27. class RecentScrobbleList(ListView):
  28. model = Scrobble
  29. def get_queryset(self):
  30. return Scrobble.objects.filter(in_progress=False)
  31. @csrf_exempt
  32. @api_view(['GET'])
  33. def scrobble_endpoint(request):
  34. """List all Scrobbles, or create a new Scrobble"""
  35. scrobble = Scrobble.objects.all()
  36. serializer = ScrobbleSerializer(scrobble, many=True)
  37. return Response(serializer.data)
  38. @csrf_exempt
  39. @api_view(['POST'])
  40. def jellyfin_websocket(request):
  41. data_dict = request.data
  42. media_type = data_dict["ItemType"]
  43. # Check if it's a TV Episode
  44. video_dict = {
  45. "title": data_dict["Name"],
  46. "imdb_id": data_dict["Provider_imdb"],
  47. "video_type": Video.VideoType.MOVIE,
  48. "year": data_dict["Year"],
  49. }
  50. if media_type == 'Episode':
  51. series_name = data_dict["SeriesName"]
  52. series, series_created = Series.objects.get_or_create(name=series_name)
  53. video_dict['video_type'] = Video.VideoType.TV_EPISODE
  54. video_dict["tv_series_id"] = series.id
  55. video_dict["episode_number"] = data_dict["EpisodeNumber"]
  56. video_dict["season_number"] = data_dict["SeasonNumber"]
  57. video_dict["tvdb_id"] = data_dict.get("Provider_tvdb", None)
  58. video_dict["tvrage_id"] = data_dict.get("Provider_tvrage", None)
  59. video, video_created = Video.objects.get_or_create(**video_dict)
  60. if video_created:
  61. video.overview = data_dict["Overview"]
  62. video.tagline = data_dict["Tagline"]
  63. video.run_time_ticks = data_dict["RunTimeTicks"]
  64. video.run_time = data_dict["RunTime"]
  65. video.save()
  66. # Now we run off a scrobble
  67. timestamp = parse(data_dict["UtcTimestamp"])
  68. scrobble_dict = {
  69. 'video_id': video.id,
  70. 'user_id': request.user.id,
  71. 'in_progress': True,
  72. }
  73. existing_finished_scrobble = (
  74. Scrobble.objects.filter(
  75. video=video, user_id=request.user.id, in_progress=False
  76. )
  77. .order_by('-modified')
  78. .first()
  79. )
  80. minutes_from_now = timezone.now() + timedelta(minutes=15)
  81. if (
  82. existing_finished_scrobble
  83. and existing_finished_scrobble.modified < minutes_from_now
  84. ):
  85. logger.info(
  86. 'Found a scrobble for this video less than 15 minutes ago, holding off scrobbling again'
  87. )
  88. return Response(video_dict, status=status.HTTP_204_NO_CONTENT)
  89. scrobble, scrobble_created = Scrobble.objects.get_or_create(
  90. **scrobble_dict
  91. )
  92. if scrobble_created:
  93. # If we newly created this, capture the client we're watching from
  94. scrobble.source = data_dict['ClientName']
  95. scrobble.source_id = data_dict['MediaSourceId']
  96. else:
  97. last_tick = scrobble.playback_position_ticks
  98. # Update a found scrobble with new position and timestamp
  99. scrobble.playback_position_ticks = data_dict["PlaybackPositionTicks"]
  100. scrobble.playback_position = data_dict["PlaybackPosition"]
  101. scrobble.timestamp = parse(data_dict["UtcTimestamp"])
  102. scrobble.is_paused = data_dict["IsPaused"] in TRUTHY_VALUES
  103. scrobble.save()
  104. # If we hit our completion threshold, save it and get ready
  105. # to scrobble again if we re-watch this.
  106. if scrobble.percent_played >= getattr(
  107. settings, "PERCENT_FOR_COMPLETION", 95
  108. ):
  109. scrobble.in_progress = False
  110. scrobble.playback_position_ticks = video.run_time_ticks
  111. scrobble.save()
  112. if scrobble.percent_played % 5 == 0:
  113. logger.info(f"You are {scrobble.percent_played}% through {video}")
  114. return Response(video_dict, status=status.HTTP_201_CREATED)