This commit is contained in:
cool.gitter.not.me.again.duh
2025-05-28 15:31:58 -06:00
parent e822284b88
commit ee261c28f4
13 changed files with 32 additions and 74 deletions

65
static/html/album.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Album Viewer - Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/album/album.css') }}" />
</head>
<body>
<div class="app-container">
<div id="album-header" class="content-header hidden">
<!-- Album Image -->
<img id="album-image" class="header-image" alt="Album cover" onerror="this.src='/static/images/placeholder.jpg'">
<!-- Album Info -->
<div id="album-info" class="header-info">
<h1 id="album-name" class="header-title"></h1>
<p id="album-artist" class="header-subtitle"></p>
<p id="album-stats" class="header-subtitle"></p>
<p id="album-copyright" class="album-copyright"></p>
<!-- Download Button -->
<div class="header-actions">
<button id="downloadAlbumBtn" class="download-btn btn-primary">
<img src="{{ url_for('static', filename='images/download.svg') }}" alt="Download">
Download Full Album
</button>
</div>
</div>
</div>
<div id="tracks-container" class="hidden">
<h2 class="section-title">Tracks</h2>
<div id="tracks-list" class="tracks-list"></div>
</div>
<!-- Loading and Error states -->
<div id="loading" class="loading">
<div class="loading-indicator">Loading...</div>
</div>
<div id="error" class="error hidden">Error loading album</div>
</div>
<!-- Fixed floating buttons for home and queue -->
<button id="homeButton" class="btn-icon home-btn floating-icon settings-icon" aria-label="Return to home">
<img src="{{ url_for('static', filename='images/home.svg') }}" alt="Home">
</button>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="Queue Icon">
</button>
<script type="module" src="{{ url_for('static', filename='js/album.js') }}"></script>
</body>
</html>

65
static/html/artist.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Artist Viewer - Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/artist/artist.css') }}" />
</head>
<body>
<div class="app-container">
<!-- Artist header container -->
<div id="artist-header" class="content-header hidden">
<!-- Artist Image -->
<img id="artist-image" class="header-image" alt="Artist image" onerror="this.src='/static/images/placeholder.jpg'">
<!-- Artist Info -->
<div id="artist-info" class="header-info">
<h1 id="artist-name" class="header-title"></h1>
<p id="artist-stats" class="header-subtitle"></p>
<!-- Download Button -->
<div class="header-actions">
<button id="downloadArtistBtn" class="download-btn btn-primary">
<img src="{{ url_for('static', filename='images/download.svg') }}" alt="Download">
Download All Discography
</button>
</div>
</div>
</div>
<!-- Albums container -->
<div id="albums-container" class="hidden">
<!-- This container will hold one section per album type -->
<div id="album-groups" class="album-groups"></div>
</div>
<!-- Loading and Error states -->
<div id="loading" class="loading">
<div class="loading-indicator">Loading...</div>
</div>
<div id="error" class="error hidden">Error loading artist info</div>
</div>
<!-- Fixed floating buttons for home and queue -->
<button id="homeButton" class="btn-icon home-btn floating-icon settings-icon" aria-label="Return to home">
<img src="{{ url_for('static', filename='images/home.svg') }}" alt="Home">
</button>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="Queue Icon">
</button>
<script type="module" src="{{ url_for('static', filename='js/artist.js') }}"></script>
</body>
</html>

287
static/html/config.html Normal file
View File

@@ -0,0 +1,287 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Configuration - Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/config/config.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
</head>
<body>
<div class="app-container">
<div class="config-container">
<header class="config-header">
<h1 class="header-title">Configuration</h1>
</header>
<div class="account-config card">
<h2 class="section-title">Download Settings</h2>
<!-- Default service selection - new element -->
<div class="config-item">
<label>Default Service:</label>
<select id="defaultServiceSelect" class="form-select">
<option value="spotify">Spotify</option>
</select>
<div class="setting-description">
The default service to use for downloads when not explicitly specified
</div>
</div>
<!-- Your account config section remains unchanged -->
<div class="config-item spotify-specific">
<label>Active Spotify Account:</label>
<select id="spotifyAccountSelect" class="form-select"></select>
<div id="spotifyAccountMessage" style="display: none; color: #888; margin-top: 5px;"></div>
</div>
<div class="config-item spotify-specific">
<label>Spotify Quality:</label>
<select id="spotifyQualitySelect" class="form-select">
<option value="NORMAL">OGG 96</option>
<option value="HIGH">OGG 160</option>
<option value="VERY_HIGH">OGG 320 (premium)</option>
</select>
</div>
<div class="config-item deezer-specific">
<label>Active Deezer Account:</label>
<select id="deezerAccountSelect" class="form-select"></select>
<div id="deezerAccountMessage" style="display: none; color: #888; margin-top: 5px;"></div>
</div>
<div class="config-item deezer-specific">
<label>Deezer Quality:</label>
<select id="deezerQualitySelect" class="form-select">
<option value="MP3_128">MP3 128</option>
<option value="MP3_320">MP3 320 (sometimes premium)</option>
<option value="FLAC">FLAC (premium)</option>
</select>
</div>
<!-- Explicit Filter Status -->
<div class="config-item">
<label>Explicit Content Filter:</label>
<div class="env-controlled-setting">
<span id="explicitFilterStatus" class="env-controlled-value">Loading...</span>
<div class="env-controlled-badge">ENV</div>
</div>
<div class="setting-description">
Filter explicit content. Controlled by environment variable EXPLICIT_FILTER.
</div>
</div>
<div class="config-item">
<label>Download Fallback:</label>
<label class="switch">
<input type="checkbox" id="fallbackToggle" />
<span class="slider"></span>
</label>
</div>
<div class="config-item">
<label>Real time downloading:</label>
<label class="switch">
<input type="checkbox" id="realTimeToggle" />
<span class="slider"></span>
</label>
</div>
<div class="config-item">
<label for="maxConcurrentDownloads">Max Concurrent Downloads:</label>
<input type="number" id="maxConcurrentDownloads" min="1" value="3" class="form-input">
</div>
<!-- New Retry Options -->
<h2 class="section-title">Retry Options</h2>
<div class="config-item">
<label for="maxRetries">Max Retry Attempts:</label>
<input type="number" id="maxRetries" min="0" max="10" value="3" class="form-input">
</div>
<div class="config-item">
<label for="retryDelaySeconds">Initial Retry Delay (seconds):</label>
<input type="number" id="retryDelaySeconds" min="1" value="5" class="form-input">
</div>
<div class="config-item">
<label for="retryDelayIncrease">Retry Delay Increase (seconds):</label>
<input type="number" id="retryDelayIncrease" min="0" value="5" class="form-input">
<div class="setting-description">
The amount of additional delay to add for each retry attempt
</div>
</div>
<!-- New Formatting Options -->
<h2 class="section-title">Formatting Options</h2>
<div class="config-item">
<label>Custom Directory Format:</label>
<input
type="text"
id="customDirFormat"
placeholder="e.g. %artist%/%album%"
class="form-input"
/>
<div class="format-help">
<select id="dirFormatHelp" class="format-selector">
<option value="">-- Select placeholder --</option>
<optgroup label="Common">
<option value="%music%">%music% - Track title</option>
<option value="%artist%">%artist% - Track artist</option>
<option value="%album%">%album% - Album name</option>
<option value="%ar_album%">%ar_album% - Album artist</option>
<option value="%tracknum%">%tracknum% - Track number</option>
<option value="%year%">%year% - Year of release</option>
</optgroup>
<optgroup label="Additional">
<option value="%discnum%">%discnum% - Disc number</option>
<option value="%date%">%date% - Release date</option>
<option value="%genre%">%genre% - Music genre</option>
<option value="%isrc%">%isrc% - International Standard Recording Code</option>
<option value="%explicit%">%explicit% - Explicit content flag</option>
<option value="%duration%">%duration% - Track duration (seconds)</option>
</optgroup>
<optgroup label="Metadata">
<option value="%publisher%">%publisher% - Publisher information</option>
<option value="%composer%">%composer% - Track composer</option>
<option value="%copyright%">%copyright% - Copyright information</option>
<option value="%author%">%author% - Author information</option>
<option value="%lyricist%">%lyricist% - Lyricist information</option>
<option value="%version%">%version% - Version information</option>
<option value="%comment%">%comment% - Comment field</option>
</optgroup>
<optgroup label="Other">
<option value="%encodedby%">%encodedby% - Encoded by information</option>
<option value="%language%">%language% - Language information</option>
<option value="%lyrics%">%lyrics% - Track lyrics</option>
<option value="%mood%">%mood% - Mood information</option>
<option value="%rating%">%rating% - Track rating</option>
<option value="%website%">%website% - Website information</option>
</optgroup>
<optgroup label="ReplayGain">
<option value="%replaygain_album_gain%">%replaygain_album_gain% - Album gain</option>
<option value="%replaygain_album_peak%">%replaygain_album_peak% - Album peak</option>
<option value="%replaygain_track_gain%">%replaygain_track_gain% - Track gain</option>
<option value="%replaygain_track_peak%">%replaygain_track_peak% - Track peak</option>
</optgroup>
</select>
</div>
</div>
<div class="config-item">
<label>Custom Track Format:</label>
<input
type="text"
id="customTrackFormat"
placeholder="e.g. %tracknum% - %music%"
class="form-input"
/>
<div class="format-help">
<select id="trackFormatHelp" class="format-selector">
<option value="">-- Select placeholder --</option>
<optgroup label="Common">
<option value="%music%">%music% - Track title</option>
<option value="%artist%">%artist% - Track artist</option>
<option value="%album%">%album% - Album name</option>
<option value="%ar_album%">%ar_album% - Album artist</option>
<option value="%tracknum%">%tracknum% - Track number</option>
<option value="%year%">%year% - Year of release</option>
</optgroup>
<optgroup label="Additional">
<option value="%discnum%">%discnum% - Disc number</option>
<option value="%date%">%date% - Release date</option>
<option value="%genre%">%genre% - Music genre</option>
<option value="%isrc%">%isrc% - International Standard Recording Code</option>
<option value="%explicit%">%explicit% - Explicit content flag</option>
<option value="%duration%">%duration% - Track duration (seconds)</option>
</optgroup>
<optgroup label="Metadata">
<option value="%publisher%">%publisher% - Publisher information</option>
<option value="%composer%">%composer% - Track composer</option>
<option value="%copyright%">%copyright% - Copyright information</option>
<option value="%author%">%author% - Author information</option>
<option value="%lyricist%">%lyricist% - Lyricist information</option>
<option value="%version%">%version% - Version information</option>
<option value="%comment%">%comment% - Comment field</option>
</optgroup>
<optgroup label="Other">
<option value="%encodedby%">%encodedby% - Encoded by information</option>
<option value="%language%">%language% - Language information</option>
<option value="%lyrics%">%lyrics% - Track lyrics</option>
<option value="%mood%">%mood% - Mood information</option>
<option value="%rating%">%rating% - Track rating</option>
<option value="%website%">%website% - Website information</option>
</optgroup>
<optgroup label="ReplayGain">
<option value="%replaygain_album_gain%">%replaygain_album_gain% - Album gain</option>
<option value="%replaygain_album_peak%">%replaygain_album_peak% - Album peak</option>
<option value="%replaygain_track_gain%">%replaygain_track_gain% - Track gain</option>
<option value="%replaygain_track_peak%">%replaygain_track_peak% - Track peak</option>
</optgroup>
</select>
</div>
<div class="setting-description">
Note that these placeholder depend on the metadata of the track, if one entry is not available in a track, the placeholder will be replaced with an empty string.
</div>
</div>
<!-- New Track Number Padding Toggle -->
<div class="config-item">
<label>Track Number Padding:</label>
<label class="switch">
<input type="checkbox" id="tracknumPaddingToggle" />
<span class="slider"></span>
</label>
<div class="setting-description">
When enabled: "01. Track" - When disabled: "1. Track"
</div>
</div>
</div>
<div class="accounts-section">
<div class="service-tabs">
<button class="tab-button active" data-service="spotify">Spotify</button>
<button class="tab-button" data-service="deezer">Deezer</button>
</div>
<!-- Wrapper for the list and the add button -->
<div class="credentials-list-wrapper card">
<div class="credentials-list-items">
<!-- Dynamic credential items will be rendered here by JavaScript -->
<!-- "No credentials" message will also be rendered here -->
</div>
<div class="add-account-item">
<button id="showAddAccountFormBtn" class="btn-add-account-styled" type="button">
<img src="{{ url_for('static', filename='images/plus-circle.svg') }}" alt="Add" /> Add New Account
</button>
</div>
</div>
<div class="credentials-form card">
<h2 id="formTitle" class="section-title">Add New Spotify Account</h2>
<form id="credentialForm">
<div class="config-item">
<label>Name:</label>
<input type="text" id="credentialName" class="form-input" required />
</div>
<div id="serviceFields"></div>
<div id="searchFields" style="display: none;"></div>
<button type="submit" id="submitCredentialBtn" class="btn btn-primary save-btn">Save Account</button>
<button type="button" id="cancelAddAccountBtn" class="btn btn-secondary cancel-btn btn-cancel-icon" style="margin-left: 10px;" title="Cancel">
<img src="{{ url_for('static', filename='images/cross.svg') }}" alt="Cancel" />
</button>
</form>
<div id="configSuccess" class="success"></div>
<div id="configError" class="error"></div>
</div>
</div>
</div>
</div>
<!-- Fixed floating buttons for back and queue -->
<a href="/" class="back-button floating-icon settings-icon" aria-label="Back to app">
<img src="{{ url_for('static', filename='images/arrow-left.svg') }}" alt="Back" />
</a>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="Queue" />
</button>
<!-- Load config.js as a module so you can import queue.js -->
<script type="module" src="{{ url_for('static', filename='js/config.js') }}"></script>
</body>
</html>

BIN
static/html/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

78
static/html/main.html Executable file
View File

@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/main.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
<script>
// Helper function to handle image loading errors
function handleImageError(img) {
img.src = '/static/images/placeholder.jpg';
}
</script>
</head>
<body>
<div class="app-container">
<div class="search-header">
<div class="search-input-container">
<input
type="text"
class="search-input"
placeholder="Search tracks, albums, playlists or artists... (Or paste in a spotify url)"
id="searchInput"
/>
<select class="search-type" id="searchType">
<option value="track">Tracks</option>
<option value="album">Albums</option>
<option value="playlist">Playlists</option>
<option value="artist">Artists</option>
</select>
</div>
<button class="search-button btn-primary" id="searchButton" aria-label="Search">
<img src="{{ url_for('static', filename='images/search.svg') }}" alt="" />
Search
</button>
</div>
<!-- Results container -->
<div id="resultsContainer" class="results-grid"></div>
<!-- Empty state when there are no results -->
<div id="emptyState" class="empty-state">
<div class="empty-state-content">
<img src="{{ url_for('static', filename='images/music.svg') }}" alt="Music" class="empty-state-icon" />
<h2>Search for music</h2>
<p>Find and download your favorite tracks, albums, playlists or artists</p>
</div>
</div>
<!-- Loading indicator -->
<div id="loadingResults" class="loading hidden">
<div class="loading-indicator">Searching...</div>
</div>
</div>
<!-- Fixed floating buttons for settings and queue -->
<a href="/config" class="btn-icon settings-icon floating-icon" aria-label="Settings">
<img src="{{ url_for('static', filename='images/settings.svg') }}" alt="Settings" onerror="handleImageError(this)"/>
</a>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="" onerror="handleImageError(this)"/>
</button>
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>

69
static/html/playlist.html Normal file
View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Playlist Viewer - Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/playlist/playlist.css') }}" />
</head>
<body>
<div class="app-container">
<div id="playlist-header" class="content-header hidden">
<!-- Playlist Image -->
<img id="playlist-image" class="header-image" alt="Playlist cover" onerror="this.src='/static/images/placeholder.jpg'">
<!-- Playlist Info -->
<div id="playlist-info" class="header-info">
<h1 id="playlist-name" class="header-title"></h1>
<p id="playlist-owner" class="header-subtitle"></p>
<p id="playlist-stats" class="header-subtitle"></p>
<p id="playlist-description" class="playlist-description"></p>
<!-- Download Buttons -->
<div class="header-actions">
<button id="downloadPlaylistBtn" class="download-btn btn-primary">
<img src="{{ url_for('static', filename='images/download.svg') }}" alt="Download">
Download Whole Playlist
</button>
<button id="downloadAlbumsBtn" class="download-btn">
<img src="{{ url_for('static', filename='images/album.svg') }}" alt="Albums">
Download Playlist's Albums
</button>
</div>
</div>
</div>
<div id="tracks-container" class="hidden">
<h2 class="section-title">Tracks</h2>
<div id="tracks-list" class="tracks-list"></div>
</div>
<!-- Loading and Error states -->
<div id="loading" class="loading">
<div class="loading-indicator">Loading...</div>
</div>
<div id="error" class="error hidden">Error loading playlist</div>
</div>
<!-- Fixed floating buttons for home and queue -->
<button id="homeButton" class="btn-icon home-btn floating-icon settings-icon" aria-label="Return to home">
<img src="{{ url_for('static', filename='images/home.svg') }}" alt="Home">
</button>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="Queue Icon">
</button>
<script type="module" src="{{ url_for('static', filename='js/playlist.js') }}"></script>
</body>
</html>

65
static/html/track.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Track Viewer - Spotizerr</title>
<!-- Add the new base.css first -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/base.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/queue/queue.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main/icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/track/track.css') }}">
</head>
<body>
<div class="app-container">
<div id="track-header" class="content-header hidden">
<!-- Album Image -->
<img id="track-album-image" class="header-image" alt="Album cover" onerror="this.src='/static/images/placeholder.jpg'">
<!-- Track Info -->
<div id="track-info" class="header-info">
<h1 id="track-name" class="header-title"></h1>
<p id="track-artist" class="header-subtitle"></p>
<p id="track-album" class="header-subtitle"></p>
<div class="track-details">
<span id="track-duration" class="track-detail-item"></span>
<span id="track-explicit" class="track-detail-item"></span>
</div>
<!-- Download Button moved here for better mobile layout -->
<div class="header-actions">
<button id="downloadTrackBtn" class="download-btn btn-primary">
<img src="{{ url_for('static', filename='images/download.svg') }}" alt="Download">
Download Track
</button>
</div>
</div>
</div>
<!-- Loading and Error states -->
<div id="loading" class="loading">
<div class="loading-indicator">Loading...</div>
</div>
<div id="error" class="error hidden">Error loading track</div>
</div>
<!-- Fixed floating buttons for home and queue -->
<button id="homeButton" class="btn-icon home-btn floating-icon settings-icon" aria-label="Return to home">
<img src="{{ url_for('static', filename='images/home.svg') }}" alt="Home">
</button>
<button
id="queueIcon"
class="btn-icon queue-icon floating-icon"
aria-label="Download queue"
aria-controls="downloadQueue"
aria-expanded="false"
>
<img src="{{ url_for('static', filename='images/queue.svg') }}" alt="Queue Icon">
</button>
<!-- The download queue container will be inserted by queue.js -->
<script type="module" src="{{ url_for('static', filename='js/track.js') }}"></script>
</body>
</html>