Merge pull request #270 from aasmoe/feat/multi-language-metadata

Add Feature: multi language metadata
This commit is contained in:
Maximilian Dorninger
2025-12-22 20:07:57 +01:00
committed by GitHub
19 changed files with 237 additions and 52 deletions

View File

@@ -17,6 +17,26 @@ If you want to use your own TMDB relay service, set this to the URL of your own
- **Default:** `https://metadata-relay.dorninger.co/tmdb` - **Default:** `https://metadata-relay.dorninger.co/tmdb`
- **Example:** `https://your-own-relay.example.com/tmdb` - **Example:** `https://your-own-relay.example.com/tmdb`
### `primary_languages`
If a TV show/movie's original language is in this list, metadata will be displayed and fetched in that language. Torrent searches done in Standard Mode uses the same fetched metadata, so if you use any language-specific tracker, you may enter the language here to get the desired search results.
Otherwise, `default_language` will be used.
**Format: ISO 639-1 codes (2 letters). Full list: https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes**
- **Default:** `[]`
- **Example:** `["no", "de", "es"]`
### `default_language`
<warning>
`default_language` sets the TMDB `language` paramater when searching and adding TV shows and movies. If TMDB does not find a matching translation, metadata in the <strong>original language</strong> will be fetched with no option for a fallback language. It is therefore highly advised to only use "broad" languages. For most use cases, the default setting is safest.
</warning>
**Format: ISO 639-1 codes (2 letters).**
- **Default:** `en`
## TVDB Settings (`[metadata.tvdb]`) ## TVDB Settings (`[metadata.tvdb]`)
<warning> <warning>

View File

@@ -0,0 +1,42 @@
"""add original_language columns to show and movie tables
Revision ID: 16e78af9e5bf
Revises: eb0bd3cc1852
Create Date: 2025-12-13 18:47:02.146038
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '16e78af9e5bf'
down_revision: Union[str, None] = 'eb0bd3cc1852'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# Add original_language column to show table
op.add_column(
'show',
sa.Column('original_language', sa.String(10), nullable=True)
)
# Add original_language column to movie table
op.add_column(
'movie',
sa.Column('original_language', sa.String(10), nullable=True)
)
def downgrade() -> None:
"""Downgrade schema."""
# Remove original_language column from movie table
op.drop_column('movie', 'original_language')
# Remove original_language column from show table
op.drop_column('show', 'original_language')

View File

@@ -172,6 +172,8 @@ rule_names = ["prefer_h265", "avoid_cam", "reject_non_freeleech"]
[metadata] [metadata]
[metadata.tmdb] [metadata.tmdb]
tmdb_relay_url = "https://metadata-relay.dorninger.co/tmdb" tmdb_relay_url = "https://metadata-relay.dorninger.co/tmdb"
primary_languages = [""]
default_language = "en"
[metadata.tvdb] [metadata.tvdb]
tvdb_relay_url = "https://metadata-relay.dorninger.co/tvdb" tvdb_relay_url = "https://metadata-relay.dorninger.co/tvdb"

View File

@@ -3,7 +3,8 @@ from pydantic_settings import BaseSettings
class TmdbConfig(BaseSettings): class TmdbConfig(BaseSettings):
tmdb_relay_url: str = "https://metadata-relay.dorninger.co/tmdb" tmdb_relay_url: str = "https://metadata-relay.dorninger.co/tmdb"
primary_languages: list[str] = [] # ISO 639-1 language codes
default_language: str = "en" # ISO 639-1 language codes
class TvdbConfig(BaseSettings): class TvdbConfig(BaseSettings):
tvdb_relay_url: str = "https://metadata-relay.dorninger.co/tvdb" tvdb_relay_url: str = "https://metadata-relay.dorninger.co/tvdb"

View File

@@ -12,4 +12,5 @@ class MetaDataProviderSearchResult(BaseModel):
metadata_provider: str metadata_provider: str
added: bool added: bool
vote_average: float | None = None vote_average: float | None = None
original_language: str | None = None
id: MovieId | ShowId | None = None # Internal ID if already added id: MovieId | ShowId | None = None # Internal ID if already added

View File

@@ -25,10 +25,29 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
def __init__(self): def __init__(self):
config = AllEncompassingConfig().metadata.tmdb config = AllEncompassingConfig().metadata.tmdb
self.url = config.tmdb_relay_url self.url = config.tmdb_relay_url
self.primary_languages = config.primary_languages
self.default_language = config.default_language
def __get_show_metadata(self, id: int) -> dict: def __get_language_param(self, original_language: str | None) -> str:
"""
Determine the language parameter to use for TMDB API calls.
Returns the original language if it's in primary_languages, otherwise returns default_language.
:param original_language: The original language code (ISO 639-1) of the media
:return: Language parameter (ISO 639-1 format, e.g., 'en', 'no')
"""
if original_language and original_language in self.primary_languages:
return original_language
return self.default_language
def __get_show_metadata(self, id: int, language: str | None = None) -> dict:
if language is None:
language = self.default_language
try: try:
response = requests.get(url=f"{self.url}/tv/shows/{id}") response = requests.get(
url=f"{self.url}/tv/shows/{id}",
params={"language": language}
)
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
except requests.RequestException as e: except requests.RequestException as e:
@@ -40,10 +59,13 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
) )
raise raise
def __get_season_metadata(self, show_id: int, season_number: int) -> dict: def __get_season_metadata(self, show_id: int, season_number: int, language: str | None = None) -> dict:
if language is None:
language = self.default_language
try: try:
response = requests.get( response = requests.get(
url=f"{self.url}/tv/shows/{show_id}/{season_number}" url=f"{self.url}/tv/shows/{show_id}/{season_number}",
params={"language": language}
) )
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
@@ -80,7 +102,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
def __get_trending_tv(self) -> dict: def __get_trending_tv(self) -> dict:
try: try:
response = requests.get(url=f"{self.url}/tv/trending") response = requests.get(url=f"{self.url}/tv/trending", params={"language": self.default_language})
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
except requests.RequestException as e: except requests.RequestException as e:
@@ -92,9 +114,14 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
) )
raise raise
def __get_movie_metadata(self, id: int) -> dict: def __get_movie_metadata(self, id: int, language: str | None = None) -> dict:
if language is None:
language = self.default_language
try: try:
response = requests.get(url=f"{self.url}/movies/{id}") response = requests.get(
url=f"{self.url}/movies/{id}",
params={"language": language}
)
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
except requests.RequestException as e: except requests.RequestException as e:
@@ -128,7 +155,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
def __get_trending_movies(self) -> dict: def __get_trending_movies(self) -> dict:
try: try:
response = requests.get(url=f"{self.url}/movies/trending") response = requests.get(url=f"{self.url}/movies/trending", params={"language": self.default_language})
response.raise_for_status() response.raise_for_status()
return response.json() return response.json()
except requests.RequestException as e: except requests.RequestException as e:
@@ -141,7 +168,12 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
raise raise
def download_show_poster_image(self, show: Show) -> bool: def download_show_poster_image(self, show: Show) -> bool:
show_metadata = self.__get_show_metadata(show.external_id) # Determine which language to use based on show's original_language
language = self.__get_language_param(show.original_language)
# Fetch metadata in the appropriate language to get localized poster
show_metadata = self.__get_show_metadata(show.external_id, language=language)
# downloading the poster # downloading the poster
# all pictures from TMDB should already be jpeg, so no need to convert # all pictures from TMDB should already be jpeg, so no need to convert
if show_metadata["poster_path"] is not None: if show_metadata["poster_path"] is not None:
@@ -160,20 +192,34 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
return False return False
return True return True
def get_show_metadata(self, id: int = None) -> Show: def get_show_metadata(self, id: int = None, language: str | None = None) -> Show:
""" """
:param id: the external id of the show :param id: the external id of the show
:type id: int :type id: int
:return: returns a ShowMetadata object :param language: optional language code (ISO 639-1) to fetch metadata in
:rtype: ShowMetadata :type language: str | None
:return: returns a Show object
:rtype: Show
""" """
show_metadata = self.__get_show_metadata(id) # If language not provided, fetch once to determine original language
if language is None:
show_metadata = self.__get_show_metadata(id)
language = show_metadata.get("original_language")
# Determine which language to use for metadata
language = self.__get_language_param(language)
# Fetch show metadata in the appropriate language
show_metadata = self.__get_show_metadata(id, language=language)
season_list = [] season_list = []
# inserting all the metadata into the objects # inserting all the metadata into the objects
for season in show_metadata["seasons"]: for season in show_metadata["seasons"]:
season_metadata = self.__get_season_metadata( season_metadata = self.__get_season_metadata(
show_id=show_metadata["id"], season_number=season["season_number"] show_id=show_metadata["id"],
season_number=season["season_number"],
language=language
) )
episode_list = [] episode_list = []
@@ -208,6 +254,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
seasons=season_list, seasons=season_list,
metadata_provider=self.name, metadata_provider=self.name,
ended=show_metadata["status"] in ENDED_STATUS, ended=show_metadata["status"] in ENDED_STATUS,
original_language=show_metadata.get("original_language"),
) )
return show return show
@@ -240,11 +287,24 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
) )
else: else:
poster_url = None poster_url = None
# Determine which name to use based on primary_languages
original_language = result.get("original_language")
original_name = result.get("original_name")
display_name = result["name"]
overview = result["overview"]
# Use original name if language is in primary_languages and skip overview
if original_language and original_language in self.primary_languages:
display_name = original_name
overview = None
formatted_results.append( formatted_results.append(
MetaDataProviderSearchResult( MetaDataProviderSearchResult(
poster_path=poster_url, poster_path=poster_url,
overview=result["overview"], overview=overview,
name=result["name"], name=display_name,
external_id=result["id"], external_id=result["id"],
year=media_manager.metadataProvider.utils.get_year_from_date( year=media_manager.metadataProvider.utils.get_year_from_date(
result["first_air_date"] result["first_air_date"]
@@ -252,21 +312,35 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
metadata_provider=self.name, metadata_provider=self.name,
added=False, added=False,
vote_average=result["vote_average"], vote_average=result["vote_average"],
original_language=original_language,
) )
) )
except Exception as e: except Exception as e:
log.warning(f"Error processing search result: {e}") log.warning(f"Error processing search result: {e}")
return formatted_results return formatted_results
def get_movie_metadata(self, id: int = None) -> Movie: def get_movie_metadata(self, id: int = None, language: str | None = None) -> Movie:
""" """
Get movie metadata with language-aware fetching.
:param id: the external id of the show :param id: the external id of the movie
:type id: int :type id: int
:return: returns a ShowMetadata object :param language: optional language code (ISO 639-1) to fetch metadata in
:rtype: ShowMetadata :type language: str | None
:return: returns a Movie object
:rtype: Movie
""" """
movie_metadata = self.__get_movie_metadata(id=id) # If language not provided, fetch once to determine original language
if language is None:
movie_metadata = self.__get_movie_metadata(id=id)
language = movie_metadata.get("original_language")
# Determine which language to use for metadata
language = self.__get_language_param(language)
# Fetch movie metadata in the appropriate language
movie_metadata = self.__get_movie_metadata(id=id, language=language)
year = media_manager.metadataProvider.utils.get_year_from_date( year = media_manager.metadataProvider.utils.get_year_from_date(
movie_metadata["release_date"] movie_metadata["release_date"]
) )
@@ -277,6 +351,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
overview=movie_metadata["overview"], overview=movie_metadata["overview"],
year=year, year=year,
metadata_provider=self.name, metadata_provider=self.name,
original_language=movie_metadata.get("original_language"),
) )
return movie return movie
@@ -309,11 +384,23 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
) )
else: else:
poster_url = None poster_url = None
# Determine which name to use based on primary_languages
original_language = result.get("original_language")
original_title = result.get("original_title")
display_name = result["title"]
overview = result["overview"]
# Use original name if language is in primary_languages and skip overview
if original_language and original_language in self.primary_languages:
display_name = original_title
overview = None
formatted_results.append( formatted_results.append(
MetaDataProviderSearchResult( MetaDataProviderSearchResult(
poster_path=poster_url, poster_path=poster_url,
overview=result["overview"], overview=overview,
name=result["title"], name=display_name,
external_id=result["id"], external_id=result["id"],
year=media_manager.metadataProvider.utils.get_year_from_date( year=media_manager.metadataProvider.utils.get_year_from_date(
result["release_date"] result["release_date"]
@@ -321,6 +408,7 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
metadata_provider=self.name, metadata_provider=self.name,
added=False, added=False,
vote_average=result["vote_average"], vote_average=result["vote_average"],
original_language=original_language,
) )
) )
except Exception as e: except Exception as e:
@@ -328,7 +416,12 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
return formatted_results return formatted_results
def download_movie_poster_image(self, movie: Movie) -> bool: def download_movie_poster_image(self, movie: Movie) -> bool:
movie_metadata = self.__get_movie_metadata(id=movie.external_id) # Determine which language to use based on movie's original_language
language = self.__get_language_param(movie.original_language)
# Fetch metadata in the appropriate language to get localized poster
movie_metadata = self.__get_movie_metadata(id=movie.external_id, language=language)
# downloading the poster # downloading the poster
# all pictures from TMDB should already be jpeg, so no need to convert # all pictures from TMDB should already be jpeg, so no need to convert
if movie_metadata["poster_path"] is not None: if movie_metadata["poster_path"] is not None:
@@ -338,11 +431,11 @@ class TmdbMetadataProvider(AbstractMetadataProvider):
if media_manager.metadataProvider.utils.download_poster_image( if media_manager.metadataProvider.utils.download_poster_image(
storage_path=self.storage_path, poster_url=poster_url, id=movie.id storage_path=self.storage_path, poster_url=poster_url, id=movie.id
): ):
log.info("Successfully downloaded poster image for show " + movie.name) log.info("Successfully downloaded poster image for movie " + movie.name)
else: else:
log.warning(f"download for image of show {movie.name} failed") log.warning(f"download for image of movie {movie.name} failed")
return False return False
else: else:
log.warning(f"image for show {movie.name} could not be downloaded") log.warning(f"image for movie {movie.name} could not be downloaded")
return False return False
return True return True

View File

@@ -19,6 +19,7 @@ class Movie(Base):
overview: Mapped[str] overview: Mapped[str]
year: Mapped[int | None] year: Mapped[int | None]
library: Mapped[str] = mapped_column(default="") library: Mapped[str] = mapped_column(default="")
original_language: Mapped[str | None] = mapped_column(default=None)
movie_requests: Mapped[list["MovieRequest"]] = relationship( movie_requests: Mapped[list["MovieRequest"]] = relationship(
"MovieRequest", back_populates="movie", cascade="all, delete-orphan" "MovieRequest", back_populates="movie", cascade="all, delete-orphan"
) )

View File

@@ -115,6 +115,7 @@ class MovieRepository:
db_movie.name = movie.name db_movie.name = movie.name
db_movie.overview = movie.overview db_movie.overview = movie.overview
db_movie.year = movie.year db_movie.year = movie.year
db_movie.original_language = movie.original_language
else: # Insert new movie else: # Insert new movie
log.debug(f"Creating new movie: {movie.name}") log.debug(f"Creating new movie: {movie.name}")
db_movie = Movie(**movie.model_dump()) db_movie = Movie(**movie.model_dump())

View File

@@ -56,11 +56,13 @@ def add_a_movie(
movie_service: movie_service_dep, movie_service: movie_service_dep,
metadata_provider: metadata_provider_dep, metadata_provider: metadata_provider_dep,
movie_id: int, movie_id: int,
language: str | None = None,
): ):
try: try:
movie = movie_service.add_movie( movie = movie_service.add_movie(
external_id=movie_id, external_id=movie_id,
metadata_provider=metadata_provider, metadata_provider=metadata_provider,
language=language,
) )
except ValueError: except ValueError:
movie = movie_service.get_movie_by_external_id( movie = movie_service.get_movie_by_external_id(

View File

@@ -23,6 +23,7 @@ class Movie(BaseModel):
external_id: int external_id: int
metadata_provider: str metadata_provider: str
library: str = "Default" library: str = "Default"
original_language: str | None = None
class MovieFile(BaseModel): class MovieFile(BaseModel):

View File

@@ -63,15 +63,16 @@ class MovieService:
self.notification_service = notification_service self.notification_service = notification_service
def add_movie( def add_movie(
self, external_id: int, metadata_provider: AbstractMetadataProvider self, external_id: int, metadata_provider: AbstractMetadataProvider, language: str | None = None
) -> Movie | None: ) -> Movie | None:
""" """
Add a new movie to the database. Add a new movie to the database.
:param external_id: The ID of the movie in the metadata provider's system. :param external_id: The ID of the movie in the metadata provider's system.
:param metadata_provider: The name of the metadata provider. :param metadata_provider: The name of the metadata provider.
:param language: Optional language code (ISO 639-1) to fetch metadata in.
""" """
movie_with_metadata = metadata_provider.get_movie_metadata(id=external_id) movie_with_metadata = metadata_provider.get_movie_metadata(id=external_id, language=language)
saved_movie = self.movie_repository.save_movie(movie=movie_with_metadata) saved_movie = self.movie_repository.save_movie(movie=movie_with_metadata)
metadata_provider.download_movie_poster_image(movie=saved_movie) metadata_provider.download_movie_poster_image(movie=saved_movie)
return saved_movie return saved_movie
@@ -697,7 +698,8 @@ class MovieService:
""" """
log.debug(f"Found movie: {db_movie.name} for metadata update.") log.debug(f"Found movie: {db_movie.name} for metadata update.")
fresh_movie_data = metadata_provider.get_movie_metadata(id=db_movie.external_id) # Use stored original_language preference for metadata fetching
fresh_movie_data = metadata_provider.get_movie_metadata(id=db_movie.external_id, language=db_movie.original_language)
if not fresh_movie_data: if not fresh_movie_data:
log.warning( log.warning(
f"Could not fetch fresh metadata for movie {db_movie.name} (External ID: {db_movie.external_id}) from {db_movie.metadata_provider}." f"Could not fetch fresh metadata for movie {db_movie.name} (External ID: {db_movie.external_id}) from {db_movie.metadata_provider}."

View File

@@ -21,6 +21,7 @@ class Show(Base):
ended: Mapped[bool] = mapped_column(default=False) ended: Mapped[bool] = mapped_column(default=False)
continuous_download: Mapped[bool] = mapped_column(default=False) continuous_download: Mapped[bool] = mapped_column(default=False)
library: Mapped[str] = mapped_column(default="") library: Mapped[str] = mapped_column(default="")
original_language: Mapped[str | None] = mapped_column(default=None)
seasons: Mapped[list["Season"]] = relationship( seasons: Mapped[list["Season"]] = relationship(
back_populates="show", cascade="all, delete" back_populates="show", cascade="all, delete"

View File

@@ -135,6 +135,7 @@ class TvRepository:
db_show.name = show.name db_show.name = show.name
db_show.overview = show.overview db_show.overview = show.overview
db_show.year = show.year db_show.year = show.year
db_show.original_language = show.original_language
else: # Insert new show else: # Insert new show
db_show = Show( db_show = Show(
id=show.id, id=show.id,
@@ -144,6 +145,7 @@ class TvRepository:
overview=show.overview, overview=show.overview,
year=show.year, year=show.year,
ended=show.ended, ended=show.ended,
original_language=show.original_language,
seasons=[ seasons=[
Season( Season(
id=season.id, id=season.id,

View File

@@ -58,12 +58,13 @@ router = APIRouter()
}, },
) )
def add_a_show( def add_a_show(
tv_service: tv_service_dep, metadata_provider: metadata_provider_dep, show_id: int tv_service: tv_service_dep, metadata_provider: metadata_provider_dep, show_id: int, language: str | None = None
): ):
try: try:
show = tv_service.add_show( show = tv_service.add_show(
external_id=show_id, external_id=show_id,
metadata_provider=metadata_provider, metadata_provider=metadata_provider,
language=language,
) )
except MediaAlreadyExists: except MediaAlreadyExists:
show = tv_service.get_show_by_external_id( show = tv_service.get_show_by_external_id(

View File

@@ -55,6 +55,7 @@ class Show(BaseModel):
continuous_download: bool = False continuous_download: bool = False
library: str = "Default" library: str = "Default"
original_language: str | None = None
seasons: list[Season] seasons: list[Season]

View File

@@ -69,15 +69,16 @@ class TvService:
self.notification_service = notification_service self.notification_service = notification_service
def add_show( def add_show(
self, external_id: int, metadata_provider: AbstractMetadataProvider self, external_id: int, metadata_provider: AbstractMetadataProvider, language: str | None = None
) -> Show | None: ) -> Show | None:
""" """
Add a new show to the database. Add a new show to the database.
:param external_id: The ID of the show in the metadata provider\\\'s system. :param external_id: The ID of the show in the metadata provider\'s system.
:param metadata_provider: The name of the metadata provider. :param metadata_provider: The name of the metadata provider.
:param language: Optional language code (ISO 639-1) to fetch metadata in.
""" """
show_with_metadata = metadata_provider.get_show_metadata(id=external_id) show_with_metadata = metadata_provider.get_show_metadata(id=external_id, language=language)
saved_show = self.tv_repository.save_show(show=show_with_metadata) saved_show = self.tv_repository.save_show(show=show_with_metadata)
metadata_provider.download_show_poster_image(show=saved_show) metadata_provider.download_show_poster_image(show=saved_show)
return saved_show return saved_show
@@ -756,7 +757,8 @@ class TvService:
log.debug(f"Found show: {db_show.name} for metadata update.") log.debug(f"Found show: {db_show.name} for metadata update.")
# old_poster_url = db_show.poster_url # poster_url removed from db_show # old_poster_url = db_show.poster_url # poster_url removed from db_show
fresh_show_data = metadata_provider.get_show_metadata(id=db_show.external_id) # Use stored original_language preference for metadata fetching
fresh_show_data = metadata_provider.get_show_metadata(id=db_show.external_id, language=db_show.original_language)
if not fresh_show_data: if not fresh_show_data:
log.warning( log.warning(
f"Could not fetch fresh metadata for show {db_show.name} (External ID: {db_show.external_id}) from {db_show.metadata_provider}." f"Could not fetch fresh metadata for show {db_show.name} (External ID: {db_show.external_id}) from {db_show.metadata_provider}."

View File

@@ -16,29 +16,29 @@ else:
tmdbsimple.API_KEY = tmdb_api_key tmdbsimple.API_KEY = tmdb_api_key
@router.get("/tv/trending") @router.get("/tv/trending")
async def get_tmdb_trending_tv(): async def get_tmdb_trending_tv(language: str = "en"):
return Trending(media_type="tv").info() return Trending(media_type="tv").info(language=language)
@router.get("/tv/search") @router.get("/tv/search")
async def search_tmdb_tv(query: str, page: int = 1): async def search_tmdb_tv(query: str, page: int = 1, language: str = "en"):
return Search().tv(page=page, query=query) return Search().tv(page=page, query=query, language=language)
@router.get("/tv/shows/{show_id}") @router.get("/tv/shows/{show_id}")
async def get_tmdb_show(show_id: int): async def get_tmdb_show(show_id: int, language: str = "en"):
return TV(show_id).info() return TV(show_id).info(language=language)
@router.get("/tv/shows/{show_id}/{season_number}") @router.get("/tv/shows/{show_id}/{season_number}")
async def get_tmdb_season(season_number: int, show_id: int): async def get_tmdb_season(season_number: int, show_id: int, language: str = "en"):
return TV_Seasons(season_number=season_number, tv_id=show_id).info() return TV_Seasons(season_number=season_number, tv_id=show_id).info(language=language)
@router.get("/movies/trending") @router.get("/movies/trending")
async def get_tmdb_trending_movies(): async def get_tmdb_trending_movies(language: str = "en"):
return Trending(media_type="movie").info() return Trending(media_type="movie").info(language=language)
@router.get("/movies/search") @router.get("/movies/search")
async def search_tmdb_movies(query: str, page: int = 1): async def search_tmdb_movies(query: str, page: int = 1, language: str = "en"):
return Search().movie(page=page, query=query) return Search().movie(page=page, query=query, language=language)
@router.get("/movies/{movie_id}") @router.get("/movies/{movie_id}")
async def get_tmdb_movie(movie_id: int): async def get_tmdb_movie(movie_id: int, language: str = "en"):
return Movies(movie_id).info() return Movies(movie_id).info(language=language)

View File

@@ -1309,6 +1309,8 @@ export interface components {
added: boolean; added: boolean;
/** Vote Average */ /** Vote Average */
vote_average?: number | null; vote_average?: number | null;
/** Original Language */
original_language?: string | null;
/** Id */ /** Id */
id?: string | null; id?: string | null;
}; };
@@ -1334,6 +1336,8 @@ export interface components {
* @default Default * @default Default
*/ */
library: string; library: string;
/** Original Language */
original_language?: string | null;
}; };
/** MovieRequest */ /** MovieRequest */
MovieRequest: { MovieRequest: {
@@ -1433,6 +1437,8 @@ export interface components {
* @default Default * @default Default
*/ */
library: string; library: string;
/** Original Language */
original_language?: string | null;
/** /**
* Downloaded * Downloaded
* @default false * @default false
@@ -1689,6 +1695,8 @@ export interface components {
* @default Default * @default Default
*/ */
library: string; library: string;
/** Original Language */
original_language?: string | null;
/** Seasons */ /** Seasons */
seasons: components['schemas']['Season'][]; seasons: components['schemas']['Season'][];
}; };
@@ -2565,6 +2573,7 @@ export interface operations {
parameters: { parameters: {
query: { query: {
show_id: number; show_id: number;
language?: string | null;
metadata_provider?: 'tmdb' | 'tvdb'; metadata_provider?: 'tmdb' | 'tvdb';
}; };
header?: never; header?: never;
@@ -3417,6 +3426,7 @@ export interface operations {
parameters: { parameters: {
query: { query: {
movie_id: number; movie_id: number;
language?: string | null;
metadata_provider?: 'tmdb' | 'tvdb'; metadata_provider?: 'tmdb' | 'tvdb';
}; };
header?: never; header?: never;

View File

@@ -22,7 +22,8 @@
params: { params: {
query: { query: {
show_id: result.external_id, show_id: result.external_id,
metadata_provider: result.metadata_provider as 'tmdb' | 'tvdb' metadata_provider: result.metadata_provider as 'tmdb' | 'tvdb',
language: result.original_language ?? undefined
} }
} }
}); });
@@ -32,7 +33,8 @@
params: { params: {
query: { query: {
movie_id: result.external_id, movie_id: result.external_id,
metadata_provider: result.metadata_provider as 'tmdb' | 'tvdb' metadata_provider: result.metadata_provider as 'tmdb' | 'tvdb',
language: result.original_language ?? undefined
} }
} }
}); });