revivetube update

This commit is contained in:
TheErrorExe 2025-02-25 16:08:44 +01:00
parent e9c12a7ef6
commit 9bef2e5f6f
6 changed files with 349 additions and 26 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ token.txt
__pycache__ __pycache__
sigma sigma
nohup.out nohup.out
cookies.txt

View file

@ -1,3 +1,4 @@
Flask Flask
Requests Requests
yt_dlp yt_dlp
bs4

View file

@ -22,6 +22,8 @@ import threading
import time import time
from threading import Thread from threading import Thread
from bs4 import BeautifulSoup
import requests import requests
import yt_dlp import yt_dlp
from flask import Flask, request, render_template_string, send_file, Response, abort, jsonify from flask import Flask, request, render_template_string, send_file, Response, abort, jsonify
@ -53,6 +55,8 @@ video_status = {}
FILE_SEPARATOR = os.sep FILE_SEPARATOR = os.sep
LOADING_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}loading_template.html") LOADING_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}loading_template.html")
CHANNEL_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}channel_template.html")
SEARCH_TEMPLATE = helper.read_file(f"site_storage{FILE_SEPARATOR}search_template.html")
os.makedirs(VIDEO_FOLDER, exist_ok=True) os.makedirs(VIDEO_FOLDER, exist_ok=True)
@ -139,29 +143,59 @@ def index():
if query: if query:
response = requests.get(f"https://invidious.materialio.us/api/v1/search?q={query}", timeout=3) response = requests.get(f"https://invidious.materialio.us/api/v1/search?q={query}", timeout=3)
else:
response = requests.get("https://invidious.materialio.us/api/v1/trending", timeout=3)
try: try:
data = response.json() data = response.json()
except ValueError: except ValueError:
return "Can't parse Data. If this Issue persist, report it in the Discord Server.", 500 return "Can't parse Data. If this Issue persists, report it in the Discord Server.", 500
if response.status_code == 200 and isinstance(data, list): if response.status_code == 200 and isinstance(data, list):
if query:
results = []
for entry in data:
if entry.get("type") == "video":
results.append({
"type": "video",
"id": entry.get("videoId"),
"title": entry.get("title"),
"uploader": entry.get("author", "Unknown"),
"thumbnail": f"/thumbnail/{entry['videoId']}",
"viewCount": entry.get("viewCountText", "Unknown"),
"published": entry.get("publishedText", "Unknown"),
"duration": helper.format_duration(entry.get("lengthSeconds", 0))
})
elif entry.get("type") == "channel":
results.append({
"type": "channel",
"id": entry.get("authorId"),
"title": entry.get("author"),
"thumbnail": entry.get("authorThumbnails")[-1]["url"] if entry.get("authorThumbnails") else "/static/default_channel_thumbnail.jpg",
"subCount": entry.get("subCount", "Unknown"),
"videoCount": entry.get("videoCount", "Unknown")
})
return render_template_string(SEARCH_TEMPLATE, results=results)
else:
results = [ results = [
{ {
"id": entry.get("videoId"), "id": entry.get("videoId"),
"title": entry.get("title"), "title": entry.get("title"),
"uploader": entry.get("author", "Unbekannt"), "uploader": entry.get("author", "Unknown"),
"thumbnail": f"/thumbnail/{entry['videoId']}", "thumbnail": f"/thumbnail/{entry['videoId']}",
"viewCount": entry.get("viewCountText", "Unbekannt"), "viewCount": entry.get("viewCountText", "Unknown"),
"published": entry.get("publishedText", "Unbekannt"), "published": entry.get("publishedText", "Unknown"),
"duration": helper.format_duration(entry.get("lengthSeconds", 0)) "duration": helper.format_duration(entry.get("lengthSeconds", 0))
} }
for entry in data for entry in data
if entry.get("videoId") if entry.get("videoId")
] ]
return render_template_string(INDEX_TEMPLATE, results=results)
else: else:
return "No Results or Error in the API.", 404 return "No Results or Error in the API.", 404
return render_template_string(INDEX_TEMPLATE, results=results)
@app.route("/watch", methods=["GET"]) @app.route("/watch", methods=["GET"])
def watch(): def watch():
@ -397,6 +431,7 @@ def serve_video(filename):
return send_file(file_path) return send_file(file_path)
@app.route('/channel', methods=['GET']) @app.route('/channel', methods=['GET'])
def channel_m(): def channel_m():
channel_id = request.args.get('channel_id', None) channel_id = request.args.get('channel_id', None)
@ -418,22 +453,48 @@ def channel_m():
if 'entries' not in info: if 'entries' not in info:
return "No videos found.", 404 return "No videos found.", 404
channel_name = info.get('uploader', 'Unknown')
invidious_url = f"https://invidious.materialio.us/channel/{channel_id}"
response = requests.get(invidious_url, timeout=10)
if response.status_code != 200:
return "Failed to fetch channel page.", 500
soup = BeautifulSoup(response.text, "html.parser")
profile_div = soup.find(class_="channel-profile")
if profile_div:
img_tag = profile_div.find("img")
if img_tag and "src" in img_tag.attrs:
channel_picture = "http://api.allorigins.win/raw?url=http://invidious.materialio.us" + img_tag["src"]
else:
channel_picture = ""
else:
channel_picture = ""
results = [ results = [
{ {
'id': video['id'], 'id': video['id'],
'duration': 'Duration not available on Channel View', 'duration': 'Duration not available on Channel View',
'title': video['title'], 'title': video['title'],
'uploader': info.get('uploader', 'Unknown'), 'uploader': channel_name,
'thumbnail': f"http://yt.old.errexe.xyz/thumbnail/{video['id']}" 'thumbnail': f"http://yt.old.errexe.xyz/thumbnail/{video['id']}"
} }
for video in info['entries'] for video in info['entries']
] ]
return render_template_string(INDEX_TEMPLATE, results=results) return render_template_string(
CHANNEL_TEMPLATE,
results=results,
channel_name=channel_name,
channel_picture=channel_picture
)
except Exception as e: except Exception as e:
return f"An error occurred: {str(e)}", 500 return f"An error occurred: {str(e)}", 500
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port=5000) app.run(host="0.0.0.0", debug=True, port=5000)

View file

@ -0,0 +1,132 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ReviveTube - A YouTube App for the Wii</title>
<style>
a {
color: #3ea6ff;
text-decoration: none;
}
a:hover {
color: #46bbff;
text-decoration: underline;
}
body {
font-family: Arial, sans-serif;
color: #fff;
background-color: #181818;
margin: 0;
padding: 0;
}
.header {
background-color: #202020;
border-bottom:2px solid #2c2c2c;
padding: 10px 20px;
display: flex;
align-items: center;
}
.logo {
font-size: 24px;
color: #fe0000;
font-weight: bold;
}
.search-container {
flex: 1;
text-align: center;
}
.search-bar {
width: 400px;
padding: 8px;
font-size: 16px;
border: 1px solid #313131;
background-color: #121212;
color: #fff;
}
.search-bar:hover {
border: 1px solid #268ee9;
}
.search-button {
padding: 8px 15px;
font-size: 16px;
background-color: #222222;
border:1px solid #3d3d3d;
color: white;
cursor: pointer;
}
.search-button:hover {
border: 1px solid #268ee9;
}
.content {
padding: 20px;
}
.video-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.video-item {
width: 320px;
margin: 10px;
background-color: #222;
padding: 10px;
}
.video-item img {
width: 100%;
}
.video-item-title {
font-weight: bold;
font-size: 14px;
margin-top: 5px;
}
.video-item-uploader, .video-item-duration {
color: #aaa;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo"><img src="../favicon.ico" style="width:32px; height:32px; display:inline; position:relative; top:3px; right:3px; padding-right:2px;"><span style="position:relative; top:-4px; padding-left:5px; border-left:1px solid #323232;">
ReviveTube</span></div>
<div class="search-container">
<form action="/" method="get">
<input class="search-bar" placeholder="Search YouTube" name="query" type="text">
<input type="submit" class="search-button" value="Search">
</form>
</div>
</div>
<div class="content">
{% if results %}
<div>
<img src="{{ channel_picture if channel_picture else 'default_profile.png' }}"
alt="Channel Profile Picture"
style="width: 48px; height: 48px; border-radius: 50%; object-fit: cover; display: inline-block; vertical-align: middle; margin-right: 10px;">
<h2 style="display: inline-block; vertical-align: middle; margin: 0; color: white;">{{ channel_name }}</h2>
</div>
<div class="video-grid">
{% for video in results %}
<div class="video-item">
<a href="/watch?video_id={{ video['id'] }}">
<img alt="{{ video['title'] }}" src="{{ video['thumbnail'] }}">
</a>
<div class="video-item-title">{{ video['title'] }}</div>
<div class="video-item-uploader">By: {{ video['uploader'] }}</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
<p style="color: red; text-align: center;">ReviveTube - A YouTube App for the Wii</p>
<p style="text-align: center;"><a href="http://revivemii.xyz" target="_blank">Visit the ReviveMii Project</a></p>
<p style="font-size: 12px; text-align: center;">We are NOT affiliated with Nintendo or YouTube.</p>
<p style="text-align: center;">
<a href="https://github.com/ReviveMii/revivetube/" target="_blank">Source Code</a> |
<a href="https://revivemii.errexe.xyz/discord-redirect.html">Discord Server</a> |
<a href="mailto:theerrorexe@gmail.com">Contact</a> |
<a href="/site_storage/credits.html">Credits</a>
</p>
</body>
</html>

View file

@ -98,7 +98,6 @@
</div> </div>
<div class="content"> <div class="content">
{% if results %} {% if results %}
<h2>Search Results:</h2>
<div class="video-grid"> <div class="video-grid">
{% for video in results %} {% for video in results %}
<div class="video-item"> <div class="video-item">

View file

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ReviveTube - A YouTube App for the Wii</title>
<style>
a {
color: #3ea6ff;
text-decoration: none;
}
a:hover {
color: #46bbff;
text-decoration: underline;
}
body {
font-family: Arial, sans-serif;
color: #fff;
background-color: #181818;
margin: 0;
padding: 0;
}
.header {
background-color: #202020;
border-bottom:2px solid #2c2c2c;
padding: 10px 20px;
display: flex;
align-items: center;
}
.logo {
font-size: 24px;
color: #fe0000;
font-weight: bold;
}
.search-container {
flex: 1;
text-align: center;
}
.search-bar {
width: 400px;
padding: 8px;
font-size: 16px;
border: 1px solid #313131;
background-color: #121212;
color: #fff;
}
.search-bar:hover {
border: 1px solid #268ee9;
}
.search-button {
padding: 8px 15px;
font-size: 16px;
background-color: #222222;
border:1px solid #3d3d3d;
color: white;
cursor: pointer;
}
.search-button:hover {
border: 1px solid #268ee9;
}
.content {
padding: 20px;
}
.video-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.video-item {
width: 320px;
margin: 10px;
background-color: #222;
padding: 10px;
}
.video-item img {
width: 100%;
}
.video-item-title {
font-weight: bold;
font-size: 14px;
margin-top: 5px;
}
.video-item-uploader, .video-item-duration {
color: #aaa;
font-size: 12px;
}
</style>
</head>
<body>
<div class="header">
<div class="logo"><img src="../favicon.ico" style="width:32px; height:32px; display:inline; position:relative; top:3px; right:3px; padding-right:2px;"><span style="position:relative; top:-4px; padding-left:5px; border-left:1px solid #323232;">
ReviveTube</span></div>
<div class="search-container">
<form action="/" method="get">
<input class="search-bar" placeholder="Search YouTube" name="query" type="text">
<input type="submit" class="search-button" value="Search">
</form>
</div>
</div>
<div class="content">
{% if results %}
<div class="video-grid">
{% for result in results %}
<div class="video-item">
<a href="{% if result.type == 'video' %}/watch?video_id={{ result.id }}{% else %}/channel?channel_id={{ result.id }}{% endif %}">
<img alt="{{ result.title }}" src="{{ result.thumbnail }}">
</a>
<div class="video-item-title">{{ result.title }}</div>
{% if result.type == 'video' %}
<div class="video-item-uploader">By: {{ result.uploader }}</div>
<div class="video-item-duration">Duration: {{ result.duration }}</div>
{% else %}
<div class="video-item-uploader">Subscribers: {{ result.subCount }}</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
<p style="color: red; text-align: center;">ReviveTube - A YouTube App for the Wii</p>
<p style="text-align: center;"><a href="http://revivemii.xyz" target="_blank">Visit the ReviveMii Project</a></p>
<p style="font-size: 12px; text-align: center;">We are NOT affiliated with Nintendo or YouTube.</p>
<p style="text-align: center;">
<a href="https://github.com/ReviveMii/revivetube/" target="_blank">Source Code</a> |
<a href="https://revivemii.errexe.xyz/discord-redirect.html">Discord Server</a> |
<a href="mailto:theerrorexe@gmail.com">Contact</a> |
<a href="/site_storage/credits.html">Credits</a>
</p>
</body>
</html>