Spaces:
Build error
Build error
| from flask import Flask, jsonify, render_template, request, Response | |
| import os | |
| import json | |
| import re | |
| import urllib.parse | |
| from threading import Thread | |
| import uuid | |
| from video import ffmpeg_stream | |
| from indexer import indexer | |
| from dotenv import load_dotenv | |
| from tvdb import fetch_and_cache_json | |
| load_dotenv() | |
| INDEX_FILE = os.getenv("INDEX_FILE") | |
| TOKEN = os.getenv("TOKEN") | |
| REPO = os.getenv("REPO") | |
| CACHE_DIR = os.getenv("CACHE_DIR") | |
| 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, year = extract_title_and_year(original_title) | |
| fetch_and_cache_json(original_title, title, media_type, year) | |
| def extract_title_and_year(original_title): | |
| 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() | |
| return title, int(year_str) | |
| else: | |
| parts = original_title.rsplit(' ', 1) | |
| if len(parts) > 1 and parts[-1].isdigit() and len(parts[-1]) == 4: | |
| return parts[0].strip(), int(parts[-1]) | |
| return original_title, None | |
| 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 start_prefetching(): | |
| prefetch_metadata() | |
| def generate(file_url): | |
| # Generate a unique stream ID | |
| stream_id = str(uuid.uuid4()) | |
| output_dir = os.path.join(CACHE_DIR, "stream", stream_id) | |
| # Ensure output directory exists | |
| if not os.path.exists(output_dir): | |
| os.makedirs(output_dir) | |
| # Set up HLS streaming | |
| token = TOKEN | |
| output_path = ffmpeg_stream(file_url, token, output_dir=output_dir, stream_id=stream_id) | |
| if output_path: | |
| return stream_id | |
| return None | |
| thread = Thread(target=start_prefetching) | |
| thread.daemon = True | |
| thread.start() | |
| app = Flask(__name__) | |
| def home(): | |
| return render_template('index.html') | |
| def tvshow_player(): | |
| return render_template('player.html') | |
| def film_player(): | |
| title = request.args.get('title') | |
| if not title: | |
| return "No film title provided", 400 | |
| return render_template('film_player.html', title=urllib.parse.unquote(title)) | |
| def films(): | |
| return render_template('films.html') | |
| 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']]) | |
| def tv_shows(): | |
| return render_template('tvshows.html') | |
| 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']]) | |
| 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 | |
| return jsonify({ | |
| 'metadata': metadata, | |
| 'file_path': film_file_path | |
| }) | |
| 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 | |
| }) | |
| 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 | |
| def film_details(title): | |
| return render_template('film_details_page.html', title=title) | |
| def stream_video(): | |
| file_path = request.args.get('path') | |
| if not file_path: | |
| return "File path not provided", 400 | |
| file_url = f"https://huggingface.co/{REPO}/resolve/main/{file_path}" | |
| stream_id = generate(file_url) | |
| if stream_id: | |
| return jsonify({'stream_id': stream_id}) | |
| return "Streaming error", 500 | |
| def stream_file(stream_id): | |
| stream_dir = os.path.join(CACHE_DIR, "stream", stream_id) | |
| playlist_path = os.path.join(stream_dir, 'output.m3u8') | |
| if os.path.exists(playlist_path): | |
| return Response( | |
| open(playlist_path, 'rb').read(), | |
| mimetype='application/vnd.apple.mpegurl' | |
| ) | |
| return "Stream not found", 404 | |
| if __name__ == '__main__': | |
| app.run(debug=True, host="0.0.0.0", port=7860) | |