mirror of
https://github.com/markuryy/shark.git
synced 2025-12-12 11:41:02 +00:00
92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import { writeFile } from '@tauri-apps/plugin-fs';
|
|
import { sanitizeFilename } from '$lib/services/deezer/paths';
|
|
import { encodeEmojis } from '$lib/utils/emoji';
|
|
|
|
export interface M3U8Track {
|
|
duration: number; // in seconds
|
|
artist: string;
|
|
title: string;
|
|
path: string; // relative path from playlist file (e.g., ../Music/Artist/Album/01 - Track.flac)
|
|
}
|
|
|
|
/**
|
|
* Write an M3U8 playlist file
|
|
* Format: Extended M3U format with EXTINF metadata
|
|
*
|
|
* @param playlistName - Name of the playlist (will be sanitized)
|
|
* @param tracks - Array of tracks to include
|
|
* @param playlistsFolder - Absolute path to playlists folder
|
|
* @returns Absolute path to created m3u8 file
|
|
*/
|
|
export async function writeM3U8(
|
|
playlistName: string,
|
|
tracks: M3U8Track[],
|
|
playlistsFolder: string
|
|
): Promise<string> {
|
|
// Encode emojis and sanitize playlist name for filename
|
|
const encodedName = encodeEmojis(playlistName);
|
|
const sanitizedName = sanitizeFilename(encodedName);
|
|
const playlistPath = `${playlistsFolder}/${sanitizedName}.m3u8`;
|
|
|
|
// Build m3u8 content
|
|
const lines: string[] = [
|
|
'#EXTM3U',
|
|
`#PLAYLIST:${encodedName}`,
|
|
'#EXTENC:UTF-8',
|
|
''
|
|
];
|
|
|
|
for (const track of tracks) {
|
|
// EXTINF format: #EXTINF:duration,artist - title
|
|
const durationSeconds = Math.round(track.duration);
|
|
const extinf = `#EXTINF:${durationSeconds},${track.artist} - ${track.title}`;
|
|
lines.push(extinf);
|
|
lines.push(track.path);
|
|
}
|
|
|
|
// Add trailing newline
|
|
lines.push('');
|
|
|
|
const content = lines.join('\n');
|
|
const encoder = new TextEncoder();
|
|
const data = encoder.encode(content);
|
|
|
|
await writeFile(playlistPath, data);
|
|
|
|
return playlistPath;
|
|
}
|
|
|
|
/**
|
|
* Convert absolute music file path to relative path from playlists folder
|
|
* Assumes music folder and playlists folder are siblings:
|
|
* /path/to/Music/Artist/Album/Track.flac
|
|
* /path/to/Playlists/playlist.m3u8
|
|
* Becomes: ../Music/Artist/Album/Track.flac
|
|
*
|
|
* @param absoluteMusicPath - Absolute path to music file
|
|
* @param musicFolderName - Name of music folder (default: 'Music')
|
|
* @returns Relative path from playlists folder
|
|
*/
|
|
export function makeRelativePath(
|
|
absoluteMusicPath: string,
|
|
musicFolderName: string = 'Music'
|
|
): string {
|
|
// Split path into parts
|
|
const parts = absoluteMusicPath.split('/');
|
|
|
|
// Find the music folder index
|
|
const musicIndex = parts.findIndex(part => part === musicFolderName);
|
|
|
|
if (musicIndex === -1) {
|
|
// Fallback: if music folder not found, use the path as-is
|
|
console.warn(`[M3U8] Could not find "${musicFolderName}" in path: ${absoluteMusicPath}`);
|
|
return absoluteMusicPath;
|
|
}
|
|
|
|
// Take everything from music folder onwards
|
|
const relativeParts = parts.slice(musicIndex);
|
|
|
|
// Prepend ../ to go up from playlists folder
|
|
return `../${relativeParts.join('/')}`;
|
|
}
|