feat(quick-001): add multi-file picker and batch import support

- Update PlaylistFilePicker to return []string via OpenMultipleFilesDialog
- Add ImportPlaylists method for sequential batch import with partial success
This commit is contained in:
2026-02-28 13:30:36 -05:00
parent 7f52dce296
commit c34e4ad029
2 changed files with 46 additions and 6 deletions
+6 -6
View File
@@ -40,14 +40,14 @@ func (fe *FrontendUtil) DirectoryPicker() (string, error) {
}
// PlaylistFilePicker opens a file selection dialog filtered
// to M3U/M3U8 playlist files.
// to M3U/M3U8 playlist files. Multiple files may be selected.
func (fe *FrontendUtil) PlaylistFilePicker() (
string,
[]string,
error,
) {
runtime.LogInfo(fe.ctx, "selecting a playlist file")
runtime.LogInfo(fe.ctx, "selecting playlist files")
file, err := runtime.OpenFileDialog(
files, err := runtime.OpenMultipleFilesDialog(
fe.ctx,
runtime.OpenDialogOptions{
Title: "Import Playlist",
@@ -60,10 +60,10 @@ func (fe *FrontendUtil) PlaylistFilePicker() (
},
)
if err != nil {
return "", fmt.Errorf(
return nil, fmt.Errorf(
"could not open file dialog: %w", err,
)
}
return file, nil
return files, nil
}
+40
View File
@@ -793,6 +793,46 @@ func (s *Service) ImportPlaylist(
return summary, nil
}
// ImportPlaylists imports multiple playlists from external M3U/M3U8
// files. Each file is imported sequentially using ImportPlaylist.
// Errors from individual imports are collected; partial success is
// possible. Returns the summaries of successfully imported playlists
// and the first error encountered (if any).
func (s *Service) ImportPlaylists(
filePaths []string,
) ([]Summary, error) {
if len(filePaths) == 0 {
return nil, errNoFilePaths
}
summaries := make([]Summary, 0, len(filePaths))
var firstErr error
for _, fp := range filePaths {
summary, err := s.ImportPlaylist(fp)
if err != nil {
s.logger.Warn(
"Failed to import playlist file",
"path", fp,
"err", err,
)
if firstErr == nil {
firstErr = fmt.Errorf(
"import %q failed: %w", fp, err,
)
}
continue
}
summaries = append(summaries, summary)
}
return summaries, firstErr
}
// RestoreAllPlaylists restores playlist tracks from M3U8 files.
// This is called after a full library rescan to repopulate
// playlist_tracks from the surviving M3U8 files.