Skip to content

Commit 5508ad0

Browse files
committed
Add playlist exporting
1 parent 4555aba commit 5508ad0

File tree

8 files changed

+59
-8
lines changed

8 files changed

+59
-8
lines changed

client/src/components/PlayerBar.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
tiny
7575
v-model="qtPlaylist"
7676
@update:model-value="loadQTPlaylist(); $1t.quickTagUnfocus()"
77-
@click.native='$1t.quickTagUnfocus'
77+
@click.native='$1t.onQuickTagEvent("generatePlaylist"); $1t.quickTagUnfocus()'
7878
class="q-mt-sm q-mr-sm"
7979
></PlaylistDropZone>
8080
</div>
@@ -86,7 +86,7 @@
8686
:min="0.0"
8787
:max="1.0"
8888
:step="0.01"
89-
@update:model-value="(v) => $1t.player.value.setVolume(v)"
89+
@update:model-value="(v: number) => $1t.player.value.setVolume(v)"
9090
@change="$1t.saveSettings(false)"
9191
style="margin-top: 6px"
9292
></q-slider>

client/src/components/PlaylistDropZone.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
label="Playlist"
3535
>
3636
<q-tooltip>
37-
Drag & drop playlist here / click to remove it
37+
Drag & drop playlist here / click to remove it, or export playlist from selected / filtered tracks
3838
</q-tooltip>
3939
</q-btn>
4040
</div>

client/src/scripts/onetagger.ts

+10
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,16 @@ class OneTagger {
322322
});
323323
break;
324324

325+
// Show notification
326+
case 'notify':
327+
Notify.create({
328+
position: 'top-right',
329+
timeout: 5000,
330+
progress: true,
331+
message: json.message
332+
});
333+
break
334+
325335
// Debug
326336
default:
327337
// Tag editor

client/src/scripts/quicktag.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { toRaw } from "vue";
22
import { QuickTagSettings } from "./settings";
3-
import { FrameName, Keybind, Separators } from "./utils";
3+
import { FrameName, Keybind } from "./utils";
4+
import { get1t } from "./onetagger";
45

56
class QuickTag {
67
tracks: QTTrack[] = [];

client/src/views/QuickTag.vue

+13
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,15 @@ function onManualTagDone() {
443443
$1t.loadQuickTag();
444444
}
445445
446+
/// Export playlist from selected tracks or filtered
447+
function generatePlaylist() {
448+
let paths = $1t.quickTag.value.track.tracks.map(t => t.path);
449+
if (paths.length == 0) {
450+
paths = tracks.value.map(t => t.path);
451+
}
452+
$1t.send('generatePlaylist', { paths });
453+
}
454+
446455
// Scroll to track index
447456
const tracklist = ref<HTMLElement | undefined>();
448457
function scrollToIndex(index: number) {
@@ -584,6 +593,10 @@ onMounted(() => {
584593
case 'onManualTag':
585594
onManualTag(data.path);
586595
return;
596+
597+
case 'generatePlaylist':
598+
generatePlaylist();
599+
break;
587600
588601
default:
589602
console.log(`Unknown QT Event: ${action} ${data}`);

crates/onetagger-playlist/src/lib.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub enum PlaylistFormat {
4646
}
4747

4848

49+
/// Get files from any playlist format
4950
pub fn get_files_from_playlist_file(path: impl AsRef<Path>) -> Result<Vec<PathBuf>, Error> {
5051
// Validate extension
5152
if !PLAYLIST_EXTENSIONS.iter().any(|e| &&path.as_ref().extension().unwrap_or_default().to_string_lossy().to_lowercase() == e) {
@@ -65,7 +66,7 @@ pub fn get_files_from_playlist_file(path: impl AsRef<Path>) -> Result<Vec<PathBu
6566
}
6667

6768

68-
// Get file list from M3U playlist
69+
/// Get file list from M3U playlist
6970
pub fn get_files_from_m3u(m3u: &str, base_path: Option<PathBuf>) -> Vec<PathBuf> {
7071
let clean = m3u.replace("\r", "\n").replace("\n\n", "\n");
7172
let entries = clean.split("\n");
@@ -90,4 +91,13 @@ pub fn get_files_from_m3u(m3u: &str, base_path: Option<PathBuf>) -> Vec<PathBuf>
9091
}
9192
}
9293
out.into_iter().map(|i| i.into()).collect()
93-
}
94+
}
95+
96+
/// Generate m3u playlist from paths
97+
pub fn create_m3u_playlist(paths: &Vec<PathBuf>) -> String {
98+
let mut playlist = "#EXTM3U\r\n".to_string();
99+
for path in paths {
100+
playlist = format!("{playlist}{}\r\n", path.to_string_lossy());
101+
}
102+
playlist
103+
}

crates/onetagger-tagger/src/custom.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use log::{Record, Level, RecordBuilder};
44
use crate::TrackMatch;
55

66
/// Version of supported custom platform
7-
pub const CUSTOM_PLATFORM_COMPATIBILITY: i32 = 42;
7+
pub const CUSTOM_PLATFORM_COMPATIBILITY: i32 = 43;
88

99
/// Logging from plugins
1010
#[no_mangle]

crates/onetagger-ui/src/socket.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ enum Action {
4040
OpenFile { path: PathBuf },
4141
DeleteFiles { paths: Vec<String> },
4242
GetLog,
43+
GeneratePlaylist { paths: Vec<String> },
4344

4445
LoadPlatforms,
4546
StartTagging { config: TaggerConfigs, playlist: Option<UIPlaylist> },
@@ -265,7 +266,23 @@ async fn handle_message(text: &str, websocket: &mut WebSocket, context: &mut Soc
265266
Action::OpenSettingsFolder => opener::open(Settings::get_folder()?.to_str().unwrap())?,
266267
Action::OpenFolder { path } => { opener::open(&path).ok(); },
267268
Action::OpenFile { path } => { opener::open(&path).ok(); },
268-
Action::DeleteFiles { paths } => { trash::delete_all(&paths)?; }
269+
Action::DeleteFiles { paths } => { trash::delete_all(&paths)?; },
270+
271+
Action::GeneratePlaylist { paths } => {
272+
let playlist = onetagger_playlist::create_m3u_playlist(&paths.into_iter().map(|i| i.into()).collect::<Vec<_>>());
273+
if let Some(path) = tinyfiledialogs::save_file_dialog_with_filter(
274+
"Save playlist",
275+
&std::env::current_dir()?.to_string_lossy().to_string(),
276+
&["m3u", "m3u8"],
277+
"Save playlist"
278+
) {
279+
std::fs::write(&path, playlist)?;
280+
send_socket(websocket, json!({
281+
"action": "notify",
282+
"message": format!("Playlist saved to: {path}")
283+
})).await.ok();
284+
}
285+
}
269286

270287
Action::LoadPlatforms => {
271288
let platforms = tokio::task::spawn_blocking(|| {

0 commit comments

Comments
 (0)