Old Code
Old Code
import threading
import numpy as np
import sounddevice as sd
from mutagen import File
import subprocess
import queue
import time
# Local import in load_source to avoid circular dependency
# from audio_fx import _read_audio_any
def start(self):
[Link] = True
# FFmpeg command: Read URL, output raw float32 little-endian, stereo,
44.1k
cmd = [
'ffmpeg', '-reconnect', '1', '-reconnect_streamed', '1', '-
reconnect_delay_max', '5',
'-i', [Link],
'-f', 'f32le', '-ac', '2', '-ar', str([Link]),
'-vn', '-' # No video, output to stdout
]
# Hide console window on Windows
startupinfo = None
if hasattr(subprocess, 'STARTUPINFO'):
startupinfo = [Link]()
[Link] |= subprocess.STARTF_USESHOWWINDOW
try:
[Link] = [Link](
cmd, stdout=[Link], stderr=[Link],
bufsize=4096, startupinfo=startupinfo
)
[Link] = [Link](target=self._reader, daemon=True)
[Link]()
except FileNotFoundError:
print("[AudioCore] CRITICAL ERROR: FFmpeg not found. Cannot
stream.")
[Link] = False
except Exception as e:
print(f"[AudioCore] Stream Start Error: {e}")
[Link] = False
def _reader(self):
chunk_size = 4096 * 2 * 4 # frames * channels * bytes_per_float
while [Link] and [Link] and [Link]() is None:
try:
raw = [Link](chunk_size)
if not raw: break
data = [Link](raw, dtype=np.float32)
data = [Link](-1, 2)
[Link](data, timeout=10)
except: break
[Link] = False
return full
def stop(self):
[Link] = False
if [Link]:
[Link]()
[Link] = None
# Drain queue
with [Link]: [Link]()
class AudioCore:
def __init__(self, fx_module):
[Link] = fx_module
[Link] = None
# Audio Sources
self.data_dry = None # Local File (Entire array in RAM)
self.net_stream = None # Network Stream (Chunked)
[Link] = 44100
[Link] = 0
[Link] = "STOPPED"
self.duration_ms = 0.0
# Flags
self.is_stream_mode = False
self.ai_mode = False # False = Mid/Side DSP, True = Deep Learning Stems
# Controls
[Link] = 1.0
self.playback_speed = 1.0
self.reverb_vol = 0.0
self.vocal_vol = 1.0
self.music_vol = 1.0
self.load_id = 0
[Link] = "LOADING"
self.is_stream_mode = is_stream
self.duration_ms = duration_known if is_stream else
self._get_duration_fast(path_or_url)
if is_stream:
# TRUE STREAMING: Pipe from URL
self.net_stream = NetworkStreamer(path_or_url, [Link])
self.net_stream.start()
self.start_playback()
else:
# Local File Loading
if not is_stream:
is_cached, cache_paths =
[Link].check_cache_status_silent(path_or_url)
if is_cached:
print(f"[AudioCore] Found existing HQ stems for:
{path_or_url}")
if blocking:
self._worker_load_with_stems(path_or_url, current_id,
cache_paths)
else:
[Link](target=self._worker_load_with_stems,
args=(path_or_url, current_id, cache_paths), daemon=True).start()
return
if blocking:
self._worker_load(path_or_url, current_id)
else:
[Link](target=self._worker_load, args=(path_or_url,
current_id), daemon=True).start()
def reset_stems(self):
self.ai_mode = False
self.data_wet = None
self.data_vox = None
self.data_acc = None
if self.net_stream:
self.net_stream.stop()
self.net_stream = None
self.data_dry = data
[Link] = fs
if self.duration_ms == 0 and len(data) > 0:
self.duration_ms = (len(data) / fs) * 1000
self.start_playback()
except Exception as e:
print(f"[AudioCore] Load Error: {e}")
[Link] = "STOPPED"
def start_playback(self):
self._start_stream()
[Link] = "PLAYING"
def _start_stream(self):
if [Link]: [Link]()
[Link] = [Link](samplerate=[Link], channels=2,
callback=[Link], blocksize=4096)
[Link]()
sz = int(frames * self.playback_speed)
mixed = None
base_mix = None
base_mix = chunk
[Link] += sz # Rough position update for UI
def get_slice(arr):
if arr is None: return [Link]((sz, 2), dtype=np.float32)
if end > len(arr):
valid = len(arr) - [Link]
return [Link](arr[[Link]:], ((0, sz-valid), (0,0)))
return arr[[Link]:end]
[Link] += sz
else:
[Link](0); return
mixed = base_mix
mixed *= [Link]
[Link](mixed, -1.0, 1.0, out=mixed)
outdata[:] = mixed
except Exception as e:
# print(f"AudioCB Error: {e}") # Suppress for stability
[Link](0)
def stop_stream_only(self):
if [Link]:
try: [Link](); [Link]()
except: pass
[Link] = None
if self.net_stream:
self.net_stream.stop()
self.net_stream = None
def get_state(self):
# For streams, pos is a rough estimate based on idx increment
pos = ([Link]/[Link])*1000 if [Link] > 0 else 0
return {
"state": [Link],
"duration": self.duration_ms,
"position": pos,
"ai_mode": self.ai_mode # Tell UI if we are in HQ mode
}
return self.ai_mode
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\audio_fx.py
================================================================================
import os
import threading
import shutil
import hashlib
import logging
import sys
import io
import time
import re
import eel
import numpy as np
import soundfile as sf
import webbrowser
import subprocess
import platform
import ctypes
import traceback
from pathlib import Path
from [Link] import fftconvolve
from audio_separator.separator import Separator
import onnxruntime as ort
def _read_audio_any(path):
try:
# CONTEXT MANAGER: Ensures file handle is closed immediately
with [Link](str(path)) as f:
data = [Link](dtype="float32", always_2d=True)
fs = [Link]
return data, fs
except Exception as e:
return None, 44100
class StderrCapture([Link]):
def __init__(self):
super().__init__()
self.last_update = 0
self.progress_re = [Link](r'(\d+)%\|.*?\[.*?<(\d{2}:\d{2}|\d{2}:
\d{2}:\d{2})')
class CloudIsolationManager:
def __init__(self, parent_fx):
[Link] = parent_fx
[Link] = False
self.upload_temp_dir = [Link](parent_fx.cache_dir, "upload_temp")
[Link](self.upload_temp_dir, exist_ok=True)
self.target_hash = None
self.original_filename_stem = None
self.downloads_dir = [Link]() / "Downloads"
self.monitor_start_time = 0
def _check_conflicts(self):
conflicts = []
try:
for f in self.downloads_dir.glob("*.*"):
if [Link]() not in ['.mp3', '.wav']: continue
name = [Link]()
if ("vocal" in name or "music" in name or "instrumental" in
name):
[Link]([Link])
except: pass
return len(conflicts) > 0
def launch_workspace(self):
if not [Link]: return
if self._check_conflicts():
eel.update_cloud_status("Conflicting files found in Downloads!", -2)
()
return
self.monitor_start_time = [Link]()
[Link]("[Link]
self._open_folder(self.upload_temp_dir)
[Link](target=self._watcher, daemon=True).start()
def _watcher(self):
eel.update_cloud_status("Scanning Downloads folder...", 0)()
while [Link]:
[Link](1)
if not [Link]: break
try:
files = [f for f in self.downloads_dir.glob("*.*") if
[Link]() in ['.mp3', '.wav']]
[Link](key=[Link], reverse=True)
candidates = files[:10]
current_v = None
current_m = None
for f in candidates:
if [Link](f) < self.monitor_start_time: continue
fname = [Link]()
if "vocal" in fname and "music" in fname: continue
if "vocal" in fname: current_v = f
elif ("music" in fname or "instrumental" in fname):
current_m = f
class AudioEffects:
def __init__(self):
self.cache_dir = [Link]([Link]("~"), "Music",
"_MaterialMusicCache")
self.iso_dir = [Link](self.cache_dir, "isolation")
self.rev_dir = [Link](self.cache_dir, "reverb")
self.model_dir = [Link](self.cache_dir, "models")
[Link](self.iso_dir, exist_ok=True)
[Link](self.rev_dir, exist_ok=True)
[Link](self.model_dir, exist_ok=True)
self.on_process_complete = None
self.is_processing = False
self.current_file_hash = None
self.cloud_mgr = CloudIsolationManager(self)
def _generate_ir(self):
fs = 44100; duration = 2.0
t = [Link](0, duration, int(fs*duration))
noise = [Link](0, 1, len(t))
envelope = [Link](-4.0 * t)
ir = (noise * envelope).astype(np.float32)
[Link](self.ir_path, ir, fs)
def get_hardware_capabilities(self):
"""Checks if GPU providers are available in ONNX Runtime."""
try:
providers = ort.get_available_providers()
# Common GPU providers: 'CUDAExecutionProvider',
'DmlExecutionProvider', 'CoreMLExecutionProvider', 'ROCMExecutionProvider'
gpu_providers = [p for p in providers if 'GPU' in [Link]() or
'CUDA' in [Link]() or 'DML' in [Link]() or 'ROCM' in [Link]()]
return {
"has_gpu": len(gpu_providers) > 0,
"providers": providers
}
except:
return { "has_gpu": False, "providers": ['CPUExecutionProvider'] }
# ==========================================================
# FORENSIC DELETE FUNCTION
# ==========================================================
def delete_cached_stems(self, src_path):
"""
FORENSIC DELETE: Attempts to delete files and prints EXACT reasons if it
fails.
"""
print(f"\n[AudioFX] --- STARTING FORENSIC DELETE FOR: {src_path} ---")
file_hash = _sha1_of_file(src_path)
song_folder = [Link](self.iso_dir, file_hash)
rev_file = [Link](self.rev_dir, file_hash + "_wet.wav")
# 4. REMOVE FOLDER
try:
if [Link](song_folder):
print(f"[AudioFX] Attempting rmtree on: {song_folder}")
[Link](song_folder, onerror=on_rm_error)
if [Link](rev_file):
print(f"[AudioFX] Deleting reverb: {rev_file}")
[Link](rev_file)
except Exception as e:
print(f"[AudioFX] Standard Delete Failed.")
traceback.print_exc() # PRINTS FULL STACK TRACE
# 6. VERIFICATION
if [Link](song_folder):
print("[AudioFX] FAILURE: Folder still exists on disk.")
[Link](ctypes.c_wchar_p(trash_path), None,
MOVEFILE_DELAY_UNTIL_REBOOT)
print("[AudioFX] Scheduled trash for deletion on reboot.")
return True # We consider this a success because the
original path is gone
except: pass
except Exception as e:
print(f"[AudioFX] Rename FAILED: {e}")
print("[AudioFX] CONCLUSION: The file is exclusively locked by a
process (probably this one) with [Link]")
return False
try:
song_folder = [Link](self.iso_dir, file_hash)
[Link](song_folder, exist_ok=True)
vocab_path = [Link](song_folder, "[Link]")
accomp_path = [Link](song_folder, "[Link]")
# 2. DETERMINE DEVICE
# Note: Separator expects 'cpu' or 'cuda'. If GPU is not available,
it defaults.
device_param = 'cuda' if use_gpu else 'cpu'
print(f"[AudioFX] Processing on: {device_param.upper()}")
print("Separating Stems...")
# Note: The 'device' from load_model usually persists, no need
to pass it here.
output_files = [Link](src_path)
self._generate_reverb_only(vocab_path, file_hash)
print("Done")
self._notify_done(file_hash)
except Exception as e:
print(f"Error: {e}")
eel.update_processing_log(f"Error: {str(e)}")()
finally:
[Link] = original_stderr
self.is_processing = False
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\[Link]
================================================================================
import os
# extensions to scan
EXTENSIONS = (".html", ".css", ".js", ".py", ".pyw")
# output file
OUTPUT_FILE = "all_code_dump.txt"
def scan_and_write(base_dir):
with open(OUTPUT_FILE, "w", encoding="utf-8", errors="ignore") as out:
for root, _, files in [Link](base_dir):
for file in files:
if [Link]().endswith(EXTENSIONS):
file_path = [Link](root, file)
[Link]("=" * 80 + "\n")
[Link](f"PATH: {file_path}\n")
[Link]("=" * 80 + "\n\n")
try:
with open(file_path, "r", encoding="utf-8",
errors="ignore") as f:
[Link]([Link]())
except Exception as e:
[Link](f"[ERROR READING FILE] {e}")
[Link]("\n\n")
if __name__ == "__main__":
scan_and_write([Link]())
print("Done. All code dumped into all_code_dump.txt")
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\[Link]
================================================================================
import subprocess, os
from pathlib import Path
BASE_DIR = Path(__file__).[Link]()
AUDIO_FILE = BASE_DIR / "ClariS - Destiny.mp3"
OUTPUT_DIR = BASE_DIR / "demucs_out"
FFMPEG_DIR = BASE_DIR / "ffmpeg"
if not AUDIO_FILE.exists():
raise FileNotFoundError(f"Missing: {AUDIO_FILE}")
cmd = [
"python", "-m", "demucs",
"-n", "htdemucs",
"--two-stems", "vocals",
str(AUDIO_FILE),
"-o", str(OUTPUT_DIR)
]
# run from a plain CMD (not VS Code debugger) to avoid weird debugpy imports
[Link](cmd, check=True, env=env)
print("Vocals + music DONE ð¥")
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\lyrics_engine.py
================================================================================
import os
import requests
import re
from [Link] import HTTPAdapter
from [Link] import Retry
class LyricsEngine:
def __init__(self):
self.base_url = "[Link]
self.lyrics_dir = [Link]([Link]("~"), "Music",
"Lyrics")
[Link](self.lyrics_dir, exist_ok=True)
params = {
'artist_name': artist,
'track_name': title,
}
if response.status_code == 200:
data = [Link]()
return [Link]('syncedLyrics', None)
elif response.status_code == 404:
print("[LyricsEngine] Lyrics not found on LRCLIB.")
return None
else:
print(f"[LyricsEngine] API Error: {response.status_code}")
return None
except Exception as e:
print(f"[LyricsEngine] Connection Error: {e}")
return None
lines = []
regex = r'\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)'
if len(ms_part) == 2:
ms = int(ms_part) / 100
else:
ms = int(ms_part) / 1000
total_sec = (m * 60) + s + ms
text = [Link](4).strip()
if text:
[Link]({"time": total_sec, "text": text})
return lines
# Safe filename
safe_title = "".join([c for c in song_title if [Link]() or c=='
']).strip()
filename = safe_title + ".lrc"
path = [Link](self.lyrics_dir, filename)
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\lyrics_mgr.py
================================================================================
import os
import json
import re
import hashlib
import requests
from [Link] import HTTPAdapter
from [Link] import Retry
from yt_mgr import YtManager
class LyricsManager:
def __init__(self):
[Link] = [Link]("~")
self.hidden_dir = [Link]([Link], "Music",
".MaterialMusicHidden", "lyrics_cache")
[Link](self.hidden_dir, exist_ok=True)
[Link] = [Link]()
[Link]({'User-Agent': 'MaterialMusicPlayer/2.0'})
retry = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500,
502])
adapter = HTTPAdapter(max_retries=retry)
[Link]("[Link] adapter)
[Link]("[Link] adapter)
self.yt_mgr = YtManager()
# 1. CHECK CACHE
if [Link](cache_path) and not is_stream_mode:
try:
with open(cache_path, 'r', encoding='utf-8') as f:
data = [Link](f)
if data: return data
except: pass
# 5. SAVE
if lyrics_data:
if lyrics_data[0]['time'] != -1:
self._calculate_line_durations(lyrics_data)
if not is_stream_mode:
try:
with open(cache_path, 'w', encoding='utf-8') as f:
[Link](lyrics_data, f)
except Exception as e:
print(f"[LyricsMgr] Failed to save cache: {e}")
return lyrics_data
def _parse_lrc_string(self, lrc_string):
if not lrc_string: return None
lines = []
regex = r'\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)'
for line in lrc_string.split('\n'):
match = [Link](regex, line)
if match:
m, s = int([Link](1)), int([Link](2))
ms_str = [Link](3)
ms = int(ms_str) / (10 ** len(ms_str))
total_sec = (m * 60) + s + ms
text = [Link](4).strip()
if text:
[Link]({"time": total_sec, "text": text, "duration":
0.0})
return lines if lines else None
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\[Link]
================================================================================
import sys, os
import eel, threading, time, webview, gc, uuid, socket
from audio_core import AudioCore
from audio_fx import AudioEffects, _sha1_of_file
from metadata_mgr import MetadataManager
from lyrics_mgr import LyricsManager
from yt_mgr import YtManager
from setup_assets import AssetManager
import sounddevice as sd
import json
script_dir = [Link]([Link](__file__))
web_dir = [Link](script_dir, 'web')
[Link]["PATH"] += [Link] + script_dir
[Link](web_dir)
fx_engine = AudioEffects()
core_engine = AudioCore(fx_engine)
meta_mgr = MetadataManager()
lyrics_mgr = LyricsManager()
yt_mgr = YtManager()
playlist = meta_mgr.get_library()
current_track_index = -1
current_track_path = ""
def _on_processing_done(paths):
global current_track_path
if current_track_path and paths['hash'] ==
_sha1_of_file(current_track_path):
core_engine.inject_hq_stems(paths)
meta_mgr.update_track_extra(current_track_path, 'has_stems', True)
try: eel.on_hq_ready()()
except Exception as e: print(f"Eel callback error: {e}")
fx_engine.on_process_complete = _on_processing_done
@[Link]
def start_asset_setup():
def work():
mgr = AssetManager(progress_callback=lambda p,s:
eel.update_setup_progress(p,s)() if eel._js_call else None)
mgr.setup_assets()
return True
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def scan_library():
def work():
global playlist
def on_progress(current, total, filename):
pct = (current / total) * 100 if total > 0 else 0
try: eel.update_loading_progress(pct, filename)()
except: pass
playlist = meta_mgr.rescan(progress_callback=on_progress)
return playlist
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def get_cached_library(): return meta_mgr.library
@[Link]
def read_library_cache():
try:
if [Link](meta_mgr.cache_file):
with open(meta_mgr.cache_file, 'r', encoding='utf-8') as f:
data = [Link](f)
return data if isinstance(data, list) else []
except: pass
return []
@[Link]
def load_track(index, start_pos=0):
def work():
global current_track_index, playlist, current_track_path
if not (0 <= index < len(playlist)): return None
track = playlist[index]
path = track['path']
if not [Link](path):
meta_mgr.remove_track(path)
if index < len(playlist): del playlist[index]
return {"error": "File not found", "removed": True}
current_track_index = index
current_track_path = path
core_engine.load_source(path, is_stream=False, blocking=True)
if start_pos > 0: core_engine.set_pos(start_pos)
if core_engine.state != "PLAYING": core_engine.play_pause()
art_data = meta_mgr.get_art(path)
is_cached, _ = fx_engine.check_cache_status(path)
track['has_stems'] = is_cached
meta_mgr.update_track_extra(path, 'has_stems', is_cached)
return {
"title": track['title'], "artist": track['artist'], "path": path,
"art": art_data, "colors": [Link]('colors', {}),
"duration": core_engine.duration_ms, "state": "PLAYING",
"has_stems": is_cached, "is_stream": False,
"offset_o": [Link]('offset_o', 0.0), "offset_k":
[Link]('offset_k', 0.0),
"karaoke_id": [Link]('karaoke_id', None),
"ignore_sync_warning": [Link]('ignore_sync_warning', False)
}
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def get_ai_hardware(): return fx_engine.get_hardware_capabilities()
@[Link]
def trigger_hq_processing(quality_mode="vocals", use_gpu=False):
if not current_track_path or not [Link](current_track_path): return
False
if core_engine.is_stream_mode: return False
fx_engine.process_specific_track(current_track_path, quality_mode, use_gpu)
return True
@[Link]
def delete_generated_stems(path):
core_engine.stop_stream_only()
try: [Link]()
except: pass
core_engine.reset_stems()
[Link]()
[Link](0.1)
success = fx_engine.delete_cached_stems(path)
if not success:
[Link](1.0)
[Link]()
success = fx_engine.delete_cached_stems(path)
if success:
meta_mgr.update_track_extra(path, 'has_stems', False)
if current_track_path == path:
core_engine.toggle_ai_mode(force_mode=False)
return success
@[Link]
def trigger_cloud_processing():
if not current_track_path or not [Link](current_track_path): return
False
if core_engine.is_stream_mode: return False
fx_engine.prepare_cloud(current_track_path)
return True
@[Link]
def launch_cloud_workspace(): fx_engine.launch_cloud()
@[Link]
def cancel_cloud_processing(): fx_engine.cancel_cloud()
@[Link]
def get_hq_status():
is_cached, _ = fx_engine.check_cache_status(current_track_path) if
current_track_path else (False, None)
return {
"active": core_engine.ai_mode, "processing": fx_engine.is_processing,
"cloud_active": fx_engine.cloud_mgr.active, "stems_cached": is_cached
}
@[Link]
def set_hq_mode(enabled): return core_engine.toggle_ai_mode(enabled)
@[Link]
def search_yt(query, filter_type='songs'):
return _start_job(lambda: yt_mgr.search(query, filter_type),
eel.on_job_result, eel.on_job_error)
@[Link]
def stream_yt(vid, title, artist, img):
def work():
path = yt_mgr.get_cached_path(vid)
if path and [Link](path):
global current_track_path
current_track_path = ""
core_engine.load_source(path, is_stream=False, blocking=True)
core_engine.play_pause()
return {
"title": title, "artist": artist, "art": img,
"colors": {"accent": "#d0bcff", "accent_rgb": "208,188,255",
"bg_stop_rgb": "20,5,40"},
"duration": core_engine.duration_ms, "state": "PLAYING",
"is_stream": True
}
return None
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def find_and_play_best_karaoke(title, artist, target_dur_ms, current_pos_ms):
def work():
target_sec = target_dur_ms / 1000
results = yt_mgr.search_karaoke(f"{title} {artist}")
if not results: return {"success": False, "msg": "No karaoke found"}
best_match = None
min_diff = 999.0
for r in results:
try:
min_part, sec_part = map(int, r['duration'].split(':'))
r_duration_sec = min_part * 60 + sec_part
except: continue
diff = abs(r_duration_sec - target_sec)
if diff < min_diff:
min_diff = diff
best_match = r
if not best_match or min_diff > 15.0: return {"success": False, "msg":
"No match found"}
path = yt_mgr.get_cached_path(best_match['videoId'])
if path:
core_engine.load_source(path, is_stream=False, blocking=True)
if current_pos_ms > 0: core_engine.set_pos(current_pos_ms)
if core_engine.state != "PLAYING": core_engine.play_pause()
return {"success": True, "title": best_match['title'], "diff":
min_diff, "warn": min_diff > 2.0, "video_id": best_match['videoId']}
return {"success": False, "msg": "Could not load karaoke"}
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def stop_stream_only(): core_engine.stop_stream_only()
@[Link]
def save_track_offset(path, key, value): return
meta_mgr.update_track_extra(path, key, value)
@[Link]
def get_karaoke_preview(video_id):
return _start_job(lambda: yt_mgr.get_direct_url(video_id),
eel.on_job_result, eel.on_job_error)
@[Link]
def apply_new_karaoke(original_path, video_id, current_pos_ms=0):
def work():
new_audio_path = yt_mgr.get_cached_path(video_id)
if new_audio_path and [Link](new_audio_path):
meta_mgr.update_track_extra(original_path, 'karaoke_id', video_id)
core_engine.load_source(new_audio_path, is_stream=False,
blocking=True)
if current_pos_ms > 0: core_engine.set_pos(current_pos_ms)
if core_engine.state != "PLAYING": core_engine.play_pause()
return True
return False
return _start_job(work, eel.on_job_result, eel.on_job_error)
@[Link]
def play_pause(): return core_engine.play_pause()
@[Link]
def next_track():
global current_track_index
if not playlist: return None
return load_track((current_track_index + 1) % len(playlist))
@[Link]
def prev_track():
global current_track_index
if not playlist: return None
return load_track((current_track_index - 1 + len(playlist)) % len(playlist))
@[Link]
def set_seek(ms): core_engine.set_pos(ms)
@[Link]
def get_player_state(): return core_engine.get_state()
@[Link]
def get_current_settings():
return {"speed": core_engine.playback_speed, "volume": core_engine.vol,
"reverb": core_engine.reverb_vol, "vocal": core_engine.vocal_vol, "music":
core_engine.music_vol}
@[Link]
def set_speed(val): core_engine.set_speed(val)
@[Link]
def set_volume(val): core_engine.set_volume(val)
@[Link]
def set_vocal_volume(val): core_engine.set_vocal_vol(val)
@[Link]
def set_music_volume(val): core_engine.set_music_vol(val)
@[Link]
def set_reverb(val): core_engine.set_reverb_vol(val)
@[Link]
def delete_track_robust(index, path_from_ui):
global playlist, current_track_index, current_track_path
if index < 0 or index >= len(playlist) or playlist[index]['path'] !=
path_from_ui:
try: eel.refresh_ui_library(playlist)()
except: pass
return {"success": False, "rescan": True, "error": "Index mismatch"}
track_to_delete = playlist[index]
if current_track_path == track_to_delete['path']:
core_engine.stop_stream_only()
current_track_index = -1
current_track_path = ""
file_deleted = False
try:
[Link](track_to_delete['path'])
file_deleted = True
except OSError:
if fx_engine.delete_cached_stems(track_to_delete['path']):
[Link](0.1)
try:
[Link](track_to_delete['path'])
file_deleted = True
except: pass
if not file_deleted and [Link](track_to_delete['path']):
return {"success": False, "error": "Could not delete physical file"}
meta_mgr.remove_track(track_to_delete['path'])
if index < len(playlist) and playlist[index]['path'] ==
track_to_delete['path']:
[Link](index)
if current_track_index != -1 and index < current_track_index:
current_track_index -= 1
elif current_track_index != -1 and index == current_track_index:
current_track_index = -1
return {"success": True}
webview_window = None
class Api: pass
def run_gui():
global webview_window
webview_window = webview.create_window('Material Music',
'[Link] js_api=Api(), width=1280, height=800,
min_size=(940, 600), frameless=False, transparent=False, text_select=False)
[Link](debug=False, http_server=False)
if __name__ == "__main__":
eel_port = 8000
eel_thread = [Link](target=lambda: [Link]('[Link]',
mode=None, host='localhost', port=eel_port, block=True))
eel_thread.daemon = True
eel_thread.start()
if wait_for_server(eel_port): run_gui()
else: [Link](1)
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\metadata_mgr.py
================================================================================
class MetadataManager:
def __init__(self):
self.cache_file =
[Link]([Link]([Link](__file__)), "library_cache.json")
[Link] = []
self._load_cache()
def _load_cache(self):
if [Link](self.cache_file):
try:
with open(self.cache_file, 'r', encoding='utf-8') as f:
[Link] = [Link](f)
# Sort fast by title, handle potential missing 'title' key
gracefully
[Link](key=lambda x: [Link]('title', '').lower())
print(f"[Metadata] Loaded {len([Link])} tracks from
cache.")
except Exception as e:
print(f"[Metadata] Cache load failed, clearing cache: {e}")
[Link] = [] # Clear corrupted cache
else:
[Link] = []
def save_cache(self):
try:
# Ensure sorting before saving
[Link](key=lambda x: [Link]('title', '').lower())
with open(self.cache_file, 'w', encoding='utf-8') as f:
[Link]([Link], f, ensure_ascii=False, indent=4) # Added
indent for readability
except Exception as e:
print(f"[Metadata] Failed to save cache: {e}")
def get_library(self):
# Only return what is currently in memory (loaded from JSON on init).
return [Link]
# --- IMPORTANT CHANGE: Only scan the main music directory for the
library view ---
# We explicitly exclude hidden folders and cache directories from the
main library listing.
scan_roots = [music_dir]
all_audio_paths = list(self._iter_audio_paths(scan_roots))
total_files = len(all_audio_paths)
if total_files == 0:
self.save_cache()
if progress_callback:
try: progress_callback(100, 100, "No audio files found.")
except: pass
print("[Metadata] No audio files found during rescan.")
return [Link]
processed = 0
for full_path in all_audio_paths:
# Check for duplicates, as _iter_audio_paths might yield paths
already processed
if full_path in seen_paths:
continue
try:
meta = self._get_meta(full_path)
# Also ensure a track with the exact same path doesn't already
exist in the list
if not any(t['path'] == meta['path'] for t in [Link]):
[Link](meta)
seen_paths.add(full_path)
except Exception as e:
print(f"[Rescan] metadata error for {full_path}: {e}")
processed += 1
if progress_callback: # Report progress for every file
try: progress_callback(processed, total_files,
[Link](full_path))
except: pass
# print(f"[Rescan] processed {processed}/{total_files} -
{[Link](full_path)}") # Uncomment for verbose console output
self.save_cache()
print(f"[Metadata] Rescan complete. Found {len([Link])} unique
tracks.")
return [Link]
def on_walk_error(err):
print(f"[Rescan] directory walk error: {err}")
for f in files:
if not [Link]().endswith(audio_ext):
continue
yield [Link]([Link](root_abs, f))
for r, g, b in colors:
# Convert to HSV to evaluate vibrancy (Saturation, Value)
h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
# Filter out dull/very dark/very bright colors
if s < 0.3 or v < 0.25 or v > 0.95:
continue
score = (s * 0.7) + (v * 0.3) # Prioritize saturation for
"accent"
if score > max_score:
max_score = score
best_color = (r, g, b)
r, g, b = best_color
h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
return {
"accent": accent_hex,
"accent_rgb": f"{r_a},{g_a},{b_a}",
"bg_stop_rgb": f"{r_b},{g_b},{b_b}"
}
except Exception as e:
# print(f"Color extraction error: {e}") # Suppress for normal
operation
return { "accent": "#d0bcff", "accent_rgb": "208,188,255",
"bg_stop_rgb": "20,5,40" }
try:
# Mutagen's File() automatically detects format and loads
appropriate tags
f = File(path)
if not f: return meta # File not readable by Mutagen
return meta
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\setup_assets.py
================================================================================
import os
import requests
import re
import threading
# Setup paths
SCRIPT_DIR = [Link]([Link](__file__))
WEB_DIR = [Link](SCRIPT_DIR, 'web')
CACHE_DIR = [Link](WEB_DIR, 'assets', 'cache')
FONTS_DIR = [Link](CACHE_DIR, 'fonts')
CSS_URLS = [
("material_symbols", "[Link]
family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-
50..200"),
("inter", "[Link]
family=Inter:wght@400;500;600;700&display=swap"),
("jetbrains_mono", "[Link]
family=JetBrains+Mono:wght@500&display=swap")
]
class AssetManager:
def __init__(self, progress_callback=None):
self.progress_callback = progress_callback
[Link](CACHE_DIR, exist_ok=True)
[Link](FONTS_DIR, exist_ok=True)
filename = f"{name}_{i}.{ext}"
local_path = [Link](FONTS_DIR, filename)
if self.download_file(font_url, local_path):
local_css = local_css.replace(font_url, f"fonts/{filename}")
def setup_assets(self):
self._report(5, "Checking assets...")
num_configs = len(CSS_URLS)
weight_per_config = 90 / num_configs
self._report(100, "Ready")
if __name__ == "__main__":
mgr = AssetManager()
mgr.setup_assets()
print("Done!")
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\verify_minimal.py
================================================================================
def test_minimal():
yt = YTMusic()
try:
print("Searching Songs...")
res_songs = [Link]("Bohemian Rhapsody karaoke", filter='songs',
limit=2)
print(f"Songs found: {len(res_songs)}")
print("Searching Videos...")
res_videos = [Link]("Bohemian Rhapsody karaoke", filter='videos',
limit=2)
print(f"Videos found: {len(res_videos)}")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
test_minimal()
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\verify_search.py
================================================================================
import sys
import os
def test_search():
mgr = YtManager()
query = "Bohemian Rhapsody karaoke"
if __name__ == "__main__":
test_search()
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\yt_mgr.py
================================================================================
import os
import time
import yt_dlp
import eel
import requests
import re
import json
from ytmusicapi import YTMusic
from mutagen.id3 import ID3, TIT2, TPE1, APIC
class YtManager:
def __init__(self):
[Link] = YTMusic()
[Link] = [Link]("~")
self.music_dir = [Link]([Link], "Music")
self.hidden_dir = [Link]([Link], "Music",
".MaterialMusicHidden")
[Link](self.hidden_dir, exist_ok=True)
[Link](self.music_dir, exist_ok=True)
self._cleanup_old_files()
if [Link] == 'nt':
try:
import ctypes
[Link](self.hidden_dir, 0x02)
except: pass
def _cleanup_old_files(self):
try:
now = [Link]()
cutoff = now - 3600 # 1 hour
stream_dir = [Link](self.hidden_dir, "stream_cache")
if [Link](stream_dir):
for f in [Link](stream_dir):
fp = [Link](stream_dir, f)
if [Link](fp) and [Link](fp) < cutoff:
try: [Link](fp)
except: pass
except Exception as e:
print(f"[YtManager] Cleanup Error: {e}")
[Link]({
"videoId": v_id,
"title": [Link]('title', 'Unknown'),
"artist": artist_text,
"album": album,
"duration": [Link]('duration', '0:00'),
"thumb": img
})
return parsed
except Exception as e:
print(f"Search Error: {e}")
return []
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': [Link](cache_dir, f"{video_id}_temp.%(ext)s"),
'postprocessors': [{'key': 'FFmpegExtractAudio','preferredcodec':
'mp3','preferredquality': '192'}],
'progress_hooks': [self._dl_progress_hook],
'quiet': True,
'no_warnings': True
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
[Link]([f"[Link]
if [Link](final_path):
print(f"Track already exists: {final_path}")
return None
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': [Link](temp_download_dir, f"{safe_title}_temp.%
(ext)s"),
'postprocessors': [{'key': 'FFmpegExtractAudio','preferredcodec':
'mp3','preferredquality': '192'}],
'quiet': True,
'no_warnings': True
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
[Link]([f"[Link]
tags = ID3(final_path)
[Link](TIT2(encoding=3, text=title))
[Link](TPE1(encoding=3, text=artist))
if image_data:
[Link](APIC(
encoding=3,
mime='image/jpeg',
type=3,
desc='Cover',
data=image_data
))
[Link](final_path)
except Exception as tag_error:
print(f"Tag error: {tag_error}")
return final_path
except Exception as e:
print(f"Record Error: {e}")
return None
subs = [Link]('requested_subtitles')
if not subs and [Link]('subtitles'):
subs = info['subtitles'].get('en') or
info['subtitles'].get('en-US')
if not subs and [Link]('automatic_captions'):
subs = info['automatic_captions'].get('en') or
info['automatic_captions'].get('en-US')
if sub_url:
r = [Link](sub_url)
if r.status_code == 200:
content = [Link]
if 'json3' in sub_url or
[Link]().startswith('{'):
return self._parse_json3(content)
else:
return self._parse_vtt(content)
except Exception as e:
print(f"[YtManager] Transcript Error: {e}")
return None
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\web\[Link]
================================================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Material Music</title>
<style>
/*
=========================================================================
1. CORE THEME & VARIABLES
========================================================================= */
:root {
--bg-body: #050505;
--glass-surface: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08);
--text-main: #ffffff;
--text-dim: rgba(255, 255, 255, 0.5);
--accent: #d0bcff;
--accent-rgb: 208, 188, 255;
--rad: 28px;
--nav-width: 80px;
--player-width: 420px;
}
* {
box-sizing: border-box;
outline: none;
user-select: none;
-webkit-user-drag: none;
}
body {
margin: 0;
padding: 16px;
font-family: 'Inter', sans-serif;
background-color: var(--bg-body);
color: var(--text-main);
height: 100vh;
width: 100vw;
overflow: hidden;
display: grid;
grid-template-columns: var(--nav-width) 1fr var(--player-width);
gap: 16px;
background-image: radial-gradient(circle at 90% 90%, rgba(var(--
accent-rgb), 0.1), transparent 60%);
}
/* Utilities */
.truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
::-webkit-scrollbar {
width: 0px;
background: transparent;
}
.icon {
font-family: 'Material Symbols Rounded';
font-size: 24px;
display: block;
}
.btn {
cursor: pointer;
transition: 0.2s;
border: none;
background: none;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.splash-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
opacity: 0;
animation: splashEntry 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
@keyframes splashEntry {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.splash-logo {
width: 80px;
height: 80px;
background: linear-gradient(135deg, var(--accent), #fff);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 20px 50px rgba(var(--accent-rgb), 0.3);
margin-bottom: 10px;
}
.splash-logo .icon {
font-size: 40px;
color: #000;
}
.splash-text {
text-align: center;
}
.splash-text h1 {
font-size: 24px;
margin: 0 0 8px 0;
letter-spacing: -0.5px;
background: linear-gradient(to right, #fff, #aaa);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 800;
}
.splash-text p {
font-size: 13px;
color: var(--text-dim);
margin: 0;
font-family: 'JetBrains Mono', monospace;
}
.splash-loader {
width: 200px;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 99px;
overflow: hidden;
position: relative;
margin-top: 10px;
}
.splash-bar {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 40%;
background: var(--accent);
border-radius: 99px;
animation: indeterminate 1.5s infinite linear;
}
@keyframes indeterminate {
0% {
left: -40%;
width: 40%;
}
50% {
left: 100%;
width: 40%;
}
100% {
left: 100%;
width: 40%;
}
}
/*
=========================================================================
2. NAVIGATION RAIL
========================================================================= */
.nav-rail {
background: var(--glass-surface);
border: 1px solid var(--glass-border);
border-radius: 99px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 24px;
padding: 20px 0;
backdrop-filter: blur(20px);
}
.nav-btn {
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-dim);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.nav-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
.[Link] {
background: var(--accent);
color: #000;
box-shadow: 0 0 20px rgba(var(--accent-rgb), 0.4);
transform: scale(1.1);
}
/*
=========================================================================
3. MAIN PANEL
========================================================================= */
.main-panel {
background: var(--glass-surface);
border: 1px solid var(--glass-border);
border-radius: var(--rad);
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
}
.view-section {
display: none;
height: 100%;
width: 100%;
flex-direction: column;
animation: fadeUp 0.3s ease;
}
.[Link] {
display: flex;
}
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.header {
padding: 30px 40px;
flex-shrink: 0;
}
.h-sup {
font-size: 11px;
font-weight: 700;
color: var(--accent);
letter-spacing: 2px;
text-transform: uppercase;
margin-bottom: 8px;
}
.h-main {
font-size: 32px;
font-weight: 800;
letter-spacing: -1px;
}
.scroll-area {
flex: 1;
overflow-y: auto;
padding: 0 40px 40px 40px;
}
.track-row {
display: grid;
grid-template-columns: auto 1fr auto;
/* Thumb - Text - Buttons */
gap: 16px;
align-items: center;
padding: 10px 16px;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s;
position: relative;
}
.track-row:hover {
background: rgba(255, 255, 255, 0.06);
}
.[Link] {
background: linear-gradient(90deg, rgba(var(--accent-rgb), 0.15),
transparent);
border-left: 3px solid var(--accent);
}
.video-thumb-container {
position: relative;
width: 90px;
/* Specific size for video search results */
height: 50px;
border-radius: 8px;
overflow: hidden;
flex-shrink: 0;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.t-info {
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
}
.t-title {
font-size: 14px;
font-weight: 600;
color: #fff;
margin-bottom: 3px;
}
.t-artist {
font-size: 12px;
color: var(--text-dim);
font-weight: 500;
}
.[Link] .t-title {
color: var(--accent);
}
.ctx-btn {
width: 32px;
height: 32px;
border-radius: 50%;
color: rgba(255, 255, 255, 0.5);
}
.ctx-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
/* Context Menu */
#ctx-menu {
position: fixed;
display: none;
background: #222;
border: 1px solid #333;
border-radius: 12px;
padding: 8px;
z-index: 100;
box-shadow: 0 10px 30px #000;
width: 160px;
}
.ctx-item {
padding: 10px;
font-size: 13px;
border-radius: 6px;
cursor: pointer;
display: flex;
gap: 10px;
align-items: center;
}
.ctx-item:hover {
background: rgba(255, 255, 255, 0.1);
}
.[Link] {
color: #ff8a80;
}
/* New Android 16 / Material 3 Style Buttons */
.row-btn {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--glass-border);
width: 42px;
height: 42px;
border-radius: 14px;
/* Squircle shape */
color: var(--accent);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.row-btn:hover {
background: var(--accent);
color: #000;
border-color: var(--accent);
box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.3);
transform: translateY(-2px);
}
.[Link] {
background: rgba(255, 255, 255, 0.05);
color: var(--text-dim);
border-color: rgba(255, 255, 255, 0.1);
}
.stem-card {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 20px;
}
.stem-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.stem-label {
font-size: 14px;
font-weight: 700;
display: flex;
align-items: center;
gap: 8px;
}
.stem-val {
font-family: 'JetBrains Mono';
font-size: 12px;
background: rgba(0, 0, 0, 0.3);
padding: 4px 8px;
border-radius: 6px;
color: var(--accent);
}
.btn-progress::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: var(--prog, 0%);
background: rgba(var(--accent-rgb), 0.3);
z-index: -1;
transition: width 0.2s linear;
}
@keyframes fakeLoad {
0% {
width: 0%;
}
80% {
width: 70%;
}
100% {
width: 100%;
}
}
.ai-btn {
width: 100%;
padding: 20px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.08),
rgba(255, 255, 255, 0.03));
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 20px;
color: #ffffff !important;
text-align: left;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 12px;
justify-content: space-between;
transition: 0.2s;
height: 140px;
}
.ai-btn:hover {
border-color: var(--accent);
background: rgba(255, 255, 255, 0.12);
transform: translateY(-2px);
}
.ai-btn .icon {
font-size: 32px;
color: var(--accent);
}
.ai-title {
font-weight: 700;
font-size: 15px;
margin-bottom: 4px;
color: #fff;
}
.ai-desc {
font-size: 11px;
opacity: 0.8;
color: #ddd;
line-height: 1.4;
}
.t-artist,
.time-row {
color: rgba(255, 255, 255, 0.8) !important;
}
.lyrics-fixed-header {
flex-shrink: 0;
padding: 40px 40px 20px 40px;
background: linear-gradient(180deg, var(--bg-body) 0%, rgba(5, 5, 5,
0.95) 100%);
z-index: 20;
border-bottom: 1px solid rgba(255, 255, 255, 0.02);
display: flex;
flex-direction: column;
gap: 12px;
position: sticky;
top: 0;
}
.hidden-btn {
display: none !important;
}
.lyrics-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
position: relative;
z-index: 22;
}
#offset-panel {
max-height: 0;
opacity: 0;
overflow: hidden;
transform: translateY(-10px);
transition: all 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
background: rgba(255, 255, 255, 0.04);
border-radius: 16px;
margin-top: 0;
position: relative;
z-index: 21;
}
#[Link] {
max-height: 140px;
opacity: 1;
transform: translateY(0);
margin-top: 8px;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
#l-full-box {
flex: 1;
overflow-y: auto;
scroll-behavior: smooth;
padding: 50vh 0;
mask-image: linear-gradient(transparent 0%, black 20%, black 80%,
transparent 100%);
-webkit-mask-image: linear-gradient(transparent 0%, black 20%, black
80%, transparent 100%);
}
#l-full-box .l-line {
min-height: 50px;
display: block;
text-align: center;
padding: 12px 60px;
font-size: 26px;
font-weight: 600;
color: rgba(255, 255, 255, 0.35);
filter: blur(1.5px);
transform: scale(0.98);
transition: color 0.5s ease, transform 0.6s cubic-bezier(0.2, 0, 0,
1), filter 0.5s ease, text-shadow 0.5s ease;
will-change: transform, opacity, filter, color;
line-height: 1.4;
cursor: pointer;
}
100% {
opacity: 1;
filter: blur(0px);
transform: scale(1.0);
}
}
#l-full-box .[Link] {
font-weight: 800;
background: linear-gradient(90deg, var(--accent) 0%, #fff 50%,
var(--accent) 100%);
-webkit-background-clip: text;
background-clip: text;
/* FIX: Added standard property */
color: transparent;
animation: snapIn var(--rand-dur, 0.6s) cubic-bezier(0.2, 0.8, 0.2,
1) forwards;
transform: scale(1.0);
opacity: 1;
text-shadow: 0 0 25px rgba(var(--accent-rgb), 0.4);
filter: drop-shadow(0 0 4px rgba(var(--accent-rgb), 0.3));
}
#l-full-box .l-line:hover {
color: rgba(255, 255, 255, 0.7);
filter: blur(0.5px);
}
#l-full-box::-webkit-scrollbar {
display: none;
}
.[Link]-text {
filter: none !important;
transform: none !important;
font-size: 18px;
color: rgba(255, 255, 255, 0.8);
text-align: left;
padding: 4px 60px;
opacity: 1;
}
.search-lyrics-btn {
background: var(--accent);
color: #000;
border: none;
padding: 12px 28px;
border-radius: 99px;
font-weight: 700;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
box-shadow: 0 8px 20px rgba(var(--accent-rgb), 0.3);
transition: 0.2s;
}
.search-lyrics-btn:hover {
transform: scale(1.05);
}
/* Resume Button */
#resume-sync-btn {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--accent);
color: #000;
border: none;
padding: 12px 24px;
border-radius: 99px;
font-weight: 700;
font-size: 13px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
z-index: 50;
display: none;
align-items: center;
gap: 8px;
opacity: 0;
transition: all 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
cursor: pointer;
}
#[Link] {
display: flex;
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* Modal Results */
.k-row {
display: flex;
align-items: center;
gap: 12px;
padding: 10px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid transparent;
transition: all 0.2s;
}
.k-row:hover {
border-color: var(--accent);
}
.k-row img {
width: 40px;
height: 40px;
border-radius: 6px;
}
/*
=========================================================================
4. PLAYER CARD
========================================================================= */
.player-card {
background: rgba(20, 20, 20, 0.6);
backdrop-filter: blur(40px);
border: 1px solid var(--glass-border);
border-radius: var(--rad);
padding: 30px;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
isolation: isolate;
transform: translateZ(0);
}
.art-container {
width: 100%;
aspect-ratio: 1;
border-radius: 24px;
background: #111;
position: relative;
overflow: hidden;
isolation: isolate;
transform: translateZ(0);
margin-bottom: 25px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
.art-img {
width: 100%;
height: 100%;
object-fit: cover;
border: none;
display: block;
}
.t-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 64px;
color: rgba(255, 255, 255, 0.15);
}
.p-title {
font-size: 20px;
font-weight: 800;
margin-bottom: 4px;
}
.p-artist {
font-size: 14px;
color: var(--accent);
font-weight: 600;
margin-bottom: 20px;
opacity: 0.9;
}
.seek-track {
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.15);
border-radius: 99px;
position: relative;
overflow: hidden;
transition: height 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.seek-container:hover .seek-track {
height: 10px;
}
.seek-fill {
height: 100%;
width: 0%;
background: var(--accent);
transition: width 0.1s linear;
}
.time-row {
display: flex;
justify-content: space-between;
font-family: 'JetBrains Mono';
font-size: 11px;
color: var(--text-dim);
margin-bottom: 20px;
}
/* Controls */
.controls {
display: flex;
justify-content: center;
align-items: center;
gap: 24px;
margin-bottom: 20px;
}
.c-btn {
opacity: 0.7;
}
.c-btn:hover {
opacity: 1;
transform: scale(1.1);
}
.play-btn {
width: 64px;
height: 64px;
border-radius: 50%;
background: #fff;
color: #000;
box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
}
.play-btn:active {
transform: scale(0.95);
}
.btn-action {
width: 100%;
padding: 14px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
color: rgba(255, 255, 255, 0.7);
font-weight: 600;
font-size: 13px;
gap: 8px;
transition: 0.2s;
}
.btn-action:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
transform: translateY(-2px);
}
.[Link] {
background: var(--accent);
color: #000;
border-color: var(--accent);
box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.3);
}
#toast {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background: #222;
border: 1px solid #444;
color: #fff;
padding: 10px 20px;
border-radius: 50px;
font-size: 13px;
z-index: 1000;
pointer-events: none;
opacity: 0;
transition: 0.3s;
}
/* Show on hover */
.art-container:hover .player-overlay {
opacity: 1;
}
/* Button Rows */
.po-row {
display: flex;
gap: 10px;
}
/* Overlay Buttons */
.po-btn {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
padding: 8px 16px;
border-radius: 99px;
cursor: pointer;
font-size: 13px;
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.po-btn:hover {
background: var(--accent);
color: #000;
border-color: var(--accent);
transform: scale(1.05);
}
.[Link] {
background: var(--accent);
color: #000;
box-shadow: 0 0 15px rgba(var(--accent-rgb), 0.4);
}
.[Link] {
padding: 6px 12px;
font-size: 11px;
}
<body>
<!-- ROBUST SPLASH SCREEN -->
<div id="splash-screen">
<div class="splash-content">
<div class="splash-logo">
<span class="icon">music_note</span>
</div>
<div class="splash-text">
<h1>Material Music</h1>
<p id="splash-status">Initializing Audio Engine...</p>
</div>
<div class="splash-loader">
<div id="splash-bar" class="splash-bar"></div>
</div>
</div>
</div>
<div class="scroll-area">
<div id="lib-list" class="list-layout">
<!-- Tracks or Karaoke List will be injected here -->
</div>
</div>
</div>
<!-- B. SEARCH VIEW -->
<div id="view-search" class="view-section">
<div class="header">
<div class="h-sup">Online</div>
<div class="h-main">Discover</div>
<div style="display:flex; gap:10px; margin-top:20px; align-
items:center;">
<button class="btn btn-action active" id="btn-mode-songs"
style="width:auto; padding:8px 20px; border-
radius:99px;" onclick="[Link]('songs')">
<span class="icon" style="font-size:18px; margin-
right:6px">music_note</span> Music
</button>
<button class="btn btn-action" id="btn-mode-videos"
style="width:auto; padding:8px 20px; border-
radius:99px;" onclick="[Link]('videos')">
<span class="icon" style="font-size:18px; margin-
right:6px">movie</span> YouTube
</button>
<input type="text" id="yt-in" class="search-box"
style="margin:0; flex:1;" placeholder="Search..."
onkeydown="if([Link]=='Enter') [Link]()">
</div>
</div>
<div class="scroll-area">
<div id="yt-list" class="list-layout"></div>
</div>
</div>
<div class="stem-card">
<div class="stem-header">
<div class="stem-label"><span class="icon" style="font-
size:20px">mic</span> Vocals</div>
<div class="stem-val" id="v-vocal">100%</div>
</div>
<input type="range" min="0" max="1.5" step="0.1" value="1.0"
oninput="[Link]('vocal', [Link])">
</div>
<div class="stem-card">
<div class="stem-header">
<div class="stem-label"><span class="icon" style="font-
size:20px">piano</span> Music</div>
<div class="stem-val" id="v-music">100%</div>
</div>
<input type="range" min="0" max="1.5" step="0.1" value="1.0"
oninput="[Link]('music', [Link])">
</div>
</div>
</div>
</div>
</div>
<div class="time-row">
<span id="t-cur">0:00</span>
<span id="t-dur">0:00</span>
</div>
<div class="controls">
<button class="c-btn btn" onclick="[Link]()"><span
class="icon">skip_previous</span></button>
<button class="play-btn btn" onclick="[Link]()">
<span class="icon" style="font-size:32px" id="ic-
play">play_arrow</span>
<span class="icon" style="font-size:32px; display:none" id="ic-
pause">pause</span>
</button>
<button class="c-btn btn" onclick="[Link]()"><span
class="icon">skip_next</span></button>
</div>
<div class="bottom-actions">
<button class="btn btn-action" id="btn-lyrics-toggle"
onclick="[Link]('view-lyrics', [Link]('.nav-
rail .nav-btn:nth-child(4)'))">
<span class="icon" style="font-size:20px">lyrics</span> Lyrics
</button>
<button class="btn btn-action" id="k-btn-main"
onclick="[Link]()">
<span class="icon" style="font-size:20px">mic</span> Karaoke
</button>
</div>
</div>
<div id="k-results"
style="flex:1; overflow-y:auto; margin-top:16px; display:flex;
flex-direction:column; gap:8px;"></div>
<div style="margin-bottom:20px;">
<label style="font-size:12px; color:var(--accent); font-
weight:700;">MODEL MODE</label>
<div style="display:grid; grid-template-columns:1fr 1fr;
gap:10px; margin-top:8px;">
<button class="btn btn-action active" id="btn-m-vox"
onclick="[Link]('vocals')">
High Quality Vocals
</button>
<button class="btn btn-action" id="btn-m-mus"
onclick="[Link]('music')">
High Quality Music
</button>
</div>
<div style="font-size:11px; color:#666; margin-top:8px;"
id="model-desc">
Best for clean vocals. Instrumental might have artifacts.
</div>
</div>
<div id="toast"></div>
function onPlayerStateChange(event) {
// 1 = Playing, 3 = Buffering
const isPlaying = ([Link] === 1 || [Link] === 3);
// Toggle play/pause buttons in your UI
if ([Link]('ic-play')) {
[Link]('ic-play').[Link] = isPlaying ?
'none' : 'block';
[Link]('ic-pause').[Link] = isPlaying ?
'block' : 'none';
}
}
function awaitJob(jobId) {
return new Promise((resolve, reject) => {
[Link](jobId, { resolve, reject });
});
}
[Link](on_job_result);
function on_job_result(jobId, payload) {
const job = [Link](jobId);
if (!job) return;
[Link](jobId);
[Link](payload);
}
[Link](on_job_error);
function on_job_error(jobId, err) {
const job = [Link](jobId);
if (!job) return;
[Link](jobId);
[Link](err);
}
[Link](update_cloud_status);
function update_cloud_status(msg, code) {
toast(msg);
if (code === 3) [Link]();
}
[Link](on_record_complete);
function on_record_complete(newPlaylist, title) {
[Link](newPlaylist);
toast(`Downloaded: ${title}`);
}
[Link](on_hq_ready);
function on_hq_ready() {
toast("HQ Stems Ready!");
if ([Link] && [Link]) {
const trackInLib = [Link](t => [Link] ===
[Link]);
if (trackInLib) {
trackInLib.has_stems = true;
[Link].has_stems = true;
}
}
if ([Link] && [Link].has_stems) {
$('stem-selector').value = 'ai';
$('ai-hint').[Link] = 'none';
eel.set_hq_mode(true)();
}
}
[Link](update_processing_status);
function update_processing_status(pct, timeLeft) {
$('ai-bar').[Link] = pct + "%";
$('ai-pct').innerText = pct + "%";
$('ai-status-txt').innerText = `Processing... ETA ${timeLeft}`;
if (pct >= 100) {
$('ai-prog-area').[Link] = 'none';
$('m-offline').[Link] = 'none';
}
}
[Link](update_loading_progress);
function update_loading_progress(pct, filename) {
const splashBar = [Link]('splash-bar');
if (splashBar && [Link] !== null) {
[Link] = 'none'; // Stop indeterminate
animation if progress is updating
[Link] = pct + "%";
[Link]('splash-status').innerText = filename;
}
if ([Link]("Buffering")) {
const pArtist = [Link]('p-artist');
[Link] = `Buffering... ${[Link](pct)}%`;
[Link] = 'var(--accent)';
$('ic-play').[Link] = 'none';
$('ic-pause').[Link] = 'block';
} else if ([Link]('p-
artist').[Link]("Buffering...")) {
if ([Link]) {
[Link]('p-artist').innerText =
[Link];
[Link]('p-artist').[Link] = 'var(--
accent)';
}
}
}
[Link](refresh_ui_library);
function refresh_ui_library(newPlaylist) {
[Link](newPlaylist);
}
try {
const cached = await eel.read_library_cache()();
[Link]('click', e => {
if (!$('ctx-menu').contains([Link]) && !
[Link]('.ctx-btn')) {
$('ctx-menu').[Link] = 'none';
}
});
bindScrollEvents();
requestAnimationFrame(updateLoop);
} catch (e) {
[Link]("Init Error", e);
toast("Initialization Failed: Check Console");
const splash = [Link]('splash-screen');
if (splash) [Link]();
}
}
function bindScrollEvents() {
const box = $('l-full-box');
const userScrollEvents = ['mousedown', 'wheel', 'touchstart',
'drag'];
[Link](evt => {
[Link](evt, () => {
isScrollingManually = true;
isAutoScrolling = false;
const btn = $('resume-sync-btn');
[Link]('show');
clearTimeout(scrollTimeout);
}, { passive: true });
});
}
function refreshLib(newPlaylist) {
if (newPlaylist) playlist = newPlaylist;
renderLib();
}
if ([Link] === 0) {
$('lib-list').innerHTML = `
<div style="padding:20px; text-align:center;
color:var(--text-dim);">
No tracks found. <br> Click the sync button at the
top for a "Rescan Library" option.
</div>
`;
return;
}
[Link]((t, i) => {
const row = [Link]('div');
[Link] = 'track-row';
if (currentMeta && [Link] === [Link])
[Link]('playing');
[Link] = `
<div onclick="[Link](${i})">${artHtml}</div>
<div class="t-info" onclick="[Link](${i})">
<div class="t-title truncate">${[Link]}</div>
<div class="t-artist truncate">${[Link]}</div>
</div>
<button class="btn ctx-btn" onclick="[Link](event,
${i})">
<span class="icon">more_vert</span>
</button>
`;
[Link] = (e) => {
if () [Link](i);
};
$('lib-list').appendChild(row);
});
}
function openCtx(e, i) {
[Link]();
ctxTargetIndex = i;
const m = $('ctx-menu');
[Link] = 'block';
let leftPos = [Link];
if (leftPos + [Link] > [Link]) {
leftPos = [Link] - [Link] - 20;
}
[Link] = leftPos + 'px';
[Link] = [Link] + 'px';
}
if (splash) {
[Link] = '0';
setTimeout(() => [Link](), 600);
}
function updateMeta(m) {
$('p-title').innerText = [Link];
$('p-artist').innerText = [Link];
$('l-page-title').innerText = [Link];
$('t-dur').innerText = fmt([Link]);
[Link] = 'none';
[Link] = 'none';
if (m.is_stream) {
if ([Link]) {
[Link] = [Link];
[Link] = 'block';
} else {
[Link] = 'flex';
[Link] = `linear-gradient(135deg, $
{getRandomColor([Link])}, #111)`;
}
} else {
if ([Link]) {
[Link] = [Link];
[Link] = 'block';
} else {
[Link] = 'flex';
[Link] = `linear-gradient(135deg, $
{getRandomColor([Link])}, #111)`;
}
}
}
if ([Link]) {
[Link]('--accent',
[Link]);
[Link]('--accent-rgb',
[Link].accent_rgb);
}
}
if (!isDragging) {
const cur = [Link]() * 1000;
const dur = [Link]() * 1000;
function updateSeekVis(e) {
const rect = $('seek-cont').getBoundingClientRect();
let pct = ([Link] - [Link]) / [Link];
pct = [Link](0, [Link](1, pct)) * 100;
$('seek-fill').[Link] = pct + "%";
}
function openOfflineAI() {
if (!currentMeta || currentMeta.is_stream ||
currentMeta.is_youtube_video_active) return toast("Select a local song first for
AI separation.");
$('m-offline').[Link] = 'flex';
$('ai-prog-area').[Link] = 'none';
$('ai-bar').[Link] = '0%';
$('ai-pct').innerText = '0%';
$('ai-status-txt').innerText = 'Initializing...';
selModel(selAiModel);
}
function selModel(m) {
selAiModel = m;
[Link]('#m-offline .btn-action').forEach(b =>
[Link]('active'));
if (m === 'vocals') {
$('btn-m-vox').[Link]('active');
$('model-desc').innerText = "Best for clean vocals.
Instrumental might have minor artifacts. Uses Kim_Vocal_2 model.";
} else {
$('btn-m-mus').[Link]('active');
$('model-desc').innerText = "Best for clean music. Vocals
might have minor artifacts. Uses UVR-MDX-NET-Inst_HQ_3 model.";
}
}
$('ai-prog-area').[Link] = 'block';
$('ai-status-txt').innerText = "Initializing...";
function openCloudModal() {
if (!currentMeta || currentMeta.is_stream ||
currentMeta.is_youtube_video_active) return toast("Select a local song first for
cloud separation.");
$('m-cloud').[Link] = 'flex';
}
async function startCloudProcess() {
$('m-cloud').[Link] = 'none';
if (!currentMeta) return toast("Select a song first.");
toast("Preparing Cloud Workspace...");
const ready = await eel.trigger_cloud_processing()();
if (ready) {
await eel.launch_cloud_workspace()();
toast("Monitoring Downloads folder for stems...");
} else {
toast("Could not prepare cloud session. Is another AI
process running?");
}
}
function switchStemMode(val) {
if (!currentMeta || currentMeta.is_stream ||
currentMeta.is_youtube_video_active) {
$('stem-selector').value = 'stereo';
return toast("Play a local track first for stem control.");
}
currentMeta = meta;
updateMeta(meta);
isScrollingManually = false;
$('resume-sync-btn').[Link]('show');
$('offset-panel').[Link]('open');
$('offset-btn-txt').innerText = "Sync";
$('btn-toggle-offset').[Link]('active');
lyrics = null;
$('l-full-box').innerHTML = '';
if ($('view-lyrics').[Link]('active')) {
renderLyricsEmptyState();
}
if (karaokeMode) {
toast("Auto-loading saved instrumental...");
const applySuccess = await pyJob(eel.apply_new_karaoke,
[Link], meta.karaoke_id, 0)();
if (!applySuccess) {
await eel.save_track_offset([Link], 'karaoke_id',
null)();
meta.karaoke_id = null;
karaokeMode = false;
$('k-btn-main').[Link]('active');
toast("Failed to auto-load instrumental. Reverting to
original.");
} else {
$('player-embed').[Link]('show');
if (ytPlayer && [Link])
[Link]();
}
}
if (meta.is_stream || $('view-
lyrics').[Link]('active')) {
searchLyricsManual();
} else {
renderLyricsEmptyState();
}
$('btn-version-toggle').classList[karaokeMode ? 'remove' :
'add']('hidden-btn');
checkOffsetWarning();
// UI Reset
$('seek-fill').[Link] = "0%";
$('t-cur').innerText = "0:00";
[Link]('p-artist').innerText = [Link];
[Link]('p-artist').[Link] = 'var(--
accent)';
}
function toggleOffsetPanel() {
const p = $('offset-panel');
const btnTxt = $('offset-btn-txt');
if ([Link]('open')) {
[Link]('open');
[Link] = "Sync";
$('btn-toggle-offset').[Link]('active');
} else {
[Link]('open');
[Link] = "Hide";
$('btn-toggle-offset').[Link]('active');
}
}
function onSliderInput(val) {
currentOffset = parseFloat(val);
$('offset-display').innerText = (currentOffset > 0 ? '+' : '') +
[Link](2) + 's';
}
function resetSync() {
onSliderInput(0);
onSliderChange(0);
$('sync-slider').value = 0;
}
function checkOffsetWarning() {
if (!currentMeta) return;
if (currentMeta.ignore_sync_warning) {
$('offset-warn-card').[Link] = 'none';
return;
}
function renderLyricsEmptyState() {
const box = $('l-full-box');
[Link] = `
<div class="lyrics-empty-state">
<span class="icon" style="font-size:48px;
opacity:0.2">lyrics</span>
<div style="opacity:0.5; font-size:14px;">No lyrics
loaded</div>
<button class="search-lyrics-btn"
onclick="[Link]()">
<span class="icon"
style="font-size:18px">search</span> Find Lyrics
</button>
</div>
`;
}
function renderLyrics() {
if (!lyrics) return;
if (isStatic) {
[Link] = "40px 0";
[Link] = "none";
[Link] = "none";
const title = [Link]('div');
[Link] = "<div style='text-align:center;
opacity:0.5; font-size:12px; margin-bottom:20px'>Static Lyrics
(Unsynced)</div>";
[Link](title);
[Link](line => {
const div = [Link]('div');
[Link] = 'l-line static-text';
[Link] = [Link];
[Link](div);
});
} else {
[Link] = "50vh 0";
[Link] = "";
[Link] = "";
[Link]((line, i) => {
const div = [Link]('div');
[Link] = 'l-line';
[Link] = `line-l-full-box-${i}`;
[Link] = [Link];
[Link] = () => {
isScrollingManually = false;
$('resume-sync-btn').[Link]('show');
eel.set_seek(([Link] + currentOffset) * 1000);
};
[Link](div);
});
}
}
function syncLyrics(timeSec) {
if (!lyrics) return;
if (lyrics[0].time === -1) return;
if (newActive) {
[Link]('active');
const randDur = 0.4 + [Link]() * 0.6;
[Link]('--rand-dur', randDur +
's');
if (!isScrollingManually) {
isAutoScrolling = true;
[Link]({ behavior: "smooth",
block: "center" });
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => isAutoScrolling
= false, 600);
}
}
}
}
}
function resumeAutoScroll() {
isScrollingManually = false;
$('resume-sync-btn').[Link]('show');
let currentMs = 0;
try {
const s = await eel.get_player_state()();
if (s) currentMs = [Link];
} catch (e) { }
if (karaokeMode) {
exitKaraokeMode(true, currentMs);
return;
}
if (t && t.karaoke_id) {
toast("Loading saved instrumental...");
const applyResult = await pyJob(eel.apply_new_karaoke,
[Link], t.karaoke_id, currentMs);
success = applyResult;
if (success) {
videoIdToUse = t.karaoke_id;
titleToUse = [Link];
}
}
if (!success) {
toast("Searching for best instrumental...");
res = await pyJob(eel.find_and_play_best_karaoke,
[Link], [Link], [Link], currentMs);
success = [Link];
if (success) {
videoIdToUse = res.video_id;
titleToUse = [Link];
warnToUse = [Link];
diffToUse = [Link];
}
}
if (success) {
if (t && !t.karaoke_id && videoIdToUse) {
t.karaoke_id = videoIdToUse;
await eel.save_track_offset([Link],
'karaoke_id', videoIdToUse)();
currentMeta.karaoke_id = videoIdToUse;
}
finalizeKaraokeMode(videoIdToUse, titleToUse, warnToUse,
diffToUse);
} else {
[Link]('active');
toast(res ? [Link] : "Failed to load karaoke.");
}
[Link]('btn-progress');
[Link] = '<span class="icon">mic</span> Karaoke';
}
karaokeMode = false;
$('k-btn-main').[Link]('active');
$('btn-version-toggle').[Link]('hidden-btn');
if ([Link]) [Link]();
// FIX: Ensure YouTube player iframe is hidden when exiting
karaoke mode
$('player-embed').[Link]('show');
if (ytPlayer && [Link]) [Link]();
if (posToSeek < 0) {
try {
const s = await eel.get_player_state()();
posToSeek = s ? [Link] : 0;
} catch (e) { posToSeek = 0; }
}
function openKaraokeModal() {
if (!currentMeta) return toast("Load a track first.");
$('k-modal-new').[Link] = 'flex';
$('k-search-in').value = `${[Link]} $
{[Link]} instrumental`;
[Link]();
$('k-search-in').focus();
}
function closeKaraokeModal() {
if ([Link]) [Link]();
$('k-modal-new').[Link] = 'none';
}
if ([Link] === 0) {
[Link] = '<div style="padding:20px; color:#666;">No
results found.</div>';
return;
}
[Link](r => {
const div = [Link]('div');
[Link] = 'k-row';
[Link] = `
${thumbHtml}
<div style="flex:1; overflow:hidden;">
<div class="truncate" style="font-weight:600">$
{[Link]}</div>
<div style="font-size:11px; opacity:0.7">${[Link]}
- ${[Link]} (${[Link]})</div>
</div>
<button class="btn row-btn" title="Preview (128kbps)"
onclick="[Link]('${[Link]}')">
<span class="icon" style="font-
size:20px">play_arrow</span>
</button>
<button class="btn row-btn" title="Download & Apply HQ"
onclick="[Link]('${[Link]}')">
<span class="icon"
style="font-size:20px">check</span>
</button>
`;
[Link](div);
});
}
let currentMs = 0;
let wasPlaying = false;
try {
const s = await eel.get_player_state()();
if (s) {
currentMs = [Link];
wasPlaying = [Link] === "PLAYING";
}
} catch (e) { }
karaokeMode = true;
$('k-btn-main').[Link]('active');
toast("Instrumental Updated!");
if (wasPlaying) eel.play_pause()();
currentMeta.is_youtube_video_active = false; // Not a video
currentMeta.youtube_vid = null;
} else {
toast("Failed to apply instrumental. Check FFmpeg.");
}
}
function setSearchMode(mode) {
searchFilter = mode;
$('btn-mode-songs').classList[mode === 'songs' ? 'add' :
'remove']('active');
$('btn-mode-videos').classList[mode === 'videos' ? 'add' :
'remove']('active');
if ([Link] === 0) {
$('yt-list').innerHTML = '<div style="padding:20px;
color:#666;">No results found.</div>';
return;
}
[Link](item => {
const row = [Link]('div');
[Link] = 'track-row';
[Link] = `
${thumbHtml}
<div class="t-info" style="overflow:hidden">
<div class="t-title truncate">${[Link]}</div>
<div class="t-artist truncate">${[Link]} $
{[Link] && [Link] !== 'Single' ? '⢠' + [Link] : ''}</div>
</div>
<button class="row-btn dl-btn" id="dl-${[Link]}"
title="Download" onclick="[Link](); [Link]('${[Link]}', '$
{safeTitle}', '${safeArt}', '${safeThumb}')">
<span class="icon" style="font-
size:18px">download</span>
</button>
`;
[Link] = () => {
// FIX: If searching videos, play as Video Embed by
default.
// If searching songs, play as Audio Stream.
if (isVideoSearch) {
[Link]([Link], [Link],
[Link], [Link]);
} else {
[Link]([Link], [Link], [Link],
[Link]);
}
};
$('yt-list').appendChild(row);
});
}
lyrics = null;
$('l-full-box').innerHTML = '';
currentMeta = {
title: t, artist: a, art: img,
is_youtube_video_active: true,
youtube_vid: vid,
is_stream: false,
duration: 0
};
setupOnNewTrack(currentMeta);
// 3. FORCE PLAY
if (isYoutubeApiReady && ytPlayer) {
[Link](vid);
[Link]();
} else {
createPlayer(vid);
}
exitKaraokeMode(false);
toast("Starting Cached Stream...");
// CHANGED: Unselect local library tracks visually for
consistency
[Link]('#lib-list .track-row').forEach(c =>
[Link]('playing'));
[Link]('downloading');
[Link]('btn-progress');
[Link]('--prog', '0%');
toast(`Recording: ${t}`);
// --- NEW: Switch between Audio Stream and Video Embed ---
function switchPlayerMode(mode) {
if (!currentMeta || !currentMeta.youtube_vid) {
return toast("Play a YouTube track first.");
}
// Update UI Buttons
$('btn-mode-audio').[Link]('active');
$('btn-mode-video').[Link]('active');
$(`btn-mode-${mode}`).[Link]('active');
return {
init, nav, load, togglePlay, next, prev,
setFX, search, stream,
openOfflineAI, selModel, runOfflineAI, openCloudModal,
startCloudProcess,
dl, refreshLib, openCtx, ctxAction, manualRescan,
toggleKaraoke, openKaraokeModal,
searchKaraokeOnly, previewK, applyK, closeKaraokeModal,
onSliderInput, onSliderChange, resetSync, ignoreWarning,
resumeAutoScroll, toggleOffsetPanel, searchLyricsManual,
switchStemMode,
setSearchMode, watchVideo,
createThumbHtml,
switchPlayerMode, setVideoQuality, // <--- ADDED THESE NEW
FUNCTIONS
playlist, currentMeta
};
})();
</html>
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\web\[Link]
================================================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Starting...</title>
<script type="text/javascript" src="/[Link]"></script>
<style>
body {
margin: 0;
padding: 0;
background-color: #050505;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Inter', 'Segoe UI', sans-serif;
overflow: hidden;
color: white;
}
.container {
text-align: center;
animation: fadeIn 0.5s ease-out;
width: 300px;
}
.logo {
width: 80px;
height: 80px;
background: linear-gradient(135deg, #d0bcff, #ffffff);
border-radius: 24px;
margin: 0 auto 20px auto;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 30px rgba(208, 188, 255, 0.4);
}
.logo svg {
width: 48px;
height: 48px;
fill: #000;
}
h1 {
font-size: 24px;
margin: 0;
background: linear-gradient(90deg, #fff, #888);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -0.5px;
font-weight: 800;
}
.status-text {
font-size: 11px;
color: rgba(255, 255, 255, 0.4);
margin-top: 24px;
font-family: 'JetBrains Mono', monospace;
text-transform: uppercase;
letter-spacing: 1px;
height: 1.2em;
}
.loader {
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.1);
border-radius: 99px;
margin: 12px auto 0 auto;
position: relative;
overflow: hidden;
}
.bar {
position: absolute;
left: 0;
top: 0;
bottom: 0;
background: #d0bcff;
width: 0%;
border-radius: 99px;
transition: width 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
</style>
</head>
<body>
<div class="container">
<div class="logo">
<svg viewBox="0 0 24 24">
<path
d="M12 3v9.28a4.39 4.39 0 00-1.5-.28C8.01 12 6 14.01 6
16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z" />
</svg>
</div>
<h1>Material Music</h1>
<div class="status-text" id="status">Initializing...</div>
<div class="loader">
<div class="bar" id="progress-bar"></div>
</div>
</div>
<script>
// Exposed to Python
[Link](update_setup_progress);
function update_setup_progress(pct, status) {
[Link]('progress-bar').[Link] = pct + '%';
[Link]('status').innerText = status;
}
[Link](on_job_result);
function on_job_result(job_id, result) {
// Asset setup job finished
setTimeout(() => {
[Link] = '[Link]';
}, 500);
}
[Link](on_job_error);
function on_job_error(job_id, err) {
[Link]('status').innerText = "Error: " + err;
[Link]('status').[Link] = "#ff8a80";
}
[Link] = function () {
// Small delay to ensure Eel is ready
setTimeout(() => {
eel.start_asset_setup()();
}, 500);
}
</script>
</body>
</html>
================================================================================
PATH: D:\#Code
Files\MusicPlayer\ModernMusicPlayer_Web\web\assets\cache\[Link]
================================================================================
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
================================================================================
PATH: D:\#Code
Files\MusicPlayer\ModernMusicPlayer_Web\web\assets\cache\jetbrains_mono.css
================================================================================
/* cyrillic-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_2.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_3.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_4.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_5.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
================================================================================
PATH: D:\#Code
Files\MusicPlayer\ModernMusicPlayer_Web\web\assets\cache\material_symbols.css
================================================================================
/* fallback */
@font-face {
font-family: 'Material Symbols Rounded';
font-style: normal;
font-weight: 100 700;
src: url(fonts/material_symbols_0.woff2) format('woff2');
}
.material-symbols-rounded {
font-family: 'Material Symbols Rounded';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
================================================================================
PATH: D:\#Code Files\MusicPlayer\ModernMusicPlayer_Web\web\cache\[Link]
================================================================================
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_2.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_3.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_4.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_5.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/inter_6.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
================================================================================
PATH: D:\#Code
Files\MusicPlayer\ModernMusicPlayer_Web\web\cache\jetbrains_mono.css
================================================================================
/* cyrillic-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_0.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_1.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_2.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_3.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-
01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_4.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(fonts/jetbrains_mono_5.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
================================================================================
PATH: D:\#Code
Files\MusicPlayer\ModernMusicPlayer_Web\web\cache\material_symbols.css
================================================================================
/* fallback */
@font-face {
font-family: 'Material Symbols Rounded';
font-style: normal;
font-weight: 400;
src: url(fonts/material_symbols_0.woff2) format('woff2');
}
.material-symbols-rounded {
font-family: 'Material Symbols Rounded';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}