feat: add thumbnail preview, audio-only detection, /download command, tests, and bugfixes
- Add thumbnail preview with metadata (title, uploader, duration) before download - Auto-detect audio-only sites (Spotify, SoundCloud, etc.) and skip type selection - Add /download command for feature parity with UI button - Fix yt-dlp defer bug: StatusFailed was overwritten to StatusCompleted - Fix handleURLInput using editText with msgID=0 (now uses sendWithKB) - Fix filename detection: use job ID prefix for reliable file finding - Fix double answerCb between handleBackStep and handleDownloadPrompt - Fix runDownload unused msgID parameter - Fix context for download goroutine (use context.Background) - Remove unused startWebhook h parameter - Remove dead buildToggleKeyboard function - Add formatBytes, formatDuration, formatLabelForDisplay tests - Add IsAudioOnlyContent, MediaType.String tests - Add repo integration tests (users, preferences, quotas, history, delete) - Add cmd/bot tests (parseAllowedUsers, env helpers) - Add edge case tests for progress parser - Add zero/negative safety guard in formatDuration - Add .gitea, TODO.md, opencode.json to gitignore
This commit is contained in:
@@ -128,40 +128,6 @@ func progressKeyboard(pct float64, speed, eta string) models.InlineKeyboardMarku
|
||||
}
|
||||
}
|
||||
|
||||
// buildToggleKeyboard creates an on/off picker for a boolean setting.
|
||||
// Matches worktimeBot's pattern with "> " prefix for the current selection.
|
||||
func buildToggleKeyboard(userID int64, setting, label string, st *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||
current := false
|
||||
switch setting {
|
||||
case "quality":
|
||||
current = st.DefaultQuality == "best"
|
||||
case "container":
|
||||
current = st.DefaultContainer == "mp4"
|
||||
}
|
||||
options := []struct {
|
||||
label string
|
||||
data string
|
||||
value bool
|
||||
}{
|
||||
{"Enabled", setting + "_enable", true},
|
||||
{"Disabled", setting + "_disable", false},
|
||||
}
|
||||
rows := [][]models.InlineKeyboardButton{}
|
||||
for _, opt := range options {
|
||||
l := opt.label
|
||||
if opt.value == current {
|
||||
l = "> " + l
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: l, CallbackData: opt.data},
|
||||
})
|
||||
}
|
||||
rows = append(rows, []models.InlineKeyboardButton{
|
||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
||||
})
|
||||
return label + ":", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||
}
|
||||
|
||||
// playlistNavKeyboard builds the paginated navigation for playlist selection.
|
||||
func playlistNavKeyboard(state *domain.PlaylistState, selectedCount int) models.InlineKeyboardMarkup {
|
||||
totalPages := (len(state.Entries) + state.PerPage - 1) / state.PerPage
|
||||
|
||||
Reference in New Issue
Block a user