diff --git a/.env.example b/.env.example index 803add0..41fd511 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,7 @@ DEFAULT_ENABLE_SILENT=false DEFAULT_ENABLE_NSFW=false DEFAULT_MEDIA_ALBUM_LIMIT=10 DEFAULT_LANGUAGE=en +DEFAULT_HIGH_QUALITY_VIDEOS=false # other REPO_URL=https://github.com/govdbot/govd @@ -46,4 +47,4 @@ AUTOMATIC_LANGUAGE_DETECTION=true # dev PGWEB_PORT=8081 PGWEB_USER=admin -PGWEB_PASSWORD=password \ No newline at end of file +PGWEB_PASSWORD=password diff --git a/internal/bot/handlers/settings/main.go b/internal/bot/handlers/settings/main.go index 5ef665b..3133a8e 100644 --- a/internal/bot/handlers/settings/main.go +++ b/internal/bot/handlers/settings/main.go @@ -153,6 +153,21 @@ var botSettings = []BotSettings{ return res.DeleteLinks }, }, + { + ID: "high_quality_videos", + ButtonKey: localization.HighQualityVideosButton.ID, + DescriptionKey: localization.HighQualityVideosSettingsMessage.ID, + + Type: SettingsTypeToggle, + Scope: SettingsScopeGroup, + + ToggleFunc: func(ctx context.Context, chatID int64) error { + return database.Q().ToggleChatHighQualityVideos(ctx, chatID) + }, + GetCurrentValueFunc: func(res *database.GetOrCreateChatRow) any { + return res.HighQualityVideos + }, + }, { ID: "disabled_extractors", ButtonKey: localization.ExtractorsButton.ID, diff --git a/internal/config/env.go b/internal/config/env.go index 097d4ba..058e696 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -1,6 +1,7 @@ package config import ( + "os" "time" "github.com/PaulSonOfLars/gotgbot/v2" @@ -40,6 +41,11 @@ func loadFromEnv() { parseEnvInt32Range("DEFAULT_MEDIA_ALBUM_LIMIT", &Env.DefaultMediaAlbumLimit, 1, 20, false) parseEnvLanguage("DEFAULT_LANGUAGE", &Env.DefaultLanguage, false) parseEnvBool("DEFAULT_DELETE_LINKS", &Env.DefaultDeleteLinks, false) + if _, ok := os.LookupEnv("DEFAULT_HIGH_QUALITY_VIDEOS"); ok { + parseEnvBool("DEFAULT_HIGH_QUALITY_VIDEOS", &Env.DefaultHighQualityVideos, false) + } else { + parseEnvBool("DEFAULT_ENABLE_HIGH_QUALITY_VIDEOS", &Env.DefaultHighQualityVideos, false) // backward compatibility + } parseEnvBool("AUTOMATIC_LANGUAGE_DETECTION", &Env.AutomaticLanguageDetection, false) } @@ -64,12 +70,13 @@ func GetDefaultConfig() *EnvConfig { CaptionsHeader: "source - @{{username}}", CaptionsDescription: "
{{text}}", - DefaultCaptions: true, - DefaultSilent: false, - DefaultNSFW: false, - DefaultMediaAlbumLimit: 10, - DefaultLanguage: "en", - DefaultDeleteLinks: false, + DefaultCaptions: true, + DefaultSilent: false, + DefaultNSFW: false, + DefaultMediaAlbumLimit: 10, + DefaultLanguage: "en", + DefaultDeleteLinks: false, + DefaultHighQualityVideos: false, AutomaticLanguageDetection: true, } diff --git a/internal/config/models.go b/internal/config/models.go index 74e50a3..4de67ee 100644 --- a/internal/config/models.go +++ b/internal/config/models.go @@ -35,12 +35,13 @@ type EnvConfig struct { CaptionsHeader string CaptionsDescription string - DefaultCaptions bool - DefaultSilent bool - DefaultNSFW bool - DefaultMediaAlbumLimit int32 - DefaultLanguage string - DefaultDeleteLinks bool + DefaultCaptions bool + DefaultSilent bool + DefaultNSFW bool + DefaultMediaAlbumLimit int32 + DefaultLanguage string + DefaultDeleteLinks bool + DefaultHighQualityVideos bool AutomaticLanguageDetection bool } diff --git a/internal/core/high_quality.go b/internal/core/high_quality.go new file mode 100644 index 0000000..1b0044d --- /dev/null +++ b/internal/core/high_quality.go @@ -0,0 +1,32 @@ +package core + +import ( + "github.com/govdbot/govd/internal/database" + "github.com/govdbot/govd/internal/models" +) + +func shouldUseHighQualityVideoUpload(chat *database.GetOrCreateChatRow, extractorID string) bool { + if chat == nil || !chat.HighQualityVideos { + return false + } + switch extractorID { + case "instagram", "tiktok": + return true + default: + return false + } +} + +func shouldUploadAsHighQualityVideo( + chat *database.GetOrCreateChatRow, + media *models.Media, + format *models.MediaFormat, +) bool { + if media == nil || format == nil { + return false + } + if format.Type != database.MediaTypeVideo { + return false + } + return shouldUseHighQualityVideoUpload(chat, media.ExtractorID) +} diff --git a/internal/core/send.go b/internal/core/send.go index 4d6252b..65dab8e 100644 --- a/internal/core/send.go +++ b/internal/core/send.go @@ -67,9 +67,15 @@ func SendFormats( if i == 0 { caption = options.Caption } + highQualityVideo := shouldUploadAsHighQualityVideo( + extractorCtx.Chat, + media, + f.Format, + ) inputMedia, err := f.Format.GetInputMedia( f.FilePath, f.ThumbnailFilePath, caption, options.IsSpoiler, + highQualityVideo, ) if err != nil { return nil, fmt.Errorf("failed to get input media: %w", err) @@ -149,9 +155,15 @@ func SendInlineFormats( fileID := util.GetMessageFileID(&msg) format.Format.FileID = fileID + highQualityVideo := shouldUploadAsHighQualityVideo( + extractorCtx.Chat, + media, + format.Format, + ) inputMedia, err := format.Format.GetInputMedia( format.FilePath, format.ThumbnailFilePath, options.Caption, options.IsSpoiler, + highQualityVideo, ) if err != nil { return err diff --git a/internal/database/chat.sql_gen.go b/internal/database/chat.sql_gen.go index 12a43df..4ef5ce5 100644 --- a/internal/database/chat.sql_gen.go +++ b/internal/database/chat.sql_gen.go @@ -17,14 +17,14 @@ WITH upsert_chat AS ( RETURNING chat_id, type, created_at, updated_at ), upsert_settings AS ( - INSERT INTO settings (chat_id, language, captions, silent, nsfw, media_album_limit, delete_links) - VALUES ($1, $3, $4, $5, $6, $7, $8) + INSERT INTO settings (chat_id, language, captions, silent, nsfw, media_album_limit, delete_links, high_quality_videos) + VALUES ($1, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (chat_id) DO UPDATE SET language = CASE WHEN settings.language = 'XX' THEN EXCLUDED.language ELSE settings.language END - RETURNING chat_id, nsfw, media_album_limit, captions, silent, language, created_at, updated_at, disabled_extractors, delete_links + RETURNING chat_id, nsfw, media_album_limit, captions, silent, language, created_at, updated_at, disabled_extractors, delete_links, high_quality_videos ), final_chat AS ( SELECT chat_id, type, created_at, updated_at FROM upsert_chat @@ -32,7 +32,7 @@ final_chat AS ( SELECT chat_id, type, created_at, updated_at FROM chat WHERE chat_id = $1 AND NOT EXISTS (SELECT 1 FROM upsert_chat) ), final_settings AS ( - SELECT chat_id, nsfw, media_album_limit, captions, silent, language, created_at, updated_at, disabled_extractors, delete_links FROM upsert_settings + SELECT chat_id, nsfw, media_album_limit, captions, silent, language, created_at, updated_at, disabled_extractors, delete_links, high_quality_videos FROM upsert_settings ) SELECT c.chat_id, @@ -43,20 +43,22 @@ SELECT s.silent, s.language, s.disabled_extractors, - s.delete_links + s.delete_links, + s.high_quality_videos FROM final_chat c JOIN final_settings s ON s.chat_id = c.chat_id ` type GetOrCreateChatParams struct { - ChatID int64 - Type ChatType - Language string - Captions bool - Silent bool - Nsfw bool - MediaAlbumLimit int32 - DeleteLinks bool + ChatID int64 + Type ChatType + Language string + Captions bool + Silent bool + Nsfw bool + MediaAlbumLimit int32 + DeleteLinks bool + HighQualityVideos bool } type GetOrCreateChatRow struct { @@ -69,6 +71,7 @@ type GetOrCreateChatRow struct { Language string DisabledExtractors []string DeleteLinks bool + HighQualityVideos bool } func (q *Queries) GetOrCreateChat(ctx context.Context, arg GetOrCreateChatParams) (GetOrCreateChatRow, error) { @@ -81,6 +84,7 @@ func (q *Queries) GetOrCreateChat(ctx context.Context, arg GetOrCreateChatParams arg.Nsfw, arg.MediaAlbumLimit, arg.DeleteLinks, + arg.HighQualityVideos, ) var i GetOrCreateChatRow err := row.Scan( @@ -93,6 +97,7 @@ func (q *Queries) GetOrCreateChat(ctx context.Context, arg GetOrCreateChatParams &i.Language, &i.DisabledExtractors, &i.DeleteLinks, + &i.HighQualityVideos, ) return i, err } diff --git a/internal/database/migrations/00011_add_high_quality_videos_setting.sql b/internal/database/migrations/00011_add_high_quality_videos_setting.sql new file mode 100644 index 0000000..4c82cda --- /dev/null +++ b/internal/database/migrations/00011_add_high_quality_videos_setting.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE settings ADD COLUMN high_quality_videos BOOLEAN NOT NULL DEFAULT FALSE; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE settings DROP COLUMN IF EXISTS high_quality_videos; +-- +goose StatementEnd diff --git a/internal/database/models_gen.go b/internal/database/models_gen.go index 7cdd522..4126dde 100644 --- a/internal/database/models_gen.go +++ b/internal/database/models_gen.go @@ -209,4 +209,5 @@ type Settings struct { UpdatedAt pgtype.Timestamptz DisabledExtractors []string DeleteLinks bool + HighQualityVideos bool } diff --git a/internal/database/queries/chat.sql b/internal/database/queries/chat.sql index 56a0f39..515922a 100644 --- a/internal/database/queries/chat.sql +++ b/internal/database/queries/chat.sql @@ -6,8 +6,8 @@ WITH upsert_chat AS ( RETURNING * ), upsert_settings AS ( - INSERT INTO settings (chat_id, language, captions, silent, nsfw, media_album_limit, delete_links) - VALUES (@chat_id, @language, @captions, @silent, @nsfw, @media_album_limit, @delete_links) + INSERT INTO settings (chat_id, language, captions, silent, nsfw, media_album_limit, delete_links, high_quality_videos) + VALUES (@chat_id, @language, @captions, @silent, @nsfw, @media_album_limit, @delete_links, @high_quality_videos) ON CONFLICT (chat_id) DO UPDATE SET language = CASE WHEN settings.language = 'XX' THEN EXCLUDED.language @@ -32,6 +32,7 @@ SELECT s.silent, s.language, s.disabled_extractors, - s.delete_links + s.delete_links, + s.high_quality_videos FROM final_chat c -JOIN final_settings s ON s.chat_id = c.chat_id; \ No newline at end of file +JOIN final_settings s ON s.chat_id = c.chat_id; diff --git a/internal/database/queries/settings.sql b/internal/database/queries/settings.sql index 533cd9c..9267970 100644 --- a/internal/database/queries/settings.sql +++ b/internal/database/queries/settings.sql @@ -37,4 +37,9 @@ WHERE chat_id = @chat_id; -- name: ToggleChatDeleteLinks :exec UPDATE settings SET delete_links = NOT delete_links, updated_at = CURRENT_TIMESTAMP -WHERE chat_id = @chat_id; \ No newline at end of file +WHERE chat_id = @chat_id; + +-- name: ToggleChatHighQualityVideos :exec +UPDATE settings +SET high_quality_videos = NOT high_quality_videos, updated_at = CURRENT_TIMESTAMP +WHERE chat_id = @chat_id; diff --git a/internal/database/settings.sql_gen.go b/internal/database/settings.sql_gen.go index 7354fdc..e724f12 100644 --- a/internal/database/settings.sql_gen.go +++ b/internal/database/settings.sql_gen.go @@ -96,6 +96,17 @@ func (q *Queries) ToggleChatDeleteLinks(ctx context.Context, chatID int64) error return err } +const toggleChatHighQualityVideos = `-- name: ToggleChatHighQualityVideos :exec +UPDATE settings +SET high_quality_videos = NOT high_quality_videos, updated_at = CURRENT_TIMESTAMP +WHERE chat_id = $1 +` + +func (q *Queries) ToggleChatHighQualityVideos(ctx context.Context, chatID int64) error { + _, err := q.db.Exec(ctx, toggleChatHighQualityVideos, chatID) + return err +} + const toggleChatNsfw = `-- name: ToggleChatNsfw :exec UPDATE settings SET nsfw = NOT nsfw, updated_at = CURRENT_TIMESTAMP diff --git a/internal/localization/locales/active.en.toml b/internal/localization/locales/active.en.toml index 7085cf5..5b572ef 100644 --- a/internal/localization/locales/active.en.toml +++ b/internal/localization/locales/active.en.toml @@ -6,6 +6,8 @@ CaptionsSettingsMessage = "when enabled, adds original description to downloaded CloseButton = "close" DeleteProcessedButton = "links" DeleteProcessedSettingsMessage = "when enabled, deletes the user's original message after successfully processing the link" +HighQualityVideosButton = "high-quality video" +HighQualityVideosSettingsMessage = "when enabled, TikTok and Instagram videos are sent as media with high-quality preference" DisabledButton = "disabled" DisabledExtractorsSettingsMessage = "select which extractors should be disabled. links from disabled extractors will be ignored by the bot" EnabledButton = "enabled" diff --git a/internal/localization/locales/active.it.toml b/internal/localization/locales/active.it.toml index 3f6ed95..7c832d1 100644 --- a/internal/localization/locales/active.it.toml +++ b/internal/localization/locales/active.it.toml @@ -106,6 +106,14 @@ other = "formato immagine non supportato" hash = "sha1-90f775f104687d04dc6c10f0a6b929d9f9060a9b" other = "estrattori" +[HighQualityVideosButton] +hash = "sha1-7f4f46c8e472f4e4354de65fa9ac9f4f95dfac28" +other = "video di alta qualità " + +[HighQualityVideosSettingsMessage] +hash = "sha1-59d702bff8d797a87e5e1f98db8c3f3d34e9f71d" +other = "quando abilitato, i video TikTok e Instagram vengono inviati come media con preferenza di alta qualità " + [GroupSettingsMessage] hash = "sha1-dbc9223b568195bdd978bf68acd969c46f28b6b3" other = "utilizza i pulsanti sottostanti per modificare le impostazioni del bot per questo gruppo" diff --git a/internal/localization/messages.go b/internal/localization/messages.go index 7bd159f..7ec6290 100644 --- a/internal/localization/messages.go +++ b/internal/localization/messages.go @@ -115,6 +115,14 @@ var ( ID: "DeleteProcessedSettingsMessage", Other: "when enabled, deletes the user's original message after successfully processing the link", } + HighQualityVideosButton = &i18n.Message{ + ID: "HighQualityVideosButton", + Other: "high-quality video", + } + HighQualityVideosSettingsMessage = &i18n.Message{ + ID: "HighQualityVideosSettingsMessage", + Other: "when enabled, TikTok and Instagram videos are sent as media with high-quality preference", + } SupportedExtractorsMessage = &i18n.Message{ ID: "SupportedExtractorsMessage", Other: "list of supported extractors by the bot", diff --git a/internal/models/media.go b/internal/models/media.go index 6382264..c9c5f5a 100644 --- a/internal/models/media.go +++ b/internal/models/media.go @@ -275,9 +275,10 @@ func (format *MediaFormat) GetInputMedia( thumbnailFilePath string, messageCaption string, spoiler bool, + highQualityVideo bool, ) (gotgbot.InputMedia, error) { if format.FileID != "" { - return format.GetInputMediaWithFileID(messageCaption, spoiler) + return format.GetInputMediaWithFileID(messageCaption, spoiler, highQualityVideo) } _, inputMediaType := format.GetInfo() @@ -306,6 +307,10 @@ func (format *MediaFormat) GetInputMedia( switch inputMediaType { case FileTypeVideo: + supportsStreaming := true + if highQualityVideo { + supportsStreaming = false + } return &gotgbot.InputMediaVideo{ Media: fileInputMedia, Thumbnail: thumbnailFileInputMedia, @@ -313,7 +318,7 @@ func (format *MediaFormat) GetInputMedia( Height: int64(format.Height), Duration: int64(format.Duration), Caption: messageCaption, - SupportsStreaming: true, + SupportsStreaming: supportsStreaming, ParseMode: gotgbot.ParseModeHTML, HasSpoiler: spoiler, }, nil @@ -349,17 +354,23 @@ func (format *MediaFormat) GetInputMedia( func (format *MediaFormat) GetInputMediaWithFileID( messageCaption string, spoiler bool, + highQualityVideo bool, ) (gotgbot.InputMedia, error) { _, inputMediaType := format.GetInfo() fileInputMedia := gotgbot.InputFileByID(format.FileID) switch inputMediaType { case FileTypeVideo: + supportsStreaming := true + if highQualityVideo { + supportsStreaming = false + } return &gotgbot.InputMediaVideo{ - Media: fileInputMedia, - Caption: messageCaption, - ParseMode: gotgbot.ParseModeHTML, - HasSpoiler: spoiler, + Media: fileInputMedia, + Caption: messageCaption, + ParseMode: gotgbot.ParseModeHTML, + HasSpoiler: spoiler, + SupportsStreaming: supportsStreaming, }, nil case FileTypeAudio: return &gotgbot.InputMediaAudio{ diff --git a/internal/util/bot.go b/internal/util/bot.go index f73855e..32d5e74 100644 --- a/internal/util/bot.go +++ b/internal/util/bot.go @@ -78,14 +78,15 @@ func ChatFromContext(ctx *ext.Context) (*database.GetOrCreateChatRow, error) { res, err := database.Q().GetOrCreateChat( context.Background(), database.GetOrCreateChatParams{ - ChatID: id, - Type: chatType, - Language: language, - Captions: config.Env.DefaultCaptions, - Silent: config.Env.DefaultSilent, - Nsfw: config.Env.DefaultNSFW, - MediaAlbumLimit: config.Env.DefaultMediaAlbumLimit, - DeleteLinks: config.Env.DefaultDeleteLinks, + ChatID: id, + Type: chatType, + Language: language, + Captions: config.Env.DefaultCaptions, + Silent: config.Env.DefaultSilent, + Nsfw: config.Env.DefaultNSFW, + MediaAlbumLimit: config.Env.DefaultMediaAlbumLimit, + DeleteLinks: config.Env.DefaultDeleteLinks, + HighQualityVideos: config.Env.DefaultHighQualityVideos, }, ) if err != nil {