export as m3u
This commit is contained in:
parent
5349ae3871
commit
77ae6b737a
3 changed files with 78 additions and 4 deletions
|
|
@ -29,6 +29,10 @@
|
|||
<span class="nav-icon">📥</span>
|
||||
<span class="nav-text">Search</span>
|
||||
</button>
|
||||
<button class="nav-button" data-page="discover">
|
||||
<span class="nav-icon">🎧</span>
|
||||
<span class="nav-text">Discover</span>
|
||||
</button>
|
||||
<button class="nav-button" data-page="artists">
|
||||
<span class="nav-icon">🎵</span>
|
||||
<span class="nav-text">Artists</span>
|
||||
|
|
@ -37,10 +41,6 @@
|
|||
<span class="nav-icon">📚</span>
|
||||
<span class="nav-text">Library</span>
|
||||
</button>
|
||||
<button class="nav-button" data-page="discover">
|
||||
<span class="nav-icon">🎧</span>
|
||||
<span class="nav-text">Discover</span>
|
||||
</button>
|
||||
<button class="nav-button" data-page="settings">
|
||||
<span class="nav-icon">⚙️</span>
|
||||
<span class="nav-text">Settings</span>
|
||||
|
|
|
|||
|
|
@ -3976,6 +3976,9 @@ async function openDownloadMissingModal(playlistId) {
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-close-section">
|
||||
<button class="download-control-btn export" onclick="exportPlaylistAsM3U('${playlistId}')">
|
||||
📋 Export as M3U
|
||||
</button>
|
||||
<button class="download-control-btn secondary" onclick="closeDownloadMissingModal('${playlistId}')">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -3986,6 +3989,57 @@ async function openDownloadMissingModal(playlistId) {
|
|||
hideLoadingOverlay();
|
||||
}
|
||||
|
||||
function exportPlaylistAsM3U(playlistId) {
|
||||
/**
|
||||
* Export the tracks from the download missing tracks modal as an M3U playlist file
|
||||
*/
|
||||
console.log(`📋 Exporting playlist ${playlistId} as M3U`);
|
||||
|
||||
// Get the process data
|
||||
const process = activeDownloadProcesses[playlistId];
|
||||
if (!process || !process.tracks || process.tracks.length === 0) {
|
||||
showToast('No tracks available to export', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const tracks = process.tracks;
|
||||
const playlistName = process.playlistName || 'Playlist';
|
||||
|
||||
// Generate M3U8 content
|
||||
let m3uContent = '#EXTM3U\n';
|
||||
m3uContent += `#PLAYLIST:${playlistName}\n\n`;
|
||||
|
||||
tracks.forEach(track => {
|
||||
// Get duration in seconds
|
||||
const durationSeconds = track.duration_ms ? Math.floor(track.duration_ms / 1000) : -1;
|
||||
|
||||
// Get artist names
|
||||
const artists = Array.isArray(track.artists) ? track.artists.join(', ') : (track.artists || 'Unknown Artist');
|
||||
|
||||
// Add track info
|
||||
m3uContent += `#EXTINF:${durationSeconds},${artists} - ${track.name}\n`;
|
||||
|
||||
// Add a placeholder path (user will need to replace with actual file paths)
|
||||
const sanitizedArtist = artists.replace(/[/\\?%*:|"<>]/g, '-');
|
||||
const sanitizedTrack = track.name.replace(/[/\\?%*:|"<>]/g, '-');
|
||||
m3uContent += `${sanitizedArtist} - ${sanitizedTrack}.mp3\n\n`;
|
||||
});
|
||||
|
||||
// Create a Blob and download it
|
||||
const blob = new Blob([m3uContent], { type: 'audio/x-mpegurl;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${playlistName.replace(/[/\\?%*:|"<>]/g, '-')}.m3u8`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showToast(`Exported ${tracks.length} tracks as M3U playlist`, 'success');
|
||||
console.log(`✅ Exported ${tracks.length} tracks to ${link.download}`);
|
||||
}
|
||||
|
||||
async function openDownloadMissingModalForYouTube(virtualPlaylistId, playlistName, spotifyTracks) {
|
||||
showLoadingOverlay('Loading YouTube playlist...');
|
||||
// Check if a process is already active for this virtual playlist
|
||||
|
|
@ -4147,6 +4201,9 @@ async function openDownloadMissingModalForYouTube(virtualPlaylistId, playlistNam
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-close-section">
|
||||
<button class="download-control-btn export" onclick="exportPlaylistAsM3U('${virtualPlaylistId}')">
|
||||
📋 Export as M3U
|
||||
</button>
|
||||
<button class="download-control-btn secondary" onclick="closeDownloadMissingModal('${virtualPlaylistId}')">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -17432,6 +17489,9 @@ async function openDownloadMissingModalForArtistAlbum(virtualPlaylistId, playlis
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-close-section">
|
||||
<button class="download-control-btn export" onclick="exportPlaylistAsM3U('${virtualPlaylistId}')">
|
||||
📋 Export as M3U
|
||||
</button>
|
||||
<button class="download-control-btn secondary" onclick="closeDownloadMissingModal('${virtualPlaylistId}')">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8619,6 +8619,19 @@ body {
|
|||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.download-control-btn.export {
|
||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(118, 75, 162, 0.3);
|
||||
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.25);
|
||||
}
|
||||
|
||||
.download-control-btn.export:hover {
|
||||
background: linear-gradient(135deg, #7c8ff0, #8a5ab8);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.35);
|
||||
}
|
||||
|
||||
.download-control-btn:disabled {
|
||||
background: #333333;
|
||||
color: #666666;
|
||||
|
|
@ -8714,6 +8727,7 @@ body {
|
|||
.modal-close-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue