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:
@@ -40,14 +40,14 @@ func (fe *FrontendUtil) DirectoryPicker() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PlaylistFilePicker opens a file selection dialog filtered
|
// 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() (
|
func (fe *FrontendUtil) PlaylistFilePicker() (
|
||||||
string,
|
[]string,
|
||||||
error,
|
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,
|
fe.ctx,
|
||||||
runtime.OpenDialogOptions{
|
runtime.OpenDialogOptions{
|
||||||
Title: "Import Playlist",
|
Title: "Import Playlist",
|
||||||
@@ -60,10 +60,10 @@ func (fe *FrontendUtil) PlaylistFilePicker() (
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"could not open file dialog: %w", err,
|
"could not open file dialog: %w", err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return file, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -793,6 +793,46 @@ func (s *Service) ImportPlaylist(
|
|||||||
return summary, nil
|
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.
|
// RestoreAllPlaylists restores playlist tracks from M3U8 files.
|
||||||
// This is called after a full library rescan to repopulate
|
// This is called after a full library rescan to repopulate
|
||||||
// playlist_tracks from the surviving M3U8 files.
|
// playlist_tracks from the surviving M3U8 files.
|
||||||
|
|||||||
Reference in New Issue
Block a user