Merge pull request #1 from rmilooo/main

This commit is contained in:
TheErrorExe 2025-01-01 22:43:58 +01:00 committed by GitHub
commit 7fe1bf52d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 459 additions and 402 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
token.txt
.venv
.idea
__pycache__

View file

@ -1,6 +1,7 @@
import os
import time
import subprocess
import time
def get_folder_size(folder_path):
total_size = 0
@ -11,6 +12,7 @@ def get_folder_size(folder_path):
total_size += os.path.getsize(filepath)
return total_size
def delete_files(folder_path, extensions):
os.system('sudo pkill -f revivetube.py')
process = subprocess.Popen(['sudo', 'nohup', 'python3', 'revivetube.py'])
@ -23,6 +25,7 @@ def delete_files(folder_path, extensions):
except:
print("ERROR")
def monitor_folder(folder_path, size_limit_gb, check_interval):
size_limit_bytes = size_limit_gb * 1024 * 1024 * 1024
while True:
@ -31,6 +34,7 @@ def monitor_folder(folder_path, size_limit_gb, check_interval):
delete_files(folder_path, [".flv", ".mp4"])
time.sleep(check_interval)
if __name__ == "__main__":
folder_to_monitor = "./sigma/videos/"
size_limit = 7

1
generateRequirements.sh Normal file
View file

@ -0,0 +1 @@
pipreqs . --force --ignore .venv

57
helper.py Normal file
View file

@ -0,0 +1,57 @@
import json
import os
import subprocess
def read_file(path):
assert isinstance(path, str), "Path must be a string"
try:
with open(path, 'r', encoding='utf-8') as file:
content = file.read()
return content
except FileNotFoundError:
return "Error: File not found."
except Exception as e:
return f"Error: {str(e)}"
def get_video_duration_from_file(video_path):
try:
result = subprocess.run(
['ffprobe', '-v', 'error', '-show_format', '-show_streams', '-of', 'json', video_path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
video_info = json.loads(result.stdout)
duration = float(video_info['format']['duration'])
return duration
except Exception as e:
print(f"Can't fetch Video-Duration: {str(e)}")
return 0
def format_duration(seconds):
minutes = seconds // 60
seconds = seconds % 60
return f"{minutes}:{str(seconds).zfill(2)}"
def get_file_size(file_path):
return os.path.getsize(file_path)
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()
except FileNotFoundError:
raise FileNotFoundError("Missing token.txt. Please go to README.md")

3
requirements.txt Normal file
View file

@ -0,0 +1,3 @@
Flask==3.1.0
Requests==2.32.3
yt_dlp==2024.12.23

View file

@ -14,29 +14,32 @@ If you use this Code, you agree to https://revivemii.fr.to/revivetube/t-and-p.ht
ReviveMii Project: https://revivemii.fr.to/
"""
import json
import isodate
from flask import Flask, request, render_template_string, send_file, Response, abort, jsonify
import tempfile
import shutil
import yt_dlp
import requests
import subprocess
import os
import shutil
import subprocess
import tempfile
import threading
from threading import Thread
import time
from threading import Thread
import requests
import yt_dlp
from flask import Flask, request, render_template_string, send_file, Response, abort, jsonify
import helper
app = Flask(__name__)
def check_and_create_folder():
while True:
folder_path = './sigma/videos'
if not os.path.exists(folder_path):
os.makedirs(folder_path)
print(f"Ordner {folder_path} wurde erstellt.")
print(f"Folder {folder_path} got created.")
time.sleep(10)
def start_folder_check():
thread = Thread(target=check_and_create_folder)
thread.daemon = True
@ -48,118 +51,16 @@ API_BASE_URL = "https://y.com.sb/api/v1/"
YOUTUBE_API_URL = "https://www.googleapis.com/youtube/v3/videos"
video_status = {}
LOADING_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Loading...</title>
<style>
body {
text-align: center;
font-family: Arial, sans-serif;
}
#loadingGif {
width: 50px;
height: 50px;
margin: 20px auto;
}
#goButton {
display: none;
margin-top: 20px;
padding: 10px 20px;
font-size: 16px;
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
}
#goButton:disabled {
background-color: gray;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>Loading</h1>
<img id="loadingGif" src="loading.gif" alt="Loading..." />
<p id="progressText">Fetching Info...</p>
<button id="goButton" onclick="startVideo()">Go</button>
<br>
<small style="color: grey">Loading Screen will NOT work in Dolphin Emulator.<br><br>Long Video = Longer Download and Converting.<br><br>For videos longer than 7 minutes, there is a chance that they wont play.</small>
<script type="text/javascript">
var goButton = document.getElementById('goButton');
var loadingGif = document.getElementById('loadingGif');
var progressText = document.getElementById('progressText');
var videoId = "{{ video_id }}";
FILE_SEPARATOR = os.sep
function simulateLoading() {
setInterval(checkStatus, 1000);
}
LOADING_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}loading_template.html")
function checkStatus() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/status/' + videoId, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var response;
try {
response = eval('(' + xhr.responseText + ')');
} catch (e) {
response = { status: 'error' };
}
updateProgress(response);
}
};
xhr.send();
}
function updateProgress(status) {
if (status.status === 'complete') {
loadingGif.style.display = 'none';
progressText.innerHTML = 'Done!';
goButton.style.display = 'inline';
} else if (status.status === 'downloading') {
progressText.innerHTML = 'The Server is Downloading...';
} else if (status.status === 'converting') {
progressText.innerHTML = 'The Server is Converting video...';
} else if (status.status === 'converting for Wii') {
progressText.innerHTML = 'The Server is Converting for Wii...';
} else {
progressText.innerHTML = 'The Server was unable to process the video! Report the Bug in the Discord Server. <br> Error Details for Developers: {{ video_id }}_unable_1.<br>Discord Server on ReviveMii Homepage Footer';
}
}
function startVideo() {
window.location.href = '/watch?video_id=' + videoId;
}
window.onload = function () {
simulateLoading();
};
</script>
</body>
</html>"""
def get_file_size(file_path):
return os.path.getsize(file_path)
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()
except FileNotFoundError:
raise FileNotFoundError("Missing token.txt. Please go to README.md")
os.makedirs(VIDEO_FOLDER, exist_ok=True)
MAX_VIDEO_SIZE = 1 * 1024 * 1024 * 1024
MAX_FOLDER_SIZE = 5 * 1024 * 1024 * 1024
MAX_VIDEO_SIZE = 1 * 1024 * 1024 * 1024
MAX_FOLDER_SIZE = 5 * 1024 * 1024 * 1024
def get_folder_size(path):
total_size = 0
@ -169,7 +70,10 @@ def get_folder_size(path):
total_size += os.path.getsize(file_path)
return total_size
"""
[UNUSED IN THE CURRENT VERSION]
def delete_videos_periodically():
while True:
time.sleep(86400)
@ -182,244 +86,13 @@ def delete_videos_periodically():
threading.Thread(target=delete_videos_periodically, daemon=True).start()
"""
INDEX_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ReviveTube by ReviveMii</title>
<style>
body {
font-family: 'Arial', sans-serif;
color: #fff;
background-color: #181818;
text-align: center;
}
h1 {
color: #ff0000;
font-size: 28px;
margin-bottom: 20px;
}
p, h2 {
font-size: 16px;
margin-bottom: 10px;
}
.search-bar {
width: 300px;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 4px;
display: block;
margin: 0 auto;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #333333;
color: white;
border: none;
cursor: pointer;
border-radius: 4px;
display: block;
margin: 10px auto;
}
.video-item {
margin-bottom: 20px;
text-align: center;
}
.video-item img {
width: 320px;
height: 180px;
border-radius: 8px;
}
.video-item-title {
color: #fff;
font-weight: bold;
font-size: 16px;
text-align: center;
}
.video-item-uploader {
color: #ccc;
font-size: 14px;
text-align: center;
}
.video-item-duration {
color: #ccc;
font-size: 14px;
text-align: center;
margin-top: 5px;
}
.dark-mode {
background-color: #181818;
color: #fff;
}
.dark-mode a {
color: #1e90ff;
}
</style>
</head>
<body class="dark-mode" id="page-body">
<h1>ReviveTube by ReviveMii</h1>
<p>A YouTube App for the Wii</p>
<form action="/" method="get">
<input class="search-bar" type="text" name="query" placeholder="Search YouTube">
<button type="submit">Go</button>
</form>
{% if results %}
<h2>Search Results</h2>
<div>
{% for video in results %}
<div class="video-item">
<a href="/watch?video_id={{ video['id'] }}">
<img src="{{ video['thumbnail'] }}" alt="{{ video['title'] }}">
<div class="video-item-title">{{ video['title'] }}</div>
<div class="video-item-uploader">By: {{ video['uploader'] }}</div>
<div class="video-item-duration">Duration: {{ video['duration'] }}</div>
</a>
</div>
{% endfor %}
</div>
{% endif %}
<p><a href="http://revivemii.errexe.xyz" target="_blank">Visit ReviveMii</a></p>
<p style="color: red;">\/ Scroll down \/</p>
<p style="font-size: 12px;">We are NOT affiliated with Nintendo or YouTube. This app uses code from Wiinet.xyz. For more information, scroll down to Open Source Software.</p>
<p style="color: blue">It's recommended to bookmark this page. Some sites may take longer to load.</p>
<a href="http://revivetube.errexe.xyz/revivetube/t-and-p.html">Terms of Service and Privacy Policy (Last Updated: 7. Dec 2024 12:41 CET)</a><br><br>
<a href="https://github.com/ReviveMii/revivetube/" target="_blank">Source Code</a><br><br>
<a href="http://revivetube.errexe.xyz/discord-redirect.html">Discord Server [Use a Compatible Device]</a>
<p>Version: v2 Beta (Sometimes I forget to update the Version Number)</p>
<a href="/licenses.html">Open Source Software Used in This App</a>
<br>
<a href="mailto:theerrorexe@gmail.com">Contact</a>
<br>
<a href="https://revivemii.errexe.xyz/feedback.html">Report Bugs & Feedback</a>
</body>
</html>
"""
INDEX_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}index_template.html")
WATCH_STANDARD_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}watch_standard_template.html")
WATCH_WII_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}watch_wii_template.html")
WATCH_STANDARD_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<style>
body { font-family: 'Arial', sans-serif; text-align: center; color: #fff; background-color: #181818; }
video { margin-top: 20px; }
h1 { color: #ff0000; font-size: 24px; }
h3, p { font-size: 16px; }
.comments { text-align: left; margin: 0 auto; width: 80%; font-size: 14px; }
.comment { margin-bottom: 15px; padding: 10px; border-bottom: 1px solid #ddd; }
.comment p { font-size: 14px; }
.dark-mode { background-color: #181818; color: #fff; }
.dark-mode a { color: #1e90ff; }
</style>
</head>
<!-- <body class="dark-mode" id="page-body">
<video width="640" height="360" controls>
<source src="{{ video_mp4 }}" type="video/mp4">
Your browser does not support the video tag.
</video>
<h1>{{ title }}</h1>
<h3>Uploaded by: <a href="/channel?channel_id={{ channelId }}">{{ uploader }}</a></h3>
<p><strong>Views:</strong> {{ viewCount }}</p>
<p><strong>Likes:</strong> {{ likeCount }}</p>
<p><strong>Upload Date:</strong> {{ publishedAt }}</p>
<a href="#comments">Skip Description</a>
<h3>Description:</h3>
<p>{{ description | safe }}</p>
<h3 id="comments" class="comments">Comments:</h3>
<div class="comments">
{% if comments %}
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment.author }}</strong> posted:</p>
<p>{{ comment.text|safe }}</p>
<p style="color: gray; font-size: 12px;">Likes: {{ comment.likeCount }} | Post date: {{ comment.publishedAt }}</p>
</div>
{% endfor %}
{% else %}
<p>No Comments.</p>
{% endif %}
</div> -->
Please access this Site on a Wii
</body>
</html>
"""
WATCH_WII_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<style>
body {
font-family: 'Arial', sans-serif;
text-align: center; /* Zentriert den Text */
color: #fff;
background-color: #181818;
}
.dark-mode {
background-color: #181818;
color: #fff;
}
.dark-mode a {
color: #1e90ff;
}
.comments {
margin: 0 auto;
width: 80%;
}
h1 {
color: red;
text-align: center;
}
h3 {
color: white;
text-align: center;
}
</style>
<script src="https://unpkg.com/@ruffle-rs/ruffle"></script>
</head>
<body class="dark-mode" id="page-body">
<div style="width: 100%; background-color: #000; text-align: center;">
<object type="application/x-shockwave-flash" data="/player.swf" width="384" height="256">
<param name="wmode" value="transparent">
<param name="allowFullScreen" value="false">
<param name="flashvars" value="filename={{ video_flv }}">
</object>
</div>
<h1 style="color: red">{{ title }}</h1>
<h3>Uploaded by: <a href="/channel?channel_id={{ channelId }}">{{ uploader }}</a></h3>
<p><strong>Views:</strong> {{ viewCount }}</p>
<p><strong>Likes:</strong> {{ likeCount }}</p>
<p><strong>Upload Date:</strong> {{ publishedAt }}</p>
<a href="#comments">Skip Description</a>
<h3 style="color: red">Description:</h3>
<p>{{ description | safe }}</p>
<h3 id="comments" class="comments" style="color: red">Comments:</h3>
<div class="comments">
{% if comments %}
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment.author }}</strong> posted:</p>
<p>{{ comment.text|safe }}</p>
<p style="color: gray; font-size: 12px;">Likes: {{ comment.likeCount }} | Post date: {{ comment.publishedAt }}</p>
</div>
{% endfor %}
{% else %}
<p>No Comments.</p>
{% endif %}
</div>
</body>
</html>
"""
@app.route("/thumbnail/<video_id>")
def get_thumbnail(video_id):
thumbnail_url = f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg"
@ -439,15 +112,16 @@ def get_thumbnail(video_id):
except requests.exceptions.RequestException as e:
return f"Error fetching thumbnail: {str(e)}", 500
def get_video_comments(video_id, max_results=20):
api_key = get_api_key()
api_key = helper.get_api_key()
params = {
"part": "snippet",
"videoId": video_id,
"key": api_key,
"maxResults": max_results,
"order": "relevance"
"order": "relevance"
}
try:
@ -472,6 +146,8 @@ def get_video_comments(video_id, max_results=20):
except requests.exceptions.RequestException as e:
print(f"Fehler beim Abrufen der Kommentare: {str(e)}")
return []
@app.route("/switch_wii", methods=["GET"])
def switch_wii():
video_id = request.args.get("video_id")
@ -489,6 +165,7 @@ def switch_wii():
else:
return "Can't start DEBUG Mode.", 500
@app.route("/switch_n", methods=["GET"])
def switch_n():
video_id = request.args.get("video_id")
@ -506,6 +183,7 @@ def switch_n():
else:
return "Can't start DEBUG Mode.", 500
@app.route("/", methods=["GET"])
def index():
query = request.args.get("query")
@ -527,7 +205,7 @@ def index():
"thumbnail": f"/thumbnail/{entry['videoId']}",
"viewCount": entry.get("viewCountText", "Unbekannt"),
"published": entry.get("publishedText", "Unbekannt"),
"duration": format_duration(entry.get("lengthSeconds", 0)) # Video Dauer formatiert
"duration": helper.format_duration(entry.get("lengthSeconds", 0)) # Video Dauer formatiert
}
for entry in data
if entry.get("videoId")
@ -537,27 +215,6 @@ def index():
return render_template_string(INDEX_TEMPLATE, results=results)
def format_duration(seconds):
minutes = seconds // 60
seconds = seconds % 60
return f"{minutes}:{str(seconds).zfill(2)}"
def get_video_duration_from_file(video_path):
try:
result = subprocess.run(
['ffprobe', '-v', 'error', '-show_format', '-show_streams', '-of', 'json', video_path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
video_info = json.loads(result.stdout)
duration = float(video_info['format']['duration'])
return duration
except Exception as e:
print(f"Can't fetch Video-Duration: {str(e)}")
return 0
@app.route("/watch", methods=["GET"])
def watch():
@ -583,7 +240,6 @@ def watch():
except requests.exceptions.RequestException as e:
return f"Can't connect to Metadata-API: {str(e)}", 500
comments = []
try:
comments = get_video_comments(video_id)
@ -592,7 +248,7 @@ def watch():
comments = []
if os.path.exists(video_mp4_path):
video_duration = get_video_duration_from_file(video_flv_path)
video_duration = helper.get_video_duration_from_file(video_flv_path)
alert_script = ""
if video_duration > 420:
alert_script = """
@ -600,28 +256,28 @@ def watch():
alert("This Video is long. There is a chance that the Wii will not play the Video. Try a Video under 7 minutes or something like that.");
</script>
"""
if is_wii and os.path.exists(video_flv_path):
return render_template_string(WATCH_WII_TEMPLATE + alert_script,
title=metadata['title'],
uploader=metadata['uploader'],
return render_template_string(WATCH_WII_TEMPLATE + alert_script,
title=metadata['title'],
uploader=metadata['uploader'],
channelId=metadata['channelId'],
description=metadata['description'].replace("\n", "<br>"),
viewCount=metadata['viewCount'],
viewCount=metadata['viewCount'],
likeCount=metadata['likeCount'],
publishedAt=metadata['publishedAt'],
comments=comments,
video_id=video_id,
video_id=video_id,
video_flv=f"/sigma/videos/{video_id}.flv",
alert_message="")
return render_template_string(WATCH_WII_TEMPLATE,
title=metadata['title'],
uploader=metadata['uploader'],
return render_template_string(WATCH_WII_TEMPLATE,
title=metadata['title'],
uploader=metadata['uploader'],
channelId=metadata['channelId'],
description=metadata['description'].replace("\n", "<br>"),
viewCount=metadata['viewCount'],
likeCount=metadata['likeCount'],
viewCount=metadata['viewCount'],
likeCount=metadata['likeCount'],
publishedAt=metadata['publishedAt'],
comments=comments,
video_id=video_id,
@ -633,6 +289,7 @@ def watch():
threading.Thread(target=process_video, args=(video_id,)).start()
return render_template_string(LOADING_TEMPLATE, video_id=video_id)
def process_video(video_id):
video_mp4_path = os.path.join(VIDEO_FOLDER, f"{video_id}.mp4")
video_flv_path = os.path.join(VIDEO_FOLDER, f"{video_id}.flv")
@ -645,7 +302,7 @@ def process_video(video_id):
command = [
"yt-dlp",
"-f worstvideo+worstaudio",
"--proxy", "http://localhost:4000",
"http://localhost:4000",
"-o", temp_video_path,
f"https://m.youtube.com/watch?v={video_id}"
]
@ -703,13 +360,15 @@ def process_video(video_id):
except Exception as e:
video_status[video_id] = {"status": "error", "message": str(e)}
@app.route("/status/<video_id>")
def check_status(video_id):
return jsonify(video_status.get(video_id, {"status": "pending"}))
@app.route("/video_metadata/<video_id>")
def video_metadata(video_id):
api_key = get_api_key()
api_key = helper.get_api_key()
params = {
"part": "snippet,statistics",
@ -719,7 +378,7 @@ def video_metadata(video_id):
try:
response = requests.get(YOUTUBE_API_URL, params=params, timeout=1)
response.raise_for_status()
response.raise_for_status()
data = response.json()
@ -750,6 +409,7 @@ def video_metadata(video_id):
except requests.exceptions.RequestException as e:
return f"Fehler bei der API-Anfrage: {str(e)}", 500
@app.route("/<path:filename>")
def serve_video(filename):
file_path = os.path.join(filename)
@ -757,7 +417,7 @@ def serve_video(filename):
if not os.path.exists(file_path):
return "File not found.", 404
file_size = get_file_size(file_path)
file_size = helper.get_file_size(file_path)
range_header = request.headers.get('Range', None)
if range_header:
@ -767,9 +427,9 @@ def serve_video(filename):
end_byte = int(end_byte) if end_byte else file_size - 1
if start_byte >= file_size or end_byte >= file_size:
abort(416)
abort(416)
data = get_range(file_path, (start_byte, end_byte))
data = helper.get_range(file_path, (start_byte, end_byte))
content_range = f"bytes {start_byte}-{end_byte}/{file_size}"
response = Response(
@ -785,10 +445,11 @@ def serve_video(filename):
return send_file(file_path)
@app.route('/channel', methods=['GET'])
def channel_m():
channel_id = request.args.get('channel_id', None)
if not channel_id:
return "Channel ID is required.", 400
@ -797,7 +458,7 @@ def channel_m():
'extract_flat': True,
'playlistend': 20,
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
url = f"https://www.youtube.com/channel/{channel_id}/videos"
@ -805,7 +466,7 @@ def channel_m():
if 'entries' not in info:
return "No videos found.", 404
results = [
{
'id': video['id'],
@ -816,11 +477,12 @@ def channel_m():
}
for video in info['entries']
]
return render_template_string(INDEX_TEMPLATE, results=results)
except Exception as e:
return f"An error occurred: {str(e)}", 500
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port=5000)

View file

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>ReviveTube by ReviveMii</title>
<style>
body {
font-family: 'Arial', sans-serif;
color: #fff;
background-color: #181818;
text-align: center;
}
h1 {
color: #ff0000;
font-size: 28px;
margin-bottom: 20px;
}
p, h2 {
font-size: 16px;
margin-bottom: 10px;
}
.search-bar {
width: 300px;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 4px;
display: block;
margin: 0 auto;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #333333;
color: white;
border: none;
cursor: pointer;
border-radius: 4px;
display: block;
margin: 10px auto;
}
.video-item {
margin-bottom: 20px;
text-align: center;
}
.video-item img {
width: 320px;
height: 180px;
border-radius: 8px;
}
.video-item-title {
color: #fff;
font-weight: bold;
font-size: 16px;
text-align: center;
}
.video-item-uploader {
color: #ccc;
font-size: 14px;
text-align: center;
}
.video-item-duration {
color: #ccc;
font-size: 14px;
text-align: center;
margin-top: 5px;
}
.dark-mode {
background-color: #181818;
color: #fff;
}
.dark-mode a {
color: #1e90ff;
}
</style>
</head>
<body class="dark-mode" id="page-body">
<h1>ReviveTube by ReviveMii</h1>
<p>A YouTube App for the Wii</p>
<form action="/" method="get">
<input class="search-bar" name="query" placeholder="Search YouTube" type="text">
<button type="submit">Go</button>
</form>
{% if results %}
<h2>Search Results</h2>
<div>
{% for video in results %}
<div class="video-item">
<a href="/watch?video_id={{ video['id'] }}">
<img alt="{{ video['title'] }}" src="{{ video['thumbnail'] }}">
<div class="video-item-title">{{ video['title'] }}</div>
<div class="video-item-uploader">By: {{ video['uploader'] }}</div>
<div class="video-item-duration">Duration: {{ video['duration'] }}</div>
</a>
</div>
{% endfor %}
</div>
{% endif %}
<p><a href="http://revivemii.errexe.xyz" target="_blank">Visit ReviveMii</a></p>
<p style="color: red;">\/ Scroll down \/</p>
<p style="font-size: 12px;">We are NOT affiliated with Nintendo or YouTube. This app uses code from Wiinet.xyz. For more
information, scroll down to Open Source Software.</p>
<p style="color: blue">It's recommended to bookmark this page. Some sites may take longer to load.</p>
<a href="http://revivetube.errexe.xyz/revivetube/t-and-p.html">Terms of Service and Privacy Policy (Last Updated: 7. Dec
2024 12:41 CET)</a><br><br>
<a href="https://github.com/ReviveMii/revivetube/" target="_blank">Source Code</a><br><br>
<a href="http://revivetube.errexe.xyz/discord-redirect.html">Discord Server [Use a Compatible Device]</a>
<p>Version: v2 Beta (Sometimes I forget to update the Version Number)</p>
<a href="/licenses.html">Open Source Software Used in This App</a>
<br>
<a href="mailto:theerrorexe@gmail.com">Contact</a>
<br>
<a href="https://revivemii.errexe.xyz/feedback.html">Report Bugs & Feedback</a>
</body>
</html>

View file

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Loading...</title>
<style>
body {
text-align: center;
font-family: Arial, sans-serif;
}
#loadingGif {
width: 50px;
height: 50px;
margin: 20px auto;
}
#goButton {
display: none;
margin-top: 20px;
padding: 10px 20px;
font-size: 16px;
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
}
#goButton:disabled {
background-color: gray;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>Loading</h1>
<img alt="Loading..." id="loadingGif" src="loading.gif"/>
<p id="progressText">Fetching Info...</p>
<button id="goButton" onclick="startVideo()">Go</button>
<br>
<small style="color: grey">Loading Screen will NOT work in Dolphin Emulator.<br><br>Long Video = Longer Download and
Converting.<br><br>For videos longer than 7 minutes, there is a chance that they wont play.</small>
<script type="text/javascript">
var goButton = document.getElementById('goButton');
var loadingGif = document.getElementById('loadingGif');
var progressText = document.getElementById('progressText');
var videoId = "{{ video_id }}";
function simulateLoading() {
setInterval(checkStatus, 1000);
}
function checkStatus() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/status/' + videoId, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var response;
try {
response = eval('(' + xhr.responseText + ')');
} catch (e) {
response = { status: 'error' };
}
updateProgress(response);
}
};
xhr.send();
}
function updateProgress(status) {
if (status.status === 'complete') {
loadingGif.style.display = 'none';
progressText.innerHTML = 'Done!';
goButton.style.display = 'inline';
} else if (status.status === 'downloading') {
progressText.innerHTML = 'The Server is Downloading...';
} else if (status.status === 'converting') {
progressText.innerHTML = 'The Server is Converting video...';
} else if (status.status === 'converting for Wii') {
progressText.innerHTML = 'The Server is Converting for Wii...';
} else {
progressText.innerHTML = 'The Server was unable to process the video! Report the Bug in the Discord Server. <br> Error Details for Developers: {{ video_id }}_unable_1.<br>Discord Server on ReviveMii Homepage Footer';
}
}
function startVideo() {
window.location.href = '/watch?video_id=' + videoId;
}
window.onload = function () {
simulateLoading();
};
</script>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>{{ title }}</title>
<style>
body { font-family: 'Arial', sans-serif; text-align: center; color: #fff; background-color: #181818; }
video { margin-top: 20px; }
h1 { color: #ff0000; font-size: 24px; }
h3, p { font-size: 16px; }
.comments { text-align: left; margin: 0 auto; width: 80%; font-size: 14px; }
.comment { margin-bottom: 15px; padding: 10px; border-bottom: 1px solid #ddd; }
.comment p { font-size: 14px; }
.dark-mode { background-color: #181818; color: #fff; }
.dark-mode a { color: #1e90ff; }
</style>
</head>
<!-- <body class="dark-mode" id="page-body">
<video width="640" height="360" controls>
<source src="{{ video_mp4 }}" type="video/mp4">
Your browser does not support the video tag.
</video>
<h1>{{ title }}</h1>
<h3>Uploaded by: <a href="/channel?channel_id={{ channelId }}">{{ uploader }}</a></h3>
<p><strong>Views:</strong> {{ viewCount }}</p>
<p><strong>Likes:</strong> {{ likeCount }}</p>
<p><strong>Upload Date:</strong> {{ publishedAt }}</p>
<a href="#comments">Skip Description</a>
<h3>Description:</h3>
<p>{{ description | safe }}</p>
<h3 id="comments" class="comments">Comments:</h3>
<div class="comments">
{% if comments %}
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment.author }}</strong> posted:</p>
<p>{{ comment.text|safe }}</p>
<p style="color: gray; font-size: 12px;">Likes: {{ comment.likeCount }} | Post date: {{ comment.publishedAt }}</p>
</div>
{% endfor %}
{% else %}
<p>No Comments.</p>
{% endif %}
</div> -->
Please access this Site on a Wii
</body>
</html>

View file

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>{{ title }}</title>
<style>
body {
font-family: 'Arial', sans-serif;
text-align: center; /* Zentriert den Text */
color: #fff;
background-color: #181818;
}
.dark-mode {
background-color: #181818;
color: #fff;
}
.dark-mode a {
color: #1e90ff;
}
.comments {
margin: 0 auto;
width: 80%;
}
h1 {
color: red;
text-align: center;
}
h3 {
color: white;
text-align: center;
}
</style>
<script src="https://unpkg.com/@ruffle-rs/ruffle"></script>
</head>
<body class="dark-mode" id="page-body">
<div style="width: 100%; background-color: #000; text-align: center;">
<object data="/player.swf" height="256" type="application/x-shockwave-flash" width="384">
<param name="wmode" value="transparent">
<param name="allowFullScreen" value="false">
<param name="flashvars" value="filename={{ video_flv }}">
</object>
</div>
<h1 style="color: red">{{ title }}</h1>
<h3>Uploaded by: <a href="/channel?channel_id={{ channelId }}">{{ uploader }}</a></h3>
<p><strong>Views:</strong> {{ viewCount }}</p>
<p><strong>Likes:</strong> {{ likeCount }}</p>
<p><strong>Upload Date:</strong> {{ publishedAt }}</p>
<a href="#comments">Skip Description</a>
<h3 style="color: red">Description:</h3>
<p>{{ description | safe }}</p>
<h3 class="comments" id="comments" style="color: red">Comments:</h3>
<div class="comments">
{% if comments %}
{% for comment in comments %}
<div class="comment">
<p><strong>{{ comment.author }}</strong> posted:</p>
<p>{{ comment.text|safe }}</p>
<p style="color: gray; font-size: 12px;">Likes: {{ comment.likeCount }} | Post date: {{ comment.publishedAt
}}</p>
</div>
{% endfor %}
{% else %}
<p>No Comments.</p>
{% endif %}
</div>
</body>
</html>