mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-09-05 07:36:36 +08:00
Implement parameter support for /ytdlp command
Co-authored-by: krau <71133316+krau@users.noreply.github.com>
This commit is contained in:
co-authored by
krau
parent
bd70160555
commit
9ee9972dec
@@ -100,7 +100,7 @@ func handleAddCallback(ctx *ext.Context, update *ext.Update) error {
|
|||||||
}
|
}
|
||||||
shortcut.CreateAndAddAria2TaskWithEdit(ctx, selectedStorage, dirPath, data.Aria2URIs, client, msgID, userID)
|
shortcut.CreateAndAddAria2TaskWithEdit(ctx, selectedStorage, dirPath, data.Aria2URIs, client, msgID, userID)
|
||||||
case tasktype.TaskTypeYtdlp:
|
case tasktype.TaskTypeYtdlp:
|
||||||
shortcut.CreateAndAddYtdlpTaskWithEdit(ctx, selectedStorage, dirPath, data.YtdlpURLs, msgID, userID)
|
shortcut.CreateAndAddYtdlpTaskWithEdit(ctx, selectedStorage, dirPath, data.YtdlpURLs, data.YtdlpFlags, msgID, userID)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unexcept task type: %s", data.TaskType)
|
return fmt.Errorf("unexcept task type: %s", data.TaskType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ func BuildAddSelectStorageKeyboard(stors []storage.Storage, adddata tcbdata.Add)
|
|||||||
DirectLinks: adddata.DirectLinks,
|
DirectLinks: adddata.DirectLinks,
|
||||||
|
|
||||||
Aria2URIs: adddata.Aria2URIs,
|
Aria2URIs: adddata.Aria2URIs,
|
||||||
YtdlpURLs: adddata.YtdlpURLs,
|
YtdlpURLs: adddata.YtdlpURLs,
|
||||||
|
YtdlpFlags: adddata.YtdlpFlags,
|
||||||
}
|
}
|
||||||
dataid := xid.New().String()
|
dataid := xid.New().String()
|
||||||
err := cache.Set(dataid, data)
|
err := cache.Set(dataid, data)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/storage"
|
"github.com/krau/SaveAny-Bot/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateAndAddYtdlpTaskWithEdit(ctx *ext.Context, stor storage.Storage, dirPath string, urls []string, msgID int, userID int64) error {
|
func CreateAndAddYtdlpTaskWithEdit(ctx *ext.Context, stor storage.Storage, dirPath string, urls []string, flags []string, msgID int, userID int64) error {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
injectCtx := tgutil.ExtWithContext(ctx.Context, ctx)
|
injectCtx := tgutil.ExtWithContext(ctx.Context, ctx)
|
||||||
|
|
||||||
@@ -29,13 +29,14 @@ func CreateAndAddYtdlpTaskWithEdit(ctx *ext.Context, stor storage.Storage, dirPa
|
|||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Infof("Creating yt-dlp task for %d URL(s)", len(urls))
|
logger.Infof("Creating yt-dlp task for %d URL(s) with %d flag(s)", len(urls), len(flags))
|
||||||
|
|
||||||
// Create yt-dlp task
|
// Create yt-dlp task
|
||||||
task := ytdlp.NewTask(
|
task := ytdlp.NewTask(
|
||||||
xid.New().String(),
|
xid.New().String(),
|
||||||
injectCtx,
|
injectCtx,
|
||||||
urls,
|
urls,
|
||||||
|
flags,
|
||||||
stor,
|
stor,
|
||||||
stor.JoinStoragePath(dirPath),
|
stor.JoinStoragePath(dirPath),
|
||||||
ytdlp.NewProgress(msgID, userID),
|
ytdlp.NewProgress(msgID, userID),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/celestix/gotgproto/dispatcher"
|
"github.com/celestix/gotgproto/dispatcher"
|
||||||
"github.com/celestix/gotgproto/ext"
|
"github.com/celestix/gotgproto/ext"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/duke-git/lancet/v2/slice"
|
|
||||||
|
|
||||||
"github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem"
|
"github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
@@ -25,29 +24,53 @@ func handleYtdlpCmd(ctx *ext.Context, update *ext.Update) error {
|
|||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
urls := args[1:]
|
// Separate URLs and flags from arguments
|
||||||
// Validate and clean URLs
|
var urls []string
|
||||||
for i, link := range urls {
|
var flags []string
|
||||||
urls[i] = strings.TrimSpace(link)
|
|
||||||
u, err := url.Parse(link)
|
for i := 1; i < len(args); i++ {
|
||||||
if err != nil || u.Scheme == "" || u.Host == "" {
|
arg := strings.TrimSpace(args[i])
|
||||||
logger.Warnf("Invalid URL: %s", link)
|
if arg == "" {
|
||||||
urls[i] = ""
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a flag (starts with - or --)
|
||||||
|
if strings.HasPrefix(arg, "-") {
|
||||||
|
flags = append(flags, arg)
|
||||||
|
// Check if the next argument is a value for this flag (not starting with -)
|
||||||
|
if i+1 < len(args) && !strings.HasPrefix(strings.TrimSpace(args[i+1]), "-") {
|
||||||
|
nextArg := strings.TrimSpace(args[i+1])
|
||||||
|
// Only treat as flag value if it's not a valid URL
|
||||||
|
u, err := url.Parse(nextArg)
|
||||||
|
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||||
|
flags = append(flags, nextArg)
|
||||||
|
i++ // Skip the next argument as it's been consumed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to parse as URL
|
||||||
|
u, err := url.Parse(arg)
|
||||||
|
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||||
|
logger.Warnf("Invalid URL: %s", arg)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
urls = append(urls, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
urls = slice.Compact(urls)
|
|
||||||
|
|
||||||
if len(urls) == 0 {
|
if len(urls) == 0 {
|
||||||
ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgYtdlpErrorNoValidUrls)), nil)
|
ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgYtdlpErrorNoValidUrls)), nil)
|
||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debugf("Preparing yt-dlp download for %d URL(s)", len(urls))
|
logger.Debugf("Preparing yt-dlp download for %d URL(s) with %d flag(s)", len(urls), len(flags))
|
||||||
|
|
||||||
// Build storage selection keyboard
|
// Build storage selection keyboard
|
||||||
markup, err := msgelem.BuildAddSelectStorageKeyboard(storage.GetUserStorages(ctx, update.GetUserChat().GetID()), tcbdata.Add{
|
markup, err := msgelem.BuildAddSelectStorageKeyboard(storage.GetUserStorages(ctx, update.GetUserChat().GetID()), tcbdata.Add{
|
||||||
TaskType: tasktype.TaskTypeYtdlp,
|
TaskType: tasktype.TaskTypeYtdlp,
|
||||||
YtdlpURLs: urls,
|
YtdlpURLs: urls,
|
||||||
|
YtdlpFlags: flags,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ bot:
|
|||||||
error_no_valid_links: "No valid links to download"
|
error_no_valid_links: "No valid links to download"
|
||||||
info_files_select_storage: "Total {{.Count}} files, please select storage"
|
info_files_select_storage: "Total {{.Count}} files, please select storage"
|
||||||
ytdlp:
|
ytdlp:
|
||||||
usage: "Usage: /ytdlp <URL1> <URL2> ..."
|
usage: "Usage: /ytdlp [OPTIONS] <URL1> [URL2] ...\nExamples:\n /ytdlp https://example.com/video\n /ytdlp --format best https://example.com/video\n /ytdlp --extract-audio --audio-format mp3 https://example.com/video"
|
||||||
error_no_valid_urls: "No valid URLs"
|
error_no_valid_urls: "No valid URLs"
|
||||||
info_urls_select_storage: "Found {{.Count}} links, please select storage"
|
info_urls_select_storage: "Found {{.Count}} links, please select storage"
|
||||||
info_downloading: "Downloading via yt-dlp..."
|
info_downloading: "Downloading via yt-dlp..."
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ bot:
|
|||||||
error_no_valid_links: "没有有效的链接可供下载"
|
error_no_valid_links: "没有有效的链接可供下载"
|
||||||
info_files_select_storage: "共 {{.Count}} 个文件, 请选择存储位置"
|
info_files_select_storage: "共 {{.Count}} 个文件, 请选择存储位置"
|
||||||
ytdlp:
|
ytdlp:
|
||||||
usage: "用法: /ytdlp <URL1> <URL2> ..."
|
usage: "用法: /ytdlp [选项] <URL1> [URL2] ...\n示例:\n /ytdlp https://example.com/video\n /ytdlp --format best https://example.com/video\n /ytdlp --extract-audio --audio-format mp3 https://example.com/video"
|
||||||
error_no_valid_urls: "没有有效的 URL"
|
error_no_valid_urls: "没有有效的 URL"
|
||||||
info_urls_select_storage: "共 {{.Count}} 个链接, 请选择存储位置"
|
info_urls_select_storage: "共 {{.Count}} 个链接, 请选择存储位置"
|
||||||
info_downloading: "正在通过 yt-dlp 下载..."
|
info_downloading: "正在通过 yt-dlp 下载..."
|
||||||
|
|||||||
@@ -80,22 +80,31 @@ func (t *Task) Execute(ctx context.Context) error {
|
|||||||
func (t *Task) downloadFiles(ctx context.Context, tempDir string) ([]string, error) {
|
func (t *Task) downloadFiles(ctx context.Context, tempDir string) ([]string, error) {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
// Configure yt-dlp command
|
// Configure yt-dlp command with default settings
|
||||||
cmd := ytdlp.New().
|
cmd := ytdlp.New().
|
||||||
FormatSort("res,ext:mp4:m4a").
|
Output(filepath.Join(tempDir, "%(title)s.%(ext)s"))
|
||||||
RecodeVideo("mp4").
|
|
||||||
Output(filepath.Join(tempDir, "%(title)s.%(ext)s")).
|
// If no custom flags are provided, use default behavior
|
||||||
RestrictFilenames()
|
if len(t.Flags) == 0 {
|
||||||
|
cmd = cmd.
|
||||||
|
FormatSort("res,ext:mp4:m4a").
|
||||||
|
RecodeVideo("mp4").
|
||||||
|
RestrictFilenames()
|
||||||
|
}
|
||||||
|
|
||||||
if t.Progress != nil {
|
if t.Progress != nil {
|
||||||
t.Progress.OnProgress(ctx, t, "Downloading...")
|
t.Progress.OnProgress(ctx, t, "Downloading...")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute download with URLs as arguments
|
// Execute download with URLs and custom flags
|
||||||
logger.Infof("Executing yt-dlp for %d URL(s)", len(t.URLs))
|
logger.Infof("Executing yt-dlp for %d URL(s) with %d custom flag(s)", len(t.URLs), len(t.Flags))
|
||||||
|
|
||||||
|
// Combine URLs and flags as arguments
|
||||||
|
// The Run method will pass flags as raw command-line arguments
|
||||||
|
args := append(t.Flags, t.URLs...)
|
||||||
|
|
||||||
// Run with context for cancellation support
|
// Run with context for cancellation support
|
||||||
result, err := cmd.Run(ctx, t.URLs...)
|
result, err := cmd.Run(ctx, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Check if context was canceled
|
// Check if context was canceled
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type Task struct {
|
|||||||
ID string
|
ID string
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
URLs []string
|
URLs []string
|
||||||
|
Flags []string
|
||||||
Storage storage.Storage
|
Storage storage.Storage
|
||||||
StorPath string
|
StorPath string
|
||||||
Progress ProgressTracker
|
Progress ProgressTracker
|
||||||
@@ -43,6 +44,7 @@ func NewTask(
|
|||||||
id string,
|
id string,
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
urls []string,
|
urls []string,
|
||||||
|
flags []string,
|
||||||
stor storage.Storage,
|
stor storage.Storage,
|
||||||
storPath string,
|
storPath string,
|
||||||
progressTracker ProgressTracker,
|
progressTracker ProgressTracker,
|
||||||
@@ -51,6 +53,7 @@ func NewTask(
|
|||||||
ID: id,
|
ID: id,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
URLs: urls,
|
URLs: urls,
|
||||||
|
Flags: flags,
|
||||||
Storage: stor,
|
Storage: stor,
|
||||||
StorPath: storPath,
|
StorPath: storPath,
|
||||||
Progress: progressTracker,
|
Progress: progressTracker,
|
||||||
|
|||||||
+2
-1
@@ -48,7 +48,8 @@ type Add struct {
|
|||||||
// aria2
|
// aria2
|
||||||
Aria2URIs []string
|
Aria2URIs []string
|
||||||
// ytdlp
|
// ytdlp
|
||||||
YtdlpURLs []string
|
YtdlpURLs []string
|
||||||
|
YtdlpFlags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetDefaultStorage struct {
|
type SetDefaultStorage struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user