From 5031481973f360df9a458ebe4d7cc322e7de9358 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:00:28 +0900 Subject: [PATCH 01/11] Separate frontend and backend --- src/Application.vala | 16 +++++++++++++++- src/Services/M3U.vala | 33 ++++++++++++--------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 58af56b57..2614bb163 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -213,7 +213,21 @@ public class Music.Application : Gtk.Application { } private void action_save_m3u_playlist () { - M3U.save_playlist ((MainWindow)active_window, playback_manager.queue_liststore); + var save_dialog = new Gtk.FileDialog () { + initial_name = _("New playlist.m3u") + }; + + save_dialog.save.begin ((MainWindow)active_window, null, (obj, res) => { + File? file; + try { + file = save_dialog.save.end (res); + } catch (Error err) { + warning ("Failed to save file: %s", err.message); + return; + } + + M3U.save_playlist (playback_manager.queue_liststore, file); + }); } private void on_bus_acquired (DBusConnection connection, string name) { diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index 55b883d4a..ed06a4aa2 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -50,7 +50,7 @@ namespace Music.M3U { } - public void save_playlist (MainWindow parent, ListStore queue_liststore) { + public void save_playlist (ListStore queue_liststore, File playlist) { debug ("Saving queue as playlist" + "\n"); string content = ""; @@ -59,28 +59,19 @@ namespace Music.M3U { content = content + item.uri + "\n"; } - var save_dialog = new Gtk.FileDialog () { - initial_name = _("New playlist.m3u") - }; - - save_dialog.save.begin (parent, null, (obj, res) => { - try { - var file = save_dialog.save.end (res); - var dostream = new DataOutputStream ( - file.replace ( - null, - false, - GLib.FileCreateFlags.REPLACE_DESTINATION - ) - ); + try { + var dostream = new DataOutputStream ( + playlist.replace ( + null, + false, + GLib.FileCreateFlags.REPLACE_DESTINATION + ) + ); dostream.put_string (content); - } catch (Error err) { - warning ("Failed to save file: %s", err.message); - } - }); - - + } catch (Error err) { + warning ("Failed to save file: %s", err.message); + } } } From 52266f4cc436c4184279c959e01bcd58a03978c5 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:01:24 +0900 Subject: [PATCH 02/11] Fix indentation --- src/Services/M3U.vala | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index ed06a4aa2..eea1bfd73 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -60,13 +60,8 @@ namespace Music.M3U { } try { - var dostream = new DataOutputStream ( - playlist.replace ( - null, - false, - GLib.FileCreateFlags.REPLACE_DESTINATION - ) - ); + var ostream = playlist.replace (null, false, GLib.FileCreateFlags.REPLACE_DESTINATION); + var dostream = new DataOutputStream (ostream); dostream.put_string (content); From eeaf75495fea379125bf2837ea2069b89ac35381 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:34:40 +0900 Subject: [PATCH 03/11] Use regex to check file suffix --- src/Application.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Application.vala b/src/Application.vala index 2614bb163..d29bc33c0 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -163,7 +163,9 @@ public class Music.Application : Gtk.Application { continue; } - if ((file_path.ascii_down ().has_suffix (".m3u")) || (file_path.ascii_down ().has_suffix (".m3u8"))) { + // Check if the file has M3U suffix: "foo.m3u", "bar.M3U8", etc. + var m3u_suffix = /^.+.m3u8?$/i; + if (m3u_suffix.match (file_path)) { foreach (var track in M3U.parse_playlist (file)) { elements += track; } From bdd5ce7226a7f2e653fdc380195d4b83d77e6445 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:44:15 +0900 Subject: [PATCH 04/11] Do not return incomplete File array if error --- src/Application.vala | 7 ++++++- src/Services/M3U.vala | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index d29bc33c0..eefd831dc 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -166,7 +166,12 @@ public class Music.Application : Gtk.Application { // Check if the file has M3U suffix: "foo.m3u", "bar.M3U8", etc. var m3u_suffix = /^.+.m3u8?$/i; if (m3u_suffix.match (file_path)) { - foreach (var track in M3U.parse_playlist (file)) { + File[] tracks = M3U.parse_playlist (file); + if (tracks == null) { + continue; + } + + foreach (var track in tracks) { elements += track; } diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index eea1bfd73..7661d214b 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -6,7 +6,7 @@ namespace Music.M3U { // Standard specification here: https://en.wikipedia.org/wiki/M3U - public File[] parse_playlist (File playlist) { + public File[]? parse_playlist (File playlist) { debug ("Parsing playlist: %s", playlist.get_path ()); File[] list = {}; @@ -44,6 +44,7 @@ namespace Music.M3U { } catch (Error e) { print ("Error: %s\n", e.message); + return null; } return list; From b3283612b3c6b87704603363ef7c616c2b26b310 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:48:15 +0900 Subject: [PATCH 05/11] Do not use print for debug/warning logs --- src/Services/M3U.vala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index 7661d214b..3a63829e5 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -16,11 +16,11 @@ namespace Music.M3U { string line; while ((line = dis.read_line ()) != null) { - print ("%s\n", line); + debug ("%s", line); - // Skip extended + // Skip extended if (line.has_prefix ("#EXT")) { - print ("Skipping EXTM3U: " + line + "\n"); + debug ("Skipping EXTM3U: " + line); } else { File target; @@ -30,7 +30,7 @@ namespace Music.M3U { //FIXME: URL get skipped. //} else if (line.ascii_down ().has_prefix ("http")) { - // print ("URL are currently unsupported:" + line + "\n"); + // debug ("URL are currently unsupported:" + line); } else { target = File.new_for_path (line); @@ -43,7 +43,7 @@ namespace Music.M3U { } } catch (Error e) { - print ("Error: %s\n", e.message); + warning ("Error: %s", e.message); return null; } @@ -52,7 +52,7 @@ namespace Music.M3U { } public void save_playlist (ListStore queue_liststore, File playlist) { - debug ("Saving queue as playlist" + "\n"); + debug ("Saving queue as playlist"); string content = ""; for (var i = 0; i < queue_liststore.n_items; i++) { From 63316af934352d043081b66157e0c6c0382a629c Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 22:54:47 +0900 Subject: [PATCH 06/11] Remove unnecessary else and newlines --- src/Services/M3U.vala | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index 3a63829e5..ff7203e68 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -21,34 +21,29 @@ namespace Music.M3U { // Skip extended if (line.has_prefix ("#EXT")) { debug ("Skipping EXTM3U: " + line); + continue; + } - } else { - File target; - - if (line.ascii_down ().has_prefix ("file:///")) { - target = File.new_for_uri (line); - - //FIXME: URL get skipped. - //} else if (line.ascii_down ().has_prefix ("http")) { - // debug ("URL are currently unsupported:" + line); - - } else { - target = File.new_for_path (line); + File target; - }; + if (line.ascii_down ().has_prefix ("file:///")) { + target = File.new_for_uri (line); + //FIXME: URL get skipped. + //} else if (line.ascii_down ().has_prefix ("http")) { + // debug ("URL are currently unsupported:" + line); + } else { + target = File.new_for_path (line); + }; - // We do not need to test yet whether files exist - list += target; - } + // We do not need to test yet whether files exist + list += target; } - } catch (Error e) { warning ("Error: %s", e.message); return null; } return list; - } public void save_playlist (ListStore queue_liststore, File playlist) { @@ -65,7 +60,6 @@ namespace Music.M3U { var dostream = new DataOutputStream (ostream); dostream.put_string (content); - } catch (Error err) { warning ("Failed to save file: %s", err.message); } From 1ac76dc17de42b1843404dd47774668e0a880571 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 23:10:16 +0900 Subject: [PATCH 07/11] Handle error when saving playlist --- src/Application.vala | 21 ++++++++++++++++++--- src/Services/M3U.vala | 3 ++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index eefd831dc..556a157c1 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -228,12 +228,27 @@ public class Music.Application : Gtk.Application { File? file; try { file = save_dialog.save.end (res); + + M3U.save_playlist (playback_manager.queue_liststore, file); } catch (Error err) { + if (err.matches (Gtk.DialogError.quark (), Gtk.DialogError.DISMISSED)) { + return; + } + warning ("Failed to save file: %s", err.message); - return; - } - M3U.save_playlist (playback_manager.queue_liststore, file); + var dialog = new Granite.MessageDialog ( + _("Couldn't save playlist"), + err.message, + new ThemedIcon ("playlist-queue") + ) { + badge_icon = new ThemedIcon ("dialog-error"), + modal = true, + transient_for = active_window + }; + dialog.present (); + dialog.response.connect (dialog.destroy); + } }); } diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index ff7203e68..d12e00381 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -46,7 +46,7 @@ namespace Music.M3U { return list; } - public void save_playlist (ListStore queue_liststore, File playlist) { + public void save_playlist (ListStore queue_liststore, File playlist) throws Error { debug ("Saving queue as playlist"); string content = ""; @@ -62,6 +62,7 @@ namespace Music.M3U { dostream.put_string (content); } catch (Error err) { warning ("Failed to save file: %s", err.message); + throw err; } } } From 5e4f4948ff4fa8d543c4b444a737e00c0ffd39bd Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 23:11:11 +0900 Subject: [PATCH 08/11] Distinguish log message --- src/Application.vala | 2 +- src/Services/M3U.vala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 556a157c1..155c849f1 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -235,7 +235,7 @@ public class Music.Application : Gtk.Application { return; } - warning ("Failed to save file: %s", err.message); + warning ("Failed to save playlist: %s", err.message); var dialog = new Granite.MessageDialog ( _("Couldn't save playlist"), diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index d12e00381..ea6b0cd5a 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -61,7 +61,7 @@ namespace Music.M3U { dostream.put_string (content); } catch (Error err) { - warning ("Failed to save file: %s", err.message); + warning ("Failed to writing to playlist: %s", err.message); throw err; } } From d0b99dc95abca4e453a5b834a3369e6b46150d9e Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 23:12:02 +0900 Subject: [PATCH 09/11] Remove unnecessary cast --- src/Application.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application.vala b/src/Application.vala index 155c849f1..96c242c96 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -224,7 +224,7 @@ public class Music.Application : Gtk.Application { initial_name = _("New playlist.m3u") }; - save_dialog.save.begin ((MainWindow)active_window, null, (obj, res) => { + save_dialog.save.begin (active_window, null, (obj, res) => { File? file; try { file = save_dialog.save.end (res); From 0b8637d9508d7ea0ee27df21c8fbb7f964ab6083 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 5 Aug 2025 23:46:01 +0900 Subject: [PATCH 10/11] Update POTFILES --- po/POTFILES | 1 - 1 file changed, 1 deletion(-) diff --git a/po/POTFILES b/po/POTFILES index 1bc38e490..5f3c92996 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -4,4 +4,3 @@ src/PlaybackManager.vala src/Views/NowPlayingView.vala src/Widgets/AlbumImage.vala src/Widgets/SeekBar.vala -src/Services/M3U.vala \ No newline at end of file From 3bdf7d9bb86e5150ddece8d58358d0ea73e21112 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Wed, 6 Aug 2025 06:49:41 +0900 Subject: [PATCH 11/11] Remove unnecessary semicolon and newlines --- src/Application.vala | 1 - src/Services/M3U.vala | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 96c242c96..43a2654b7 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -228,7 +228,6 @@ public class Music.Application : Gtk.Application { File? file; try { file = save_dialog.save.end (res); - M3U.save_playlist (playback_manager.queue_liststore, file); } catch (Error err) { if (err.matches (Gtk.DialogError.quark (), Gtk.DialogError.DISMISSED)) { diff --git a/src/Services/M3U.vala b/src/Services/M3U.vala index ea6b0cd5a..982de5da5 100644 --- a/src/Services/M3U.vala +++ b/src/Services/M3U.vala @@ -33,7 +33,7 @@ namespace Music.M3U { // debug ("URL are currently unsupported:" + line); } else { target = File.new_for_path (line); - }; + } // We do not need to test yet whether files exist list += target; @@ -58,7 +58,6 @@ namespace Music.M3U { try { var ostream = playlist.replace (null, false, GLib.FileCreateFlags.REPLACE_DESTINATION); var dostream = new DataOutputStream (ostream); - dostream.put_string (content); } catch (Error err) { warning ("Failed to writing to playlist: %s", err.message);