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)