from flask import Flask, jsonify, render_template, request, Response, abort import os import urllib.parse from hf_scrapper import download_and_cache_file, get_system_proxies from indexer import indexer from tvdb import fetch_and_cache_json from dotenv import load_dotenv import json import re from threading import Thread load_dotenv() INDEX_FILE = os.getenv("INDEX_FILE") TOKEN = os.getenv("TOKEN") REPO = os.getenv("REPO") CACHE_DIR = os.getenv("CACHE_DIR") # Ensure CACHE_DIR exists if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR) indexer() if not os.path.exists(INDEX_FILE): raise FileNotFoundError(f"{INDEX_FILE} not found. Please make sure the file exists.") with open(INDEX_FILE, 'r') as f: file_structure = json.load(f) def prefetch_metadata(): for item in file_structure: if 'contents' in item: for sub_item in item['contents']: original_title = sub_item['path'].split('/')[-1] media_type = 'series' if item['path'].startswith('tv') else 'movie' title = original_title year = None match = re.search(r'\((\d{4})\)', original_title) if match: year_str = match.group(1) if year_str.isdigit() and len(year_str) == 4: title = original_title[:match.start()].strip() year = int(year_str) else: parts = original_title.rsplit(' ', 1) if len(parts) > 1 and parts[-1].isdigit() and len(parts[-1]) == 4: title = parts[0].strip() year = int(parts[-1]) fetch_and_cache_json(original_title, title, media_type, year) def start_prefetching(): prefetch_metadata() thread = Thread(target=start_prefetching) thread.daemon = True thread.start() app = Flask(__name__) def get_film_file_path(title): decoded_title = urllib.parse.unquote(title) normalized_title = decoded_title.split(' (')[0].strip() for item in file_structure: if item['path'].startswith('films'): for sub_item in item['contents']: sub_item_title = sub_item['path'].split('/')[-1] normalized_sub_item_title = sub_item_title.split(' (')[0].strip() if normalized_title == normalized_sub_item_title: for file in sub_item['contents']: if file['type'] == 'file': return file['path'] return None def get_tv_show_seasons(title): seasons = [] for item in file_structure: if item['path'].startswith('tv'): for sub_item in item['contents']: if sub_item['type'] == 'directory' and title in sub_item['path']: for season in sub_item['contents']: if season['type'] == 'directory': episodes = [ {"title": episode['path'].split('/')[-1], "path": episode['path']} for episode in season['contents'] if episode['type'] == 'file' ] seasons.append({ "season": season['path'].split('/')[-1], "episodes": episodes }) return seasons return [] def download_film_if_needed(file_path): cached_file_path = os.path.join(CACHE_DIR, file_path) if not os.path.exists(cached_file_path): file_url = f"https://huggingface.co/{REPO}/resolve/main/{file_path}" success = download_and_cache_file(file_url, TOKEN, cached_file_path, proxies=get_system_proxies()) if not success: abort(404, description="File not found or failed to download.") return cached_file_path @app.route('/') def home(): return render_template('index.html') @app.route('/films') def films(): return render_template('films.html') @app.route('/api/films') def list_films(): films = [item for item in file_structure if item['path'].startswith('films')] return jsonify([sub_item for film in films for sub_item in film['contents']]) @app.route('/tv') def tv_shows(): return render_template('tvshows.html') @app.route('/api/tv') def list_tv(): tv_shows = [item for item in file_structure if item['path'].startswith('tv')] return jsonify([sub_item for show in tv_shows for sub_item in show['contents']]) @app.route('/api/film/') def film_page(title): title = urllib.parse.unquote(title) film_file_path = get_film_file_path(title) if not film_file_path: return jsonify({'error': 'Film not found'}), 404 json_cache_path = os.path.join(CACHE_DIR, f"{urllib.parse.quote(title)}.json") if os.path.exists(json_cache_path): with open(json_cache_path, 'r') as f: metadata = json.load(f) else: return jsonify({'error': 'Metadata not found'}), 404 cached_url = f"/cached_films/{urllib.parse.quote(title)}" return jsonify({ 'metadata': metadata, 'cached_url': cached_url }) @app.route('/api/tv/') def tv_page(show_title): show_title = urllib.parse.unquote(show_title) seasons = get_tv_show_seasons(show_title) if not seasons: return jsonify({'error': 'TV show not found'}), 404 json_cache_path = os.path.join(CACHE_DIR, f"{urllib.parse.quote(show_title)}.json") if os.path.exists(json_cache_path): with open(json_cache_path, 'r') as f: metadata = json.load(f) else: return jsonify({'error': 'Metadata not found'}), 404 return jsonify({ 'metadata': metadata, 'seasons': seasons }) @app.route('/get_metadata') def get_metadata(): title = request.args.get('title') if not title: return jsonify({'error': 'No title provided'}), 400 json_cache_path = os.path.join(CACHE_DIR, f"{urllib.parse.quote(title)}.json") if os.path.exists(json_cache_path): with open(json_cache_path, 'r') as f: data = json.load(f) return jsonify(data) return jsonify({'error': 'Metadata not found'}), 404 @app.route('/api/cache_film/') def cache_film(title): title = urllib.parse.unquote(title) film_file_path = get_film_file_path(title) if not film_file_path: return jsonify({'error': 'Film not found'}), 404 cached_file_path = os.path.join(CACHE_DIR, film_file_path) if not os.path.exists(cached_file_path): file_url = f"https://huggingface.co/{REPO}/resolve/main/{film_file_path}" success = download_and_cache_file(file_url, TOKEN, cached_file_path, proxies=get_system_proxies()) if not success: return jsonify({'error': 'Failed to cache film'}), 500 return jsonify({'success': True}) @app.route('/film/') def film_details(title): return render_template('film_details_page.html', title=title) @app.route('/cached_films/') def serve_cached_film(title): cached_file_path = os.path.join(CACHE_DIR, urllib.parse.unquote(title)) if not os.path.exists(cached_file_path): return jsonify({'error': 'Film not cached'}), 404 def generate(): with open(cached_file_path, 'rb') as f: while chunk := f.read(8192): yield chunk return Response(generate(), mimetype='video/mp4') if __name__ == '__main__': app.run(debug=True, host="0.0.0.0", port=7860)