Skip to content

Commit f2d5e0c

Browse files
refactor: remove unused TMDB addon configurations and improve metadata fetching logic; update logging and catalog generation methods
1 parent 0874530 commit f2d5e0c

File tree

5 files changed

+198
-126
lines changed

5 files changed

+198
-126
lines changed

app/core/app.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import logging
21
import os
32
from contextlib import asynccontextmanager
43
from pathlib import Path
@@ -14,18 +13,17 @@
1413

1514
from .config import settings
1615

16+
# class InterceptHandler(logging.Handler):
17+
# def emit(self, record):
18+
# try:
19+
# level = logger.level(record.levelname).name
20+
# except Exception:
21+
# level = record.levelno
1722

18-
class InterceptHandler(logging.Handler):
19-
def emit(self, record):
20-
try:
21-
level = logger.level(record.levelname).name
22-
except Exception:
23-
level = record.levelno
23+
# logger.opt(depth=6, exception=record.exc_info).log(level, record.getMessage())
2424

25-
logger.opt(depth=6, exception=record.exc_info).log(level, record.getMessage())
2625

27-
28-
logging.basicConfig(handlers=[InterceptHandler()], level=logging.INFO, force=True)
26+
# logging.basicConfig(handlers=[InterceptHandler()], level=logging.INFO, force=True)
2927

3028
# Global catalog updater instance
3129
catalog_updater: BackgroundCatalogUpdater | None = None
@@ -46,7 +44,6 @@ async def lifespan(app: FastAPI):
4644
"Background catalog updates enabled (interval=%ss)",
4745
settings.CATALOG_REFRESH_INTERVAL_SECONDS,
4846
)
49-
5047
yield
5148

5249
# Shutdown

app/core/config.py

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,6 @@ class Settings(BaseSettings):
1414
)
1515

1616
TMDB_API_KEY: str | None = None
17-
TMDB_API_URL: str = "https://api.themoviedb.org/3"
18-
TMDB_ADDON_CONFIG_DICT: dict[str, str] = {
19-
"provideImdbId": "true",
20-
"returnImdbId": "true",
21-
"language": "en-US",
22-
"enableEpisodeProvider": "true",
23-
"useDomain": "",
24-
"cacheItemExpiryInHours": "24",
25-
"returnPoster": "true",
26-
"returnBackdrop": "true",
27-
"returnStreamingData": "true",
28-
"streamingDataLanguage": "en",
29-
"disableImdbLookup": "false",
30-
"type": "catalog",
31-
"enableHopAgeRating": "false",
32-
"enableAgeRating": "false",
33-
"showAgeRatingWithImdbRating": "false",
34-
}
35-
TMDB_ADDON_CONFIG: str = (
36-
"N4IgDgTg9gbglgEwKYEkC2CBGKEgFwgAuEArkiADQgRKEkQB26WO+Rp5VANgIYMDmJHv3IEkDALQBVAMqUQAZ2JIeaOAPwBtALpUAxj0I8uUfgq27FKiHoAWAUQY9MXJLgIAzYws4gDSgGEoEgZCfABWKgVbKAB3AEERACVDdX4UBgBxcRpzAmIyeXFnV0SkFMI0ti8uH3louLKKtIB1OEJbZkxmjU9vcgBfIA" # noqa
37-
)
38-
TMDB_ADDON_HOST: str = "https://94c8cb9f702d-tmdb-addon.baby-beamup.club"
3917
PORT: int = 8000
4018
ADDON_ID: str = "com.bimal.watchly"
4119
ADDON_NAME: str = "Watchly"
@@ -44,16 +22,11 @@ class Settings(BaseSettings):
4422
TOKEN_TTL_SECONDS: int = 0 # 0 = never expire
4523
ANNOUNCEMENT_HTML: str = ""
4624
AUTO_UPDATE_CATALOGS: bool = True
47-
CATALOG_REFRESH_INTERVAL_SECONDS: int = 21600 # 6 hours
25+
CATALOG_REFRESH_INTERVAL_SECONDS: int = 60 # 6 hours
4826
APP_ENV: Literal["development", "production"] = "development"
4927
HOST_NAME: str = "https://1ccea4301587-watchly.baby-beamup.club"
5028

51-
# recommendation Settings
5229
RECOMMENDATION_SOURCE_ITEMS_LIMIT: int = 10
5330

54-
@property
55-
def TMDB_ADDON_URL(self) -> str:
56-
return f"{self.TMDB_ADDON_HOST}/{self.TMDB_ADDON_CONFIG}"
57-
5831

5932
settings = Settings()

app/services/catalog.py

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import asyncio
22
from collections import Counter
33

4+
from loguru import logger
5+
46
from app.services.stremio_service import StremioService
57
from app.services.tmdb_service import TMDBService
68

@@ -59,6 +61,32 @@ async def get_watched_loved_catalogs(self, library_items: list[dict]):
5961

6062
return catalogs
6163

64+
async def _get_item_genres(self, item_id: str, item_type: str) -> list[str]:
65+
"""Fetch genres for a specific item from TMDB."""
66+
try:
67+
# Convert IMDB ID to TMDB ID
68+
tmdb_id = None
69+
media_type = "movie" if item_type == "movie" else "tv"
70+
71+
if item_id.startswith("tt"):
72+
tmdb_id, _ = await self.tmdb_service.find_by_imdb_id(item_id)
73+
elif item_id.startswith("tmdb:"):
74+
tmdb_id = int(item_id.split(":")[1])
75+
76+
if not tmdb_id:
77+
return []
78+
79+
# Fetch details
80+
if media_type == "movie":
81+
details = await self.tmdb_service.get_movie_details(tmdb_id)
82+
else:
83+
details = await self.tmdb_service.get_tv_details(tmdb_id)
84+
85+
return [g.get("name") for g in details.get("genres", [])]
86+
except Exception as e:
87+
logger.warning(f"Failed to fetch genres for {item_id}: {e}")
88+
return []
89+
6290
async def get_genre_based_catalogs(self, library_items: list[dict]):
6391
# get separate movies and series lists from loved items
6492
loved_movies = [item for item in library_items.get("loved", []) if item.get("type") == "movie"]
@@ -68,22 +96,19 @@ async def get_genre_based_catalogs(self, library_items: list[dict]):
6896
loved_movies = loved_movies[:5]
6997
loved_series = loved_series[:5]
7098

71-
# fetch details:: genre details from tmdb addon
72-
movie_tasks = [self.tmdb_service.get_addon_meta("movie", item.get("_id").strip()) for item in loved_movies]
73-
series_tasks = [self.tmdb_service.get_addon_meta("series", item.get("_id").strip()) for item in loved_series]
74-
movie_details = await asyncio.gather(*movie_tasks)
75-
series_details = await asyncio.gather(*series_tasks)
99+
# fetch genres concurrently
100+
movie_tasks = [self._get_item_genres(item.get("_id").strip(), "movie") for item in loved_movies]
101+
series_tasks = [self._get_item_genres(item.get("_id").strip(), "series") for item in loved_series]
76102

77-
# now fetch all genres for moviees and series and sort them by their occurance
78-
movie_genres = [detail.get("meta", {}).get("genres", []) for detail in movie_details]
79-
series_genres = [detail.get("meta", {}).get("genres", []) for detail in series_details]
103+
movie_genres_list = await asyncio.gather(*movie_tasks)
104+
series_genres_list = await asyncio.gather(*series_tasks)
80105

81106
# now flatten list and count the occurance of each genre for both movies and series separately
82107
movie_genre_counts = Counter(
83-
[genre for sublist in movie_genres for genre in sublist if genre in MOVIE_GENRE_TO_ID_MAP]
108+
[genre for sublist in movie_genres_list for genre in sublist if genre in MOVIE_GENRE_TO_ID_MAP]
84109
)
85110
series_genre_counts = Counter(
86-
[genre for sublist in series_genres for genre in sublist if genre in SERIES_GENRE_TO_ID_MAP]
111+
[genre for sublist in series_genres_list for genre in sublist if genre in SERIES_GENRE_TO_ID_MAP]
87112
)
88113
sorted_movie_genres = sorted(movie_genre_counts.items(), key=lambda x: x[1], reverse=True)
89114
sorted_series_genres = sorted(series_genre_counts.items(), key=lambda x: x[1], reverse=True)
@@ -97,22 +122,24 @@ async def get_genre_based_catalogs(self, library_items: list[dict]):
97122
top_2_series_genres = [str(SERIES_GENRE_TO_ID_MAP[genre_name]) for genre_name in top_2_series_genre_names]
98123
catalogs = []
99124

100-
catalogs.append(
101-
{
102-
"type": "movie",
103-
"id": f"watchly.genre.{'_'.join(top_2_movie_genres)}",
104-
"name": "You might also Like",
105-
"extra": [],
106-
}
107-
)
108-
109-
catalogs.append(
110-
{
111-
"type": "series",
112-
"id": f"watchly.genre.{'_'.join(top_2_series_genres)}",
113-
"name": "You might also Like",
114-
"extra": [],
115-
}
116-
)
125+
if top_2_movie_genres:
126+
catalogs.append(
127+
{
128+
"type": "movie",
129+
"id": f"watchly.genre.{'_'.join(top_2_movie_genres)}",
130+
"name": "You might also Like",
131+
"extra": [],
132+
}
133+
)
134+
135+
if top_2_series_genres:
136+
catalogs.append(
137+
{
138+
"type": "series",
139+
"id": f"watchly.genre.{'_'.join(top_2_series_genres)}",
140+
"name": "You might also Like",
141+
"extra": [],
142+
}
143+
)
117144

118145
return catalogs

0 commit comments

Comments
 (0)