fix: show bitrate for audio-only formats, filter subtitle languages, improve feedback
All checks were successful
CI / build (push) Successful in 50s
All checks were successful
CI / build (push) Successful in 50s
- Prioritize IsAudioOnly check in formatLabelForDisplay so bitrate is shown instead of yt-dlp's generic 'audio only' resolution - Only collect languages from formats with audio/video to prevent subtitle-only tracks from triggering the language selection prompt - Show 'Fetching metadata...' message before GetMediaInfo and edit with results, improving UX for URL input - Add test coverage for audio-only format labels
This commit is contained in:
@@ -72,6 +72,16 @@ func (h *Handler) handleURLInput(ctx context.Context, chatID int64, text string,
|
||||
return
|
||||
}
|
||||
|
||||
// Show a temporary status message that we will edit with results later.
|
||||
fetchingMsg, _ := h.Bot.SendMessage(ctx, &tgbot.SendMessageParams{
|
||||
ChatID: chatID,
|
||||
Text: "Fetching metadata...",
|
||||
})
|
||||
fetchingMsgID := 0
|
||||
if fetchingMsg != nil {
|
||||
fetchingMsgID = fetchingMsg.ID
|
||||
}
|
||||
|
||||
info, err := h.YtDlp.GetMediaInfo(url)
|
||||
if err != nil {
|
||||
errMsg := err.Error()
|
||||
@@ -86,57 +96,68 @@ func (h *Handler) handleURLInput(ctx context.Context, chatID int64, text string,
|
||||
{{Text: "Cancel", CallbackData: "pending_cancel"}},
|
||||
},
|
||||
}
|
||||
h.Bot.SendMessage(ctx, &tgbot.SendMessageParams{
|
||||
ChatID: chatID, Text: "This content is DRM protected and no YouTube alternative was found automatically. Try searching by name:", ReplyMarkup: kb,
|
||||
})
|
||||
h.editText(ctx, chatID, fetchingMsgID, "This content is DRM protected and no YouTube alternative was found automatically. Try searching by name:", &kb)
|
||||
return
|
||||
}
|
||||
h.sendText(ctx, chatID, fmt.Sprintf("This content is DRM protected. Found on YouTube: %s", ytTitle))
|
||||
h.editText(ctx, chatID, fetchingMsgID, fmt.Sprintf("This content is DRM protected. Found on YouTube: %s", ytTitle), nil)
|
||||
info, err = h.YtDlp.GetMediaInfo(youtubeURL)
|
||||
if err != nil {
|
||||
h.sendText(ctx, chatID, fmt.Sprintf("YouTube fallback failed: %s", err.Error()))
|
||||
h.editText(ctx, chatID, fetchingMsgID, fmt.Sprintf("YouTube fallback failed: %s", err.Error()), nil)
|
||||
return
|
||||
}
|
||||
url = youtubeURL
|
||||
} else {
|
||||
switch {
|
||||
case strings.Contains(errMsg, "Unsupported URL") || strings.Contains(errMsg, "is not a valid URL"):
|
||||
h.sendText(ctx, chatID, "This URL is not supported.")
|
||||
h.editText(ctx, chatID, fetchingMsgID, "This URL is not supported.", nil)
|
||||
case strings.Contains(errMsg, "HTTP Error 403") || strings.Contains(errMsg, "cookies"):
|
||||
h.sendText(ctx, chatID, "This content requires authentication (cookies).")
|
||||
h.editText(ctx, chatID, fetchingMsgID, "This content requires authentication (cookies).", nil)
|
||||
case strings.Contains(errMsg, "live"):
|
||||
h.sendText(ctx, chatID, "Cannot download live streams.")
|
||||
h.editText(ctx, chatID, fetchingMsgID, "Cannot download live streams.", nil)
|
||||
default:
|
||||
h.sendText(ctx, chatID, fmt.Sprintf("Error: %s", errMsg))
|
||||
h.editText(ctx, chatID, fetchingMsgID, fmt.Sprintf("Error: %s", errMsg), nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if info.IsPlaylist {
|
||||
h.editText(ctx, chatID, fetchingMsgID, fmt.Sprintf("Playlist detected: %s (%d videos)", info.Title, info.PlaylistCount), nil)
|
||||
h.handlePlaylist(ctx, chatID, userID, url, info)
|
||||
return
|
||||
}
|
||||
|
||||
if len(info.Formats) == 0 {
|
||||
h.sendText(ctx, chatID, "No formats available for this URL.")
|
||||
h.editText(ctx, chatID, fetchingMsgID, "No formats available for this URL.", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Reject if user has already exhausted quota (limit of 0 = unlimited).
|
||||
q, err := h.Repo.GetOrCreateQuotas(userID)
|
||||
if err == nil {
|
||||
q, qErr := h.Repo.GetOrCreateQuotas(userID)
|
||||
if qErr == nil {
|
||||
q = h.resetQuotasIfNeeded(q)
|
||||
if (q.DailyLimitMB > 0 && q.DailyUsedMB >= q.DailyLimitMB) ||
|
||||
(q.WeeklyLimitMB > 0 && q.WeeklyUsedMB >= q.WeeklyLimitMB) ||
|
||||
(q.MonthlyLimitMB > 0 && q.MonthlyUsedMB >= q.MonthlyLimitMB) {
|
||||
h.sendText(ctx, chatID, fmt.Sprintf(
|
||||
h.editText(ctx, chatID, fetchingMsgID, fmt.Sprintf(
|
||||
"Quota exceeded. Daily: %d/%d MB, Weekly: %d/%d MB, Monthly: %d/%d MB.",
|
||||
q.DailyUsedMB, q.DailyLimitMB, q.WeeklyUsedMB, q.WeeklyLimitMB, q.MonthlyUsedMB, q.MonthlyLimitMB))
|
||||
q.DailyUsedMB, q.DailyLimitMB, q.WeeklyUsedMB, q.WeeklyLimitMB, q.MonthlyUsedMB, q.MonthlyLimitMB), nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Edit the fetching message to show the media title, then send a separate photo preview.
|
||||
previewText := fmt.Sprintf("Title: %s", info.Title)
|
||||
if info.Uploader != "" {
|
||||
previewText += fmt.Sprintf("\nChannel: %s", info.Uploader)
|
||||
}
|
||||
if info.Duration > 0 {
|
||||
previewText += fmt.Sprintf("\nDuration: %s", formatDuration(info.Duration))
|
||||
}
|
||||
h.editText(ctx, chatID, fetchingMsgID, previewText, nil)
|
||||
|
||||
h.sendMediaPreview(ctx, chatID, info)
|
||||
|
||||
ss := &stepState{
|
||||
URL: url,
|
||||
MediaInfo: info,
|
||||
@@ -144,8 +165,6 @@ func (h *Handler) handleURLInput(ctx context.Context, chatID int64, text string,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
h.sendMediaPreview(ctx, chatID, info)
|
||||
|
||||
ss.FormatIDs, _ = buildFormatList(info.Formats)
|
||||
h.setUserStepState(chatID, ss)
|
||||
labels := make([]string, len(ss.FormatIDs))
|
||||
@@ -675,6 +694,19 @@ func findFormatByID(formats []domain.Format, id string) *domain.Format {
|
||||
}
|
||||
|
||||
func formatLabelForDisplay(f domain.Format) string {
|
||||
if f.IsAudioOnly {
|
||||
label := f.Bitrate
|
||||
if label == "" {
|
||||
label = f.ID
|
||||
if f.Extension != "" {
|
||||
label += " (" + f.Extension + ")"
|
||||
}
|
||||
}
|
||||
if f.Filesize > 0 {
|
||||
label += fmt.Sprintf(" (%s)", formatBytes(f.Filesize))
|
||||
}
|
||||
return label
|
||||
}
|
||||
if f.Resolution != "" {
|
||||
label := f.Resolution
|
||||
if f.Filesize > 0 {
|
||||
@@ -689,17 +721,6 @@ func formatLabelForDisplay(f domain.Format) string {
|
||||
}
|
||||
return label
|
||||
}
|
||||
// Audio-only with no bitrate: show format ID + extension
|
||||
if f.IsAudioOnly {
|
||||
label := f.ID
|
||||
if f.Extension != "" {
|
||||
label += " (" + f.Extension + ")"
|
||||
}
|
||||
if f.Filesize > 0 {
|
||||
label += fmt.Sprintf(" (%s)", formatBytes(f.Filesize))
|
||||
}
|
||||
return label
|
||||
}
|
||||
return f.ID
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user