Compare commits
2 Commits
e65ade6c3c
...
e08ed77884
| Author | SHA1 | Date | |
|---|---|---|---|
|
e08ed77884
|
|||
|
30a99ac2fd
|
@@ -220,6 +220,9 @@ func (c *Client) StartDownload(job *domain.DownloadJob, downloadDir string) (<-c
|
|||||||
// Use explicit format string if set (video+audio combination)
|
// Use explicit format string if set (video+audio combination)
|
||||||
if job.FormatString != "" {
|
if job.FormatString != "" {
|
||||||
args = append(args, "-f", job.FormatString)
|
args = append(args, "-f", job.FormatString)
|
||||||
|
if job.Container != "" {
|
||||||
|
args = append(args, "--merge-output-format", job.Container)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Build format string for merge
|
// Build format string for merge
|
||||||
switch job.MediaType {
|
switch job.MediaType {
|
||||||
@@ -243,8 +246,8 @@ func (c *Client) StartDownload(job *domain.DownloadJob, downloadDir string) (<-c
|
|||||||
outputPath := filepath.Join(downloadDir, job.ID+"_%(id)s.%(ext)s")
|
outputPath := filepath.Join(downloadDir, job.ID+"_%(id)s.%(ext)s")
|
||||||
args = append(args, "--output", outputPath)
|
args = append(args, "--output", outputPath)
|
||||||
|
|
||||||
// Progress reporting
|
// Progress reporting (--newline for line-based, no --no-progress so we get actual output)
|
||||||
args = append(args, "--newline", "--no-progress")
|
args = append(args, "--newline")
|
||||||
|
|
||||||
// Language selection if specified
|
// Language selection if specified
|
||||||
if job.Language != "" {
|
if job.Language != "" {
|
||||||
@@ -337,6 +340,40 @@ func CancelDownload(job *domain.DownloadJob) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ytdlpSearchResult holds a single flat search result from yt-dlp.
|
||||||
|
type ytdlpSearchResult struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchYoutube searches YouTube via yt-dlp ytsearch and returns the first result URL and title.
|
||||||
|
func (c *Client) SearchYoutube(query string) (url, title string, err error) {
|
||||||
|
args := []string{
|
||||||
|
"--flat-playlist", "-J", "--no-download",
|
||||||
|
"--no-warnings",
|
||||||
|
"ytsearch1:" + query,
|
||||||
|
}
|
||||||
|
if c.cookiesFile != "" {
|
||||||
|
args = append(args, "--cookies", c.cookiesFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := c.run(args)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", fmt.Errorf("youtube search failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var info struct {
|
||||||
|
Entries []ytdlpSearchResult `json:"entries"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(out, &info); err != nil {
|
||||||
|
return "", "", fmt.Errorf("parse search result: %w", err)
|
||||||
|
}
|
||||||
|
if len(info.Entries) == 0 {
|
||||||
|
return "", "", fmt.Errorf("no results found")
|
||||||
|
}
|
||||||
|
return info.Entries[0].URL, info.Entries[0].Title, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) run(args []string) ([]byte, error) {
|
func (c *Client) run(args []string) ([]byte, error) {
|
||||||
cmd := exec.Command(c.binaryPath, args...)
|
cmd := exec.Command(c.binaryPath, args...)
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ type DownloadJob struct {
|
|||||||
// UserPreferences holds per-user default preferences.
|
// UserPreferences holds per-user default preferences.
|
||||||
type UserPreferences struct {
|
type UserPreferences struct {
|
||||||
DefaultMediaType MediaType
|
DefaultMediaType MediaType
|
||||||
DefaultQuality string
|
DefaultAudioFormat string
|
||||||
|
DefaultVideoFormat string
|
||||||
DefaultContainer string
|
DefaultContainer string
|
||||||
DefaultLanguage string
|
DefaultLanguage string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,22 @@ func (h *Handler) handleURLInput(ctx context.Context, chatID int64, text string,
|
|||||||
info, err := h.YtDlp.GetMediaInfo(url)
|
info, err := h.YtDlp.GetMediaInfo(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg := err.Error()
|
errMsg := err.Error()
|
||||||
|
|
||||||
|
// DRM content (Spotify, etc.): fall back to YouTube search
|
||||||
|
if strings.Contains(errMsg, "DRM") {
|
||||||
|
youtubeURL, ytTitle, searchErr := h.YtDlp.SearchYoutube(text)
|
||||||
|
if searchErr != nil {
|
||||||
|
h.sendText(ctx, chatID, fmt.Sprintf("This content is DRM protected and no YouTube alternative was found: %s", errMsg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.sendText(ctx, chatID, fmt.Sprintf("This content is DRM protected. Found on YouTube: %s", ytTitle))
|
||||||
|
info, err = h.YtDlp.GetMediaInfo(youtubeURL)
|
||||||
|
if err != nil {
|
||||||
|
h.sendText(ctx, chatID, fmt.Sprintf("YouTube fallback failed: %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = youtubeURL
|
||||||
|
} else {
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(errMsg, "Unsupported URL") || strings.Contains(errMsg, "is not a valid URL"):
|
case strings.Contains(errMsg, "Unsupported URL") || strings.Contains(errMsg, "is not a valid URL"):
|
||||||
h.sendText(ctx, chatID, "This URL is not supported.")
|
h.sendText(ctx, chatID, "This URL is not supported.")
|
||||||
@@ -77,6 +93,7 @@ func (h *Handler) handleURLInput(ctx context.Context, chatID int64, text string,
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if info.IsPlaylist {
|
if info.IsPlaylist {
|
||||||
h.handlePlaylist(ctx, chatID, userID, url, info)
|
h.handlePlaylist(ctx, chatID, userID, url, info)
|
||||||
@@ -571,6 +588,17 @@ func formatLabelForDisplay(f domain.Format) string {
|
|||||||
}
|
}
|
||||||
return label
|
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
|
return f.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,9 @@ func (h *Handler) HandleCallback(ctx context.Context, cb *models.CallbackQuery)
|
|||||||
h.answerCb(ctx, cb.ID)
|
h.answerCb(ctx, cb.ID)
|
||||||
case data == "history":
|
case data == "history":
|
||||||
h.historyCallback(ctx, chatID, msgID, cb.ID, userID)
|
h.historyCallback(ctx, chatID, msgID, cb.ID, userID)
|
||||||
|
case data == "deleteaccount":
|
||||||
|
h.deleteAccountPrompt(ctx, chatID, msgID, userID)
|
||||||
|
h.answerCb(ctx, cb.ID)
|
||||||
case data == "pending_cancel":
|
case data == "pending_cancel":
|
||||||
h.backToMenu(ctx, chatID, msgID, cb.ID, userID)
|
h.backToMenu(ctx, chatID, msgID, cb.ID, userID)
|
||||||
default:
|
default:
|
||||||
@@ -259,6 +262,12 @@ func (h *Handler) routePrefixedCallback(ctx context.Context, chatID int64, msgID
|
|||||||
h.handlePlaylistSelectAll(ctx, chatID, msgID, userID)
|
h.handlePlaylistSelectAll(ctx, chatID, msgID, userID)
|
||||||
case data == "pl_confirm":
|
case data == "pl_confirm":
|
||||||
h.handlePlaylistConfirm(ctx, chatID, msgID, userID)
|
h.handlePlaylistConfirm(ctx, chatID, msgID, userID)
|
||||||
|
case strings.HasPrefix(data, "delaccount_"):
|
||||||
|
if uid, err := strconv.ParseInt(data[11:], 10, 64); err == nil && uid > 0 {
|
||||||
|
h.deleteAccountConfirm(ctx, chatID, msgID, uid)
|
||||||
|
}
|
||||||
|
case data == "back_format":
|
||||||
|
h.handleSettingsSelection(ctx, chatID, msgID, userID, "format")
|
||||||
case data == "back_settings":
|
case data == "back_settings":
|
||||||
h.backToSettings(ctx, chatID, msgID, userID)
|
h.backToSettings(ctx, chatID, msgID, userID)
|
||||||
case strings.HasPrefix(data, "settings_set_"):
|
case strings.HasPrefix(data, "settings_set_"):
|
||||||
|
|||||||
@@ -143,14 +143,19 @@ func (h *Handler) handlePlaylistConfirm(ctx context.Context, chatID int64, msgID
|
|||||||
if prefErr != nil {
|
if prefErr != nil {
|
||||||
prefs = &domain.UserPreferences{
|
prefs = &domain.UserPreferences{
|
||||||
DefaultMediaType: domain.MediaTypeVideoAudio,
|
DefaultMediaType: domain.MediaTypeVideoAudio,
|
||||||
DefaultQuality: "best",
|
DefaultAudioFormat: "best",
|
||||||
|
DefaultVideoFormat: "best",
|
||||||
DefaultContainer: "mp4",
|
DefaultContainer: "mp4",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format := &domain.Format{ID: prefs.DefaultQuality}
|
formatID := prefs.DefaultVideoFormat
|
||||||
|
if prefs.DefaultMediaType == domain.MediaTypeAudio {
|
||||||
|
formatID = prefs.DefaultAudioFormat
|
||||||
|
}
|
||||||
|
format := &domain.Format{ID: formatID}
|
||||||
for _, f := range info.Formats {
|
for _, f := range info.Formats {
|
||||||
if f.ID == prefs.DefaultQuality {
|
if f.ID == formatID {
|
||||||
format = &f
|
format = &f
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (h *Handler) buildSettingsKeyboard(userID int64, prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
func (h *Handler) buildSettingsKeyboard(userID int64, prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||||
mediaTypeLabel := "Video+Audio"
|
audioFmt := prefs.DefaultAudioFormat
|
||||||
switch prefs.DefaultMediaType {
|
if audioFmt == "" {
|
||||||
case domain.MediaTypeAudio:
|
audioFmt = "best"
|
||||||
mediaTypeLabel = "Audio Only"
|
|
||||||
case domain.MediaTypeVideo:
|
|
||||||
mediaTypeLabel = "Video Only"
|
|
||||||
}
|
}
|
||||||
qualityLabel := prefs.DefaultQuality
|
videoFmt := prefs.DefaultVideoFormat
|
||||||
if qualityLabel == "" {
|
if videoFmt == "" {
|
||||||
qualityLabel = "best"
|
videoFmt = "best"
|
||||||
}
|
}
|
||||||
containerLabel := prefs.DefaultContainer
|
containerLabel := prefs.DefaultContainer
|
||||||
if containerLabel == "" {
|
if containerLabel == "" {
|
||||||
@@ -34,8 +31,7 @@ func (h *Handler) buildSettingsKeyboard(userID int64, prefs *domain.UserPreferen
|
|||||||
|
|
||||||
rows := [][]models.InlineKeyboardButton{
|
rows := [][]models.InlineKeyboardButton{
|
||||||
{
|
{
|
||||||
{Text: fmt.Sprintf("Type: %s", mediaTypeLabel), CallbackData: "settings_media_type"},
|
{Text: fmt.Sprintf("Format: %s/%s", audioFmt, videoFmt), CallbackData: "settings_format"},
|
||||||
{Text: fmt.Sprintf("Quality: %s", qualityLabel), CallbackData: "settings_quality"},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{Text: fmt.Sprintf("Container: %s", containerLabel), CallbackData: "settings_container"},
|
{Text: fmt.Sprintf("Container: %s", containerLabel), CallbackData: "settings_container"},
|
||||||
@@ -73,11 +69,14 @@ func (h *Handler) handleSettingsSelection(ctx context.Context, chatID int64, msg
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch setting {
|
switch setting {
|
||||||
case "media_type":
|
case "format":
|
||||||
text, kb := h.buildMediaTypePicker(prefs)
|
text, kb := h.buildFormatPicker(prefs)
|
||||||
h.editText(ctx, chatID, msgID, text, &kb)
|
h.editText(ctx, chatID, msgID, text, &kb)
|
||||||
case "quality":
|
case "format_audio":
|
||||||
text, kb := h.buildQualityPicker(prefs)
|
text, kb := h.buildAudioFormatPicker(prefs)
|
||||||
|
h.editText(ctx, chatID, msgID, text, &kb)
|
||||||
|
case "format_video":
|
||||||
|
text, kb := h.buildVideoFormatPicker(prefs)
|
||||||
h.editText(ctx, chatID, msgID, text, &kb)
|
h.editText(ctx, chatID, msgID, text, &kb)
|
||||||
case "container":
|
case "container":
|
||||||
text, kb := h.buildContainerPicker(prefs)
|
text, kb := h.buildContainerPicker(prefs)
|
||||||
@@ -88,53 +87,54 @@ func (h *Handler) handleSettingsSelection(ctx context.Context, chatID int64, msg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) buildMediaTypePicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
func (h *Handler) buildFormatPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||||
options := []struct {
|
rows := [][]models.InlineKeyboardButton{
|
||||||
label string
|
{{Text: "Audio", CallbackData: "settings_format_audio"}},
|
||||||
value domain.MediaType
|
{{Text: "Video", CallbackData: "settings_format_video"}},
|
||||||
data string
|
{{Text: "Back to Settings", CallbackData: "back_settings"}},
|
||||||
}{
|
|
||||||
{"Audio Only", domain.MediaTypeAudio, "settings_set_type_audio"},
|
|
||||||
{"Video Only", domain.MediaTypeVideo, "settings_set_type_video"},
|
|
||||||
{"Video+Audio", domain.MediaTypeVideoAudio, "settings_set_type_both"},
|
|
||||||
}
|
}
|
||||||
|
return "Choose format type to set default:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) buildAudioFormatPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||||
|
bitrates := []string{"best", "128k", "192k", "256k", "320k"}
|
||||||
rows := [][]models.InlineKeyboardButton{}
|
rows := [][]models.InlineKeyboardButton{}
|
||||||
for _, opt := range options {
|
for _, b := range bitrates {
|
||||||
label := opt.label
|
label := b
|
||||||
if opt.value == prefs.DefaultMediaType {
|
if b == prefs.DefaultAudioFormat {
|
||||||
label = "> " + label
|
label = "> " + label
|
||||||
}
|
}
|
||||||
rows = append(rows, []models.InlineKeyboardButton{
|
rows = append(rows, []models.InlineKeyboardButton{
|
||||||
{Text: label, CallbackData: opt.data},
|
{Text: label, CallbackData: "settings_set_audioformat_" + b},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
rows = append(rows, []models.InlineKeyboardButton{
|
rows = append(rows, []models.InlineKeyboardButton{
|
||||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
{Text: "Back", CallbackData: "back_format"},
|
||||||
})
|
})
|
||||||
return "Select default media type:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
return "Select default audio format:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) buildQualityPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
func (h *Handler) buildVideoFormatPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||||
qualities := []string{"best", "2160p", "1080p", "720p", "480p", "360p"}
|
resolutions := []string{"best", "2160p", "1440p", "1080p", "720p", "480p", "360p"}
|
||||||
rows := [][]models.InlineKeyboardButton{}
|
rows := [][]models.InlineKeyboardButton{}
|
||||||
row := []models.InlineKeyboardButton{}
|
row := []models.InlineKeyboardButton{}
|
||||||
for i, q := range qualities {
|
for i, r := range resolutions {
|
||||||
label := q
|
label := r
|
||||||
if q == prefs.DefaultQuality {
|
if r == prefs.DefaultVideoFormat {
|
||||||
label = "> " + label
|
label = "> " + label
|
||||||
}
|
}
|
||||||
row = append(row, models.InlineKeyboardButton{
|
row = append(row, models.InlineKeyboardButton{
|
||||||
Text: label, CallbackData: "settings_set_quality_" + q,
|
Text: label, CallbackData: "settings_set_videoformat_" + r,
|
||||||
})
|
})
|
||||||
if len(row) == 3 || i == len(qualities)-1 {
|
if len(row) == 3 || i == len(resolutions)-1 {
|
||||||
rows = append(rows, row)
|
rows = append(rows, row)
|
||||||
row = nil
|
row = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = append(rows, []models.InlineKeyboardButton{
|
rows = append(rows, []models.InlineKeyboardButton{
|
||||||
{Text: "Back to Settings", CallbackData: "back_settings"},
|
{Text: "Back", CallbackData: "back_format"},
|
||||||
})
|
})
|
||||||
return "Select default quality:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
return "Select default video format:", models.InlineKeyboardMarkup{InlineKeyboard: rows}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) buildContainerPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
func (h *Handler) buildContainerPicker(prefs *domain.UserPreferences) (string, models.InlineKeyboardMarkup) {
|
||||||
@@ -203,18 +203,11 @@ func (h *Handler) handleSettingsSet(ctx context.Context, chatID int64, msgID int
|
|||||||
|
|
||||||
changed := false
|
changed := false
|
||||||
switch action {
|
switch action {
|
||||||
case "type":
|
case "audioformat":
|
||||||
switch value {
|
prefs.DefaultAudioFormat = value
|
||||||
case "audio":
|
|
||||||
prefs.DefaultMediaType = domain.MediaTypeAudio
|
|
||||||
case "video":
|
|
||||||
prefs.DefaultMediaType = domain.MediaTypeVideo
|
|
||||||
case "both":
|
|
||||||
prefs.DefaultMediaType = domain.MediaTypeVideoAudio
|
|
||||||
}
|
|
||||||
changed = true
|
changed = true
|
||||||
case "quality":
|
case "videoformat":
|
||||||
prefs.DefaultQuality = value
|
prefs.DefaultVideoFormat = value
|
||||||
changed = true
|
changed = true
|
||||||
case "container":
|
case "container":
|
||||||
prefs.DefaultContainer = value
|
prefs.DefaultContainer = value
|
||||||
|
|||||||
7
internal/repo/migrations/002_preferences_format.sql
Normal file
7
internal/repo/migrations/002_preferences_format.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
-- +goose Up
|
||||||
|
ALTER TABLE user_preferences ADD COLUMN default_audio_format TEXT NOT NULL DEFAULT 'best';
|
||||||
|
ALTER TABLE user_preferences ADD COLUMN default_video_format TEXT NOT NULL DEFAULT 'best';
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
ALTER TABLE user_preferences DROP COLUMN default_audio_format;
|
||||||
|
ALTER TABLE user_preferences DROP COLUMN default_video_format;
|
||||||
@@ -75,12 +75,14 @@ func (s *Store) GetOrCreatePreferences(userID int64) (*domain.UserPreferences, e
|
|||||||
|
|
||||||
func (s *Store) getPreferences(userID int64) (*domain.UserPreferences, error) {
|
func (s *Store) getPreferences(userID int64) (*domain.UserPreferences, error) {
|
||||||
row := s.db.QueryRow(`
|
row := s.db.QueryRow(`
|
||||||
SELECT default_media_type, default_quality, default_container, default_language
|
SELECT default_media_type, default_audio_format, default_video_format,
|
||||||
|
default_container, default_language
|
||||||
FROM user_preferences WHERE user_id = ?
|
FROM user_preferences WHERE user_id = ?
|
||||||
`, userID)
|
`, userID)
|
||||||
var p domain.UserPreferences
|
var p domain.UserPreferences
|
||||||
var mediaType string
|
var mediaType string
|
||||||
if err := row.Scan(&mediaType, &p.DefaultQuality, &p.DefaultContainer, &p.DefaultLanguage); err != nil {
|
if err := row.Scan(&mediaType, &p.DefaultAudioFormat, &p.DefaultVideoFormat,
|
||||||
|
&p.DefaultContainer, &p.DefaultLanguage); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch mediaType {
|
switch mediaType {
|
||||||
@@ -107,11 +109,11 @@ func mediaTypeToString(mt domain.MediaType) string {
|
|||||||
|
|
||||||
func (s *Store) UpdatePreferences(userID int64, prefs *domain.UserPreferences) error {
|
func (s *Store) UpdatePreferences(userID int64, prefs *domain.UserPreferences) error {
|
||||||
_, err := s.db.Exec(`
|
_, err := s.db.Exec(`
|
||||||
UPDATE user_preferences SET default_media_type=?, default_quality=?,
|
UPDATE user_preferences SET default_media_type=?, default_audio_format=?,
|
||||||
default_container=?, default_language=?
|
default_video_format=?, default_container=?, default_language=?
|
||||||
WHERE user_id=?
|
WHERE user_id=?
|
||||||
`, mediaTypeToString(prefs.DefaultMediaType), prefs.DefaultQuality,
|
`, mediaTypeToString(prefs.DefaultMediaType), prefs.DefaultAudioFormat,
|
||||||
prefs.DefaultContainer, prefs.DefaultLanguage, userID)
|
prefs.DefaultVideoFormat, prefs.DefaultContainer, prefs.DefaultLanguage, userID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ func TestPreferences(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prefs.DefaultMediaType = domain.MediaTypeAudio
|
prefs.DefaultMediaType = domain.MediaTypeAudio
|
||||||
prefs.DefaultQuality = "best"
|
prefs.DefaultAudioFormat = "best"
|
||||||
|
prefs.DefaultVideoFormat = "1080p"
|
||||||
prefs.DefaultContainer = "mp3"
|
prefs.DefaultContainer = "mp3"
|
||||||
prefs.DefaultLanguage = "en"
|
prefs.DefaultLanguage = "en"
|
||||||
if err := s.UpdatePreferences(userID, prefs); err != nil {
|
if err := s.UpdatePreferences(userID, prefs); err != nil {
|
||||||
@@ -78,8 +79,11 @@ func TestPreferences(t *testing.T) {
|
|||||||
if got.DefaultMediaType != domain.MediaTypeAudio {
|
if got.DefaultMediaType != domain.MediaTypeAudio {
|
||||||
t.Errorf("media type = %v, want Audio", got.DefaultMediaType)
|
t.Errorf("media type = %v, want Audio", got.DefaultMediaType)
|
||||||
}
|
}
|
||||||
if got.DefaultQuality != "best" {
|
if got.DefaultAudioFormat != "best" {
|
||||||
t.Errorf("quality = %q, want best", got.DefaultQuality)
|
t.Errorf("audio format = %q, want best", got.DefaultAudioFormat)
|
||||||
|
}
|
||||||
|
if got.DefaultVideoFormat != "1080p" {
|
||||||
|
t.Errorf("video format = %q, want 1080p", got.DefaultVideoFormat)
|
||||||
}
|
}
|
||||||
if got.DefaultContainer != "mp3" {
|
if got.DefaultContainer != "mp3" {
|
||||||
t.Errorf("container = %q, want mp3", got.DefaultContainer)
|
t.Errorf("container = %q, want mp3", got.DefaultContainer)
|
||||||
|
|||||||
Reference in New Issue
Block a user