refactor: redesign format selection with unified list and independent audio/video picking
All checks were successful
CI / build (push) Successful in 52s

- Replace type/quality selection flow with unified format list (video+audio combined)
- Add independent audio/video format picking: video-only formats prompt for audio track,
  audio-only formats offer optional video addition (skip when content is audio-only)
- Fix formatKeyboard to use format IDs as callback data instead of display labels
- Remove dead mediaTypeKeyboard function
- Fix double-close panic in readProgress (caller is sole owner of updates channel)
- Add FormatString field to DownloadJob for composite format specs (e.g. '137+140')
- Change quota calculation from sum of all format sizes to max single format size
- Fix 'Delete all data' button to use danger style with proper text
- Clean up routePrefixedCallback: remove type_/quality_, add format_/secondary_ routes
- Fix back navigation to rebuild format IDs list
This commit is contained in:
2026-06-25 15:37:47 +03:30
parent 7de79b50e1
commit e65ade6c3c
7 changed files with 286 additions and 198 deletions

View File

@@ -110,6 +110,7 @@ func (c *Client) GetMediaInfo(url string) (*domain.MediaInfo, error) {
}
langSet := make(map[string]bool)
var maxSize int64
for _, f := range info.Formats {
ff := c.convertFormat(f)
mi.Formats = append(mi.Formats, ff)
@@ -117,10 +118,11 @@ func (c *Client) GetMediaInfo(url string) (*domain.MediaInfo, error) {
langSet[ff.Language] = true
mi.Languages = append(mi.Languages, ff.Language)
}
if ff.Filesize > 0 {
mi.EstimatedSize += ff.Filesize
if ff.Filesize > maxSize {
maxSize = ff.Filesize
}
}
mi.EstimatedSize = maxSize
return mi, nil
}
@@ -215,20 +217,25 @@ func (c *Client) StartDownload(job *domain.DownloadJob, downloadDir string) (<-c
formatID := job.SelectedFormat.ID
var args []string
// Build format string for merge
switch job.MediaType {
case domain.MediaTypeAudio:
args = append(args, "-f", formatID, "-x")
if job.Container != "" {
args = append(args, "--audio-format", job.Container)
}
case domain.MediaTypeVideo:
args = append(args, "-f", formatID)
case domain.MediaTypeVideoAudio:
// Download best video + best audio that match
args = append(args, "-f", formatID+"+bestaudio/best")
if job.Container != "" {
args = append(args, "--merge-output-format", job.Container)
// Use explicit format string if set (video+audio combination)
if job.FormatString != "" {
args = append(args, "-f", job.FormatString)
} else {
// Build format string for merge
switch job.MediaType {
case domain.MediaTypeAudio:
args = append(args, "-f", formatID, "-x")
if job.Container != "" {
args = append(args, "--audio-format", job.Container)
}
case domain.MediaTypeVideo:
args = append(args, "-f", formatID)
case domain.MediaTypeVideoAudio:
// Download best video + best audio that match
args = append(args, "-f", formatID+"+bestaudio/best")
if job.Container != "" {
args = append(args, "--merge-output-format", job.Container)
}
}
}