mirror of
https://github.com/iyear/tdl
synced 2025-01-07 03:16:41 +08:00
refactor(cmd): create cmd in functions
This commit is contained in:
parent
5e3a798f42
commit
dd71331ac5
44
cmd/archive.go
Normal file
44
cmd/archive.go
Normal file
@ -0,0 +1,44 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/archive"
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewBackup() *cobra.Command {
|
||||
var dst string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "backup",
|
||||
Short: "Backup your data",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if dst == "" {
|
||||
dst = fmt.Sprintf("tdl-backup-%s.zip", time.Now().Format("2006-01-02-15_04_05"))
|
||||
}
|
||||
|
||||
return archive.Backup(cmd.Context(), dst)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&dst, "dst", "d", "", "destination file path. Default: tdl-backup-<time>.zip")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewRecover() *cobra.Command {
|
||||
var file string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "recover",
|
||||
Short: "Recover your data",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return archive.Recover(cmd.Context(), file)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&file, "file", "f", "", "backup file path")
|
||||
|
||||
return cmd
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/archive"
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
)
|
||||
|
||||
var dst string
|
||||
|
||||
var CmdBackup = &cobra.Command{
|
||||
Use: "backup",
|
||||
Short: "Backup your data",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if dst == "" {
|
||||
dst = fmt.Sprintf("tdl-backup-%s.zip", time.Now().Format("2006-01-02-15_04_05"))
|
||||
}
|
||||
|
||||
return archive.Backup(cmd.Context(), dst)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CmdBackup.Flags().StringVarP(&dst, "dst", "d", "", "destination file path. Default: tdl-backup-<time>.zip")
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"github.com/iyear/tdl/app/archive"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var file string
|
||||
|
||||
var CmdRecover = &cobra.Command{
|
||||
Use: "recover",
|
||||
Short: "Recover your data",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return archive.Recover(cmd.Context(), file)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CmdRecover.Flags().StringVarP(&file, "file", "f", "", "backup file path")
|
||||
}
|
87
cmd/chat.go
Normal file
87
cmd/chat.go
Normal file
@ -0,0 +1,87 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/chat"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/iyear/tdl/pkg/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewChat() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "chat",
|
||||
Short: "A set of chat tools",
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewChatList(), NewChatExport())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewChatList() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List your chats",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return chat.List(logger.Named(cmd.Context(), "ls"))
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewChatExport() *cobra.Command {
|
||||
var opts chat.ExportOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "export messages from (protected) chat for download",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
switch opts.Type {
|
||||
case chat.ExportTypeTime, chat.ExportTypeID:
|
||||
// set default value
|
||||
switch len(opts.Input) {
|
||||
case 0:
|
||||
opts.Input = []int{0, math.MaxInt}
|
||||
case 1:
|
||||
opts.Input = append(opts.Input, math.MaxInt)
|
||||
}
|
||||
|
||||
if len(opts.Input) != 2 {
|
||||
return fmt.Errorf("input data should be 2 integers when export type is %s", opts.Type)
|
||||
}
|
||||
|
||||
// sort helper
|
||||
if opts.Input[0] > opts.Input[1] {
|
||||
opts.Input[0], opts.Input[1] = opts.Input[1], opts.Input[0]
|
||||
}
|
||||
case chat.ExportTypeLast:
|
||||
if len(opts.Input) != 1 {
|
||||
return fmt.Errorf("input data should be 1 integer when export type is %s", opts.Type)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown export type: %s", opts.Type)
|
||||
}
|
||||
|
||||
// set default filters
|
||||
for _, filter := range chat.Filters {
|
||||
if opts.Filter[filter] == "" {
|
||||
opts.Filter[filter] = ".*"
|
||||
}
|
||||
}
|
||||
|
||||
return chat.Export(logger.Named(cmd.Context(), "export"), &opts)
|
||||
},
|
||||
}
|
||||
|
||||
utils.Cmd.StringEnumFlag(cmd, &opts.Type, "type", "T", chat.ExportTypeTime, []string{chat.ExportTypeTime, chat.ExportTypeID, chat.ExportTypeLast}, "export type. time: timestamp range, id: message id range, last: last N messages")
|
||||
cmd.Flags().StringVarP(&opts.Chat, "chat", "c", "", "chat id or domain")
|
||||
cmd.Flags().IntSliceVarP(&opts.Input, "input", "i", []int{}, "input data, depends on export type")
|
||||
cmd.Flags().StringToStringVarP(&opts.Filter, "filter", "f", map[string]string{}, "only export media files that match the filter (regex). Default to all. Options: "+strings.Join(chat.Filters, ", "))
|
||||
cmd.Flags().StringVarP(&opts.Output, "output", "o", "tdl-export.json", "output JSON file path")
|
||||
|
||||
return cmd
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "chat",
|
||||
Short: "A set of chat tools",
|
||||
}
|
||||
|
||||
func init() {
|
||||
Cmd.AddCommand(cmdList, cmdExport)
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/chat"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/iyear/tdl/pkg/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var expOpts = &chat.ExportOptions{}
|
||||
|
||||
var cmdExport = &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "export messages from (protected) chat for download",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
switch expOpts.Type {
|
||||
case chat.ExportTypeTime, chat.ExportTypeID:
|
||||
// set default value
|
||||
switch len(expOpts.Input) {
|
||||
case 0:
|
||||
expOpts.Input = []int{0, math.MaxInt}
|
||||
case 1:
|
||||
expOpts.Input = append(expOpts.Input, math.MaxInt)
|
||||
}
|
||||
|
||||
if len(expOpts.Input) != 2 {
|
||||
return fmt.Errorf("input data should be 2 integers when export type is %s", expOpts.Type)
|
||||
}
|
||||
|
||||
// sort helper
|
||||
if expOpts.Input[0] > expOpts.Input[1] {
|
||||
expOpts.Input[0], expOpts.Input[1] = expOpts.Input[1], expOpts.Input[0]
|
||||
}
|
||||
case chat.ExportTypeLast:
|
||||
if len(expOpts.Input) != 1 {
|
||||
return fmt.Errorf("input data should be 1 integer when export type is %s", expOpts.Type)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown export type: %s", expOpts.Type)
|
||||
}
|
||||
|
||||
// set default filters
|
||||
for _, filter := range chat.Filters {
|
||||
if expOpts.Filter[filter] == "" {
|
||||
expOpts.Filter[filter] = ".*"
|
||||
}
|
||||
}
|
||||
|
||||
return chat.Export(logger.Named(cmd.Context(), "export"), expOpts)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
utils.Cmd.StringEnumFlag(cmdExport, &expOpts.Type, "type", "T", chat.ExportTypeTime, []string{chat.ExportTypeTime, chat.ExportTypeID, chat.ExportTypeLast}, "export type. time: timestamp range, id: message id range, last: last N messages")
|
||||
cmdExport.Flags().StringVarP(&expOpts.Chat, "chat", "c", "", "chat id or domain")
|
||||
cmdExport.Flags().IntSliceVarP(&expOpts.Input, "input", "i", []int{}, "input data, depends on export type")
|
||||
cmdExport.Flags().StringToStringVarP(&expOpts.Filter, "filter", "f", map[string]string{}, "only export media files that match the filter (regex). Default to all. Options: "+strings.Join(chat.Filters, ", "))
|
||||
cmdExport.Flags().StringVarP(&expOpts.Output, "output", "o", "tdl-export.json", "output JSON file path")
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"github.com/iyear/tdl/app/chat"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdList = &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List your chats",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return chat.List(logger.Named(cmd.Context(), "ls"))
|
||||
},
|
||||
}
|
67
cmd/dl.go
Normal file
67
cmd/dl.go
Normal file
@ -0,0 +1,67 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/dl"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewDownload() *cobra.Command {
|
||||
var opts dl.Options
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "download",
|
||||
Aliases: []string{"dl"},
|
||||
Short: "Download anything from Telegram (protected) chat",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// only one of include and exclude can be specified
|
||||
if len(opts.Include) > 0 && len(opts.Exclude) > 0 {
|
||||
return errors.New("only one of `include` and `exclude` can be specified")
|
||||
}
|
||||
|
||||
// only one of continue and restart can be specified
|
||||
if opts.Continue && opts.Restart {
|
||||
return errors.New("only one of `continue` and `restart` can be specified, or none of them")
|
||||
}
|
||||
|
||||
opts.Template = viper.GetString(consts.FlagDlTemplate)
|
||||
return dl.Run(logger.Named(cmd.Context(), "dl"), &opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringSliceVarP(&opts.URLs, consts.FlagDlUrl, "u", []string{}, "telegram message links")
|
||||
cmd.Flags().StringSliceVarP(&opts.Files, consts.FlagDlFile, "f", []string{}, "official client exported files")
|
||||
|
||||
// generate default replacer
|
||||
builder := strings.Builder{}
|
||||
chars := []string{`/`, `\`, `:`, `*`, `?`, `<`, `>`, `|`, ` `}
|
||||
for _, c := range chars {
|
||||
builder.WriteString(fmt.Sprintf("`%s` `_` ", c))
|
||||
}
|
||||
t := fmt.Sprintf(`{{ .DialogID }}_{{ .MessageID }}_{{ replace .FileName %s }}`, builder.String())
|
||||
cmd.Flags().String(consts.FlagDlTemplate, t, "download file name template")
|
||||
|
||||
cmd.Flags().StringSliceVarP(&opts.Include, consts.FlagDlInclude, "i", []string{}, "include the specified file extensions, and only judge by file name, not file MIME. Example: -i mp4,mp3")
|
||||
cmd.Flags().StringSliceVarP(&opts.Exclude, consts.FlagDlExclude, "e", []string{}, "exclude the specified file extensions, and only judge by file name, not file MIME. Example: -e png,jpg")
|
||||
|
||||
cmd.Flags().StringVarP(&opts.Dir, consts.FlagDlDir, "d", "downloads", "specify the download directory. If the directory does not exist, it will be created automatically")
|
||||
cmd.Flags().BoolVar(&opts.RewriteExt, consts.FlagDlRewriteExt, false, "rewrite file extension according to file header MIME")
|
||||
// do not match extension, because some files' extension is corrected by --rewrite-ext flag
|
||||
cmd.Flags().BoolVar(&opts.SkipSame, consts.FlagDlSkipSame, false, "skip files with the same name(without extension) and size")
|
||||
|
||||
cmd.Flags().Int64Var(&opts.PoolSize, consts.FlagDlPool, 3, "specify the size of the DC pool")
|
||||
cmd.Flags().BoolVar(&opts.Desc, consts.FlagDlDesc, false, "download files from the newest to the oldest ones (may affect resume download)")
|
||||
|
||||
// resume flags, if both false then ask user
|
||||
cmd.Flags().BoolVar(&opts.Continue, consts.FlagDlContinue, false, "continue the last download directly")
|
||||
cmd.Flags().BoolVar(&opts.Restart, consts.FlagDlRestart, false, "restart the last download directly")
|
||||
|
||||
_ = viper.BindPFlag(consts.FlagDlTemplate, cmd.Flags().Lookup(consts.FlagDlTemplate))
|
||||
|
||||
return cmd
|
||||
}
|
65
cmd/dl/dl.go
65
cmd/dl/dl.go
@ -1,65 +0,0 @@
|
||||
package dl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/iyear/tdl/app/dl"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var opts = &dl.Options{}
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "dl",
|
||||
Aliases: []string{"download"},
|
||||
Short: "Download anything from Telegram (protected) chat",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// only one of include and exclude can be specified
|
||||
if len(opts.Include) > 0 && len(opts.Exclude) > 0 {
|
||||
return errors.New("only one of `include` and `exclude` can be specified")
|
||||
}
|
||||
|
||||
// only one of continue and restart can be specified
|
||||
if opts.Continue && opts.Restart {
|
||||
return errors.New("only one of `continue` and `restart` can be specified, or none of them")
|
||||
}
|
||||
|
||||
opts.Template = viper.GetString(consts.FlagDlTemplate)
|
||||
return dl.Run(logger.Named(cmd.Context(), "dl"), opts)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Cmd.Flags().StringSliceVarP(&opts.URLs, consts.FlagDlUrl, "u", []string{}, "telegram message links")
|
||||
Cmd.Flags().StringSliceVarP(&opts.Files, consts.FlagDlFile, "f", []string{}, "official client exported files")
|
||||
|
||||
// generate default replacer
|
||||
builder := strings.Builder{}
|
||||
chars := []string{`/`, `\`, `:`, `*`, `?`, `<`, `>`, `|`, ` `}
|
||||
for _, c := range chars {
|
||||
builder.WriteString(fmt.Sprintf("`%s` `_` ", c))
|
||||
}
|
||||
t := fmt.Sprintf(`{{ .DialogID }}_{{ .MessageID }}_{{ replace .FileName %s }}`, builder.String())
|
||||
Cmd.Flags().String(consts.FlagDlTemplate, t, "download file name template")
|
||||
|
||||
Cmd.Flags().StringSliceVarP(&opts.Include, consts.FlagDlInclude, "i", []string{}, "include the specified file extensions, and only judge by file name, not file MIME. Example: -i mp4,mp3")
|
||||
Cmd.Flags().StringSliceVarP(&opts.Exclude, consts.FlagDlExclude, "e", []string{}, "exclude the specified file extensions, and only judge by file name, not file MIME. Example: -e png,jpg")
|
||||
|
||||
Cmd.Flags().StringVarP(&opts.Dir, consts.FlagDlDir, "d", "downloads", "specify the download directory. If the directory does not exist, it will be created automatically")
|
||||
Cmd.Flags().BoolVar(&opts.RewriteExt, consts.FlagDlRewriteExt, false, "rewrite file extension according to file header MIME")
|
||||
// do not match extension, because some files' extension is corrected by --rewrite-ext flag
|
||||
Cmd.Flags().BoolVar(&opts.SkipSame, consts.FlagDlSkipSame, false, "skip files with the same name(without extension) and size")
|
||||
|
||||
Cmd.Flags().Int64Var(&opts.PoolSize, consts.FlagDlPool, 3, "specify the size of the DC pool")
|
||||
Cmd.Flags().BoolVar(&opts.Desc, consts.FlagDlDesc, false, "download files from the newest to the oldest ones (may affect resume download)")
|
||||
|
||||
// resume flags, if both false then ask user
|
||||
Cmd.Flags().BoolVar(&opts.Continue, consts.FlagDlContinue, false, "continue the last download directly")
|
||||
Cmd.Flags().BoolVar(&opts.Restart, consts.FlagDlRestart, false, "restart the last download directly")
|
||||
|
||||
_ = viper.BindPFlag(consts.FlagDlTemplate, Cmd.Flags().Lookup(consts.FlagDlTemplate))
|
||||
}
|
36
cmd/login.go
Normal file
36
cmd/login.go
Normal file
@ -0,0 +1,36 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/app/login"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewLogin() *cobra.Command {
|
||||
var (
|
||||
code bool
|
||||
opts login.Options
|
||||
)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "login",
|
||||
Short: "Login to Telegram",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
color.Yellow("WARN: If data exists in the namespace, data will be overwritten")
|
||||
|
||||
if code {
|
||||
return login.Code(logger.Named(cmd.Context(), "login"))
|
||||
}
|
||||
|
||||
return login.Desktop(cmd.Context(), &opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.Desktop, consts.FlagLoginDesktop, "d", "", "official desktop client path, and automatically find possible paths if empty")
|
||||
cmd.Flags().StringVarP(&opts.Passcode, consts.FlagLoginPasscode, "p", "", "passcode for desktop client, keep empty if no passcode")
|
||||
cmd.Flags().BoolVar(&code, consts.FlagLoginCode, false, "login with code, instead of importing session from desktop client")
|
||||
|
||||
return cmd
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/app/login"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
code bool
|
||||
opts login.Options
|
||||
)
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "login",
|
||||
Short: "Login to Telegram",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
color.Yellow("WARN: If data exists in the namespace, data will be overwritten")
|
||||
|
||||
if code {
|
||||
return login.Code(logger.Named(cmd.Context(), "login"))
|
||||
}
|
||||
|
||||
return login.Desktop(cmd.Context(), &opts)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Cmd.Flags().StringVarP(&opts.Desktop, consts.FlagLoginDesktop, "d", "", "official desktop client path, and automatically find possible paths if empty")
|
||||
Cmd.Flags().StringVarP(&opts.Passcode, consts.FlagLoginPasscode, "p", "", "passcode for desktop client, keep empty if no passcode")
|
||||
Cmd.Flags().BoolVar(&code, consts.FlagLoginCode, false, "login with code, instead of importing session from desktop client")
|
||||
}
|
77
cmd/root.go
77
cmd/root.go
@ -1,14 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/cmd/archive"
|
||||
"github.com/iyear/tdl/cmd/chat"
|
||||
"github.com/iyear/tdl/cmd/dl"
|
||||
"github.com/iyear/tdl/cmd/login"
|
||||
"github.com/iyear/tdl/cmd/up"
|
||||
"github.com/iyear/tdl/cmd/version"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/iyear/tdl/pkg/utils"
|
||||
@ -16,39 +9,39 @@ import (
|
||||
"github.com/spf13/cobra/doc"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var cmd = &cobra.Command{
|
||||
Use: "tdl",
|
||||
Short: "Telegram Downloader, but more than a downloader",
|
||||
DisableAutoGenTag: true,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
// init logger
|
||||
debug, level := viper.GetBool(consts.FlagDebug), zap.InfoLevel
|
||||
if debug {
|
||||
level = zap.DebugLevel
|
||||
}
|
||||
cmd.SetContext(logger.With(cmd.Context(), logger.New(level)))
|
||||
func New() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tdl",
|
||||
Short: "Telegram Downloader, but more than a downloader",
|
||||
DisableAutoGenTag: true,
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
// init logger
|
||||
debug, level := viper.GetBool(consts.FlagDebug), zap.InfoLevel
|
||||
if debug {
|
||||
level = zap.DebugLevel
|
||||
}
|
||||
cmd.SetContext(logger.With(cmd.Context(), logger.New(level)))
|
||||
|
||||
ns := viper.GetString(consts.FlagNamespace)
|
||||
if ns != "" {
|
||||
color.Cyan("Namespace: %s", ns)
|
||||
logger.From(cmd.Context()).Info("Namespace",
|
||||
zap.String("namespace", ns))
|
||||
}
|
||||
},
|
||||
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return logger.From(cmd.Context()).Sync()
|
||||
},
|
||||
}
|
||||
ns := viper.GetString(consts.FlagNamespace)
|
||||
if ns != "" {
|
||||
color.Cyan("Namespace: %s", ns)
|
||||
logger.From(cmd.Context()).Info("Namespace",
|
||||
zap.String("namespace", ns))
|
||||
}
|
||||
},
|
||||
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return logger.From(cmd.Context()).Sync()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewVersion(), NewLogin(), NewDownload(),
|
||||
NewChat(), NewUpload(), NewBackup(), NewRecover())
|
||||
|
||||
func init() {
|
||||
cmd.AddCommand(version.Cmd, login.Cmd, dl.Cmd, chat.Cmd, up.Cmd, archive.CmdBackup, archive.CmdRecover)
|
||||
cmd.PersistentFlags().String(consts.FlagProxy, "", "proxy address, only socks5 is supported, format: protocol://username:password@host:port")
|
||||
cmd.PersistentFlags().StringP(consts.FlagNamespace, "n", "", "namespace for Telegram session")
|
||||
cmd.PersistentFlags().Bool(consts.FlagDebug, false, "enable debug mode")
|
||||
@ -66,18 +59,16 @@ func init() {
|
||||
viper.SetEnvPrefix("tdl")
|
||||
viper.AutomaticEnv()
|
||||
|
||||
generateCommandDocs(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func generateCommandDocs(cmd *cobra.Command) {
|
||||
docs := filepath.Join(consts.DocsPath, "command")
|
||||
if utils.FS.PathExists(docs) {
|
||||
if err := doc.GenMarkdownTree(cmd, docs); err != nil {
|
||||
color.Red("generate cmd docs failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Execute() error {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
return cmd.ExecuteContext(ctx)
|
||||
}
|
||||
|
27
cmd/up.go
Normal file
27
cmd/up.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/iyear/tdl/app/up"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewUpload() *cobra.Command {
|
||||
var opts up.Options
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "upload",
|
||||
Aliases: []string{"up"},
|
||||
Short: "Upload anything to Telegram",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return up.Run(logger.Named(cmd.Context(), "up"), &opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&opts.Chat, "chat", "c", "", "chat id or domain, and empty means 'Saved Messages'")
|
||||
cmd.Flags().StringSliceVarP(&opts.Paths, consts.FlagUpPath, "p", []string{}, "dirs or files")
|
||||
cmd.Flags().StringSliceVarP(&opts.Excludes, consts.FlagUpExcludes, "e", []string{}, "exclude the specified file extensions")
|
||||
|
||||
return cmd
|
||||
}
|
25
cmd/up/up.go
25
cmd/up/up.go
@ -1,25 +0,0 @@
|
||||
package up
|
||||
|
||||
import (
|
||||
"github.com/iyear/tdl/app/up"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/iyear/tdl/pkg/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var opts = &up.Options{}
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "up",
|
||||
Aliases: []string{"upload"},
|
||||
Short: "Upload anything to Telegram",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return up.Run(logger.Named(cmd.Context(), "up"), opts)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Cmd.Flags().StringVarP(&opts.Chat, "chat", "c", "", "chat id or domain, and empty means 'Saved Messages'")
|
||||
Cmd.Flags().StringSliceVarP(&opts.Paths, consts.FlagUpPath, "p", []string{}, "dirs or files")
|
||||
Cmd.Flags().StringSliceVarP(&opts.Excludes, consts.FlagUpExcludes, "e", []string{}, "exclude the specified file extensions")
|
||||
}
|
36
cmd/version.go
Normal file
36
cmd/version.go
Normal file
@ -0,0 +1,36 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/spf13/cobra"
|
||||
"runtime"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed version.tmpl
|
||||
var version string
|
||||
|
||||
func NewVersion() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Check the version info",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
buf := &bytes.Buffer{}
|
||||
if err := template.Must(template.New("version").Parse(version)).Execute(buf, map[string]interface{}{
|
||||
"Version": consts.Version,
|
||||
"Commit": consts.Commit,
|
||||
"Date": consts.CommitDate,
|
||||
"GoVersion": runtime.Version(),
|
||||
"GOOS": runtime.GOOS,
|
||||
"GOARCH": runtime.GOARCH,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
color.Blue(buf.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/pkg/consts"
|
||||
"github.com/spf13/cobra"
|
||||
"runtime"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed version.tmpl
|
||||
var version string
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Check the version info",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
buf := &bytes.Buffer{}
|
||||
_ = template.Must(template.New("version").Parse(version)).Execute(buf, map[string]interface{}{
|
||||
"Version": consts.Version,
|
||||
"Commit": consts.Commit,
|
||||
"Date": consts.CommitDate,
|
||||
"GoVersion": runtime.Version(),
|
||||
"GOOS": runtime.GOOS,
|
||||
"GOARCH": runtime.GOARCH,
|
||||
})
|
||||
color.Blue(buf.String())
|
||||
},
|
||||
}
|
@ -19,9 +19,9 @@ Telegram Downloader, but more than a downloader
|
||||
|
||||
* [tdl backup](tdl_backup.md) - Backup your data
|
||||
* [tdl chat](tdl_chat.md) - A set of chat tools
|
||||
* [tdl dl](tdl_dl.md) - Download anything from Telegram (protected) chat
|
||||
* [tdl download](tdl_download.md) - Download anything from Telegram (protected) chat
|
||||
* [tdl login](tdl_login.md) - Login to Telegram
|
||||
* [tdl recover](tdl_recover.md) - Recover your data
|
||||
* [tdl up](tdl_up.md) - Upload anything to Telegram
|
||||
* [tdl upload](tdl_upload.md) - Upload anything to Telegram
|
||||
* [tdl version](tdl_version.md) - Check the version info
|
||||
|
||||
|
@ -9,11 +9,12 @@ tdl chat export [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
-c, --chat string chat id or domain
|
||||
-h, --help help for export
|
||||
-i, --input ints input data, depends on export type
|
||||
-o, --output string output JSON file path (default "tdl-export.json")
|
||||
-T, --type string export type. time: timestamp range, id: message id range, last: last N messages: {time|id|last} (default "time")
|
||||
-c, --chat string chat id or domain
|
||||
-f, --filter stringToString only export media files that match the filter (regex). Default to all. Options: file, content (default [])
|
||||
-h, --help help for export
|
||||
-i, --input ints input data, depends on export type
|
||||
-o, --output string output JSON file path (default "tdl-export.json")
|
||||
-T, --type string export type. time: timestamp range, id: message id range, last: last N messages: {time|id|last} (default "time")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
42
docs/command/tdl_download.md
Normal file
42
docs/command/tdl_download.md
Normal file
@ -0,0 +1,42 @@
|
||||
## tdl download
|
||||
|
||||
Download anything from Telegram (protected) chat
|
||||
|
||||
```
|
||||
tdl download [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--continue continue the last download directly
|
||||
--desc download files from the newest to the oldest ones (may affect resume download)
|
||||
-d, --dir string specify the download directory. If the directory does not exist, it will be created automatically (default "downloads")
|
||||
-e, --exclude strings exclude the specified file extensions, and only judge by file name, not file MIME. Example: -e png,jpg
|
||||
-f, --file strings official client exported files
|
||||
-h, --help help for download
|
||||
-i, --include strings include the specified file extensions, and only judge by file name, not file MIME. Example: -i mp4,mp3
|
||||
--pool int specify the size of the DC pool (default 3)
|
||||
--restart restart the last download directly
|
||||
--rewrite-ext rewrite file extension according to file header MIME
|
||||
--skip-same skip files with the same name(without extension) and size
|
||||
--template string download file name template (default "{{ .DialogID }}_{{ .MessageID }}_{{ replace .FileName `/` `_` `\\` `_` `:` `_` `*` `_` `?` `_` `<` `_` `>` `_` `|` `_` ` ` `_` }}")
|
||||
-u, --url strings telegram message links
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--debug enable debug mode
|
||||
-l, --limit int max number of concurrent tasks (default 2)
|
||||
-n, --ns string namespace for Telegram session
|
||||
--ntp string ntp server host, if not set, use system time
|
||||
--proxy string proxy address, only socks5 is supported, format: protocol://username:password@host:port
|
||||
-s, --size int part size for transfer, max is 512*1024 (default 131072)
|
||||
-t, --threads int max threads for transfer one item (default 4)
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tdl](tdl.md) - Telegram Downloader, but more than a downloader
|
||||
|
33
docs/command/tdl_upload.md
Normal file
33
docs/command/tdl_upload.md
Normal file
@ -0,0 +1,33 @@
|
||||
## tdl upload
|
||||
|
||||
Upload anything to Telegram
|
||||
|
||||
```
|
||||
tdl upload [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-c, --chat string chat id or domain, and empty means 'Saved Messages'
|
||||
-e, --excludes strings exclude the specified file extensions
|
||||
-h, --help help for upload
|
||||
-p, --path strings dirs or files
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--debug enable debug mode
|
||||
-l, --limit int max number of concurrent tasks (default 2)
|
||||
-n, --ns string namespace for Telegram session
|
||||
--ntp string ntp server host, if not set, use system time
|
||||
--proxy string proxy address, only socks5 is supported, format: protocol://username:password@host:port
|
||||
-s, --size int part size for transfer, max is 512*1024 (default 131072)
|
||||
-t, --threads int max threads for transfer one item (default 4)
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tdl](tdl.md) - Telegram Downloader, but more than a downloader
|
||||
|
8
main.go
8
main.go
@ -1,12 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/fatih/color"
|
||||
"github.com/iyear/tdl/cmd"
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := cmd.Execute(); err != nil {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
if err := cmd.New().ExecuteContext(ctx); err != nil {
|
||||
color.Red("%v", err)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user