Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a4ef678a8 | |||
| 5ca22efeaa | |||
| 912ea8bfac | |||
| b541e1084d | |||
| c9b9da4abc |
10
PROJECT.org
10
PROJECT.org
@ -498,7 +498,8 @@ needed import celery task. This is how the WebDAV celery task currently works.
|
||||
This would also be an opporunity to clean up the code around WebDAV imports
|
||||
and make them more re-usable for other import services.
|
||||
|
||||
** TODO [#B] Add OMDB source as backup when TMDB returns nothing :videos:metadata:imdb:
|
||||
* Version 47.2 [1/1]
|
||||
** DONE [#B] Add OMDB source as backup when TMDB returns nothing :videos:metadata:imdb:
|
||||
:PROPERTIES:
|
||||
:ID: 20195445-7fdd-49be-9767-103b12da0bfb
|
||||
:END:
|
||||
@ -512,6 +513,13 @@ epiodes up in three parts, while they were always broadcast three-in-one, and
|
||||
that's how IMDB lists them. Thus, the IMDB ID means nothing, and the videos end
|
||||
up unenriched.
|
||||
|
||||
|
||||
* Version 47.1 [1/1]
|
||||
** DONE [#A] Untangle the sports migrations errors :sports:bug:migrations:
|
||||
:PROPERTIES:
|
||||
:ID: 4d50ca2e-f45b-dde8-e3c9-cd84f353b349
|
||||
:END:
|
||||
|
||||
* Version 47.0 [1/1]
|
||||
** DONE [#B] Change sports scrobbling a bit :feature:sports:scrobbles:
|
||||
:PROPERTIES:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "vrobbler"
|
||||
version = "47.0"
|
||||
version = "47.2"
|
||||
description = ""
|
||||
authors = ["Colin Powell <colin@unbl.ink>"]
|
||||
|
||||
|
||||
@ -108,20 +108,4 @@ class Migration(migrations.Migration):
|
||||
migrations.RunPython(
|
||||
migrate_sport_event_data, reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="home_team",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="away_team",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="player_one",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="player_two",
|
||||
),
|
||||
]
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("sports", "0021_team_logo"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="home_team",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="away_team",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="player_one",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="sportevent",
|
||||
name="player_two",
|
||||
),
|
||||
]
|
||||
@ -71,6 +71,7 @@ class VideoMetadata:
|
||||
twitch_id: Optional[str] = "",
|
||||
base_run_time_seconds: int = 900,
|
||||
):
|
||||
self.title = ""
|
||||
self.imdb_id = imdb_id
|
||||
self.youtube_id = youtube_id
|
||||
self.twitch_id = twitch_id
|
||||
|
||||
@ -20,6 +20,7 @@ from scrobbles.mixins import (
|
||||
)
|
||||
from taggit.managers import TaggableManager
|
||||
from videos.metadata import VideoMetadata
|
||||
from videos.sources.omdb import lookup_video_from_omdb
|
||||
from videos.sources.tmdb import lookup_video_from_tmdb
|
||||
from videos.sources.youtube import lookup_video_from_youtube
|
||||
|
||||
@ -255,9 +256,22 @@ class Series(TimeStampedModel):
|
||||
logger.info("Series not created and overwrite=False, returning")
|
||||
return series
|
||||
|
||||
vdict, _, cover, genres = lookup_video_from_tmdb(
|
||||
imdb_id
|
||||
).as_dict_with_cover_and_genres()
|
||||
try:
|
||||
metadata = lookup_video_from_tmdb(imdb_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"TMDB lookup failed for series {imdb_id}: {e}")
|
||||
metadata = None
|
||||
|
||||
if not metadata or not metadata.title:
|
||||
metadata = lookup_video_from_omdb(imdb_id)
|
||||
|
||||
if not metadata or not metadata.title:
|
||||
logger.warning(
|
||||
f"No metadata found for series {imdb_id} from TMDB or OMDB"
|
||||
)
|
||||
return series
|
||||
|
||||
vdict, _, cover, genres = metadata.as_dict_with_cover_and_genres()
|
||||
vdict.pop("video_type")
|
||||
|
||||
vdict["name"] = vdict.pop("title")
|
||||
@ -432,9 +446,22 @@ class Video(ScrobblableMixin):
|
||||
if not created and not overwrite:
|
||||
return video
|
||||
|
||||
vdict, series_id, cover, genres = lookup_video_from_tmdb(
|
||||
imdb_id
|
||||
).as_dict_with_cover_and_genres()
|
||||
try:
|
||||
metadata = lookup_video_from_tmdb(imdb_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"TMDB lookup failed for {imdb_id}: {e}")
|
||||
metadata = None
|
||||
|
||||
if not metadata or not metadata.title:
|
||||
metadata = lookup_video_from_omdb(imdb_id)
|
||||
|
||||
if not metadata or not metadata.title:
|
||||
logger.warning(
|
||||
f"No metadata found for {imdb_id} from TMDB or OMDB"
|
||||
)
|
||||
return video
|
||||
|
||||
vdict, series_id, cover, genres = metadata.as_dict_with_cover_and_genres()
|
||||
|
||||
if created or overwrite:
|
||||
for k, v in vdict.items():
|
||||
|
||||
83
vrobbler/apps/videos/sources/omdb.py
Normal file
83
vrobbler/apps/videos/sources/omdb.py
Normal file
@ -0,0 +1,83 @@
|
||||
import logging
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from videos.metadata import VideoMetadata, VideoType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
OMDB_API_KEY = getattr(settings, "OMDB_API_KEY", "")
|
||||
|
||||
OMDB_URL = "https://www.omdbapi.com/"
|
||||
RUNTIME_RE = re.compile(r"(\d+)\s*min")
|
||||
|
||||
|
||||
def lookup_video_from_omdb(imdb_id: str) -> Optional[VideoMetadata]:
|
||||
if not imdb_id.startswith("tt"):
|
||||
imdb_id = f"tt{imdb_id}"
|
||||
|
||||
if not OMDB_API_KEY:
|
||||
logger.warning("No OMDB API key configured")
|
||||
return None
|
||||
|
||||
params = {"apikey": OMDB_API_KEY, "i": imdb_id, "plot": "full"}
|
||||
|
||||
try:
|
||||
response = requests.get(OMDB_URL, params=params)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"OMDB API error for {imdb_id}: {e}")
|
||||
return None
|
||||
|
||||
if data.get("Response") == "False":
|
||||
logger.info(f"OMDB no result for {imdb_id}: {data.get('Error')}")
|
||||
return None
|
||||
|
||||
metadata = VideoMetadata(imdb_id=imdb_id)
|
||||
metadata.title = data.get("Title")
|
||||
metadata.plot = data.get("Plot")
|
||||
metadata.overview = data.get("Plot")
|
||||
|
||||
raw_year = data.get("Year")
|
||||
if raw_year and raw_year.isdigit():
|
||||
metadata.year = int(raw_year)
|
||||
|
||||
raw_rating = data.get("imdbRating")
|
||||
if raw_rating and raw_rating != "N/A":
|
||||
metadata.imdb_rating = raw_rating
|
||||
|
||||
raw_cover = data.get("Poster")
|
||||
if raw_cover and raw_cover != "N/A":
|
||||
metadata.cover_url = raw_cover
|
||||
|
||||
raw_runtime = data.get("Runtime")
|
||||
if raw_runtime:
|
||||
match = RUNTIME_RE.match(raw_runtime)
|
||||
if match:
|
||||
metadata.base_run_time_seconds = int(match.group(1)) * 60
|
||||
|
||||
media_type = data.get("Type")
|
||||
if media_type == "movie":
|
||||
metadata.video_type = VideoType.MOVIE.value
|
||||
elif media_type in ("series", "episode"):
|
||||
metadata.video_type = VideoType.TV_EPISODE.value
|
||||
|
||||
if media_type == "episode":
|
||||
raw_season = data.get("Season")
|
||||
if raw_season and raw_season != "N/A":
|
||||
metadata.season_number = int(raw_season)
|
||||
raw_episode = data.get("Episode")
|
||||
if raw_episode and raw_episode != "N/A":
|
||||
metadata.episode_number = int(raw_episode)
|
||||
series_imdb_id = data.get("seriesID")
|
||||
if series_imdb_id and series_imdb_id != "N/A":
|
||||
metadata.tv_series_imdb_id = series_imdb_id
|
||||
|
||||
raw_genres = data.get("Genre")
|
||||
if raw_genres:
|
||||
metadata.genres = [g.strip() for g in raw_genres.split(",") if g.strip()]
|
||||
|
||||
return metadata
|
||||
@ -3,14 +3,11 @@ import logging
|
||||
import pendulum
|
||||
from django.conf import settings
|
||||
from themoviedb import TMDb
|
||||
from tmdbv3api import TV, Movie, TMDb as TMDb_direct
|
||||
from tmdbv3api import TV, Movie
|
||||
from videos.metadata import VideoMetadata, VideoType
|
||||
|
||||
TMDB_KEY = getattr(settings, "TMDB_API_KEY", "")
|
||||
|
||||
tmdb_direct = TMDb_direct()
|
||||
tmdb_direct.api_key = TMDB_KEY
|
||||
|
||||
tmdb = TMDb(key=TMDB_KEY, language="en-US", region="US")
|
||||
|
||||
TMDB_IMAGE_URL = "https://image.tmdb.org/t/p/original"
|
||||
@ -36,7 +33,7 @@ def lookup_video_from_tmdb(name_or_id: str, kind: str = "movie") -> VideoMetadat
|
||||
video_metadata = VideoMetadata(imdb_id=imdb_id)
|
||||
|
||||
media = None
|
||||
show = None
|
||||
show_data = None
|
||||
if len(tmdb_result.movie_results) > 0:
|
||||
media = Movie().details(tmdb_result.movie_results[0].id)
|
||||
video_metadata.video_type = VideoType.MOVIE.value
|
||||
|
||||
@ -60,6 +60,7 @@ THEAUDIODB_API_KEY = os.getenv("VROBBLER_THEAUDIODB_API_KEY", "2")
|
||||
PODCASTINDEX_API_KEY = os.getenv("VROBBLER_PODCASTINDEX_API_KEY", "")
|
||||
PODCASTINDEX_API_SECRET = os.getenv("VROBBLER_PODCASTINDEX_API_SECRET", "")
|
||||
TMDB_API_KEY = os.getenv("VROBBLER_TMDB_API_KEY", "")
|
||||
OMDB_API_KEY = os.getenv("VROBBLER_OMDB_API_KEY", "")
|
||||
LASTFM_API_KEY = os.getenv("VROBBLER_LASTFM_API_KEY")
|
||||
LASTFM_SECRET_KEY = os.getenv("VROBBLER_LASTFM_SECRET_KEY")
|
||||
IGDB_CLIENT_ID = os.getenv("VROBBLER_IGDB_CLIENT_ID")
|
||||
|
||||
Reference in New Issue
Block a user