From e41d3082cd7fbc4ff133a900a381c25628628262 Mon Sep 17 00:00:00 2001 From: TheErrorExe <161362055+TheErrorExe@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:08:56 +0100 Subject: [PATCH] Create betaserver.py --- betaserver.py | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 betaserver.py diff --git a/betaserver.py b/betaserver.py new file mode 100644 index 0000000..3e12ba2 --- /dev/null +++ b/betaserver.py @@ -0,0 +1,352 @@ +from flask import Flask, request, render_template_string, send_file, Response, abort +import requests +import subprocess +import os +import threading +import time + +# Flask-Setup +app = Flask(__name__) + +# Konstanten +RIITUBE_BASE_URL = "https://riitube.rc24.xyz/" +VIDEO_FOLDER = "sigma/videos" +API_BASE_URL = "https://y.com.sb/api/v1/" +YOUTUBE_API_URL = "https://www.googleapis.com/youtube/v3/videos" + +# Diese Funktion dient dazu, die Dateigröße zu ermitteln +def get_file_size(file_path): + return os.path.getsize(file_path) + +# Diese Funktion dient dazu, einen bestimmten Abschnitt einer Datei zurückzugeben +def get_range(file_path, byte_range): + with open(file_path, 'rb') as f: + f.seek(byte_range[0]) + return f.read(byte_range[1] - byte_range[0] + 1) + +def get_api_key(): + try: + with open("token.txt", "r") as f: + return f.read().strip() # Den API Key zurückgeben + except FileNotFoundError: + raise FileNotFoundError("Die Datei token.txt wurde nicht gefunden. Bitte stelle sicher, dass sie vorhanden ist.") + +# Videos-Ordner erstellen, falls nicht vorhanden +os.makedirs(VIDEO_FOLDER, exist_ok=True) + +# Maximum size limits (1 GB and 5 GB) +MAX_VIDEO_SIZE = 1 * 1024 * 1024 * 1024 # 1 GB +MAX_FOLDER_SIZE = 5 * 1024 * 1024 * 1024 # 5 GB + +# Helper function to calculate the total size of the folder +def get_folder_size(path): + total_size = 0 + for dirpath, dirnames, filenames in os.walk(path): + for f in filenames: + file_path = os.path.join(dirpath, f) + total_size += os.path.getsize(file_path) + return total_size + +# Function to periodically delete videos every 5 minutes +def delete_videos_periodically(): + while True: + time.sleep(86400) # 24 hours + for filename in os.listdir(VIDEO_FOLDER): + file_path = os.path.join(VIDEO_FOLDER, filename) + if os.path.isfile(file_path): + os.remove(file_path) + print(f"Deleted: {file_path}") + +# Start the periodic deletion in a separate thread +threading.Thread(target=delete_videos_periodically, daemon=True).start() + +# HTML-Templates als Strings +INDEX_TEMPLATE = """ + + + + + + ReviveTube by ReviveMii + + +

ReviveTube by ReviveMii

+
+ + +
+ {% if results %} +

Search Results

+ + {% endif %} +
+ Visit ReviveMii +

This app uses the RiiConnect24 WiiMC API. We are NOT afiliated with RiiConnect24, Nintendo or YouTube. This app is using Code from Wiinet.xyz.

+

It's recommend to bookmark this Page

+

It's normal that Sites take long to load

+ + +""" + +WATCH_STANDARD_TEMPLATE = """ + + + + + + {{ title }} + + +

{{ title }}

+

Uploaded by: {{ uploader }}

+ +

Description:

+

{{ description }}

+ + +""" + +WATCH_WII_TEMPLATE = """ + + + + + + {{ title }} + + +
+ + + + + +
+

If the video does not play smoothly, restart the Internet Channel by pressing the Home button and then Reset. It's a bug. It happens if you visit too many Sites

+

{{ title }}

+

Uploaded by: {{ uploader }}

+

Description:

+

{{ description }}

+ + +""" +@app.route("/thumbnail/") +def get_thumbnail(video_id): + thumbnail_url = f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg" + + try: + # Thumbnail von YouTube abrufen + response = requests.get(thumbnail_url, stream=True, timeout=5) + if response.status_code == 200: + # Content-Type weiterleiten + return send_file( + response.raw, + mimetype=response.headers.get("Content-Type", "image/jpeg"), + as_attachment=False, + ) + else: + return f"Failed to fetch thumbnail. Status: {response.status_code}", 500 + except requests.exceptions.RequestException as e: + return f"Error fetching thumbnail: {str(e)}", 500 + +@app.route("/", methods=["GET"]) +def index(): + query = request.args.get("query") + results = None + + if query: + # API-Anfrage an y.com.sb für die Suchergebnisse + response = requests.get(f"{API_BASE_URL}search?q={query}", timeout=3) + try: + data = response.json() # Parst die JSON-Antwort der API + except ValueError: + return "Fehler beim Parsen der API-Antwort.", 500 + + # Ergebnisse verarbeiten, falls die API-Antwort erfolgreich und im erwarteten Format ist + if response.status_code == 200 and isinstance(data, list): + results = [ + { + "id": entry.get("videoId"), # Die Video-ID + "title": entry.get("title"), # Der Titel des Videos + "uploader": entry.get("author", "Unbekannt"), # Der Name des Uploaders + "thumbnail": f"/thumbnail/{entry['videoId']}", + "viewCount": entry.get("viewCountText", "Unbekannt"), # Anzahl der Aufrufe + "published": entry.get("publishedText", "Unbekannt") # Veröffentlichungsdatum + } + for entry in data # Iteriere durch jedes Video + if entry.get("videoId") # Sicherstellen, dass ein VideoID vorhanden ist + ] + else: + return "Keine Ergebnisse gefunden oder Fehler in der API-Antwort.", 404 + + return render_template_string(INDEX_TEMPLATE, results=results) + +@app.route("/watch", methods=["GET"]) +def watch(): + video_id = request.args.get("video_id") + if not video_id: + return "Missing video ID.", 400 + + # Metadaten abrufen + metadata_response = requests.get(f"http://127.0.0.1:5000/video_metadata/{video_id}") + if metadata_response.status_code != 200: + return f"Failed to fetch video metadata: {metadata_response.text}", 500 + + metadata = metadata_response.json() + + # User-Agent prüfen + user_agent = request.headers.get("User-Agent", "").lower() + is_wii = "wii" in user_agent and "wiiu" not in user_agent + + # Video-Pfade + video_mp4_path = os.path.join(VIDEO_FOLDER, f"{video_id}.mp4") + video_flv_path = os.path.join(VIDEO_FOLDER, f"{video_id}.flv") + + # Video herunterladen, falls nicht vorhanden + if not os.path.exists(video_mp4_path): + video_url = f"{RIITUBE_BASE_URL}video/wii/?q={video_id}" + + try: + response = requests.get(video_url, stream=True, timeout=10) + if response.status_code != 200: + return f"Failed to download video. HTTP Status: {response.status_code}, Reason: {response.reason}", 500 + + # Check file size during download + total_size = 0 + with open(video_mp4_path, "wb") as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) + total_size += len(chunk) + if total_size > MAX_VIDEO_SIZE: + os.remove(video_mp4_path) + return "Video exceeds 1 GB in size.", 400 + + except requests.exceptions.RequestException as e: + return f"An error occurred while downloading the video: {str(e)}", 500 + + # Für Wii in FLV umwandeln + if is_wii and not os.path.exists(video_flv_path): + try: + subprocess.run( + [ + "ffmpeg", + "-i", video_mp4_path, + "-ar", "22050", + "-f", "flv", + "-s", "320x240", + "-ab", "32k", + "-filter:v", "fps=fps=15", + video_flv_path + ], + check=True + ) + except subprocess.CalledProcessError as e: + return f"Failed to convert video to FLV for Wii: {str(e)}", 500 + + # HTML basierend auf User-Agent rendern + if is_wii: + return render_template_string(WATCH_WII_TEMPLATE, **metadata, video_flv=f"/sigma/videos/{video_id}.flv") + else: + return render_template_string(WATCH_STANDARD_TEMPLATE, **metadata, video_mp4=f"/sigma/videos/{video_id}.mp4") + +# Video-Metadaten zurückgeben (Simulation für Metadaten) +@app.route("/video_metadata/") +def video_metadata(video_id): + api_key = get_api_key() + + # API-Anfrage an YouTube Data API v3 + params = { + "part": "snippet,statistics", + "id": video_id, + "key": api_key + } + + try: + response = requests.get(YOUTUBE_API_URL, params=params, timeout=2) + response.raise_for_status() # Raise HTTPError für schlechte Antworten + + data = response.json() + + # Überprüfen, ob Video-Daten vorhanden sind + if "items" not in data or len(data["items"]) == 0: + return f"Video mit ID {video_id} wurde nicht gefunden.", 404 + + # Metadaten extrahieren + video_data = data["items"][0] + title = video_data["snippet"]["title"] + description = video_data["snippet"]["description"] + uploader = video_data["snippet"]["channelTitle"] + view_count = video_data["statistics"].get("viewCount", "Unknown") + like_count = video_data["statistics"].get("likeCount", "Unknown") + dislike_count = video_data["statistics"].get("dislikeCount", "Unknown") + + # Metadaten als JSON zurückgeben + return { + "title": title, + "uploader": uploader, + "description": description, + "viewCount": view_count, + "likeCount": like_count, + "dislikeCount": dislike_count + } + + except requests.exceptions.RequestException as e: + return f"Fehler bei der API-Anfrage: {str(e)}", 500 + +@app.route("/") +def serve_video(filename): + file_path = os.path.join(filename) + + # Überprüfen, ob die Datei existiert + if not os.path.exists(file_path): + return "File not found.", 404 + + file_size = get_file_size(file_path) + + # Überprüfen, ob ein Range-Header vorhanden ist + range_header = request.headers.get('Range', None) + if range_header: + # Range-Header parsen (Beispiel: 'bytes=0-499') + byte_range = range_header.strip().split('=')[1] + start_byte, end_byte = byte_range.split('-') + start_byte = int(start_byte) + end_byte = int(end_byte) if end_byte else file_size - 1 + + # Wenn der angeforderte Bereich ungültig ist + if start_byte >= file_size or end_byte >= file_size: + abort(416) # 416 Range Not Satisfiable + + # Abschnitt der Datei zurückgeben + data = get_range(file_path, (start_byte, end_byte)) + content_range = f"bytes {start_byte}-{end_byte}/{file_size}" + + # Antwort mit Status 206 (Partial Content) + response = Response( + data, + status=206, + mimetype="video/mp4", + content_type="video/mp4", + direct_passthrough=True + ) + response.headers["Content-Range"] = content_range + response.headers["Content-Length"] = str(len(data)) + return response + + # Wenn kein Range-Header vorhanden ist, wird die ganze Datei gesendet + return send_file(file_path) + +if __name__ == "__main__": + app.run(debug=True)