226 lines
7.3 KiB
Python
226 lines
7.3 KiB
Python
import os
|
||
import sqlite3
|
||
import datetime
|
||
# For now
|
||
import flask
|
||
|
||
def read_music_database():
|
||
conn = sqlite3.connect("assets/localwrapped/music.db")
|
||
c = conn.cursor()
|
||
c.execute('SELECT * FROM music')
|
||
music_list = c.fetchall()
|
||
conn.close()
|
||
return music_list
|
||
|
||
def read_count_database(year: int):
|
||
db_path = f'assets/localwrapped/count-{year}.db' if year != datetime.datetime.now().year else 'assets/localwrapped/count.db'
|
||
if not os.path.exists(db_path):
|
||
return []
|
||
|
||
conn = sqlite3.connect(db_path)
|
||
c = conn.cursor()
|
||
c.execute('SELECT * FROM count')
|
||
count_list = c.fetchall()
|
||
conn.close()
|
||
return count_list
|
||
|
||
def get_available_years():
|
||
years = []
|
||
for file in os.listdir('assets/localwrapped'):
|
||
if file.startswith('count') and file.endswith('.db'):
|
||
year = file.split('-')[-1].split('.')[0]
|
||
if year.isdigit():
|
||
years.append(int(year))
|
||
return sorted(years, reverse=True)
|
||
|
||
def total_play_time(year: int):
|
||
total_time = 0
|
||
music_data = {row[0]: row for row in read_music_database()}
|
||
|
||
for count_entry in read_count_database(year):
|
||
if count_entry[0] in music_data:
|
||
total_time += float(music_data[count_entry[0]][7]) * count_entry[1]
|
||
|
||
return total_time
|
||
|
||
def generatehtmlcode(year: int = datetime.datetime.now().year):
|
||
available_years = get_available_years()
|
||
current_year = datetime.datetime.now().year
|
||
selected_year = year if year in available_years else current_year
|
||
|
||
html = '''<!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' Local Wrapped</title>
|
||
<link rel="icon" type="image/png" href="assets/favicon.png">
|
||
<meta name="description" content="Halhadus' Local Wrapped">
|
||
<meta name="author" content="Halhadus">
|
||
<meta property="og:title" content="Halhadus' Local Wrapped">
|
||
<meta property="og:description" content="Halhadus' Local Wrapped">
|
||
<meta property="og:url" content="https://halhadus.rocks/localwrapped.html">
|
||
<link rel="icon" type="image/png" href="assets/favicon.png">
|
||
<style>
|
||
:root {
|
||
--bg-color: #1f1f1f;
|
||
--card-bg: #2a2a2a;
|
||
--border-color: #333;
|
||
--text-color: #ffffff;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.year-selector {
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
margin: 1rem 0;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.year-button {
|
||
background: #333;
|
||
border: 1px solid #444;
|
||
color: var(--text-color);
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 5px;
|
||
text-decoration: none;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
|
||
.year-button.active {
|
||
background: #444;
|
||
border-color: #555;
|
||
}
|
||
|
||
.music-card {
|
||
background: var(--card-bg);
|
||
border-radius: 8px;
|
||
margin: 1rem 0;
|
||
padding: 1rem;
|
||
display: grid;
|
||
grid-template-columns: 120px 1fr;
|
||
gap: 1rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.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.5rem 1rem;
|
||
margin: 0.3rem;
|
||
border-radius: 5px;
|
||
text-decoration: none;
|
||
display: inline-block;
|
||
text-align: center;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
|
||
.stats {
|
||
background: var(--card-bg);
|
||
border-radius: 8px;
|
||
padding: 1rem;
|
||
margin: 1rem 0;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.music-card {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
.source-banner {
|
||
background: #2a2a2a;
|
||
padding: 12px;
|
||
border-radius: 8px;
|
||
margin: 20px 0;
|
||
text-align: center;
|
||
border: 1px solid #333333;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body style="background-color: var(--bg-color); color: var(--text-color); font-family: 'JetBrains Mono', monospace;">
|
||
<div class="container">
|
||
<h1>🎵 Halhadus' Local Wrapped</h1>
|
||
<a href="/index.html" class="play-button">← Main Page</a>
|
||
<div class="source-banner">
|
||
<a href="https://git.halhadus.rocks/Halhadus/my-local-wrapped" style="color: #ffffff; text-decoration: none;">📁 Source Codes</a>
|
||
</div>
|
||
|
||
<div class="year-selector">
|
||
{% for y in available_years %}
|
||
<a href="?year={{ y }}" class="year-button {% if y == selected_year %}active{% endif %}">
|
||
{{ y }}
|
||
</a>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<div class="stats">
|
||
<h2>📊 Statistics for {{ selected_year }}</h2>
|
||
<p>⏳ Total Play Time: {{ total_time }} minutes</p>
|
||
<p>🕒 Last Updated: {{ last_updated }}</p>
|
||
</div>
|
||
|
||
<h2>🎶 Most Played Tracks</h2>
|
||
{% for music in top_tracks %}
|
||
<div class="music-card">
|
||
<img src="https://img.youtube.com/vi/{{ music.video_id }}/hqdefault.jpg"
|
||
class="thumbnail"
|
||
alt="{{ music.name }} cover">
|
||
<div>
|
||
<h3>{{ music.name }}</h3>
|
||
<p>▶ Played {{ music.count }} times</p>
|
||
<div>
|
||
<a href="https://www.youtube.com/watch?v={{ music.video_id }}"
|
||
class="play-button"
|
||
target="_blank">
|
||
YouTube
|
||
</a>
|
||
<a href="https://music.youtube.com/watch?v={{ music.video_id }}"
|
||
class="play-button"
|
||
target="_blank">
|
||
YT Music
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</body>
|
||
</html>'''
|
||
|
||
# Verileri hazırla
|
||
music_data = {row[0]: row for row in read_music_database()}
|
||
count_data = read_count_database(selected_year)
|
||
|
||
top_tracks = []
|
||
for count_entry in count_data:
|
||
if count_entry[0] in music_data:
|
||
video_id = music_data[count_entry[0]][1]
|
||
top_tracks.append({
|
||
'name': count_entry[0],
|
||
'count': count_entry[1],
|
||
'video_id': video_id
|
||
})
|
||
|
||
top_tracks.sort(key=lambda x: x['count'], reverse=True)
|
||
|
||
total_time = int(total_play_time(selected_year) / 60)
|
||
|
||
db_path = f'assets/localwrapped/count-{selected_year}.db' if selected_year != current_year else 'assets/localwrapped/count.db'
|
||
last_updated = datetime.datetime.utcfromtimestamp(os.path.getmtime(db_path)).strftime('%Y-%m-%d %H:%M UTC')
|
||
|
||
return flask.render_template_string(html, top_tracks=top_tracks, total_time=total_time, last_updated=last_updated, available_years=available_years, selected_year=selected_year)
|