meta4ra-check utility is used verify corresponding files integrity.
-meta4ra-url-sort utility is used to sort "pri|cc|URL" lines by specified
-country codes, continents, priority.
-
meta4ra-dl utility can be used to download specified URL.
meta4ra-hash utility can be used to hash the data with a single hash
fn=$(meta4ra-list .meta4 | head -1)
size=$(meta4ra-list -size .meta4 $fn)
meta4ra-list .meta4 $fn |
- meta4ra-url-sort ru c:eu "" rand |
+ urls-sort ru c:eu "" rand |
while read url ; do
meta4ra-dl -size $size -progress "$url" |
meta4ra-check -pipe .meta4 $fn >$fn || {
done
[ -s $fn ]
+urls-sort is taken from BASS project (http://www.bass.cypherpunks.su/).
+
meta4ra is copylefted free software: see the file COPYING for copying
conditions. It should work on all POSIX-compatible systems.
+++ /dev/null
-// meta4ra -- Metalink 4.0 utilities
-// Copyright (C) 2021-2026 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
- "bufio"
- "flag"
- "fmt"
- "log"
- "math/rand/v2"
- "net"
- "net/url"
- "os"
- "slices"
- "sort"
- "strings"
-
- meta4ra "go.stargrave.org/meta4ra/internal"
-)
-
-type ByPriority []*meta4ra.URL
-
-func (urls ByPriority) Len() int {
- return len(urls)
-}
-
-func (urls ByPriority) Less(i, j int) bool {
- return urls[i].Priority < urls[j].Priority
-}
-
-func (urls ByPriority) Swap(i, j int) {
- urls[i], urls[j] = urls[j], urls[i]
-}
-
-// https://datahub.io/core/continent-codes/_r/-/data/continent-codes.csv
-// https://datahub.io/core/country-codes/_r/-/data/country-codes.csv
-
-var Continents = map[string]string{
- "af": "ao bf bi bj bw cd cf cg ci cm cv dj dz eg eh er et ga gh gm gn gq gw ke km lr ls ly ma mg ml mr mu mw mz na ne ng re rw sc sd sh sl sn so ss st sz td tg tn tz ug yt za zm zw",
- "an": "aq bv gs hm tf",
- "as": "ae af am az bd bh bn bt cc cn ge hk id il in io iq ir jo jp kg kh kp kr kw kz la lb lk mm mn mo mv my np om ph pk ps qa sa sg sy th tj tm tr tw uz vn ye",
- "eu": "ad al at ax ba be bg by ch cy cz de dk ee es eu fi fo fr gb gg gi gr hr hu ie im is it je li lt lu lv mc md me mk mt nl no pl pt ro rs ru se si sj sk sm ua va",
- "na": "ag ai aw bb bl bm bq bs bz ca cr cu cw dm do gd gl gp gt hn ht jm kn ky lc mf mq ms mx ni pa pm pr sv sx tc tt us vc vg vi",
- "oc": "as au ck cx fj fm gu ki mh mp nc nf nr nu nz pf pg pn pw sb tk tl to tv um vu wf ws",
- "sa": "ar bo br cl co ec fk gf gy pe py sr uy ve",
-}
-
-type ByCC struct {
- cc string
- urls []*meta4ra.URL
-}
-
-func (by ByCC) Len() int {
- return len(by.urls)
-}
-
-func (by ByCC) Less(i, j int) bool {
- return strings.Contains(by.cc, by.urls[i].Location)
-}
-
-func (by ByCC) Swap(i, j int) {
- by.urls[i], by.urls[j] = by.urls[j], by.urls[i]
-}
-
-func runURLSort() {
- ipv6 := flag.Bool("6", false, "Only IPv6-capable hostnames")
- flag.Usage = func() {
- fmt.Fprintf(flag.CommandLine.Output(),
- "Usage: %s [options] [cc ...] <urls.txt\n", os.Args[0])
- flag.PrintDefaults()
- fmt.Fprint(flag.CommandLine.Output(), `
-By default all URLs are sorted by priority. If "cc"s are specified, then
-sort by them with descending order. By specifying "!" before "cc", you
-reverse the order. If "cc" is "rand", then shuffle URLs.
-For specifying the region/continent use:
- c:af -- Africa
- c:an -- Antarctica
- c:as -- Asia
- c:eu -- Europe
- c:na -- North America
- c:oc -- Oceania
- c:sa -- South America
-For example to set Russia first, then Germany and France of same order,
-then Europe, then North America, least priority Ukraine, then location-less,
-randomise remaining:
- ru "de fr" "!ua" c:eu c:na "" rand
-`)
- }
- flag.Parse()
-
- if *showVersion {
- fmt.Println(meta4ra.Version())
- return
- }
- if *showWarranty {
- fmt.Println(meta4ra.Warranty)
- return
- }
-
- var urls []*meta4ra.URL
- {
- scanner := bufio.NewScanner(os.Stdin)
- for scanner.Scan() {
- u, err := meta4ra.ParseURL(scanner.Text())
- if err != nil {
- log.Fatal(err)
- }
- if u.Priority == 0 {
- u.Priority = 999999
- }
- urls = append(urls, u)
- }
- if err := scanner.Err(); err != nil {
- log.Fatal(err)
- }
- }
- for i := len(flag.Args()) - 1; i >= 0; i-- {
- cc := flag.Args()[i]
- if cc == "rand" {
- rand.Shuffle(len(urls), func(i, j int) {
- urls[i], urls[j] = urls[j], urls[i]
- })
- continue
- }
- reverse := false
- if len(cc) > 0 && cc[0] == '!' {
- reverse = true
- cc = cc[1:]
- slices.Reverse(urls)
- }
- if strings.HasPrefix(cc, "c:") {
- cc = Continents[cc[2:]]
- }
- sort.Stable(ByCC{cc: cc, urls: urls})
- if reverse {
- slices.Reverse(urls)
- }
- }
- sort.Stable(ByPriority(urls))
- for _, u := range urls {
- if u.Priority == 999999 {
- u.Priority = 0
- }
- if *ipv6 {
- parsed, err := url.Parse(u.URL)
- if err != nil {
- continue
- }
- _, err = net.ResolveIPAddr("ip6", parsed.Hostname())
- if err != nil {
- continue
- }
- }
- fmt.Println(u)
- }
-}