models.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import logging
  2. from typing import Dict
  3. from uuid import uuid4
  4. from django.conf import settings
  5. from django.db import models
  6. from django.urls import reverse
  7. from django.utils.translation import gettext_lazy as _
  8. from django_extensions.db.models import TimeStampedModel
  9. from scrobbles.utils import convert_to_seconds
  10. from scrobbles.mixins import ScrobblableMixin
  11. logger = logging.getLogger(__name__)
  12. BNULL = {"blank": True, "null": True}
  13. class Series(TimeStampedModel):
  14. uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
  15. name = models.CharField(max_length=255)
  16. overview = models.TextField(**BNULL)
  17. tagline = models.TextField(**BNULL)
  18. # tvdb_id = models.CharField(max_length=20, **BNULL)
  19. # imdb_id = models.CharField(max_length=20, **BNULL)
  20. def __str__(self):
  21. return self.name
  22. def imdb_link(self):
  23. return f"https://www.imdb.com/title/{self.imdb_id}"
  24. class Meta:
  25. verbose_name_plural = "series"
  26. class Video(ScrobblableMixin):
  27. COMPLETION_PERCENT = getattr(settings, 'VIDEO_COMPLETION_PERCENT', 90)
  28. class VideoType(models.TextChoices):
  29. UNKNOWN = 'U', _('Unknown')
  30. TV_EPISODE = 'E', _('TV Episode')
  31. MOVIE = 'M', _('Movie')
  32. video_type = models.CharField(
  33. max_length=1,
  34. choices=VideoType.choices,
  35. default=VideoType.UNKNOWN,
  36. )
  37. overview = models.TextField(**BNULL)
  38. tagline = models.TextField(**BNULL)
  39. year = models.IntegerField(**BNULL)
  40. # TV show specific fields
  41. tv_series = models.ForeignKey(Series, on_delete=models.DO_NOTHING, **BNULL)
  42. season_number = models.IntegerField(**BNULL)
  43. episode_number = models.IntegerField(**BNULL)
  44. tvdb_id = models.CharField(max_length=20, **BNULL)
  45. imdb_id = models.CharField(max_length=20, **BNULL)
  46. tvrage_id = models.CharField(max_length=20, **BNULL)
  47. class Meta:
  48. unique_together = [['title', 'imdb_id']]
  49. def __str__(self):
  50. if self.video_type == self.VideoType.TV_EPISODE:
  51. return f"{self.tv_series} - Season {self.season_number}, Episode {self.episode_number}"
  52. return self.title
  53. def get_absolute_url(self):
  54. return reverse("videos:video_detail", kwargs={'slug': self.uuid})
  55. @property
  56. def imdb_link(self):
  57. return f"https://www.imdb.com/title/{self.imdb_id}"
  58. @classmethod
  59. def find_or_create(cls, data_dict: Dict) -> "Video":
  60. """Given a data dict from Jellyfin, does the heavy lifting of looking up
  61. the video and, if need, TV Series, creating both if they don't yet
  62. exist.
  63. """
  64. video_dict = {
  65. "title": data_dict.get("Name", ""),
  66. "imdb_id": data_dict.get("Provider_imdb", None),
  67. "video_type": Video.VideoType.MOVIE,
  68. }
  69. series = None
  70. if data_dict.get("ItemType", "") == "Episode":
  71. series_name = data_dict.get("SeriesName", "")
  72. series, series_created = Series.objects.get_or_create(
  73. name=series_name
  74. )
  75. if series_created:
  76. logger.debug(f"Created new series {series}")
  77. else:
  78. logger.debug(f"Found series {series}")
  79. video_dict['video_type'] = Video.VideoType.TV_EPISODE
  80. video, created = cls.objects.get_or_create(**video_dict)
  81. run_time_ticks = data_dict.get("RunTimeTicks", None)
  82. if run_time_ticks:
  83. run_time_ticks = run_time_ticks // 10000
  84. video_extra_dict = {
  85. "year": data_dict.get("Year", ""),
  86. "overview": data_dict.get("Overview", None),
  87. "tagline": data_dict.get("Tagline", None),
  88. "run_time_ticks": run_time_ticks,
  89. "run_time": convert_to_seconds(data_dict.get("RunTime", "")),
  90. "tvdb_id": data_dict.get("Provider_tvdb", None),
  91. "tvrage_id": data_dict.get("Provider_tvrage", None),
  92. "episode_number": data_dict.get("EpisodeNumber", None),
  93. "season_number": data_dict.get("SeasonNumber", None),
  94. }
  95. if series:
  96. video_extra_dict["tv_series_id"] = series.id
  97. if not video.run_time_ticks:
  98. logger.debug(f"Created new video: {video}")
  99. for key, value in video_extra_dict.items():
  100. setattr(video, key, value)
  101. video.save()
  102. else:
  103. logger.debug(f"Found video {video}")
  104. return video