280 lines
11 KiB
Python
280 lines
11 KiB
Python
import flask
|
|
import datetime
|
|
import random
|
|
import string
|
|
import os
|
|
import re
|
|
|
|
app = flask.Flask(__name__)
|
|
app.config['LYRICS_DIR'] = 'lyrics'
|
|
code = ""
|
|
history = []
|
|
|
|
def is_youtube_url(url):
|
|
yt_patterns = [
|
|
r'youtube\.com/watch\?v=',
|
|
r'music\.youtube\.com/watch\?v=',
|
|
r'youtu\.be/'
|
|
]
|
|
return any(re.search(pattern, url) for pattern in yt_patterns)
|
|
|
|
def extract_yt_id(url):
|
|
patterns = [
|
|
r'v=([a-zA-Z0-9_-]{11})',
|
|
r'youtu\.be/([a-zA-Z0-9_-]{11})',
|
|
r'/([a-zA-Z0-9_-]{11})$'
|
|
]
|
|
for pattern in patterns:
|
|
match = re.search(pattern, url)
|
|
if match:
|
|
return match.group(1)
|
|
return None
|
|
|
|
@app.route('/musicstatus.html', methods=['GET', 'POST'])
|
|
def musicstatus():
|
|
global code, history
|
|
|
|
if flask.request.method == 'POST':
|
|
data = flask.request.get_json()
|
|
|
|
if code != data.get('verificationcode'):
|
|
return "Verification failed", 403
|
|
|
|
entry = (
|
|
data['music'],
|
|
data['time'],
|
|
data['resetstatus'],
|
|
data['videoid']
|
|
)
|
|
|
|
if data.get('resetstatus', '').lower() == "true":
|
|
history.clear()
|
|
|
|
history.append(entry)
|
|
return "Entry added successfully"
|
|
|
|
current_playing = history[-1] if history else None
|
|
lyrics_content = []
|
|
|
|
if current_playing:
|
|
lrc_path = os.path.join(app.config['LYRICS_DIR'], f"{current_playing[0]}.lrc")
|
|
if os.path.exists(lrc_path):
|
|
with open(lrc_path, 'r') as f:
|
|
lyrics = [line.split("]")[-1].strip() for line in f if "]" in line]
|
|
lyrics_content = [line for line in lyrics if line]
|
|
|
|
return flask.render_template_string('''
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Halhadus' Music Status</title>
|
|
<link rel="icon" type="image/png" href="assets/favicon.png">
|
|
<meta name="description" content="Halhadus' Music Status">
|
|
<meta name="author" content="Halhadus">
|
|
<meta property="og:title" content="Halhadus' Music Status">
|
|
<meta property="og:description" content="Halhadus' Music Status">
|
|
<meta property="og:url" content="https://halhadus.rocks/musicstatus.html">
|
|
<style>
|
|
:root {
|
|
--bg-color: #1f1f1f;
|
|
--card-bg: #2a2a2a;
|
|
--border-color: #333;
|
|
--text-color: #ffffff;
|
|
--font-family: 'JetBrains Mono', monospace;
|
|
}
|
|
.container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 1rem;
|
|
}
|
|
.music-card {
|
|
background: var(--card-bg);
|
|
border-radius: 8px;
|
|
margin: 1rem 0;
|
|
padding: 1rem;
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 1rem;
|
|
}
|
|
.thumbnail {
|
|
width: 100%;
|
|
border-radius: 6px;
|
|
aspect-ratio: 16/9;
|
|
object-fit: cover;
|
|
border: 2px solid var(--border-color);
|
|
}
|
|
.play-button {
|
|
background: #333;
|
|
border: 1px solid #444;
|
|
color: var(--text-color);
|
|
padding: 0.6rem 1rem;
|
|
margin: 0.3rem;
|
|
border-radius: 5px;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
text-align: center;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
}
|
|
.history-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 2rem;
|
|
overflow-x: auto;
|
|
}
|
|
.history-table th, .history-table td {
|
|
border: 1px solid var(--border-color);
|
|
padding: 0.8rem;
|
|
min-width: 120px;
|
|
}
|
|
.lyrics-container {
|
|
background: #333;
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-top: 1rem;
|
|
text-align: center;
|
|
}
|
|
.lyrics-line {
|
|
margin: 0.5rem 0;
|
|
color: #ccc;
|
|
}
|
|
@media (min-width: 768px) {
|
|
.music-card {
|
|
grid-template-columns: 200px 1fr;
|
|
gap: 2rem;
|
|
padding: 2rem;
|
|
}
|
|
.play-button {
|
|
padding: 0.8rem 1.5rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body style="background-color: var(--bg-color); color: var(--text-color); font-family: var(--font-family);">
|
|
<div class="container">
|
|
<h1>🎵 Halhadus' Music Status</h1>
|
|
<a href="/index.html" class="play-button">← Main Page</a>
|
|
<a href="https://git.halhadus.rocks/halhadus/localwrappedmusicstatus-combo-allinonerepo" class="play-button">Source Code →</a>
|
|
|
|
{% if current_playing %}
|
|
<div class="music-card">
|
|
{% if is_youtube(current_playing[3]) %}
|
|
<img src="https://img.youtube.com/vi/{{ extract_yt_id(current_playing[3]) }}/hqdefault.jpg"
|
|
class="thumbnail"
|
|
alt="{{ current_playing[0] }} cover">
|
|
{% else %}
|
|
<div class="thumbnail" style="background: #333; display: flex; align-items: center; justify-content: center;">
|
|
<span style="color: #666;">No thumbnail available</span>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div>
|
|
<h2>{{ current_playing[0] }}</h2>
|
|
<p>🕒 Last Updated: {{ format_timestamp(current_playing[1]) }}</p>
|
|
<div>
|
|
{% if is_youtube(current_playing[3]) %}
|
|
<a href="https://www.youtube.com/watch?v={{ extract_yt_id(current_playing[3]) }}"
|
|
class="play-button"
|
|
target="_blank">
|
|
▶ YouTube
|
|
</a>
|
|
<a href="https://music.youtube.com/watch?v={{ extract_yt_id(current_playing[3]) }}"
|
|
class="play-button"
|
|
target="_blank">
|
|
▶ YT Music
|
|
</a>
|
|
{% else %}
|
|
<a href="{{ current_playing[3] }}"
|
|
class="play-button"
|
|
target="_blank">
|
|
▶ Play Source
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
{% if lyrics_content %}
|
|
<div class="lyrics-container">
|
|
<h3>Lyrics</h3>
|
|
{% for line in lyrics_content %}
|
|
<p class="lyrics-line">{{ line }}</p>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="music-card">
|
|
<p>No music currently playing</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<h2>Play History</h2>
|
|
<table class="history-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Cover</th>
|
|
<th>Title</th>
|
|
<th>Time</th>
|
|
<th>Play</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for entry in history|reverse %}
|
|
<tr>
|
|
<td>
|
|
{% if is_youtube(entry[3]) %}
|
|
<img src="https://img.youtube.com/vi/{{ extract_yt_id(entry[3]) }}/hqdefault.jpg"
|
|
style="width: 80px; border-radius: 4px;"
|
|
alt="{{ entry[0] }} thumbnail">
|
|
{% else %}
|
|
<div style="width: 80px; height: 45px; background: #333; border-radius: 4px; display: flex; align-items: center; justify-content: center;">
|
|
<span style="color: #666;">N/A</span>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ entry[0] }}</td>
|
|
<td>{{ format_timestamp(entry[1]) }}</td>
|
|
<td>
|
|
<a href="{{ entry[3] }}"
|
|
class="play-button"
|
|
target="_blank">
|
|
▶
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
''', current_playing=current_playing,
|
|
history=history,
|
|
format_timestamp=lambda ts: datetime.datetime.fromtimestamp(int(ts), datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC"),
|
|
is_youtube=is_youtube_url,
|
|
extract_yt_id=extract_yt_id,
|
|
lyrics_content=lyrics_content)
|
|
|
|
@app.route('/verifykey', methods=['POST'])
|
|
def verifycert():
|
|
global code
|
|
data = flask.request.get_json()
|
|
with open("key.txt", "r") as f:
|
|
if data.get('key') == f.read():
|
|
code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=64))
|
|
return code
|
|
return "0"
|
|
|
|
@app.route('/<path:path>')
|
|
def catch_all(path):
|
|
return flask.redirect(f'https://halhadus.rocks/{path}')
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return flask.redirect('https://halhadus.rocks')
|
|
|
|
if __name__ == '__main__':
|
|
if not os.path.exists(app.config['LYRICS_DIR']):
|
|
os.makedirs(app.config['LYRICS_DIR'], exist_ok=True)
|
|
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
|