Spaces:
Running
Running
ChandimaPrabath
commited on
Commit
·
3d4bf49
1
Parent(s):
fc1153c
add routes
Browse files- .gitignore +1 -3
- app.py +14 -0
- tvdb.py +2 -0
- tvdbApiClient.py +97 -0
.gitignore
CHANGED
@@ -7,6 +7,4 @@ __pycache__
|
|
7 |
# stream-test.py
|
8 |
stream-test.py
|
9 |
#test
|
10 |
-
test.py
|
11 |
-
#tvdbApiClient.py
|
12 |
-
tvdbApiClient.py
|
|
|
7 |
# stream-test.py
|
8 |
stream-test.py
|
9 |
#test
|
10 |
+
test.py
|
|
|
|
app.py
CHANGED
@@ -75,3 +75,17 @@ async def get_tv_metadata_api(title: str):
|
|
75 |
return JSONResponse(content=data)
|
76 |
|
77 |
raise HTTPException(status_code=404, detail="Metadata not found")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
return JSONResponse(content=data)
|
76 |
|
77 |
raise HTTPException(status_code=404, detail="Metadata not found")
|
78 |
+
|
79 |
+
@app.get("/api/get/tv/metadata/{id}/{season}")
|
80 |
+
async def get_season_metadata_api(id: int, season: str):
|
81 |
+
"""Endpoint to get the TV show season metadata by id and season."""
|
82 |
+
if not season:
|
83 |
+
raise HTTPException(status_code=400, detail="Season must be provided and cannot be empty")
|
84 |
+
|
85 |
+
json_cache_path = os.path.join(CACHE_DIR, f"metadata/{id}/{urllib.parse.quote(season)}.json")
|
86 |
+
|
87 |
+
if os.path.exists(json_cache_path):
|
88 |
+
data = await read_json_file(json_cache_path)
|
89 |
+
return JSONResponse(content=data)
|
90 |
+
|
91 |
+
raise HTTPException(status_code=404, detail="Metadata not found")
|
tvdb.py
CHANGED
@@ -5,6 +5,7 @@ import urllib.parse
|
|
5 |
from datetime import datetime, timedelta
|
6 |
from dotenv import load_dotenv
|
7 |
import json
|
|
|
8 |
|
9 |
load_dotenv()
|
10 |
THETVDB_API_KEY = os.getenv("THETVDB_API_KEY")
|
@@ -73,6 +74,7 @@ def fetch_and_cache_json(original_title, title, media_type, year=None):
|
|
73 |
extended_url = f"{THETVDB_API_URL}/movies/{tvdb_id}/extended?meta=translations"
|
74 |
elif media_type == 'series':
|
75 |
extended_url = f"{THETVDB_API_URL}/series/{tvdb_id}/extended?meta=translations"
|
|
|
76 |
else:
|
77 |
print(f"Unsupported media type: {media_type}")
|
78 |
return
|
|
|
5 |
from datetime import datetime, timedelta
|
6 |
from dotenv import load_dotenv
|
7 |
import json
|
8 |
+
from tvdbApiClient import fetch_and_cache_seasons
|
9 |
|
10 |
load_dotenv()
|
11 |
THETVDB_API_KEY = os.getenv("THETVDB_API_KEY")
|
|
|
74 |
extended_url = f"{THETVDB_API_URL}/movies/{tvdb_id}/extended?meta=translations"
|
75 |
elif media_type == 'series':
|
76 |
extended_url = f"{THETVDB_API_URL}/series/{tvdb_id}/extended?meta=translations"
|
77 |
+
fetch_and_cache_seasons(tvdb_id)
|
78 |
else:
|
79 |
print(f"Unsupported media type: {media_type}")
|
80 |
return
|
tvdbApiClient.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
import logging
|
4 |
+
from pathlib import Path
|
5 |
+
import tvdb_v4_official
|
6 |
+
|
7 |
+
THETVDB_API_KEY = os.getenv("THETVDB_API_KEY")
|
8 |
+
CACHE_DIR = os.getenv("CACHE_DIR")
|
9 |
+
SAVE_DIR = os.path.join(CACHE_DIR,"metadata")
|
10 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
11 |
+
|
12 |
+
# Initialize TVDB client
|
13 |
+
tvdb = tvdb_v4_official.TVDB(THETVDB_API_KEY)
|
14 |
+
|
15 |
+
def get_series_info(series_id):
|
16 |
+
"""Fetch series information including episodes from TVDB."""
|
17 |
+
try:
|
18 |
+
series = tvdb.get_series_extended(series_id, meta="episodes")
|
19 |
+
logging.info("Series info fetched successfully.")
|
20 |
+
return series
|
21 |
+
except Exception as e:
|
22 |
+
logging.error(f"Error fetching series info: {e}")
|
23 |
+
return None
|
24 |
+
|
25 |
+
def filter_episode_data(episode):
|
26 |
+
"""Filter episode data to include only necessary fields."""
|
27 |
+
return {
|
28 |
+
"id": episode.get("id"),
|
29 |
+
"seriesId": episode.get("seriesId"),
|
30 |
+
"name": episode.get("name"),
|
31 |
+
"aired": episode.get("aired"),
|
32 |
+
"runtime": episode.get("runtime"),
|
33 |
+
"overview": episode.get("overview"),
|
34 |
+
"image": episode.get("image"),
|
35 |
+
"imageType": episode.get("imageType"),
|
36 |
+
"isMovie": episode.get("isMovie"),
|
37 |
+
"number": episode.get("number"),
|
38 |
+
"absoluteNumber": episode.get("absoluteNumber"),
|
39 |
+
"seasonNumber": episode.get("seasonNumber"),
|
40 |
+
"finaleType": episode.get("finaleType"),
|
41 |
+
"year": episode.get("year")
|
42 |
+
}
|
43 |
+
|
44 |
+
def save_to_json(data, path):
|
45 |
+
"""Save data to a JSON file."""
|
46 |
+
try:
|
47 |
+
with open(path, 'w', encoding='utf-8') as f:
|
48 |
+
json.dump(data, f, indent=4, ensure_ascii=False)
|
49 |
+
logging.info(f"Data saved to {path}")
|
50 |
+
except IOError as e:
|
51 |
+
logging.error(f"Error saving data to {path}: {e}")
|
52 |
+
|
53 |
+
def fetch_and_cache_seasons(series_id):
|
54 |
+
"""Fetch and cache episodes for a given series ID."""
|
55 |
+
series_info = get_series_info(series_id)
|
56 |
+
if not series_info:
|
57 |
+
logging.error("Series info could not be fetched.")
|
58 |
+
return
|
59 |
+
|
60 |
+
all_seasons = {}
|
61 |
+
for season in series_info.get('seasons', []):
|
62 |
+
season_id = season['id']
|
63 |
+
season_number = season.get('number')
|
64 |
+
|
65 |
+
if season_number == 0:
|
66 |
+
season_key = "Specials"
|
67 |
+
else:
|
68 |
+
season_key = f"Season {season_number}"
|
69 |
+
|
70 |
+
all_seasons[season_key] = []
|
71 |
+
try:
|
72 |
+
season_info = tvdb.get_season_extended(season_id)
|
73 |
+
for episode in season_info.get('episodes', []):
|
74 |
+
filtered_data = filter_episode_data(episode)
|
75 |
+
all_seasons[season_key].append(filtered_data)
|
76 |
+
logging.info(f"Fetched episodes for {season_key}.")
|
77 |
+
except Exception as e:
|
78 |
+
logging.error(f"Error fetching season info for {season_key}: {e}")
|
79 |
+
|
80 |
+
# Create folder for the series
|
81 |
+
series_folder = Path(SAVE_DIR) / series_id
|
82 |
+
series_folder.mkdir(parents=True, exist_ok=True)
|
83 |
+
|
84 |
+
# Save episodes for each season in separate JSON files
|
85 |
+
for season_key, episodes in sorted(all_seasons.items()):
|
86 |
+
episodes_sorted = sorted(episodes, key=lambda e: e.get('number'))
|
87 |
+
season_file = series_folder / f"{season_key}.json"
|
88 |
+
save_to_json(episodes_sorted, season_file)
|
89 |
+
|
90 |
+
def main(series_id):
|
91 |
+
"""Main function to fetch and cache episodes."""
|
92 |
+
fetch_and_cache_seasons(series_id)
|
93 |
+
|
94 |
+
if __name__ == "__main__":
|
95 |
+
# Replace with your series ID
|
96 |
+
SERIES_ID = "315103"
|
97 |
+
main(SERIES_ID)
|