Skip to content

Commit 52b1ca4

Browse files
committed
improve qb 5.x support; improve mktorrent cmd
1 parent 2195297 commit 52b1ca4

File tree

6 files changed

+66
-29
lines changed

6 files changed

+66
-29
lines changed

client/qbittorrent/qbittorrent.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,34 @@ func (qbclient *Client) AddTorrent(torrentContent []byte, option *client.Torrent
174174
}
175175
torrentPartWriter.Write(torrentContent)
176176
}
177+
// qb 5.0+ API 似乎有变化(Github 文档页面尚未更新):
178+
// 1. 将 paused 更名为 stopped 。
179+
// 2. 增加了 stopCondition 字段 (Stop condition): None (default) | MetadataReceived | FilesChecked 。
180+
// 3. 将 root_folder (true | false | <unset>) 替换为 contentLayout 字段: Original | Subfolder | NoSubfolder 。
181+
// 为向下兼容,同时设置 4.X 和 5.X 的 API 字段。
177182
mp.WriteField("rename", name)
178183
mp.WriteField("root_folder", "true")
184+
mp.WriteField("contentLayout", "Subfolder")
179185
if option != nil {
180186
if option.Category != constants.NONE {
181187
mp.WriteField("category", option.Category)
182188
}
183189
mp.WriteField("tags", strings.Join(option.Tags, ",")) // qb 4.3.2+ new
184190
mp.WriteField("paused", fmt.Sprint(option.Pause))
191+
mp.WriteField("stopped", fmt.Sprint(option.Pause))
192+
if option.SkipChecking {
193+
if option.Pause {
194+
// @todo: 这里处理方式可能有问题。
195+
mp.WriteField("stopCondition", "FilesChecked")
196+
}
197+
mp.WriteField("skip_checking", "true")
198+
}
185199
mp.WriteField("upLimit", fmt.Sprint(option.UploadSpeedLimit))
186200
mp.WriteField("dlLimit", fmt.Sprint(option.DownloadSpeedLimit))
187201
if option.SavePath != "" {
188202
mp.WriteField("savepath", option.SavePath)
189203
mp.WriteField("autoTMM", "false")
190204
}
191-
if option.SkipChecking {
192-
mp.WriteField("skip_checking", "true")
193-
}
194205
if option.SequentialDownload {
195206
mp.WriteField("sequentialDownload", "true")
196207
}

cmd/add/add.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package add
22

33
import (
44
"fmt"
5+
"net/url"
56
"os"
67
"strings"
78

@@ -13,6 +14,8 @@ import (
1314
"github.com/sagan/ptool/cmd/common"
1415
"github.com/sagan/ptool/config"
1516
"github.com/sagan/ptool/constants"
17+
"github.com/sagan/ptool/site/public"
18+
"github.com/sagan/ptool/site/tpl"
1619
"github.com/sagan/ptool/util"
1720
"github.com/sagan/ptool/util/helper"
1821
"github.com/sagan/ptool/util/torrentutil"
@@ -142,6 +145,9 @@ func add(cmd *cobra.Command, args []string) error {
142145
sizeAdded := int64(0)
143146

144147
for i, torrent := range torrents {
148+
if i > 0 && slowMode {
149+
util.Sleep(3)
150+
}
145151
fmt.Printf("(%d/%d) ", i+1, len(torrents))
146152
option.Category = ""
147153
option.Tags = nil
@@ -151,6 +157,26 @@ func add(cmd *cobra.Command, args []string) error {
151157
option.Category = addCategory
152158
option.Tags = fixedTags
153159
option.SavePath = savePath
160+
isPublicTorrentUrl := false
161+
if util.IsPureTorrentUrl(torrent) {
162+
// All magnet: link should be public torrent.
163+
isPublicTorrentUrl = true
164+
} else if urlObj, err := url.Parse(torrent); err == nil {
165+
if sitename, _ := tpl.GuessSiteByDomain(urlObj.Host, ""); sitename != "" {
166+
option.Tags = append(option.Tags, client.GenerateTorrentTagFromSite(sitename))
167+
} else if publicSite := public.GetSiteByDomain(urlObj.Host); publicSite != nil {
168+
isPublicTorrentUrl = true
169+
option.Tags = append(option.Tags, client.GenerateTorrentTagFromSite(publicSite.Name))
170+
}
171+
}
172+
if isPublicTorrentUrl {
173+
option.Tags = append(option.Tags, config.PUBLIC_TAG)
174+
if ratioLimit == 0 {
175+
option.RatioLimit = config.Get().PublicTorrentRatioLimit
176+
}
177+
} else {
178+
option.Tags = append(option.Tags, config.PRIVATE_TAG)
179+
}
154180
if err = clientInstance.AddTorrent([]byte(torrent), option, nil); err != nil {
155181
fmt.Printf("✕ %s: failed to add to client: %v\n", torrent, err)
156182
errorCnt++
@@ -159,9 +185,6 @@ func add(cmd *cobra.Command, args []string) error {
159185
}
160186
continue
161187
}
162-
if i > 0 && slowMode {
163-
util.Sleep(3)
164-
}
165188
// Note: tinfo coule be nil here. It's a workaround as anacrolix/torrent failed to parse some torrents.
166189
content, tinfo, siteInstance, sitename, filename, id, isLocal, err :=
167190
helper.GetTorrentContent(torrent, defaultSite, forceLocal, false, stdinTorrentContents, true, nil)

cmd/maketorrent/maketorrent.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ var (
5151
private = false
5252
public = false
5353
force = false
54-
allowLongName = false
5554
allowFilenameRestrictedCharacters = false
55+
filenameLengthLimit = int64(0)
5656
pieceLengthStr = ""
5757
infoName = ""
5858
comment = ""
@@ -65,11 +65,6 @@ var (
6565
)
6666

6767
func init() {
68-
command.Flags().BoolVarP(&allowLongName, "allow-long-name", "", false,
69-
fmt.Sprintf("By default, ptool refuses to make torrent which contents contain any file which name's length "+
70-
"(UTF-8 bytes) is longer than (>) %d bytes. Those long name files could cause problems when downloading / "+
71-
"seeding the torrent. Set this flag to lift this restriction",
72-
constants.TORRENT_CONTENT_FILENAME_LENGTH_LIMIT))
7368
command.Flags().BoolVarP(&allowFilenameRestrictedCharacters, "allow-filename-restricted-characters", "", false,
7469
`Allow making torrent which content filenames contain invalid char in Windows, e.g. '?' char`)
7570
command.Flags().BoolVarP(&all, "all", "a", false, `Index all files of content folder to created torrent. `+
@@ -79,6 +74,12 @@ func init() {
7974
command.Flags().BoolVarP(&public, "public", "P", false, `Mark created torrent as public (non-private), `+
8075
`ptool will automatically add common pre-defined open trackers to it`)
8176
command.Flags().BoolVarP(&force, "force", "", false, "Force overwrite existing output .torrent file in disk")
77+
command.Flags().Int64VarP(&filenameLengthLimit, "filename-length-limit", "",
78+
constants.TORRENT_CONTENT_FILENAME_LENGTH_LIMIT,
79+
"By default, ptool refuses to make torrent which contents contain any file which name's length "+
80+
"(or any segment of it's relative path's length) is longer than (>) these bytes (UTF-8 string). "+
81+
"Too long name files could cause problems when downloading / "+
82+
"seeding the torrent. Set to -1 to lift the restriction")
8283
command.Flags().StringVarP(&pieceLengthStr, "piece-length", "", constants.TORRENT_DEFAULT_PIECE_LENGTH,
8384
`Set the piece length ("info"."piece length" field) of created .torrent`)
8485
command.Flags().StringVarP(&output, "output", "", "", `Set the output .torrent filename. `+
@@ -125,7 +126,7 @@ func maketorrent(cmd *cobra.Command, args []string) (err error) {
125126
CreatedBy: createdBy,
126127
CreationDate: creationDate,
127128
AllowRestrictedCharInFilename: allowFilenameRestrictedCharacters,
128-
AllowLongName: allowLongName,
129+
FilenameLengthLimit: filenameLengthLimit,
129130
}
130131
if len(optoins.Trackers) == 0 && !optoins.Public {
131132
log.Warnf(`Warning: the created .torrent file will NOT have any trackers. ` +

config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,12 +715,12 @@ func MatchSite(domain string, siteConfig *SiteConfigStruct) bool {
715715
}
716716
if siteConfig.Url != "" {
717717
siteDomain := util.GetUrlDomain(siteConfig.Url)
718-
if domain == siteDomain {
718+
if domain == siteDomain || strings.HasSuffix(domain, "."+siteDomain) {
719719
return true
720720
}
721721
}
722722
for _, siteDomain := range siteConfig.Domains {
723-
if siteDomain == domain {
723+
if siteDomain == domain || strings.HasSuffix(domain, "."+siteDomain) {
724724
return true
725725
}
726726
}

site/public/public.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var (
2828
TrackerDomains: []string{"sukebei.tracker.wf", "nyaa.tracker.wf"},
2929
TorrentUrlIdRegexp: regexp.MustCompile(`\bview/(?P<id>\d+)\b`),
3030
TorrentDownloadUrl: `{{origin}}/download/{{id}}.torrent`,
31-
TorrentDownloadInterval: 3000, // nyaa 限流。每几秒钟内只能下载1个种子
31+
TorrentDownloadInterval: 5000, // nyaa 限流。每几秒钟内只能下载1个种子
3232
},
3333
}
3434
// site name & domain (main or tracker) => site
@@ -47,12 +47,11 @@ func init() {
4747
}
4848
}
4949

50-
// Get a site by a website or tracker url or domain.
51-
func GetSiteByDomain(defaultSite string, domainOrUrls ...string) *PublicBittorrentSite {
52-
if SitesMap[defaultSite] != nil {
53-
return SitesMap[defaultSite]
54-
}
55-
for _, domain := range domainOrUrls {
50+
// Get a public site by a website or tracker url or domain.
51+
// defaultSite is a site name or domain.
52+
// If none of extraDomainOrUrls matches with a existing site, use defaultSite as fallback.
53+
func GetSiteByDomain(defaultSite string, extraDomainOrUrls ...string) *PublicBittorrentSite {
54+
for _, domain := range extraDomainOrUrls {
5655
if util.IsUrl(domain) {
5756
if urlObj, err := url.Parse(domain); err != nil {
5857
continue
@@ -64,5 +63,8 @@ func GetSiteByDomain(defaultSite string, domainOrUrls ...string) *PublicBittorre
6463
return SitesMap[domain]
6564
}
6665
}
66+
if SitesMap[defaultSite] != nil {
67+
return SitesMap[defaultSite]
68+
}
6769
return nil
6870
}

util/torrentutil/torrent.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,8 @@ type TorrentMakeOptions struct {
6868
MinSize int64
6969
Excludes []string
7070
AllowRestrictedCharInFilename bool
71-
// By default, limit filename length to at most 240 bytes (UTF-8).
72-
// It's the limit imposed by libtorrent on Linux.
73-
AllowLongName bool
71+
// If > 0, limit filename (not full path) length to at most these bytes (UTF-8 string).
72+
FilenameLengthLimit int64
7473
}
7574

7675
var (
@@ -720,7 +719,7 @@ func MakeTorrent(options *TorrentMakeOptions) (tinfo *TorrentMeta, err error) {
720719
}
721720
log.Infof("Creating torrent for %q", options.ContentPath)
722721
if err := infoBuildFromFilePath(info, options.ContentPath, options.Excludes,
723-
options.AllowRestrictedCharInFilename, options.AllowLongName); err != nil {
722+
options.AllowRestrictedCharInFilename, options.FilenameLengthLimit); err != nil {
724723
return nil, fmt.Errorf("failed to build info from content-path: %w", err)
725724
}
726725
if len(info.Files) == 0 {
@@ -780,7 +779,7 @@ func MakeTorrent(options *TorrentMakeOptions) (tinfo *TorrentMeta, err error) {
780779
// Adapted from metainfo.BuildFromFilePath.
781780
// excludes: gitignore style exclude-file-patterns.
782781
func infoBuildFromFilePath(info *metainfo.Info, root string, excludes []string,
783-
allowAnyCharInName bool, allowLongName bool) (err error) {
782+
allowAnyCharInName bool, filenameLengthLimit int64) (err error) {
784783
info.Name = func() string {
785784
b := filepath.Base(root)
786785
switch b {
@@ -807,7 +806,7 @@ func infoBuildFromFilePath(info *metainfo.Info, root string, excludes []string,
807806
}
808807
}
809808
}
810-
if !allowLongName && len(fi.Name()) > constants.TORRENT_CONTENT_FILENAME_LENGTH_LIMIT {
809+
if filenameLengthLimit > 0 && int64(len(fi.Name())) > filenameLengthLimit {
811810
return fmt.Errorf("filename %q is too long (%d bytes in UTF-8). Consider truncate it to %q", fi.Name(),
812811
len(fi.Name()), util.StringPrefixInBytes(fi.Name(), constants.TORRENT_CONTENT_FILENAME_LENGTH_LIMIT))
813812
}
@@ -824,7 +823,8 @@ func infoBuildFromFilePath(info *metainfo.Info, root string, excludes []string,
824823
return fmt.Errorf("error getting relative path: %s", err)
825824
}
826825
if !allowAnyCharInName && constants.FilepathInvalidCharsRegex.MatchString(relPath) {
827-
return fmt.Errorf("invalid content file path %q: contains restrictive chars", relPath)
826+
return fmt.Errorf("invalid content file path %q: contains restrictive chars. Consider rename it to %q",
827+
relPath, constants.FilenameRestrictedCharacterReplacer.Replace(relPath))
828828
}
829829
info.Files = append(info.Files, metainfo.FileInfo{
830830
Path: strings.Split(relPath, string(filepath.Separator)),

0 commit comments

Comments
 (0)