Skip to content

Commit

Permalink
add firefox121 impersonate
Browse files Browse the repository at this point in the history
  • Loading branch information
sagan committed Jan 3, 2024
1 parent 3e16163 commit f9c388c
Show file tree
Hide file tree
Showing 19 changed files with 81 additions and 37 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ cookie = "cookie_here" # 浏览器 F12 获取的网站 cookie

配置文件里可以使用 `[[clients]]``[[sites]]` 区块添加任意多个 BT 客户端和站点。

`[[site]]` 区块有两种配置方式:
`[[sites]]` 区块有两种配置方式:

```toml
# 方式 1(推荐):直接使用站点 ID 或 alias 作为类型(type)。无需手动输入站点 url。
Expand Down Expand Up @@ -234,7 +234,7 @@ ptool clientctl local global_upload_speed_limit=10M
命令格式均为:

```
ptool <command> [client] [flags] [<infoHash>...]
ptool <command> <client> [flags] [<infoHash>...]
```

`<infoHash>` 参数为指定的 BT 客户端里需要操作的种子的 infoHash 列表。也可以使用以下特殊值参数操作多个种子(delete 命令根据除 infoHash 以外的条件删除种子时需要二次确认):
Expand Down Expand Up @@ -416,9 +416,9 @@ ptool batchdl <site> --action add --add-client local
- --max-torrents int : 最多下载多少个种子。默认 -1 (无限制,一直运行除非手动 Ctrl + C 停止)。
- --sort string : 站点种子排序方式:size|time|name|seeders|leechers|snatched|none (default size)
- --order string : 排序顺序:asc|desc。默认 asc。
- --min-torrent-size string : 种子大小的最小值限制 (eg. "100MiB", "1GiB")。默认为 "-1"(无限制)。
- --min-torrent-size string : 种子大小的最小值限制 (e.g.: "100MiB", "1GiB")。默认为 "-1"(无限制)。
- --max-torrent-size string : 种子大小的最大值限制。默认为 "-1"(无限制)。
- --max-total-size string : 下载种子内容总体积最大值限制 (eg. "512GiB", "1TiB")。默认为 "-1"(无限制)。
- --max-total-size string : 下载种子内容总体积最大值限制 (e.g.: "512GiB", "1TiB")。默认为 "-1"(无限制)。
- --free : 只下载免费种子。
- --no-hr : 跳过存在 HR 的种子。
- --no-paid : 跳过"付费"的种子。(部分站点存在"付费"种子,第一次下载或汇报时扣除积分)
Expand Down Expand Up @@ -518,7 +518,7 @@ ptool cookiecloud get <site>...
### 查看内置支持站点信息 (sites)

```
# 显示所有内置支持的站点列表。ptool.toml 配置文件里将 [[site]] 配置块的 type 设为站点的 Type 或 Alias。
# 显示所有内置支持的站点列表。ptool.toml 配置文件里将 [[sites]] 配置块的 type 设为站点的 Type 或 Alias。
ptool sites
# 显示对应站点在本程序内部使用的详细配置参数。参数为站点的 Type 或 Alias。
Expand Down Expand Up @@ -587,7 +587,7 @@ ptool search acg clannad

### 命令别名 (Alias) 功能

ptool.toml 里可以使用 `[[alias]]` 区块自定义命令别名,例如:
ptool.toml 里可以使用 `[[aliases]]` 区块自定义命令别名,例如:

```
[[aliases]]
Expand Down
2 changes: 1 addition & 1 deletion cmd/addlocal/addlocal.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var command = &cobra.Command{
Annotations: map[string]string{"cobra-prompt-dynamic-suggestions": "addlocal"},
Short: "Add local torrents to client.",
Long: `Add local torrents to client.
It's possible to use "*" wildcard in filename to match multiple torrents. eg. "*.torrent".
It's possible to use "*" wildcard in filename to match multiple torrents. e.g.: "*.torrent".
`,
Args: cobra.MatchAll(cobra.MinimumNArgs(2), cobra.OnlyValidArgs),
RunE: addlocal,
Expand Down
4 changes: 2 additions & 2 deletions cmd/batchdl/batchdl.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func init() {
command.Flags().StringVarP(&maxTotalSizeStr, "max-total-size", "", "-1", "Will at most download torrents with total contents size of this value. -1 == no limit")
command.Flags().Int64VarP(&minSeeders, "min-seeders", "", 1, "Skip torrent with seeders less than (<) this value. -1 == no limit")
command.Flags().Int64VarP(&maxSeeders, "max-seeders", "", -1, "Skip torrent with seeders more than (>) this value. -1 == no limit")
command.Flags().StringVarP(&freeTimeAtLeastStr, "free-time", "", "", "Used with --free. Set the allowed minimal remaining torrent free time. eg. 12h, 1d")
command.Flags().StringVarP(&freeTimeAtLeastStr, "free-time", "", "", "Used with --free. Set the allowed minimal remaining torrent free time. e.g.: 12h, 1d")
command.Flags().StringVarP(&filter, "filter", "", "", "If set, skip torrent which name does NOT contains this string")
command.Flags().StringArrayVarP(&includes, "includes", "", nil, "A comma-separated string list. If set, ONLY torrent which name contains any one in the list will be downloaded. Can be provided multiple times, in which case every list MUST be matched")
command.Flags().StringVarP(&excludes, "excludes", "", "", "A comma-separated string list that torrent which name contains any one in the list will be skipped")
Expand All @@ -99,7 +99,7 @@ func init() {
command.Flags().StringVarP(&addTags, "add-tags", "", "", "Used with '--action add'. Set the tags when adding torrent to client (comma-separated)")
command.Flags().StringVarP(&savePath, "add-save-path", "", "", "Set contents save path of added torrents")
command.Flags().StringVarP(&exportFile, "export-file", "", "", "Used with '--action export|printid'. Set the output file. (If not set, will use stdout)")
command.Flags().StringVarP(&baseUrl, "base-url", "", "", `Manually set the base url of torrents list page. eg. "special.php", "adult.php", "torrents.php?cat=100"`)
command.Flags().StringVarP(&baseUrl, "base-url", "", "", `Manually set the base url of torrents list page. e.g.: "special.php", "adult.php", "torrents.php?cat=100"`)
cmd.AddEnumFlagP(command, &action, "action", "", ActionEnumFlag)
cmd.AddEnumFlagP(command, &sortFlag, "sort", "", common.SiteTorrentSortFlag)
cmd.AddEnumFlagP(command, &orderFlag, "order", "", common.OrderFlag)
Expand Down
4 changes: 2 additions & 2 deletions cmd/clientctl/clientctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ var (
{"global_upload_speed", 1, true, false, "Current global upload speed (/s)"},
{"free_disk_space", 2, true, false, "Current free disk space of default save path"},
{"save_path", 0, false, false, "Default save path"},
{"qb_*", 0, false, false, "The qBittorrent specific preferences. For full list see https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-application-preferences . eg. qb_start_paused_enabled"},
{"tr_*", 0, false, false, "The transmission specific preferences. For full list see https://github.com/transmission/transmission/blob/3.00/extras/rpc-spec.txt#L482 . Convert argument name to snake_case. eg. tr_config_dir"},
{"qb_*", 0, false, false, "The qBittorrent specific preferences. For full list see https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-application-preferences . e.g.: qb_start_paused_enabled"},
{"tr_*", 0, false, false, "The transmission specific preferences. For full list see https://github.com/transmission/transmission/blob/3.00/extras/rpc-spec.txt#L482 . Convert argument name to snake_case. e.g.: tr_config_dir"},
}
showRaw = false
showValuesOnly = false
Expand Down
2 changes: 1 addition & 1 deletion cmd/common/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func YesNoAutoFlag(desc string) *cmd.EnumFlag {
// pure flag: bool or counter flag. It does not have a value.
// all single-letter name (shorthand) flags are always considered as pure (for now),
// so they are not included in the list.
// none-pure flag: a flag which has a value. eg. "--name=value", "--name value".
// none-pure flag: a flag which has a value. e.g.: "--name=value", "--name value".
// This list is manually maintenanced for now.
var pureFlags = []string{
"add-category-auto",
Expand Down
2 changes: 1 addition & 1 deletion cmd/iyuu/bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var (
)

func init() {
command.Flags().StringVarP(&site, "site", "", "", "(Required) Iyuu sitename used for binding. eg. zhuque")
command.Flags().StringVarP(&site, "site", "", "", "(Required) Iyuu sitename used for binding. e.g.: zhuque")
command.Flags().Int64VarP(&uid, "uid", "", 0, "(Required) Site uid")
command.Flags().StringVarP(&passkey, "passkey", "", "", "(Required) Site passkey (or equivalent key)")
command.MarkFlagRequired("site")
Expand Down
4 changes: 2 additions & 2 deletions cmd/iyuu/iyuu.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ type Site struct {
Sid int64 `gorm:"primaryKey"`
Name string `gorm:"index"`
Nickname string
Url string // site homepage url. eg. https://hdvideo.one/
DownloadPage string // (relative) torrent download url. eg. "download.php?id={}&passkey={passkey}"
Url string // site homepage url. e.g.: https://hdvideo.one/
DownloadPage string // (relative) torrent download url. e.g.: "download.php?id={}&passkey={passkey}"
}

// gorm "meta" (not metas!) table
Expand Down
2 changes: 1 addition & 1 deletion cmd/partialdownload/partialdownload.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func init() {
command.Flags().BoolVarP(&originalOrder, "original-order", "", false, "Split torrent files to chunks by their original order instead of path order")
command.Flags().Int64VarP(&chunkIndex, "chunk-index", "", 0, "Set the split chunk index (0-based) to download")
command.Flags().Int64VarP(&startIndex, "start-index", "", 0, "Set the index (0-based) of the first file in torrent to download. The prior files of torrent will be skipped")
command.Flags().StringVarP(&chunkSizeStr, "chunk-size", "", "", "Set the split chunk size string. eg. 500GiB")
command.Flags().StringVarP(&chunkSizeStr, "chunk-size", "", "", "Set the split chunk size string. e.g.: 500GiB")
command.MarkFlagRequired("chunk-size")
cmd.RootCmd.AddCommand(command)
}
Expand Down
11 changes: 10 additions & 1 deletion cmd/search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var command = &cobra.Command{
var (
dense = false
largestFlag = false
newestFlag = false
showJson = false
maxResults = int64(0)
perSiteMaxResults = int64(0)
Expand All @@ -43,10 +44,11 @@ var (
func init() {
command.Flags().BoolVarP(&dense, "dense", "", false, "Dense mode: show full torrent title & subtitle")
command.Flags().BoolVarP(&largestFlag, "largest", "l", false, "Sort search result by torrent size in desc order")
command.Flags().BoolVarP(&newestFlag, "newest", "n", false, "Sort search result by torrent time in desc order")
command.Flags().BoolVarP(&showJson, "json", "", false, "Show output in json format")
command.Flags().Int64VarP(&maxResults, "max-results", "", 100, "Number limit of search result of all sites combined. -1 == no limit")
command.Flags().Int64VarP(&perSiteMaxResults, "per-site-max-results", "", -1, "Number limit of search result of any single site. -1 == no limit")
command.Flags().StringVarP(&baseUrl, "base-url", "", "", "Manually set the base url of search page. eg. adult.php or https://kp.m-team.cc/adult.php for M-Team site")
command.Flags().StringVarP(&baseUrl, "base-url", "", "", "Manually set the base url of search page. e.g.: adult.php, special.php")
cmd.RootCmd.AddCommand(command)
}

Expand Down Expand Up @@ -106,6 +108,13 @@ func search(cmd *cobra.Command, args []string) error {
}
return torrents[i].Seeders > torrents[j].Seeders
})
} else if newestFlag {
sort.Slice(torrents, func(i, j int) bool {
if torrents[i].Time != torrents[j].Time {
return torrents[i].Time > torrents[j].Time
}
return torrents[i].Seeders > torrents[j].Seeders
})
}
if maxResults >= 0 && len(torrents) > int(maxResults) {
torrents = torrents[:maxResults]
Expand Down
4 changes: 3 additions & 1 deletion cmd/versioncmd/versioncmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func versioncmd(cmd *cobra.Command, args []string) error {
}
fmt.Printf("Impersonate '%s'\n", impersonate)
fmt.Printf("- navigator: %s\n", impersonateProfile.Navigator)
fmt.Printf("- comment: %s\n", impersonateProfile.Comment)
fmt.Printf("- tls_ja3: %s\n", impersonateProfile.Ja3)
fmt.Printf("- h2_fingerprint: %s\n", impersonateProfile.H2fingerpring)
fmt.Printf("- http_request_headers:\n")
Expand All @@ -57,6 +58,7 @@ func versioncmd(cmd *cobra.Command, args []string) error {
fmt.Printf("- go/version: %s\n", runtime.Version())
fmt.Printf("- config_file: %s%c%s\n", config.ConfigDir, filepath.Separator, config.ConfigFile)
fmt.Printf("- config_dir: %s\n", config.ConfigDir)
fmt.Printf("- config/supported_impersonates: %s\n", strings.Join(util.Impersonates, ", "))
fmt.Printf("- config/default_impersonate: %s\n", util.DEFAULT_IMPERSONATE)
fmt.Printf("- config/supported_impersonates: %s, none\n", strings.Join(util.Impersonates, ", "))
return nil
}
3 changes: 2 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type SiteConfigStruct struct {
Domains []string `yaml:"domains"` // other site domains (do not include subdomain part)
TorrentsUrl string `yaml:"torrentsUrl"`
SearchUrl string `yaml:"searchUrl"`
SearchQueryVariable string `yaml:"searchQueryVariable"`
TorrentsExtraUrls []string `yaml:"torrentsExtraUrls"`
Cookie string `yaml:"cookie"`
UserAgent string `yaml:"userAgent"`
Expand Down Expand Up @@ -488,7 +489,7 @@ func (siteConfig *SiteConfigStruct) GetTimezone() string {
return tz
}

// parse a site internal url (eg. special.php), return absolute url
// parse a site internal url (e.g.: special.php), return absolute url
func (siteConfig *SiteConfigStruct) ParseSiteUrl(siteUrl string, appendQueryStringDelimiter bool) string {
pageUrl := ""
if siteUrl != "" {
Expand Down
8 changes: 7 additions & 1 deletion site/nexusphp/nexusphp.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ func (npclient *Site) SearchTorrents(keyword string, baseUrl string) ([]site.Tor
if baseUrl == "" {
if npclient.SiteConfig.SearchUrl != "" {
baseUrl = npclient.SiteConfig.SearchUrl
} else if npclient.SiteConfig.TorrentsUrl != "" {
baseUrl = npclient.SiteConfig.TorrentsUrl
} else {
baseUrl = DEFAULT_TORRENTS_URL
}
}
searchUrl := npclient.SiteConfig.ParseSiteUrl(baseUrl, true)
if !strings.Contains(searchUrl, "%s") {
searchUrl += "search=%s"
searchQueryVariable := "search"
if npclient.SiteConfig.SearchQueryVariable != "" {
searchQueryVariable = npclient.SiteConfig.SearchQueryVariable
}
searchUrl += searchQueryVariable + "=%s"
}
searchUrl = strings.Replace(searchUrl, "%s", url.PathEscape(keyword), 1)

Expand Down
4 changes: 2 additions & 2 deletions site/nexusphp/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func parseTorrents(doc *goquery.Document, option *TorrentsParserOption,
if containerElNode != nil {
containerEl = nodeSelectionMap[containerElNode]
}
} else if torrentEls.Length() == 1 { // only one torrent found (eg. search result page)
} else if torrentEls.Length() == 1 { // only one torrent found (e.g.: search result page)
containerEl = doc.Find(SELECTOR_TORRENTS_LIST_DEFAULT)
if containerEl.Length() > 0 {
containerElNode = containerEl.Get(0)
Expand Down Expand Up @@ -303,7 +303,7 @@ func parseTorrents(doc *goquery.Document, option *TorrentsParserOption,
if titleEl == nil {
titleEl = s.Find(option.selectorTorrentDetailsLink)
}
// 尽量不使用 a img 这种题图类型的标题元素(eg. M-Team)
// 尽量不使用 a img 这种题图类型的标题元素(e.g.: M-Team)
titleTextEl := titleEl.FilterFunction(func(i int, s *goquery.Selection) bool {
parentNode := s.Parent().Get(0)
if parentNode.DataAtom == atom.Img || parentNode.DataAtom == atom.Image {
Expand Down
4 changes: 2 additions & 2 deletions site/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ type Site interface {
// default sent http request headers
GetDefaultHttpHeaders() [][]string
GetSiteConfig() *config.SiteConfigStruct
// download torrent by id (eg. 12345), sitename.id (eg. mteam.12345), or absolute download url (eg. https://kp.m-team.cc/download.php?id=12345)
// download torrent by id (e.g.: 12345), sitename.id (e.g.: mteam.12345), or absolute download url (e.g.: https://kp.m-team.cc/download.php?id=12345)
DownloadTorrent(url string) (content []byte, filename string, err error)
// download torrent by torrent id (eg. 12345)
// download torrent by torrent id (e.g.: 12345)
DownloadTorrentById(id string) (content []byte, filename string, err error)
GetLatestTorrents(full bool) ([]Torrent, error)
// sort: size|name|none(or "")
Expand Down
16 changes: 9 additions & 7 deletions site/tpl/tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,7 @@ var (
Type: "nexusphp",
Url: "https://ptvicomo.net/",
TorrentsExtraUrls: []string{"special.php"},
// 该网站可能需要配置 ja3 才能正常访问
Comment: "象站",
Comment: "象站",
},
"rousi": {
Type: "nexusphp",
Expand Down Expand Up @@ -498,11 +497,14 @@ var (
Comment: "聆音",
},
"totheglory": {
Type: "nexusphp",
Aliases: []string{"ttg"},
Url: "https://totheglory.im/",
TorrentsUrl: "browse.php?c=M",
TorrentsExtraUrls: []string{"browse.php?c=G"},
Type: "nexusphp",
Aliases: []string{"ttg"},
Url: "https://totheglory.im/",
TorrentsUrl: "browse.php?c=M",
TorrentsExtraUrls: []string{"browse.php?c=G"},
// 是否能够直接同时搜索影视区和游戏区?
// SearchUrl: "browse.php?search_field=%s",
SearchQueryVariable: "search_field",
SelectorTorrent: `a.dl_a[href^="/dl/"]`,
SelectorTorrentDownloadLink: `a.dl_a[href^="/dl/"]`,
SelectorTorrentDetailsLink: `.name_left a[href^="/t/"]`,
Expand Down
26 changes: 25 additions & 1 deletion util/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ImpersonateProfile struct {
Ja3 string
H2fingerpring string
Headers [][]string // use "\n" as placeholder for order; use "" (empty) to delete a header
Comment string
}

const (
Expand All @@ -38,6 +39,7 @@ const (
var ImpersonateProfiles = map[string]*ImpersonateProfile{
"chrome120": {
Navigator: "chrome",
Comment: "Chrome 120 on Windows 11 x64 en-US",
// TLS ja3 指纹。参考: https://scrapfly.io/blog/how-to-avoid-web-scraping-blocking-tls/ .
// Ja3 should be generated without the "TLS Session has been resurected" warning
Ja3: "772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,65281-45-11-65037-18-5-51-0-23-27-43-16-10-35-17513-13,29-23-24,0",
Expand All @@ -56,11 +58,33 @@ var ImpersonateProfiles = map[string]*ImpersonateProfile{
{"Sec-Fetch-Mode", `navigate`},
{"Sec-Fetch-User", `?1`},
{"Sec-Fetch-Dest", `document`},
// {"Accept-Encoding", "gzip, deflate, br"},
{"Accept-Encoding", "gzip, deflate, br"},
{"Accept-Language", "en-US,en;q=0.9"},
{"Cookie", HTTP_HEADER_PLACEHOLDER},
},
},
"firefox121": {
Navigator: "firefox",
Comment: "Firefox 121 on Windows 11 x64 en-US",
// Ja3: "772,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-34-51-43-13-45-28-65037,29-23-24-25-256-257,0",
// utls do not support TLS 34 delegated_credentials (34) (IANA) extension at this time.
// see https://github.com/refraction-networking/utls/issues/274
Ja3: "772,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-51-43-13-45-28-65037,29-23-24-25-256-257,0",
H2fingerpring: "1:65536,4:131072,5:16384|12517377|3:0:0:201,5:0:0:101,7:0:0:1,9:0:7:1,11:0:3:1,13:0:0:241|m,p,a,s",
Headers: [][]string{
{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0"},
{"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"},
{"Accept-Language", "en-US,en;q=0.5"},
{"Accept-Encoding", "gzip, deflate, br"},
{"Cookie", HTTP_HEADER_PLACEHOLDER},
{"Upgrade-Insecure-Requests", "1"},
{"Sec-Fetch-Dest", `document`},
{"Sec-Fetch-Mode", `navigate`},
{"Sec-Fetch-Site", `none`},
{"Sec-Fetch-User", `?1`},
{"te", "trailers"},
},
},
}

var (
Expand Down
2 changes: 1 addition & 1 deletion util/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func AppendUrlQueryString(url string, qs string) string {
return url + qs
}

// return (top-level) domain of a url. eg. https://www.google.com/ => google.com
// return (top-level) domain of a url. e.g.: https://www.google.com/ => google.com
func GetUrlDomain(url string) string {
u, err := tld.Parse(url)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions util/units.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,19 @@ func HumanSizeWithPrecision(size float64, precision int) string {
}

// HumanSize returns a human-readable approximation of a size
// capped at 4 valid numbers (eg. "2.746 MB", "796 KB").
// capped at 4 valid numbers (e.g.: "2.746 MB", "796 KB").
func HumanSize(size float64) string {
return HumanSizeWithPrecision(size, 2)
}

// BytesSize returns a human-readable size in bytes, kibibytes,
// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB").
// mebibytes, gibibytes, or tebibytes (e.g.: "44kiB", "17MiB").
func BytesSize(size float64) string {
return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs)
}

// FromHumanSize returns an integer from a human-readable specification of a
// size using SI standard (eg. "44kB", "17MB").
// size using SI standard (e.g.: "44kB", "17MB").
func FromHumanSize(size string) (int64, error) {
return parseSize(size, decimalMap)
}
Expand Down

0 comments on commit f9c388c

Please sign in to comment.