Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var AccountCmd = &cli.Command{ Name: "accounts", Aliases: []string{"acc"}, Usage: "list configured accounts", Action: func(ctx context.Context, c *cli.Command) error { cfg := config.FromContext(ctx) accounts := cfg.AllAccounts() if len(accounts) == 0 { fmt.Println("no accounts configured") return nil } sessionDir, err := config.SessionsDir() if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Fprintln(w, "ALIAS\tUSERNAME\tSESSION") for _, acc := range accounts { state := "-" if session.Exists(sessionDir, acc.Username) { state = "cached" } fmt.Fprintf(w, "%s\t%s\t%s\n", acc.Alias, acc.Username, state) } return w.Flush() }, }
View Source
var DownloadCmd = &cli.Command{ Name: "download", Aliases: []string{"d"}, Usage: "download a file, or the direct child files of a folder, by id or remote path", ArgsUsage: "<file_id|path> [file_id|path...]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "output", Aliases: []string{"o"}, Usage: "output path", }, &cli.IntFlag{ Name: "parallel", Aliases: []string{"p"}, Usage: "parallel connections for ranged download (default 4, 1 disables)", }, &cli.StringFlag{ Name: "chunk-min", Aliases: []string{"c"}, Usage: "minimum file size to use parallel mode, e.g. 32MB (default 32MB)", }, &cli.BoolFlag{ Name: "force", Aliases: []string{"f"}, Usage: "redownload even if local file size matches", }, }, Action: func(ctx context.Context, c *cli.Command) error { if c.Args().Len() < 1 { return errors.New("download requires at least one <file_id|path> argument") } opts := pikpak.DownloadOptions{ Parallel: c.Int("parallel"), Force: c.Bool("force"), } if cm := c.String("chunk-min"); cm != "" { n, err := parseSize(cm) if err != nil { return fmt.Errorf("--chunk-min: %w", err) } opts.ChunkMin = n } targets := c.Args().Slice() output := c.String("output") clients := make(map[string]*pikpak.Client) getClient := func(alias string) (*pikpak.Client, config.Account, error) { if cl, ok := clients[alias]; ok { return cl, config.Account{Alias: alias}, nil } cfg := config.FromContext(ctx) acc, err := cfg.FindAccount(alias) if err != nil { return nil, config.Account{}, err } sessionDir, err := config.SessionsDir() if err != nil { return nil, config.Account{}, err } cl := pikpak.New(acc, sessionDir) if err := cl.Login(ctx); err != nil { return nil, config.Account{}, err } clients[alias] = cl return cl, acc, nil } if c.String("account") != "" { client, acc, err := clientFromContext(ctx, c) if err != nil { return err } fmt.Printf("account: %s\n", acc.Alias) var errs []error for i, target := range targets { if len(targets) > 1 { fmt.Printf("\n[%d/%d] downloading: %s\n", i+1, len(targets), target) } if err := client.Download(ctx, target, output, opts); err != nil { fmt.Fprintf(c.ErrWriter, "error downloading %s: %v\n", target, err) errs = append(errs, fmt.Errorf("%s: %w", target, err)) } } if len(errs) > 0 { return fmt.Errorf("failed to download %d of %d files", len(errs), len(targets)) } return nil } cfg := config.FromContext(ctx) allAccounts := cfg.AllAccounts() if len(allAccounts) == 0 { return fmt.Errorf("no accounts configured") } var errs []error defaultAcc := allAccounts[0] for i, target := range targets { if len(targets) > 1 { fmt.Printf("\n[%d/%d] downloading: %s\n", i+1, len(targets), target) } var client *pikpak.Client var acc config.Account if pikpak.IsFileID(target) { cl, a, err := resolveFileIDAccount(ctx, c, target) if err != nil { fmt.Fprintf(c.ErrWriter, "error resolving account for %s: %v\n", target, err) errs = append(errs, fmt.Errorf("%s: %w", target, err)) continue } client = cl acc = a } else { cl, a, err := getClient(defaultAcc.Alias) if err != nil { fmt.Fprintf(c.ErrWriter, "error logging in %s: %v\n", defaultAcc.Alias, err) errs = append(errs, fmt.Errorf("%s: %w", target, err)) continue } client = cl acc = a } fmt.Printf("account: %s\n", acc.Alias) if err := client.Download(ctx, target, output, opts); err != nil { fmt.Fprintf(c.ErrWriter, "error downloading %s: %v\n", target, err) errs = append(errs, fmt.Errorf("%s: %w", target, err)) } } if len(errs) > 0 { return fmt.Errorf("failed to download %d of %d files", len(errs), len(targets)) } return nil }, }
View Source
var FileCmd = &cli.Command{ Name: "file", Aliases: []string{"f"}, Usage: "file manage", Commands: []*cli.Command{ listCmd, DownloadCmd, deleteCmd, clearCmd, }, }
View Source
var QuotaCmd = &cli.Command{ Name: "quota", Aliases: []string{"q"}, Usage: "query quota for account", Action: func(ctx context.Context, c *cli.Command) error { cfg := config.FromContext(ctx) sessionDir, err := config.SessionsDir() if err != nil { return err } var targets []config.Account if alias := c.String("account"); alias != "" { acc, err := cfg.FindAccount(alias) if err != nil { return err } targets = []config.Account{acc} } else { targets = cfg.AllAccounts() } if len(targets) == 0 { fmt.Println("no accounts configured") return nil } state, err := pool.LoadState() if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Fprintln(w, "ACCOUNT\tCLOUD_DOWNLOAD(REMAINING/TOTAL)\tSTORAGE") for _, acc := range targets { client := pikpak.New(acc, sessionDir) if err := client.Login(ctx); err != nil { fmt.Fprintf(w, "%s\tERROR\t%s\n", acc.Alias, err) continue } q, err := client.Quota(ctx) if err != nil { fmt.Fprintf(w, "%s\tERROR\t%s\n", acc.Alias, err) continue } as := state.GetOrCreate(acc.Alias) as.QuotaCache = &pool.QuotaSnapshot{ CloudDownloadLimit: q.Quotas.CloudDownload.Limit, CloudDownloadUsage: q.Quotas.CloudDownload.Usage, UpdatedAt: time.Now(), } fmt.Fprintf(w, "%s\t%d/%d\t%s/%s\n", acc.Alias, q.Quotas.CloudDownload.Limit-q.Quotas.CloudDownload.Usage, q.Quotas.CloudDownload.Limit, pikpak.ByteSize(q.Quota.Usage), pikpak.ByteSize(q.Quota.Limit), ) } if err := w.Flush(); err != nil { return err } return pool.SaveState(state) }, }
View Source
var ServeCmd = &cli.Command{ Name: "serve", Usage: "run an HTTP server that accepts offline task submissions", Flags: []cli.Flag{ &cli.StringFlag{ Name: "addr", Aliases: []string{"l"}, Value: "127.0.0.1:8080", Usage: "listen address (use 0.0.0.0:8080 for LAN access; no auth)", }, &cli.StringFlag{ Name: "folder", Aliases: []string{"f"}, Usage: "destination folder: path (e.g. /movies/2024) or folder-id", }, }, Action: serveAction, }
ServeCmd runs a long-lived HTTP server that accepts offline task submissions from the browser extension or any HTTP client.
POST /api/tasks body: {"hash": "<40-hex>"} | {"magnet": "magnet:?..."} | {"url": "https://..."}
200/201 queued, 409 duplicate (already submitted), 400 bad input, 500 server error
GET /healthz liveness probe
View Source
var TaskCmd = &cli.Command{ Name: "task", Aliases: []string{"t"}, Usage: "manage offline tasks", Commands: []*cli.Command{ taskAddCmd, taskListCmd, taskDeleteCmd, taskClearCmd, }, }
View Source
var TrashCmd = &cli.Command{ Name: "trash", Usage: "manage trash", Commands: []*cli.Command{ emptyCmd, }, }
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.