torlnq 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bairon.dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ <p align="center">
2
+ <img src="preview/splash.svg" alt="torlink, curated torrents straight from your terminal" style="max-width: 832px; width: 100%; height: auto;">
3
+ </p>
4
+
5
+ Finding a torrent these days sucks. One site is a minefield of fake download buttons. Another hides the real link under a popup that spawns two more tabs. And after all that, half the results are dead, zero seeders.
6
+
7
+ torlink is a torrent finder that lives in your terminal, with zero setup and nothing to configure. One search checks a short, curated list of reputable sources at once, and whatever you pick downloads straight to your computer. The files are yours, saved to your downloads folder.
8
+
9
+ ## Get started
10
+
11
+ 1. **Install Node** (from [nodejs.org](https://nodejs.org)), it's all torlink needs.
12
+ 2. **Open your terminal.**
13
+ 3. **Install torlink:**
14
+
15
+ ```sh
16
+ npm install -g torlnq
17
+ ```
18
+
19
+ 4. **Start it:**
20
+
21
+ ```sh
22
+ torlnq
23
+ ```
24
+
25
+ That's the only thing you'll type. torlink opens straight to a search bar: search for what you want, paste in a magnet link, or just press Enter on an empty box to browse the curated library. From there it's all keypresses, nothing to memorize, and `?` brings up the full list anytime.
26
+
27
+ ## Finding something
28
+
29
+ Type what you're looking for and press Enter. Results stream in from every source as they answer, tagged with size and how many people are sharing each one, so you can see what'll come down fast. Arrow to what you want and press `d` to save it.
30
+
31
+ <p align="center">
32
+ <img src="preview/browse.svg" alt="torlink's browse view: the sidebar, the search bar, and merged results from every source" style="max-width: 832px; width: 100%; height: auto;">
33
+ </p>
34
+
35
+ ## Your downloads
36
+
37
+ Active downloads sit up top with their progress, speed, and time left; when one finishes it drops into Recently downloaded just below, so the list stays tidy. Everything's still there when you come back, and anything interrupted picks up where it left off.
38
+
39
+ Downloads run in the background while you keep searching, so you can queue up as many as you want. They save to your downloads folder, and the Downloads pane keeps tabs on each one. When something finishes it keeps seeding automatically so the next person can find it too, and the Seeding tab lets you pause or stop that anytime.
40
+
41
+ <p align="center">
42
+ <img src="preview/downloads.svg" alt="torlink's Downloads pane: live progress on top, recently downloaded below" style="max-width: 832px; width: 100%; height: auto;">
43
+ </p>
44
+
45
+ ## What it searches
46
+
47
+ A short, hand-picked list of trusted sources:
48
+
49
+ | Category | Sources |
50
+ | --- | --- |
51
+ | Games | FitGirl |
52
+ | Movies | YTS, The Pirate Bay, 1337x |
53
+ | TV | EZTV, SolidTorrents, The Pirate Bay, 1337x |
54
+ | Anime | Nyaa, SubsPlease |
55
+
56
+ Games are the only category that can run code, so they come from FitGirl alone, a repacker with a long, trusted track record; everything else is plain video and subtitles. If a source is down, the search carries on without it, and torlink tells you which one is offline.
57
+
58
+ ## Contributing
59
+
60
+ To run or work on torlink locally:
61
+
62
+ 1. Clone the repository and open the folder.
63
+ 2. Install dependencies:
64
+ ```sh
65
+ npm install
66
+ ```
67
+ 3. Run the development version:
68
+ ```sh
69
+ npm run dev
70
+ ```
71
+ Or build it and run the bundled version:
72
+ ```sh
73
+ npm run build
74
+ npm install -g .
75
+ torlnq
76
+ ```
77
+
78
+ Before opening a PR, skim [CONTRIBUTING.md](CONTRIBUTING.md); it lays out the bar with examples from real merged PRs.
79
+
80
+ ## Privacy
81
+
82
+ Your files stay on your disk, and nothing routes through a central server; torlink only talks to the torrent network directly. Once a download finishes it keeps seeding by default, sharing it back so the next person can find it just as easily. The network only works because people pass things along, and even a few minutes makes a real difference. If you'd rather not, opt out anytime: open the Seeding tab, press `p` to pause or stop any item, and press it again to pick it back up. Always your call.
83
+
84
+ ## Star History
85
+
86
+ <a href="https://www.star-history.com/?repos=BlusceLabs%2Ftorlink&type=date&legend=top-left">
87
+ <picture>
88
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=BlusceLabs/torlink&type=date&theme=dark&legend=top-left" />
89
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=BlusceLabs/torlink&type=date&legend=top-left" />
90
+ <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=BlusceLabs/torlink&type=date&legend=top-left" />
91
+ </picture>
92
+ </a>
package/dist/cli.cjs ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var major = parseInt(process.versions.node.split('.')[0], 10);
5
+ if (major < 22) {
6
+ process.stderr.write(
7
+ '\ntorlnq requires Node.js v22 or later.\n' +
8
+ 'You are running v' + process.versions.node + '.\n\n' +
9
+ 'Upgrade: https://nodejs.org\n' +
10
+ 'With nvm: nvm install 22 && nvm use 22\n\n'
11
+ );
12
+ process.exit(1);
13
+ }
14
+
15
+ import('./index.js').catch(function (err) {
16
+ process.stderr.write(String((err && err.message) || err) + '\n');
17
+ process.exit(1);
18
+ });
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import{render as Yi}from"ink";function vr(t){let e=t.filter(o=>o.trim()!=="");if(e.length===0)return{kind:"run"};let r=e[0];return r==="--version"||r==="-v"?{kind:"version"}:r==="--help"||r==="-h"?{kind:"help"}:/^magnet:\?/i.test(r)?{kind:"run",initialMagnet:r}:/\.torrent$/i.test(r)?{kind:"run",initialTorrent:r}:{kind:"invalid",arg:r}}var Gt=`torlink, terminal-native torrent search
3
+
4
+ usage
5
+ torlnq open the search TUI
6
+ torlnq "magnet:?xt=..." start a download on launch
7
+ torlnq path/to/file.torrent open a .torrent file on launch
8
+ torlnq --version print the version
9
+
10
+ once open: type to search every source at once, enter to run, arrows to move,
11
+ d to download, ? for keys
12
+ tip: quote magnet links (they contain & characters)
13
+ `;var Cr="1.0.0";import{useCallback as Ie,useEffect as pt,useMemo as zi,useRef as Gi,useState as ce}from"react";import{Box as Me,Text as Qi,useApp as Wi,useInput as ji,useStdout as Vi,useStdin as qi}from"ink";import{promises as wr}from"fs";import{promises as vn}from"fs";import yn from"os";import Ce from"path";import wn from"env-paths";var Rr="torlink",Er=wn(Rr,{suffix:""}),bt=process.env.TORLINK_STATE_DIR,Tt=bt?Ce.join(bt,"data"):Er.data,bn=bt?Ce.join(bt,"config"):Er.config,Qt=Ce.join(yn.homedir(),"Downloads",Rr),Wt=Ce.join(bn,"config.json"),Oe=Ce.join(Tt,"queue.json"),_e=Ce.join(Tt,"history.json"),Le=Ce.join(Tt,"seeds.json"),jt=Ce.join(Tt,"torrents");import{promises as Vt}from"fs";import Tn from"path";function Ne(){let t=Promise.resolve();return e=>(t=t.then(e).catch(()=>{}),t)}async function ke(t,e){await Vt.mkdir(Tn.dirname(t),{recursive:!0});let r=`${t}.tmp`;await Vt.writeFile(r,JSON.stringify(e,null,2),"utf8"),await Vt.rename(r,t)}var qt={downloadDir:Qt};async function Br(){let t;try{t=await vn.readFile(Wt,"utf8")}catch{return{...qt}}try{let e=JSON.parse(t),r={...qt,...e};return(!r.downloadDir||typeof r.downloadDir!="string")&&(r.downloadDir=Qt),r}catch{return{...qt}}}var Cn=Ne();function Ir(t){return Cn(()=>ke(Wt,t))}import Mr from"os";import kr from"path";function Rn(t,e=Mr.homedir()){let r=t.trim();return r==="~"?e:r.startsWith("~/")||r.startsWith("~\\")?kr.join(e,r.slice(2)):r}function Ar(t,e=Mr.homedir()){let r=Rn(t,e);return r?kr.normalize(r):""}import{EventEmitter as _n}from"events";import En from"webtorrent";function Pr(t){return t instanceof Error?t.message:String(t)}var vt=class{client=null;torrents=new Map;ensureClient(){return this.client||(this.client=new En,this.client.on("error",()=>{})),this.client}add(e,r,o,n){let s=this.ensureClient(),i=this.torrents.get(e);if(i){this.torrents.delete(e);try{i.destroy()}catch{}}let a;try{a=s.add(r,{path:o})}catch(l){n.onError?.(Pr(l));return}this.torrents.set(e,a),a.on("metadata",()=>{n.onMetadata?.({name:a.name,total:a.length,files:a.files?.length??0,torrentFile:a.torrentFile})}),a.on("done",()=>{n.onDone?.()}),a.on("error",l=>{n.onError?.(Pr(l)),this.torrents.delete(e);try{a.destroy()}catch{}})}listenPort(){return this.client?.torrentPort??null}stats(e){let r=this.torrents.get(e);return r?{progress:r.progress,downloaded:r.downloaded,total:r.length,speed:r.downloadSpeed,uploadSpeed:r.uploadSpeed,uploaded:r.uploaded,peers:r.numPeers,timeRemaining:r.timeRemaining,name:r.name}:null}remove(e){let r=this.torrents.get(e);if(this.torrents.delete(e),r)try{r.destroy()}catch{}}destroy(){this.torrents.clear();let e=this.client;this.client=null,e&&setImmediate(()=>{try{e.destroy()}catch{}})}};import{promises as et,mkdirSync as Hr,writeFileSync as $r,renameSync as Dr,existsSync as Bn,rmSync as In}from"fs";import Yt from"path";var Or=Ne();function _r(t){return Or(()=>ke(Oe,t))}function Lr(t){try{Hr(Yt.dirname(Oe),{recursive:!0});let e=`${Oe}.sync.tmp`;$r(e,JSON.stringify(t,null,2),"utf8"),Dr(e,Oe)}catch{}}function Mn(t){if(!t||typeof t!="object")return!1;let e=t;return typeof e.id=="string"&&typeof e.magnet=="string"}async function Nr(){let t;try{t=await et.readFile(Oe,"utf8")}catch{return[]}try{let e=JSON.parse(t);return Array.isArray(e)?e.filter(Mn):[]}catch{return[]}}function Fr(t){return Or(()=>ke(Le,t))}function Ur(t){try{Hr(Yt.dirname(Le),{recursive:!0});let e=`${Le}.sync.tmp`;$r(e,JSON.stringify(t,null,2),"utf8"),Dr(e,Le)}catch{}}function tt(t){return Yt.join(jt,`${t}.torrent`)}function zr(t){return Bn(tt(t))}async function Gr(t,e){try{await et.mkdir(jt,{recursive:!0});let r=tt(t),o=`${r}.tmp`;await et.writeFile(o,e),await et.rename(o,r)}catch{}}function Ct(t){try{In(tt(t),{force:!0})}catch{}}async function Qr(){let t;try{t=await et.readFile(Le,"utf8")}catch{return[]}try{let e=JSON.parse(t);if(!Array.isArray(e))return[];let r=[];for(let o of e)if(typeof o=="string")r.push({id:o,status:"seeding"});else if(o&&typeof o=="object"){let n=o;typeof n.id=="string"&&(n.status==="seeding"||n.status==="paused")&&r.push({id:n.id,status:n.status})}return r}catch{return[]}}import{promises as kn,mkdirSync as An,writeFileSync as Pn,renameSync as Hn}from"fs";import $n from"path";var Kt=500,Dn=Ne();function Rt(t){return Dn(()=>ke(_e,t.slice(0,Kt)))}function Wr(t){try{An($n.dirname(_e),{recursive:!0});let e=`${_e}.sync.tmp`;Pn(e,JSON.stringify(t.slice(0,Kt),null,2),"utf8"),Hn(e,_e)}catch{}}function On(t){if(!t||typeof t!="object")return!1;let e=t;return typeof e.id=="string"&&typeof e.name=="string"&&typeof e.magnet=="string"}async function jr(){let t;try{t=await kn.readFile(_e,"utf8")}catch{return[]}try{let e=JSON.parse(t);return Array.isArray(e)?e.filter(On).slice(0,Kt):[]}catch{return[]}}function Ln(t){return t.total>0&&t.progress<1&&t.speed>0}var Nn=2,Fn=1e4,Un=500,Vr=500,Et=class extends _n{items=new Map;engine=new vt;poll=null;history=[];seeds=new Map;strayHits=new Map;seedStartedAt=new Map;getItems(){return[...this.items.values()].sort((e,r)=>r.addedAt-e.addedAt)}get activeCount(){let e=0;for(let r of this.items.values())r.status==="downloading"&&e++;return e}has(e){return this.items.has(e)}add(e,r){this.seeds.has(e.id)&&(this.engine.remove(e.id),this.seeds.delete(e.id),this.strayHits.delete(e.id),this.seedStartedAt.delete(e.id),this.persistSeeds());let o=this.items.get(e.id);if(o&&o.status!=="failed")return;let n=o?{...o,status:"downloading",error:void 0,speed:0}:{id:e.id,name:e.name,source:e.source,magnet:e.magnet,dir:r,status:"downloading",progress:0,totalBytes:e.sizeBytes??0,downloadedBytes:0,speed:0,peers:0,addedAt:Date.now()};this.items.set(n.id,n),this.startEngine(n),this.ensurePoll(),this.changed(),this.persist()}startEngine(e){this.engine.add(e.id,e.magnet,e.dir,this.engineHandlers(e.id))}engineHandlers(e){return{onMetadata:r=>{r.torrentFile&&Gr(e,r.torrentFile);let o=this.items.get(e);o&&(r.name&&(o.name=r.name),r.total&&(o.totalBytes=r.total),o.files=r.files,this.changed(),this.persist())},onDone:()=>{let r=this.items.get(e);if(r){r.totalBytes&&(r.downloadedBytes=r.totalBytes),this.complete(r);return}this.seeds.has(e)&&(this.strayHits.set(e,0),this.seedStartedAt.delete(e))},onError:r=>{let o=this.items.get(e);if(o){o.status="failed",o.error=r,o.speed=0,o.peers=0,this.changed(),this.persist(),this.maybeStopPoll();return}let n=this.seeds.get(e);n&&(n.status="missing",n.uploadSpeed=0,n.peers=0,this.seedStartedAt.delete(e),this.changed(),this.persistSeeds(),this.maybeStopPoll())}}}complete(e){this.recordHistory(e),this.items.delete(e.id),this.beginSeed(e),this.emit("completed",e.name),this.changed(),this.persist(),this.maybeStopPoll()}beginSeed(e){e.magnet&&(this.seeds.set(e.id,{id:e.id,name:e.name,source:e.source,magnet:e.magnet,dir:e.dir,sizeBytes:e.totalBytes,status:"seeding",uploadSpeed:0,uploaded:0,peers:0}),this.strayHits.set(e.id,0),this.seedStartedAt.set(e.id,Date.now()),this.ensurePoll(),this.persistSeeds())}tick(){let e=!1;for(let o of this.items.values()){if(o.status!=="downloading")continue;let n=this.engine.stats(o.id);n&&(o.progress=Math.min(100,Math.round(n.progress*100)),o.downloadedBytes=n.downloaded,n.total&&(o.totalBytes=n.total),o.speed=n.speed,o.peers=n.peers,o.eta=n.timeRemaining>0&&Number.isFinite(n.timeRemaining)?n.timeRemaining/1e3:void 0,n.name&&(o.name=n.name),e=!0)}let r=Date.now();for(let o of this.seeds.values()){if(o.status!=="seeding")continue;let n=this.engine.stats(o.id);if(!n)continue;if(r-(this.seedStartedAt.get(o.id)??0)>Fn&&Ln(n)){let i=(this.strayHits.get(o.id)??0)+1;this.strayHits.set(o.id,i),i>=Nn&&(this.engine.remove(o.id),this.strayHits.delete(o.id),this.seedStartedAt.delete(o.id),o.status="missing",o.uploadSpeed=0,o.peers=0,this.persistSeeds()),e=!0;continue}this.strayHits.set(o.id,0),o.uploadSpeed=n.uploadSpeed,o.uploaded=n.uploaded,o.peers=n.peers,e=!0}e&&this.changed()}ensurePoll(){this.poll||(this.poll=setInterval(()=>this.tick(),Un),this.poll.unref())}maybeStopPoll(){this.activeCount===0&&this.seedingCount===0&&this.poll&&(clearInterval(this.poll),this.poll=null)}pause(e){let r=this.items.get(e);!r||r.status!=="downloading"||(r.status="paused",r.speed=0,r.peers=0,r.eta=void 0,this.engine.remove(e),this.changed(),this.persist(),this.maybeStopPoll())}resume(e){let r=this.items.get(e);!r||r.status!=="paused"||(r.status="downloading",this.startEngine(r),this.ensurePoll(),this.changed(),this.persist())}togglePause(e){let r=this.items.get(e);r&&(r.status==="downloading"?this.pause(e):r.status==="paused"&&this.resume(e))}cancel(e){this.items.has(e)&&(this.engine.remove(e),this.items.delete(e),Ct(e),this.changed(),this.persist(),this.maybeStopPoll())}retry(e){let r=this.items.get(e);!r||r.status!=="failed"||(r.status="downloading",r.error=void 0,this.startEngine(r),this.ensurePoll(),this.changed(),this.persist())}retryFailed(){for(let e of[...this.items.values()])e.status==="failed"&&this.retry(e.id)}getSeed(e){return this.seeds.get(e)}getSeeds(){return[...this.seeds.values()]}get seedingCount(){let e=0;for(let r of this.seeds.values())r.status==="seeding"&&e++;return e}startSeeding(e){if(this.seeds.get(e.id)?.status==="seeding"||this.items.has(e.id))return;let r={id:e.id,name:e.name,source:e.source,magnet:e.magnet,dir:e.dir,sizeBytes:e.sizeBytes,status:"seeding",uploadSpeed:0,uploaded:0,peers:0};if(!e.magnet){this.seeds.set(e.id,{...r,status:"missing"}),this.changed(),this.persistSeeds();return}this.seeds.set(e.id,r),this.strayHits.set(e.id,0),this.seedStartedAt.set(e.id,Date.now());let o=zr(e.id)?tt(e.id):e.magnet;this.engine.add(e.id,o,e.dir,this.engineHandlers(e.id)),this.ensurePoll(),this.changed(),this.persistSeeds()}stopSeeding(e){let r=this.seeds.get(e);r&&(this.engine.remove(e),this.strayHits.delete(e),this.seedStartedAt.delete(e),r.status==="seeding"&&(r.status="paused",r.uploadSpeed=0,r.peers=0),this.changed(),this.persistSeeds(),this.maybeStopPoll())}toggleSeeding(e){this.seeds.get(e.id)?.status==="seeding"?this.stopSeeding(e.id):this.startSeeding(e)}restoreSeeds(e){for(let r of e){let o=this.history.find(n=>n.id===r.id);o&&(r.status==="seeding"?this.startSeeding(o):this.restorePaused(o))}}restorePaused(e){this.seeds.has(e.id)||(this.seeds.set(e.id,{id:e.id,name:e.name,source:e.source,magnet:e.magnet,dir:e.dir,sizeBytes:e.sizeBytes,status:"paused",uploadSpeed:0,uploaded:0,peers:0}),this.changed())}seedRecords(){let e=[];for(let r of this.seeds.values())r.status==="seeding"?e.push({id:r.id,status:"seeding"}):e.push({id:r.id,status:"paused"});return e}persistSeeds(){return Fr(this.seedRecords()).catch(()=>{})}restore(e){for(let r of e)this.items.set(r.id,r),r.status==="downloading"&&this.startEngine(r);this.activeCount>0&&this.ensurePoll(),this.changed()}restoreHistory(e){this.history=e.slice(0,Vr)}getHistory(){return this.history}recordHistory(e){let r={id:e.id,name:e.name,source:e.source,sizeBytes:e.totalBytes,magnet:e.magnet,dir:e.dir,completedAt:Date.now()};this.history=[r,...this.history.filter(o=>o.id!==e.id)].slice(0,Vr),Rt(this.history).catch(()=>{})}removeHistory(e){let r=this.history.filter(o=>o.id!==e);r.length!==this.history.length&&(this.history=r,this.seeds.has(e)&&(this.engine.remove(e),this.seeds.delete(e),this.strayHits.delete(e),this.seedStartedAt.delete(e),this.persistSeeds(),this.maybeStopPoll()),Ct(e),Rt(this.history).catch(()=>{}),this.changed())}clearHistory(){if(this.history.length!==0){for(let e of this.history)Ct(e.id);if(this.history=[],this.seeds.size>0){for(let e of this.seeds.keys())this.engine.remove(e);this.seeds.clear(),this.strayHits.clear(),this.seedStartedAt.clear(),this.persistSeeds(),this.maybeStopPoll()}Rt(this.history).catch(()=>{}),this.changed()}}changed(){this.emit("update")}async persist(){await _r(this.getItems()).catch(()=>{})}persistSync(){Lr(this.getItems()),Wr(this.history),Ur(this.seedRecords())}suspend(){for(let e of this.items.values())e.status==="downloading"&&(e.speed=0,e.peers=0,e.eta=void 0);this.persistSync(),this.poll&&(clearInterval(this.poll),this.poll=null),this.engine.destroy()}};function qr(t){let e=new Set,r=[];for(let o of t){if(!o?.id||e.has(o.id)||(e.add(o.id),o.status==="completed"))continue;let n=o.status==="failed"?"failed":o.status==="paused"?"paused":"downloading";r.push({...o,status:n,speed:0,peers:0,eta:void 0})}return r}var zn=["udp://tracker.opentrackr.org:1337/announce","udp://open.demonii.com:1337/announce","udp://tracker.openbittorrent.com:6969/announce","udp://tracker.torrent.eu.org:451/announce","udp://exodus.desync.com:6969/announce","udp://open.stealth.si:80/announce","udp://tracker.dler.org:6969/announce"];function de(t,e){let r=encodeURIComponent(e),o=zn.map(n=>`&tr=${encodeURIComponent(n)}`).join("");return`magnet:?xt=urn:btih:${t}&dn=${r}${o}`}var Gn=/xt=urn:btih:([a-f0-9]{40}|[a-z2-7]{32})/i,Qn="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function Wn(t){let e=0,r=0,o="";for(let n of t.toUpperCase()){let s=Qn.indexOf(n);if(s===-1)return null;r=r<<5|s,e+=5,e>=8&&(e-=8,o+=(r>>>e&255).toString(16).padStart(2,"0"),r&=(1<<e)-1)}return o.length===40?o:null}function jn(t){return t.length===32?Wn(t)??t.toLowerCase():t.toLowerCase()}function Fe(t){let e=t.trim();if(!/^magnet:\?/i.test(e))return null;let r=Gn.exec(e);if(!r)return null;let o=jn(r[1]),n=o;try{let s=new URL(e).searchParams.get("dn");s&&(n=s)}catch{}return{infoHash:o,name:n,magnet:e}}import{promises as Vn}from"fs";import qn from"parse-torrent";async function Yr(t){try{let e=await Vn.readFile(t),r=await qn(new Uint8Array(e)),o=r?.infoHash?.toLowerCase();if(!o)return null;let n=r.name||o;return{infoHash:o,name:n,magnet:de(o,n)}}catch{return null}}import{spawn as Kr}from"child_process";function Jt(t,e){return new Promise(r=>{let o="";try{let n=Kr(t,e,{windowsHide:!0}),s=setTimeout(()=>{try{n.kill()}catch{}r("")},4e3);s.unref?.(),n.stdout.on("data",i=>o+=i.toString("utf8")),n.on("error",()=>{clearTimeout(s),r("")}),n.on("close",()=>{clearTimeout(s),r(o)})}catch{r("")}})}function Xt(t,e,r){return new Promise(o=>{try{let n=Kr(t,e,{windowsHide:!0}),s=!1,i,a=l=>{s||(s=!0,clearTimeout(i),o(l))};i=setTimeout(()=>{try{n.kill()}catch{}a(!1)},4e3),i.unref?.(),n.on("error",()=>a(!1)),n.on("close",l=>a(l===0)),n.stdin?.end(r)}catch{o(!1)}})}var Yn=[["wl-paste",["--no-newline"]],["xclip",["-selection","clipboard","-o"]],["xsel",["-b"]]],Kn=[["wl-copy",[]],["xclip",["-selection","clipboard"]],["xsel",["-b","-i"]]];async function Jr(){if(process.platform==="win32")return(await Jt("powershell",["-NoProfile","-Command","Get-Clipboard"])).trim();if(process.platform==="darwin")return(await Jt("pbpaste",[])).trim();for(let[t,e]of Yn){let r=(await Jt(t,e)).trim();if(r)return r}return""}async function Xr(t){if(process.platform==="win32")return Xt("powershell",["-NoProfile","-Command","Set-Clipboard -Value ([Console]::In.ReadToEnd())"],t);if(process.platform==="darwin")return Xt("pbcopy",[],t);for(let[e,r]of Kn)if(await Xt(e,r,t))return!0;return!1}function be(t){if(t===void 0||!Number.isFinite(t)||t<=0)return"0 B";let e=["B","KB","MB","GB","TB"],r=t,o=0;for(;r>=1024&&o<e.length-1;)r/=1024,o++;return`${r.toFixed(o===0?0:2)} ${e[o]}`}var Jn={B:1,KIB:1024,MIB:1024**2,GIB:1024**3,TIB:1024**4,KB:1e3,MB:1e6,GB:1e9,TB:1e12};function Bt(t){let e=t.match(/([\d.]+)\s*([KMGT]?I?B)/i);return e?Math.round(parseFloat(e[1])*(Jn[e[2].toUpperCase()]??1)):0}function rt(t){if(t===void 0||!Number.isFinite(t)||t<=0)return"";let e=["B/s","KB/s","MB/s","GB/s"],r=t,o=0;for(;r>=1024&&o<e.length-1;)r/=1024,o++;return`${r.toFixed(r<10&&o>0?1:0)} ${e[o]}`}function ot(t){if(!t||!Number.isFinite(t)||t<=0)return"";let e=Date.now()/1e3-t;if(e<60)return"now";let r=Math.floor(e/60);if(r<60)return`${r}m ago`;let o=Math.floor(r/60);if(o<24){let i=r%60;return i>0?`${o}hr ${i}m ago`:`${o}hr ago`}let n=Math.floor(o/24);if(n<30){let i=o%24;return i>0?`${n}d ${i}hr ago`:`${n}d ago`}let s=Math.floor(n/30);return s<12?`${s}mo ago`:`${Math.floor(s/12)}y ago`}function Zr(t){if(t===void 0||!Number.isFinite(t)||t<0)return"";let e=Math.round(t),r=Math.floor(e/86400),o=Math.floor(e%86400/3600),n=Math.floor(e%3600/60),s=e%60;return r>0?[`${r}d`,o>0?`${o}hr`:"",n>0?`${n}m`:""].filter(Boolean).join(" "):o>0?n>0?`${o}hr ${n}m`:`${o}hr`:n>0?s>0?`${n}m ${s}s`:`${n}m`:`${s}s`}function Xn(t){return t<32||t===127||t===65533||t>=8203&&t<=8207||t>=8232&&t<=8238||t===8288||t===65279||t===8205||t===65039||t===8419||t>=9728&&t<=10175||t>=11008&&t<=11263||t>=126976&&t<=131071}function ie(t){let e="";for(let r of t.normalize("NFC"))Xn(r.codePointAt(0))||(e+=r);return e.replace(/\s+/g," ").trim()||"Untitled"}function J(t,e){return e<=1?t.slice(0,Math.max(0,e)):t.length<=e?t:t.slice(0,e-1)+"\u2026"}import{createContext as Zn,useContext as es,useEffect as Zt,useState as er}from"react";var nt=[{key:"all",label:"All"},{key:"games",label:"Games",group:"Games"},{key:"movies",label:"Movies",group:"Movies"},{key:"tv",label:"TV",group:"TV"},{key:"anime",label:"Anime",group:"Anime"}],It=Zn(null);function X(){let t=es(It);if(!t)throw new Error("Store not available");return t}function Ue(t){let[e,r]=er(()=>t.getItems());return Zt(()=>{let o=null,n=()=>{o||(o=setTimeout(()=>{o=null,r(t.getItems())},200))};return t.on("update",n),n(),()=>{t.off("update",n),o&&clearTimeout(o)}},[t]),e}function Mt(t){let[e,r]=er(()=>t.getHistory());return Zt(()=>{let o=null,n=()=>{o||(o=setTimeout(()=>{o=null,r(t.getHistory())},200))};return t.on("update",n),n(),()=>{t.off("update",n),o&&clearTimeout(o)}},[t]),e}function eo(t){let[e,r]=er(()=>new Map(t.getSeeds().map(o=>[o.id,o])));return Zt(()=>{let o=null,n=()=>{o||(o=setTimeout(()=>{o=null,r(new Map(t.getSeeds().map(s=>[s.id,s])))},200))};return t.on("update",n),n(),()=>{t.off("update",n),o&&clearTimeout(o)}},[t]),e}import{Box as so,Text as tr}from"ink";var kt=[" \u{104CF} "," \u2580\u2588\u2580 \u2588\u2580\u2588 \u2588\u2580\u2588 \u2588 \u2588 \u2588\u2584 \u2588 \u2588\u2584\u2580"," \u2588 \u2588\u2584\u2588 \u2588\u2580\u2584 \u2588\u2584\u2584 \u2588 \u2588 \u2580\u2588 \u2588 \u2588"],to=Math.max(...kt.map(t=>[...t].length)),ro=new Set(["0,6"]);var d={accent:"#a78bfa",text:"#e9e4f5",alt:"#b9a7e6",good:"#86d6a2",warn:"#f0c560",bad:"#ee7d92",bright:"#d8b4fe"},b={done:"\u2713",error:"\u2717",pending:"\xB7",pointer:"\u276F",dot:"\xB7",warn:"\u26A0",bar:"\u258C",down:"\u2193",up:"\u2191",peer:"\u2022",pause:"\u23F8"},we="#6b6577",Z=2,Re={fitgirl:{tag:"FG",color:d.accent},yts:{tag:"YTS",color:d.good},eztv:{tag:"EZTV",color:d.warn},nyaa:{tag:"NYAA",color:d.bright},subsplease:{tag:"SUB",color:"#b9a7e6"},solid:{tag:"SLD",color:"#60a5fa"},"tpb-movies":{tag:"TPB",color:"#5fd0c5"},"tpb-tv":{tag:"TPB",color:"#5fd0c5"},"x1337-movies":{tag:"1337",color:"#f6a55c"},"x1337-tv":{tag:"1337",color:"#f6a55c"}};function oo(t){let e=parseInt(t.slice(1),16);return[e>>16&255,e>>8&255,e&255]}function ae(t,e,r){let[o,n,s]=oo(t),[i,a,l]=oo(e),c=(u,p)=>Math.round(u+(p-u)*r).toString(16).padStart(2,"0");return`#${c(o,i)}${c(n,a)}${c(s,l)}`}var no=[d.accent,d.bright];import{jsx as st}from"react/jsx-runtime";var ts="#ffffff",io=d.bright,ao="#7c5cd6",rs="#4c3a8a",os="#5ae87a";function ns(t){return t<.15?ae(ts,io,t/.15):t<.4?ae(io,d.accent,(t-.15)/.25):t<.7?ae(d.accent,ao,(t-.4)/.3):ae(ao,rs,(t-.7)/.3)}function At(){let t=kt.length;return st(so,{flexDirection:"column",children:kt.map((e,r)=>{let o=Math.max(0,r-1),n=Math.max(1,t-1),s=o/(n-1||1),i=[...e],a=Math.max(1,i.length-1);return st(so,{children:i.map((l,c)=>{if(l===" ")return st(tr,{children:" "},c);if(ro.has(`${r},${c}`))return st(tr,{bold:!0,color:os,children:l},c);let p=(c/a+s)/2;return st(tr,{bold:!0,color:ns(p),children:l},c)})},r)})})}import{Box as it,Text as rr,useInput as ss}from"ink";function he(t,e,r){return r<=0?0:((t+e)%r+r)%r}function Ae(t,e,r){if(e<=r)return 0;let o=Math.floor(r/2);return Math.max(0,Math.min(t-o,e-r))}import{jsx as Pe,jsxs as us}from"react/jsx-runtime";var is=nt.map(t=>({key:t.key,label:t.label})),as=[{key:"downloads",label:"Downloads"},{key:"seeding",label:"Seeding"}],ls=t=>t==="downloads"||t==="seeding",lo=[is,as],ze=lo.flat(),cs=5,or=Z+Math.max(...ze.map(t=>t.label.length+(ls(t.key)?cs:0)));function co(){let{section:t,setSection:e,region:r,setRegion:o,queue:n}=X(),s=r==="sidebar",i=Math.max(0,ze.findIndex(c=>c.key===t));Ue(n);let a=n.activeCount,l=n.seedingCount;return ss((c,u)=>{u.upArrow?e(ze[he(i,-1,ze.length)].key):u.downArrow?e(ze[he(i,1,ze.length)].key):u.return&&o("content")},{isActive:s}),Pe(it,{flexDirection:"column",width:or,marginRight:1,children:lo.map((c,u)=>Pe(it,{flexDirection:"column",marginTop:u>0?1:0,children:c.map(p=>{let f=p.key===t;return us(it,{children:[Pe(it,{width:Z,flexShrink:0,children:f?Pe(rr,{color:s?no[1]:we,bold:s,children:b.bar}):null}),Pe(rr,{color:f?s?d.accent:d.alt:void 0,dimColor:!f,bold:f&&s,children:p.label}),(()=>{let x=p.key==="downloads"?a:p.key==="seeding"?l:0;return x>0?Pe(it,{flexShrink:0,children:Pe(rr,{dimColor:!0,children:` (${x})`})}):null})()]},p.key)})},u))})}import{Text as ds}from"ink";import{jsx as ms}from"react/jsx-runtime";function Pt({width:t}){return ms(ds,{color:we,children:"\u2500".repeat(Math.max(1,t))})}import{Box as fs,Text as at}from"ink";import{jsx as lt,jsxs as ps}from"react/jsx-runtime";function uo({hints:t}){return lt(fs,{children:lt(at,{children:t.map((e,r)=>ps(at,{children:[r>0?lt(at,{dimColor:!0,children:" "}):null,lt(at,{color:d.alt,children:e.keys}),lt(at,{dimColor:!0,children:` ${e.label}`})]},e.keys+e.label))})})}import{Box as Qe,Text as We}from"ink";var Ge=[{title:"Navigate",hints:[{keys:"\u2191 \u2193 \u2190 \u2192",label:"Navigate content and panes"},{keys:"\u21B5",label:"Open"},{keys:"tab",label:"Switch pane"},{keys:"esc",label:"Back"},{keys:"o",label:"Download folder"},{keys:"q",label:"Quit"}]},{title:"Search",hints:[{keys:"/",label:"Edit search"},{keys:"\u21B5",label:"Run search"},{keys:"s",label:"Sort results"},{keys:"y",label:"Copy magnet"},{keys:"m",label:"Paste magnet"}]},{title:"Downloads",hints:[{keys:"p",label:"Pause/resume"},{keys:"c",label:"Cancel or remove from list"},{keys:"f",label:"Retry failed"},{keys:"d",label:"Download again"},{keys:"x",label:"Clear recent"}]},{title:"Seeding",hints:[{keys:"p",label:"Pause/resume"},{keys:"c",label:"Remove from list"}]}],nr={keys:"\u2191\u2193\u2190\u2192",label:"Move"},He={keys:"?",label:"Keys"},$e={keys:"tab",label:"Switch"};function mo(t,e,r,o){return t==="sidebar"?[nr,{keys:"\u21B5",label:"Open"},$e,He,{keys:"q",label:"Quit"}]:e==="seeding"?[{keys:"p",label:o==="seeding"?"Pause":o==="missing"?"Retry":"Resume"},{keys:"c",label:"Remove"},$e,He]:e==="downloads"?r==="paused"?[{keys:"p",label:"Resume"},{keys:"c",label:"Cancel"},$e,He]:r==="failed"?[{keys:"f",label:"Retry"},{keys:"c",label:"Remove"},$e,He]:r==="recent"?[nr,{keys:"d",label:"Download again"},{keys:"c",label:"Remove"},{keys:"x",label:"Clear"},$e,He]:[{keys:"p",label:"Pause"},{keys:"c",label:"Cancel"},$e,He]:[nr,{keys:"d",label:"Download"},{keys:"y",label:"Copy"},{keys:"s",label:"Sort"},{keys:"/",label:"Search"},$e,He]}import{jsx as Ee,jsxs as Ht}from"react/jsx-runtime";var hs=ae(d.accent,we,.55),gs=2,fo=2,sr=Ge.map(t=>Math.max(...t.hints.map(e=>e.keys.length))+gs),po=Ge.map((t,e)=>sr[e]+Math.max(...t.hints.map(r=>r.label.length))),xs=po.reduce((t,e)=>t+e,0)+(Ge.length-1)*fo+4,Ss=Math.max(...sr);function ho(){let{cols:t}=X(),e=t>=xs;return Ht(Qe,{flexDirection:"column",alignSelf:"flex-start",borderStyle:"round",borderColor:hs,paddingX:e?1:2,paddingY:1,children:[Ee(We,{bold:!0,color:d.accent,children:"Keyboard"}),Ee(Qe,{marginTop:1,flexDirection:e?"row":"column",children:Ge.map((r,o)=>Ht(Qe,{flexDirection:"column",width:e?po[o]:void 0,marginRight:e&&o<Ge.length-1?fo:0,marginTop:!e&&o>0?1:0,children:[Ee(We,{bold:!0,children:r.title}),r.hints.map(n=>Ht(Qe,{children:[Ee(Qe,{width:e?sr[o]:Ss,flexShrink:0,children:Ee(We,{color:d.alt,children:n.keys})}),Ee(We,{dimColor:!0,children:n.label})]},n.keys+n.label))]},r.title))}),Ht(Qe,{marginTop:1,flexDirection:"column",children:[Ee(We,{dimColor:!0,children:"Your downloaded files always stay on disk."}),Ee(We,{dimColor:!0,children:"Press ? or esc to close"})]})]})}import{useEffect as fr,useMemo as pr,useState as Lt}from"react";import{Box as M,Text as w,useInput as hr}from"ink";import{useEffect as ys,useState as ws}from"react";import{Text as ir}from"ink";import{jsx as xo,jsxs as bs}from"react/jsx-runtime";var go=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];function $t({label:t}){let[e,r]=ws(0);return ys(()=>{let o=setInterval(()=>r(n=>(n+1)%go.length),80);return o.unref?.(),()=>clearInterval(o)},[]),bs(ir,{children:[xo(ir,{color:d.accent,children:go[e]}),t?xo(ir,{dimColor:!0,children:` ${t}`}):null]})}import{Box as To,Text as cr}from"ink";import{useState as So}from"react";import{Text as Be,useInput as Ts}from"ink";import{jsx as je,jsxs as wo}from"react/jsx-runtime";function vs(t,e){return e===0?{value:t,cursor:e}:{value:t.slice(0,e-1)+t.slice(e),cursor:e-1}}function Cs(t,e){let r=e;for(;r>0&&t[r-1]===" ";)r--;for(;r>0&&t[r-1]!==" ";)r--;return{value:t.slice(0,r)+t.slice(e),cursor:r}}function Rs(t,e){return{value:t.slice(0,e),cursor:e}}function Es(t,e,r){return{value:t.slice(0,e)+r+t.slice(e),cursor:e+r.length}}var yo=" ";function Dt({isDisabled:t=!1,defaultValue:e="",placeholder:r="",onChange:o,onSubmit:n,onExitDown:s,onExitLeft:i}){let[a,l]=So(e),[c,u]=So(e.length);function p(S){l(S.value),u(Math.max(0,Math.min(S.value.length,S.cursor))),S.value!==a&&o?.(S.value)}if(Ts((S,y)=>{if(y.downArrow){s?.();return}if(y.upArrow||y.tab||y.ctrl&&S==="c")return;if(y.return){n?.(a);return}if(y.ctrl)switch(S){case"u":p({value:"",cursor:0});return;case"w":p(Cs(a,c));return;case"k":p(Rs(a,c));return;case"a":u(0);return;case"e":u(a.length);return;default:return}if(y.leftArrow){if(c===0){i?.();return}u(c-1);return}if(y.rightArrow){u(Math.min(a.length,c+1));return}if(y.backspace||y.delete){p(vs(a,c));return}if(y.meta||!S)return;let R=S.replace(/\x1b?\[<\d+;\d+;\d+[Mm]/g,"");R&&p(Es(a,c,R))},{isActive:!t}),t)return a?je(Be,{children:a}):je(Be,{dimColor:!0,children:r});if(a.length===0)return r?wo(Be,{children:[je(Be,{inverse:!0,children:r[0]}),je(Be,{dimColor:!0,children:r.slice(1)})]}):je(Be,{inverse:!0,children:yo});let f=a.slice(0,c),x=a[c]??yo,v=c<a.length?a.slice(c+1):"";return wo(Be,{children:[f,je(Be,{inverse:!0,children:x}),v]})}import{Box as ar,Text as lr}from"ink";import{jsx as Ot,jsxs as bo}from"react/jsx-runtime";function me({title:t,width:e,focused:r,count:o,height:n,children:s}){let i=r?d.accent:we,a=Math.max(10,e),l=t.charAt(0).toUpperCase()+t.slice(1),c=o?`${l} ${o}`:l,u=Math.max(0,a-5-c.length);return bo(ar,{flexDirection:"column",width:a,children:[bo(ar,{children:[Ot(lr,{color:i,children:"\u256D\u2500 "}),Ot(lr,{bold:!0,color:i,children:c}),Ot(lr,{color:i,children:` ${"\u2500".repeat(u)}\u256E`})]}),Ot(ar,{width:a,height:n,flexGrow:n?0:1,flexDirection:"column",borderStyle:"round",borderTop:!1,borderColor:i,paddingX:1,overflow:"hidden",children:s})]})}import{jsx as Ve,jsxs as Bs}from"react/jsx-runtime";function _t({width:t,value:e,placeholder:r="Search torrents\u2026",editing:o,onSubmit:n,onChange:s,onExitDown:i,onExitLeft:a}){return Ve(me,{title:"search",width:t,focused:o,height:2,children:Bs(To,{children:[Ve(cr,{color:d.accent,children:`${b.pointer} `}),Ve(To,{flexGrow:1,minWidth:0,children:o?Ve(Dt,{defaultValue:e,placeholder:r,onSubmit:n,onChange:s,onExitDown:i,onExitLeft:a}):e?Ve(cr,{wrap:"truncate-end",children:e}):Ve(cr,{dimColor:!0,children:r})})]})})}import{useEffect as ci,useState as ui}from"react";var G="torlink (+https://www.npmjs.com/package/torlnq)",H=class extends Error{status;constructor(e,r){super(r??`HTTP ${e}`),this.name="HttpError",this.status=e}},Is=new Set([408,425,429,500,502,503,504]),Ms=5,ks=500,As=2e4;function Ps(t){return new Promise(e=>setTimeout(e,t))}function Hs(t){return t instanceof Error&&(t.name==="AbortError"||/aborted/i.test(t.message))}function $s(t,e=Date.now()){if(!t)return;let r=t.trim();if(/^\d+$/.test(r))return Number(r)*1e3;let o=Date.parse(r);if(!Number.isNaN(o))return Math.max(0,o-e)}function vo(t,e,r,o,n=Math.random){let s=Math.min(r,e*2**t),i=Math.floor(n()*s);return o!==void 0?Math.max(i,o):i}async function Q(t,e={}){let{retries:r=Ms,baseMs:o=ks,capMs:n=As,fetchImpl:s=fetch,sleepImpl:i=Ps,signal:a,...l}=e,c=a?{...l,signal:a}:l,u;for(let p=0;p<=r;p++){if(a?.aborted)throw new H(0,"aborted");let f;try{f=await s(t,c)}catch(S){if(Hs(S)||a?.aborted)throw S;if(u=S,p<r){await i(vo(p,o,n));continue}throw S}if(!Is.has(f.status))return f;let x=f.headers.get("server")?.toLowerCase()||"";if(f.status===503&&(x.includes("ddos-guard")||x.includes("cloudflare")))throw new H(f.status,`Request to ${t} blocked by ${x} (HTTP ${f.status}).`);if(p>=r)throw new H(f.status,`Request to ${t} failed after ${r} retries (HTTP ${f.status}).`);let v=$s(f.headers.get("retry-after"));await i(vo(p,o,n,v))}throw u instanceof Error?u:new H(0,"fetchResilient exhausted without a response")}var Ds="https://eztvx.to/api/get-torrents";async function Os(t,e={}){if(t.trim())return[];let r=await Q(`${Ds}?limit=100&page=1`,{headers:{"User-Agent":G},signal:e.signal,retries:1});if(!r.ok)throw new H(r.status,`EZTV returned ${r.status}`);let o=await r.json(),n=[];for(let s of o.torrents??[]){let i=(s.hash??"").toLowerCase(),a=s.title||s.filename||i,l=s.magnet_url||(i?de(i,a):"");!l||!i||n.push({infoHash:i,name:a,sizeBytes:Number(s.size_bytes??0)||0,seeders:s.seeds??0,leechers:s.peers??0,source:"eztv",magnet:l,added:s.date_released_unix})}return n}var Co={id:"eztv",label:"EZTV",group:"TV",homepage:"https://eztvx.to",search:Os};function De(t){return t.replace(/&#0?38;|&amp;/g,"&").replace(/&#8211;|&#8212;/g,"-").replace(/&#8217;|&#0?39;|&apos;/g,"'").replace(/&#8220;|&#8221;|&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">")}function _s(t,e){let r=t.split("<item>").slice(1),o=[];for(let n of r){let s=n.match(/href="(magnet:\?xt=urn:btih:[^"]+)"/i);if(!s)continue;let i=De(s[1]),a=i.match(/urn:btih:([a-zA-Z0-9]+)/)?.[1]?.toLowerCase()??"";if(!a)continue;let l=De(n.match(/<title>(.*?)<\/title>/)?.[1]??"Unknown Title"),c=n.match(/<pubDate>(.*?)<\/pubDate>/)?.[1]??"",u=c?new Date(c).getTime()/1e3:0;o.push({infoHash:a,name:l,sizeBytes:0,seeders:0,leechers:0,source:e,magnet:i,added:u})}return o}async function Ro(t,e,r,o={}){let n=r.trim(),s=n?`${t}/?s=${encodeURIComponent(n)}&feed=rss2`:`${t}/feed/`,i=await Q(s,{headers:{"User-Agent":G},signal:o.signal});if(!i.ok)throw new H(i.status,`${e} feed returned ${i.status}`);return _s(await i.text(),e)}var Eo="https://fitgirl-repacks.site",Bo={id:"fitgirl",label:"FitGirl",group:"Games",homepage:Eo,search:(t,e)=>Ro(Eo,"fitgirl",t,e)};var Ls="https://nyaa.si/";function qe(t,e){return t.match(new RegExp(`<${e}>(?:<!\\[CDATA\\[)?(.*?)(?:\\]\\]>)?</${e}>`,"s"))?.[1]?.trim()??""}async function Ns(t,e={}){let r=new URLSearchParams({page:"rss",q:t.trim(),c:"0_0",f:"0"}),o=await Q(`${Ls}?${r.toString()}`,{headers:{"User-Agent":G},signal:e.signal});if(!o.ok)throw new H(o.status,`Nyaa returned ${o.status}`);let n=await o.text(),s=[];for(let i of n.split("<item>").slice(1)){let a=qe(i,"nyaa:infoHash").toLowerCase(),l=De(qe(i,"title"));if(!a||!l)continue;let c=Number(qe(i,"nyaa:seeders")),u=Number(qe(i,"nyaa:leechers")),p=qe(i,"pubDate");s.push({infoHash:a,name:l,sizeBytes:Bt(qe(i,"nyaa:size")),seeders:Number.isFinite(c)?c:0,leechers:Number.isFinite(u)?u:0,source:"nyaa",magnet:de(a,l),added:p?new Date(p).getTime()/1e3:void 0})}return s}var Io={id:"nyaa",label:"Nyaa",group:"Anime",homepage:"https://nyaa.si",search:Ns};var Fs="https://subsplease.org/api/",Us=["1080","720","480"];function zs(t){for(let e of Us){let r=t.find(o=>o.res===e&&o.magnet);if(r)return r}return t.find(e=>e.magnet)}async function Gs(t,e={}){let r=t.trim(),o=new URLSearchParams({tz:"UTC"});r?(o.set("f","search"),o.set("s",r)):o.set("f","latest");let n=await Q(`${Fs}?${o.toString()}`,{headers:{"User-Agent":G},signal:e.signal});if(!n.ok)throw new H(n.status,`SubsPlease returned ${n.status}`);let s=await n.json();if(!s||Array.isArray(s))return[];let i=[];for(let a of Object.values(s)){let l=zs(a.downloads??[]);if(!l?.magnet)continue;let c=Fe(l.magnet);if(!c)continue;let u=a.show??"Unknown",p=a.episode?` - ${a.episode}`:"",f=l.magnet.match(/[?&]xl=(\d+)/);i.push({infoHash:c.infoHash,name:`${u}${p} [${l.res??"?"}p]`,sizeBytes:f?Number(f[1]):0,seeders:0,leechers:0,source:"subsplease",magnet:c.magnet,added:a.release_date?new Date(a.release_date).getTime()/1e3:void 0})}return i}var Mo={id:"subsplease",label:"SubsPlease",group:"Anime",homepage:"https://subsplease.org",search:Gs};async function Qs(t,e={}){let r=t.trim()||"tv show",n=`https://solidtorrents.net/api/v1/search?${new URLSearchParams({q:r}).toString()}`,s=await Q(n,{headers:{"User-Agent":G},signal:e.signal,retries:1});if(!s.ok)throw new H(s.status,`SolidTorrents returned ${s.status}`);let i=await s.json(),a=[];for(let l of i.results??[]){if(!l.infohash)continue;let c=l.infohash.toLowerCase(),u=l.title||"Unknown",p=l.updatedAt?Math.floor(new Date(l.updatedAt).getTime()/1e3):void 0;a.push({infoHash:c,name:u,sizeBytes:l.size??0,seeders:l.seeders??0,leechers:l.leechers??0,source:"solid",magnet:de(c,u),added:p})}return a}var ko={id:"solid",label:"Solid",group:"TV",homepage:"https://solidtorrents.net",search:Qs};var ur="https://apibay.org",Ws=new Set([201,202,207,209]),js=new Set([205,208]),Vs=`${ur}/precompiled/data_top100_207.json`,qs=`${ur}/precompiled/data_top100_208.json`,Ys="0000000000000000000000000000000000000000";function Ks(t,e){let r=(t.info_hash??"").toLowerCase();if(!r||r===Ys||t.id==="0")return null;let o=t.name||"Unknown",n=Number(t.num_files);return{infoHash:r,name:o,sizeBytes:Number(t.size)||0,seeders:Number(t.seeders)||0,leechers:Number(t.leechers)||0,numFiles:Number.isFinite(n)&&n>0?n:void 0,source:e,magnet:de(r,o),added:Number(t.added)||void 0}}async function Js(t,e){let r=await Q(t,{headers:{"User-Agent":G},signal:e.signal,retries:1});if(!r.ok)throw new H(r.status,`Pirate Bay returned ${r.status}`);let o=await r.json();return Array.isArray(o)?o:[]}async function Ao(t,e,r,o,n){let s=t.trim(),i=await Js(s?`${ur}/q.php?q=${encodeURIComponent(s)}`:r,n),a=[];for(let l of i){if(s&&!e.has(Number(l.category)))continue;let c=Ks(l,o);c&&a.push(c)}return a}var Po={id:"tpb-movies",label:"TPB",group:"Movies",homepage:"https://thepiratebay.org",search:(t,e={})=>Ao(t,Ws,Vs,"tpb-movies",e)},Ho={id:"tpb-tv",label:"TPB",group:"TV",homepage:"https://thepiratebay.org",search:(t,e={})=>Ao(t,js,qs,"tpb-tv",e)};var Xs=["1337x.to","1337x.st","x1337x.ws","1337xx.to"],Zs=8,ei=new Set(["the","a","an","of","and","or","to"]);function ti(t){let e=t.indexOf("table-list");if(e<0)return[];let r=[];for(let o of t.slice(e).split(/<tr[\s>]/i).slice(1)){let n=o.match(/href="(\/torrent\/[^"]+)"[^>]*>([^<]+)<\/a>/i);if(!n)continue;let s=o.match(/class="coll-4 size[^"]*">\s*([\d.]+\s*[KMGT]i?B)/i)?.[1]??"";r.push({name:De(n[2].trim()),path:n[1],seeders:Number(o.match(/class="coll-2 seeds[^"]*">\s*(\d+)/i)?.[1]??0),leechers:Number(o.match(/class="coll-3 leeches[^"]*">\s*(\d+)/i)?.[1]??0),sizeBytes:Bt(s)})}return r}async function $o(t,e,r){let o=await Q(t,{headers:{"User-Agent":G},signal:e.signal,retries:r});if(!o.ok)throw new H(o.status,`1337x returned ${o.status}`);return o.text()}async function ri(t,e,r){try{let n=(await $o(`${t}${e}`,r,1)).match(/magnet:\?xt=urn:btih:[^"'<>\s]+/i)?.[0];return n?De(n):null}catch{return null}}async function Do(t,e,r,o={}){let n=t.trim(),s=n?`/category-search/${encodeURIComponent(n).replace(/%20/g,"+")}/${e}/1/`:`/popular-${e==="Movies"?"movies":"tv"}`,i="",a="",l;for(let y of Xs)try{let R=`https://${y}`;a=await $o(`${R}${s}`,o,2),i=R;break}catch(R){if(o.signal?.aborted)throw R;l=R}if(!i)throw l instanceof Error?l:new H(0,"1337x unreachable");let c=ti(a),u=n.toLowerCase().split(/\s+/).filter(Boolean),p=u.filter(y=>!ei.has(y)),f=p.length?p:u,x=f.length?c.filter(y=>{let R=y.name.toLowerCase();return f.every(k=>R.includes(k))}):c;x.sort((y,R)=>R.seeders-y.seeders);let v=x.slice(0,Zs);return(await Promise.all(v.map(async y=>{let R=await ri(i,y.path,o),k=R?.match(/urn:btih:([a-zA-Z0-9]+)/i)?.[1]?.toLowerCase();return!R||!k?null:{infoHash:k,name:y.name,sizeBytes:y.sizeBytes,seeders:y.seeders,leechers:y.leechers,source:r,magnet:R}}))).filter(y=>y!==null)}var Oo={id:"x1337-movies",label:"1337x",group:"Movies",homepage:"https://1337x.to",search:(t,e={})=>Do(t,"Movies","x1337-movies",e)},_o={id:"x1337-tv",label:"1337x",group:"TV",homepage:"https://1337x.to",search:(t,e={})=>Do(t,"TV","x1337-tv",e)};var oi=["yts.mx","yts.am","yts.rs"];async function ni(t,e){let r;for(let o of oi)try{let n=await Q(`https://${o}/api/v2/list_movies.json?${t.toString()}`,{headers:{"User-Agent":G},signal:e.signal,retries:1});if(n.ok)return await n.json();r=new H(n.status,`YTS returned ${n.status}`)}catch(n){if(e.signal?.aborted)throw n;r=n}throw r instanceof Error?r:new H(0,"YTS unreachable")}async function si(t,e={}){let r=t.trim(),o=new URLSearchParams({limit:"50"});r?o.set("query_term",r):o.set("sort_by","date_added");let n=await ni(o,e),s=[];for(let i of n.data?.movies??[]){let a=i.title_long||i.title||"Unknown";for(let l of i.torrents??[]){if(!l.hash)continue;let c=l.hash.toLowerCase(),u=[l.quality,l.type].filter(Boolean).join(" "),p=u?`${a} [${u}]`:a;s.push({infoHash:c,name:p,sizeBytes:l.size_bytes??0,seeders:l.seeds??0,leechers:l.peers??0,source:"yts",magnet:de(c,p),added:i.date_uploaded_unix})}}return s}var Lo={id:"yts",label:"YTS",group:"Movies",homepage:"https://yts.mx",search:si};var ee=[Bo,Lo,Po,Oo,Co,ko,Ho,_o,Io,Mo],ii=ee[0];function No(t){return ee.find(e=>e.id===t)??ii}var ai=["Games","Movies","TV","Anime"];function Fo(){return ai.map(t=>({group:t,sources:ee.filter(e=>e.group===t)})).filter(t=>t.sources.length>0)}var Uo=new Map;function li(t,e){return`${t}::${e.trim().toLowerCase()}`}async function zo(t,e,r={}){let o=li(t.id,e),n=Uo.get(o);if(n&&Date.now()-n.at<3e5)return n.results;let s=await t.search(e,r);return Uo.set(o,{at:Date.now(),results:s}),s}function di(t,e){return e?"timed out":t instanceof H&&t.status>0?`HTTP ${t.status}`:"no response"}var mi=25e3;function Go(t){let e={};for(let r of ee)e[r.id]={loading:t,error:null,code:null,count:0};return e}function fi(t){let e=new Map;for(let r of t){let o=e.get(r.infoHash);(!o||r.seeders>o.seeders)&&e.set(r.infoHash,r)}return[...e.values()]}function pi(t){return t.sort((e,r)=>r.seeders!==e.seeders?r.seeders-e.seeders:(r.added??0)-(e.added??0))}function hi(){return{results:[],perSource:Go(!1),loading:!1,done:0,total:ee.length}}function Qo(t){let[e,r]=ui(hi);return ci(()=>{let o=new AbortController,n=!0,s=[],i=Go(!0),a=0;r({results:[],perSource:{...i},loading:!0,done:0,total:ee.length});for(let l of ee){let c=new AbortController,u=()=>c.abort();o.signal.addEventListener("abort",u);let p=setTimeout(()=>c.abort(),mi);zo(l,t,{signal:c.signal}).then(f=>{n&&(s.push(...f),i[l.id]={loading:!1,error:null,code:null,count:f.length})}).catch(f=>{if(!n||o.signal.aborted)return;let x=c.signal.aborted;i[l.id]={loading:!1,error:x?"timed out":f instanceof Error?f.message:String(f),code:di(f,x),count:0}}).finally(()=>{clearTimeout(p),o.signal.removeEventListener("abort",u),n&&(a+=1,r({results:pi(fi(s.slice())),perSource:{...i},loading:a<ee.length,done:a,total:ee.length}))})}return()=>{n=!1,o.abort()}},[t]),e}var dr=["none",{field:"size",dir:"asc"},{field:"size",dir:"desc"},{field:"seeders",dir:"asc"},{field:"seeders",dir:"desc"},{field:"source",dir:"asc"},{field:"source",dir:"desc"}];function gi(t,e){return t==="none"||e==="none"?t===e:t.field===e.field&&t.dir===e.dir}function Wo(t){let e=dr.findIndex(r=>gi(r,t));return dr[(e+1)%dr.length]}function mr(t){return t==="asc"?"\u25B4":"\u25BE"}function jo(t){return t==="none"?"default":`${t.field} ${mr(t.dir)}`}function Vo(t,e){let r=t.slice();if(e==="none")return r;let o=e.dir==="asc"?1:-1;switch(e.field){case"size":r.sort((n,s)=>o*(n.sizeBytes-s.sizeBytes)||s.seeders-n.seeders);break;case"seeders":r.sort((n,s)=>o*(n.seeders-s.seeders)||(s.added??0)-(n.added??0));break;case"source":r.sort((n,s)=>o*n.source.localeCompare(s.source)||s.seeders-n.seeders);break}return r}import{Fragment as Nt,jsx as m,jsxs as te}from"react/jsx-runtime";var xi="Search or paste a magnet link\u2026";function Ye({label:t,value:e}){return te(M,{children:[m(M,{width:9,flexShrink:0,children:m(w,{dimColor:!0,children:t})}),m(M,{flexGrow:1,minWidth:0,children:e})]})}function Si({r:t,width:e}){let r=Re[t.source],o=ot(t.added),n=t.seeders||t.leechers?te(w,{children:[m(w,{color:t.seeders>0?d.good:void 0,bold:t.seeders>0,children:t.seeders}),m(w,{dimColor:!0,children:` seeders ${b.dot} ${t.leechers} leechers`})]}):m(w,{dimColor:!0,children:"unknown"});return te(M,{flexDirection:"column",children:[te(M,{children:[m(M,{flexGrow:1,minWidth:0,children:m(w,{bold:!0,color:d.text,wrap:"truncate-end",children:ie(t.name)})}),m(M,{flexShrink:0,marginLeft:2,children:m(w,{color:r.color,bold:!0,children:r.tag})})]}),m(Pt,{width:e}),te(M,{marginTop:1,flexDirection:"column",children:[m(Ye,{label:"Size",value:t.sizeBytes>0?m(w,{color:d.text,children:be(t.sizeBytes)}):m(w,{dimColor:!0,children:"unknown"})}),m(Ye,{label:"Health",value:n}),t.numFiles?m(Ye,{label:"Files",value:m(w,{dimColor:!0,children:String(t.numFiles)})}):null,o?m(Ye,{label:"Added",value:m(w,{dimColor:!0,children:o})}):null,m(Ye,{label:"Hash",value:m(w,{color:d.alt,dimColor:!0,wrap:"truncate-end",children:t.infoHash})}),m(Ye,{label:"Magnet",value:m(w,{color:d.alt,dimColor:!0,wrap:"truncate-end",children:t.magnet})})]}),te(M,{marginTop:1,children:[m(w,{color:d.accent,bold:!0,children:"d"}),m(w,{color:d.text,children:" Download"}),m(w,{dimColor:!0,children:` ${b.dot} `}),m(w,{color:d.accent,bold:!0,children:"y"}),m(w,{color:d.text,children:" Copy magnet"}),m(w,{dimColor:!0,children:` ${b.dot} `}),m(w,{color:d.alt,children:"esc"}),m(w,{dimColor:!0,children:" back"})]})]})}function qo(){let{query:t,submitQuery:e,section:r,region:o,setRegion:n,setCaptureMode:s,startDownload:i,copyMagnet:a,contentWidth:l,listRows:c}=X(),u=Qo(t),[p,f]=Lt("none"),x=pr(()=>{let g=nt.find(O=>O.key===r),A=g?.group?u.results.filter(O=>No(O.source).group===g.group):u.results;return Vo(A,p)},[u.results,r,p]),v=o==="content",[S,y]=Lt("list"),[R,k]=Lt(0),[F,L]=Lt(null);fr(()=>{k(0)},[x]),fr(()=>{if(v)return s(S==="search"?"text":S==="detail"?"esc":"none"),()=>s("none")},[S,v,s]),fr(()=>{v||y("list")},[v]);let $=Math.min(R,Math.max(0,x.length-1)),V=Math.max(5,c-3-1),D=Math.max(3,V-4),ge=Math.max(1,D-1),ne=g=>i({id:g.infoHash,name:g.name,magnet:g.magnet,source:g.source,sizeBytes:g.sizeBytes}),xe=g=>a({name:g.name,magnet:g.magnet});hr((g,A)=>{if(g==="/"){y("search");return}if(A.upArrow){x.length>0&&$>0?k($-1):y("search");return}if(x.length!==0)if(A.downArrow)k(he($,1,x.length));else if(A.pageUp)k(Math.max(0,$-ge));else if(A.pageDown)k(Math.min(x.length-1,$+ge));else if(A.return){let O=x[$];O&&(L(O),y("detail"))}else if(g==="d"){let O=x[$];O&&ne(O)}else if(g==="y"){let O=x[$];O&&xe(O)}else g==="s"&&f(O=>Wo(O))},{isActive:v&&S==="list"}),hr((g,A)=>{A.escape?(y("list"),L(null)):g==="d"&&F?ne(F):g==="y"&&F&&xe(F)},{isActive:v&&S==="detail"}),hr((g,A)=>{A.escape&&y("list")},{isActive:v&&S==="search"});let q=g=>{y("list"),e(g)},fe=t.trim()==="",Y=pr(()=>Object.values(u.perSource).filter(g=>g.error).length,[u.perSource]),pe=nt.find(g=>g.key===r),ue=pe?.group?ee.filter(g=>g.group===pe.group):ee,h=ue.length>0&&ue.every(g=>u.perSource[g.id]?.error),j=pr(()=>x.some(g=>g.sizeBytes>0||g.seeders>0),[x]),C=Math.max(2,String(x.length).length),se=g=>{let A=[...new Set(g.map(O=>u.perSource[O.id]?.code).filter(Boolean))];return A.length?` (${A.join(", ")})`:""},Se=()=>{if(u.loading)return x.length>0?m(w,{dimColor:!0,children:`searching\u2026 ${u.done}/${u.total} sources`}):m($t,{label:`${fe?"Loading":"Searching"} ${u.done}/${u.total} sources`});if(x.length===0){if(Y>=u.total){let K=ee.filter(ve=>u.perSource[ve.id]?.error);return m(w,{color:d.warn,children:`Couldn't reach any source. They may be down${se(K)}.`})}if(h&&pe){let K=ue.filter(yt=>u.perSource[yt.id]?.error),ve=K.length===1?"The source":`All ${K.length} sources`;return m(w,{color:d.warn,children:`Couldn't reach ${pe.label}. ${ve} may be down${se(K)}.`})}return u.results.length>0&&pe?.group?m(w,{dimColor:!0,children:`No ${pe.label.toLowerCase()} results yet. Try another tab or a search.`}):m(w,{dimColor:!0,children:fe?"Nothing new right now.":`No results for "${J(t,28)}".`})}let g=Y>0?` (${Y} source${Y===1?"":"s"} down)`:"",A=fe?"newest across all sources":`${x.length} result${x.length===1?"":"s"}`,O=p==="none"?"":` ${b.dot} sort: ${jo(p)}`;return m(w,{dimColor:!0,children:`${A}${g}${O}`})},Xe=(g,A)=>p==="none"||p.field!==g?A:te(Nt,{children:[m(w,{color:d.accent,bold:!0,children:mr(p.dir)}),A]}),ye=Ae($,x.length,D),xt=x.slice(ye,ye+D),St=x.length>0?`(${x.length})`:void 0;return te(M,{flexDirection:"column",children:[m(_t,{width:l,value:t,editing:S==="search",placeholder:xi,onSubmit:q,onExitDown:()=>y("list"),onExitLeft:()=>n("sidebar")}),m(M,{marginTop:1,children:m(me,{title:S==="detail"?"details":fe?"latest":"results",width:l,focused:v&&S!=="search",count:S==="detail"?void 0:St,height:V,children:S==="detail"&&F?m(Si,{r:F,width:Math.max(10,l-4)}):te(Nt,{children:[m(M,{children:Se()}),te(M,{flexDirection:"column",marginTop:x.length>0?1:0,children:[x.length>0?te(M,{children:[m(M,{width:Z,flexShrink:0}),m(M,{width:C,flexShrink:0,justifyContent:"flex-end",children:m(w,{bold:!0,dimColor:!0,children:"#"})}),m(M,{flexGrow:1,minWidth:0,marginLeft:1,children:m(w,{bold:!0,dimColor:!0,children:"Name"})}),j?te(Nt,{children:[m(M,{width:10,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{bold:!0,dimColor:!0,children:Xe("size","Size")})}),m(M,{width:9,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{bold:!0,dimColor:!0,children:Xe("seeders","Seed:Lch")})})]}):m(M,{width:12,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{bold:!0,dimColor:!0,children:"Added"})}),m(M,{width:4,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{bold:!0,dimColor:!0,children:Xe("source","Src")})})]}):null,xt.map((g,A)=>{let O=ye+A,K=O===$&&v&&S==="list",ve=Re[g.source];return te(M,{children:[m(M,{width:Z,flexShrink:0,children:m(w,{color:d.accent,children:K?b.pointer:""})}),m(M,{width:C,flexShrink:0,justifyContent:"flex-end",children:m(w,{dimColor:!0,children:O+1})}),m(M,{flexGrow:1,minWidth:0,marginLeft:1,children:m(w,{wrap:"truncate-end",color:K?d.accent:void 0,dimColor:!K,bold:K,children:ie(g.name)})}),j?te(Nt,{children:[m(M,{width:10,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{dimColor:!0,children:g.sizeBytes>0?be(g.sizeBytes):"-"})}),m(M,{width:9,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{color:g.seeders>0?d.good:void 0,dimColor:g.seeders===0,children:g.seeders||g.leechers?`${g.seeders}:${g.leechers}`:"-"})})]}):m(M,{width:12,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{dimColor:!0,children:ot(g.added)||"-"})}),m(M,{width:4,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:m(w,{color:ve.color,dimColor:!K,children:ve.tag})})]},g.infoHash)})]})]})})})]})}import{useEffect as vi,useState as Ci}from"react";import{Box as U,Text as re,useInput as Ri}from"ink";import{useEffect as wi,useState as bi}from"react";import{Text as ct}from"ink";var Yo="#f4efff";function Ko(t){return Math.ceil(t+4.5*2)+8}function Jo(t,e){return t*.45%e-4.5}function Xo(t,e){let r=Math.abs(t-e);return r>=4.5?0:.5*(1+Math.cos(Math.PI*r/4.5))*.9}import{jsx as gr,jsxs as rn}from"react/jsx-runtime";var Ti="#7c5cd6";function Zo(t,e,r,o){return t<=.5?ae(e,r,t/.5):ae(r,o,(t-.5)/.5)}function en(t){let e=[];for(let r of t){let o=e[e.length-1];o&&o.color===r?o.len++:e.push({color:r,len:1})}return e}function tn(t){return t.map((e,r)=>gr(ct,{color:e.color,children:"\u2588".repeat(e.len)},r))}function on({pct:t,width:e,color:r=d.accent,animate:o=!1}){let n=Math.max(0,Math.min(100,t)),s=Math.round(n/100*e),i=Math.max(0,e-s),a=Math.max(1,e-1),[l,c]=bi(0);wi(()=>{if(!o)return;let v=setInterval(()=>c(S=>S+1),40);return v.unref?.(),()=>clearInterval(v)},[o]);let u=i>0?gr(ct,{color:we,children:"\u2591".repeat(i)}):null;if(s===0)return gr(ct,{children:u});if(!o){let v=ae(r,"#000000",.3),S=ae(r,d.text,.35),y=Array.from({length:s},(R,k)=>Zo(k/a,v,r,S));return rn(ct,{children:[tn(en(y)),u]})}let p=Ko(e),f=Jo(l,p),x=Array.from({length:s},(v,S)=>{let y=Zo(S/a,Ti,d.accent,d.bright),R=Xo(S,f);return R>0&&(y=ae(y,Yo,R)),y});return rn(ct,{children:[tn(en(x)),u]})}import{jsx as B,jsxs as dt}from"react/jsx-runtime";var ut=2,Ft=2,Ei="#7c7785";function Bi(t){return t==="failed"?d.bad:t==="paused"?Ei:d.accent}function Ii(t){return t==="failed"?b.error:t==="paused"?b.pause:b.down}function Mi(t){if(t.status==="downloading"){let e=rt(t.speed)||"\u2026",r=t.eta?` ${Zr(t.eta)}`:"";return`${t.progress}% ${e} ${b.peer}${t.peers}${r}`}return t.status==="paused"?`paused ${t.progress}%`:J(t.error||"failed",28)}function nn(){let{queue:t,region:e,contentWidth:r,listRows:o,startDownload:n,setDownloadFocus:s}=X(),i=Ue(t),a=Mt(t),l=e==="content",c=i.length+a.length,[u,p]=Ci(0),f=Math.min(u,Math.max(0,c-1)),x=f<i.length,v=f-i.length;Ri((h,j)=>{if(j.upArrow)p(he(f,-1,c));else if(j.downArrow)p(he(f,1,c));else if(h==="f")t.retryFailed();else if(h==="x")t.clearHistory();else if(x){let C=i[f];if(!C)return;h==="c"?t.cancel(C.id):h==="p"&&t.togglePause(C.id)}else{let C=a[v];if(!C)return;j.return||h==="d"?n({id:C.id,name:C.name,magnet:C.magnet,source:C.source,sizeBytes:C.sizeBytes}):h==="c"&&t.removeHistory(C.id)}},{isActive:l&&c>0});let S=null;if(l&&c>0)if(!x)S="recent";else{let h=i[f]?.status;(h==="downloading"||h==="paused"||h==="failed")&&(S=h)}vi(()=>(s(S),()=>s(null)),[S,s]);let y=Math.max(5,o-1);if(c===0)return B(me,{title:"downloads",width:r,focused:l,height:y,children:B(re,{dimColor:!0,children:"No downloads yet. Find something and press d to grab it."})});let R=i.length>0,k=a.length>0,F=k?1:0,L=Math.max(1,y-1),$=R&&k?1:0,I=0,V=0;if(!k)I=Math.max(1,Math.floor(L/ut));else if(!R)V=Math.max(1,L-F);else{let h=L-F-$;h<ut+1&&($=0,h=L-F);let j=Math.max(ut,Math.floor(h*.55));I=Math.min(i.length,Math.max(1,Math.floor(j/ut))),V=Math.max(1,h-I*ut)}let D=Ae(x?f:0,i.length,I),ge=i.slice(D,D+I),ne=Ae(x?0:v,a.length,V),xe=a.slice(ne,ne+V),q=r-4,fe=2,Y=Math.max(8,Math.min(28,Math.floor(q*.4))),pe=Math.max(6,q-Ft-Z-Y-fe),ue=R?`(${i.length})`:void 0;return dt(me,{title:"downloads",width:r,focused:l,count:ue,height:y,children:[ge.map((h,j)=>{let C=D+j===f&&l&&x,se=Bi(h.status),Se=Re[h.source??"fitgirl"];return dt(U,{flexDirection:"column",children:[dt(U,{children:[B(U,{width:Ft,flexShrink:0,children:B(re,{color:d.accent,bold:!0,children:C?b.pointer:""})}),B(U,{width:Z,flexShrink:0,children:B(re,{color:se,children:Ii(h.status)})}),B(U,{flexGrow:1,minWidth:0,children:B(re,{wrap:"truncate-end",bold:C,color:C?d.accent:void 0,dimColor:!C,children:ie(h.name)})}),B(U,{width:10,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:B(re,{dimColor:!0,children:h.totalBytes>0?be(h.totalBytes):"-"})}),B(U,{width:4,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:B(re,{color:h.source?Se.color:void 0,dimColor:!h.source||!C,children:h.source?Se.tag:"mag"})})]}),dt(U,{children:[B(U,{width:Ft+Z,flexShrink:0}),B(on,{pct:h.progress,width:Y,color:se,animate:h.status==="downloading"}),B(U,{marginLeft:fe,flexShrink:0,children:B(re,{dimColor:!0,children:J(Mi(h),pe)})})]})]},h.id)}),k?B(U,{marginTop:$?1:0,children:B(re,{dimColor:!0,children:`Recently downloaded${a.length>1?` (${a.length})`:""}`})}):null,xe.map((h,j)=>{let C=ne+j===v&&l&&!x,se=Re[h.source??"fitgirl"],Se=ot(h.completedAt/1e3);return dt(U,{children:[B(U,{width:Ft,flexShrink:0,children:B(re,{color:d.accent,bold:!0,children:C?b.pointer:""})}),B(U,{width:Z,flexShrink:0,children:B(re,{color:d.good,dimColor:!C,children:b.done})}),B(U,{flexGrow:1,minWidth:0,children:B(re,{wrap:"truncate-end",bold:C,color:C?d.accent:void 0,dimColor:!C,children:ie(h.name)})}),B(U,{width:10,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:B(re,{dimColor:!0,children:h.sizeBytes>0?be(h.sizeBytes):"-"})}),B(U,{width:12,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:B(re,{dimColor:!0,children:Se||"-"})}),B(U,{width:4,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:B(re,{color:h.source?se.color:void 0,dimColor:!h.source||!C,children:h.source?se.tag:"mag"})})]},h.id)})]})}import{useEffect as ki,useState as Ai}from"react";import{Box as W,Text as oe,useInput as Pi}from"ink";import{jsx as P,jsxs as mt}from"react/jsx-runtime";var sn=2,an=10,xr=14,ln=4,Hi="#7c7785";function $i(t){return t?t.status==="seeding"?{icon:b.up,color:d.good}:t.status==="paused"?{icon:b.pause,color:Hi}:{icon:b.warn,color:d.warn}:{icon:b.done,color:d.good}}function Di(t){return t?t.status==="seeding"?{text:`${b.up}${rt(t.uploadSpeed)||"0 B/s"} ${b.peer}${t.peers}`,color:d.good,dim:!1}:t.status==="paused"?{text:"paused",dim:!0}:{text:"file gone",color:d.warn,dim:!1}:{text:"ready",dim:!0}}function cn(){let{queue:t,region:e,contentWidth:r,listRows:o,setNotice:n,setSeedFocus:s}=X(),i=Mt(t),a=eo(t),l=e==="content",c=i.length,[u,p]=Ai(0),f=Math.min(u,Math.max(0,c-1)),x=l&&c>0?a.get(i[f]?.id??"")?.status??"idle":null;ki(()=>(s(x),()=>s(null)),[x,s]),Pi((I,V)=>{if(V.upArrow)p(he(f,-1,c));else if(V.downArrow)p(he(f,1,c));else if(I==="p"){let D=i[f];if(!D)return;t.toggleSeeding(D),t.getSeed(D.id)?.status==="missing"&&n(`${b.warn} That file isn't on disk anymore.`)}else if(I==="c"){let D=i[f];D&&t.removeHistory(D.id)}},{isActive:l&&c>0});let v=Math.max(5,o-1),S=t.seedingCount;if(c===0)return P(me,{title:"seeding",width:r,focused:l,height:v,children:P(oe,{dimColor:!0,children:"Nothing here yet. Downloads start seeding automatically when they finish, and show up here."})});let y=0,R=0,k=0;for(let I of a.values())k+=I.uploaded,I.status==="seeding"&&(y+=I.uploadSpeed,R+=I.peers);let F=Math.max(1,v-2),L=Ae(f,c,F),$=i.slice(L,L+F);return mt(me,{title:"seeding",width:r,focused:l,count:S>0?`(${S})`:void 0,height:v,children:[P(W,{children:S>0?mt(oe,{color:d.good,children:[b.up," ",rt(y)||"0 B/s",P(oe,{dimColor:!0,children:` ${b.dot} ${R} peers ${b.dot} ${be(k)} shared back`})]}):P(oe,{dimColor:!0,children:"Downloads seed automatically when they finish. Press p to pause or resume any of them."})}),mt(W,{flexDirection:"column",marginTop:1,children:[mt(W,{children:[P(W,{width:sn,flexShrink:0}),P(W,{width:Z,flexShrink:0}),P(W,{flexGrow:1,minWidth:0,marginLeft:1,children:P(oe,{bold:!0,dimColor:!0,children:"Name"})}),P(W,{width:an,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{bold:!0,dimColor:!0,children:"Size"})}),P(W,{width:xr,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{bold:!0,dimColor:!0,children:"Status"})}),P(W,{width:ln,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{bold:!0,dimColor:!0,children:"Src"})})]}),$.map((I,V)=>{let D=L+V===f&&l,ge=a.get(I.id),ne=$i(ge),xe=Di(ge),q=Re[I.source??"fitgirl"];return mt(W,{children:[P(W,{width:sn,flexShrink:0,children:P(oe,{color:d.accent,bold:!0,children:D?b.pointer:""})}),P(W,{width:Z,flexShrink:0,children:P(oe,{color:ne.color,dimColor:!ge&&!D,children:ne.icon})}),P(W,{flexGrow:1,minWidth:0,marginLeft:1,children:P(oe,{wrap:"truncate-end",bold:D,color:D?d.accent:void 0,dimColor:!D,children:ie(I.name)})}),P(W,{width:an,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{dimColor:!0,children:I.sizeBytes>0?be(I.sizeBytes):"-"})}),P(W,{width:xr,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{color:xe.color,dimColor:xe.dim,children:J(xe.text,xr)})}),P(W,{width:ln,flexShrink:0,marginLeft:1,justifyContent:"flex-end",children:P(oe,{color:I.source?q.color:void 0,dimColor:!I.source||!D,children:I.source?q.tag:"mag"})})]},I.id)})]})]})}import{useEffect as Oi}from"react";function Sr(){let{queue:t}=X();Ue(t);let e=t.activeCount;return Oi(()=>{let r=e>0?`\u2193${e} \xB7 torlink`:"torlink";process.stdout.write(`\x1B]0;${r}\x07`),process.platform==="win32"&&(process.title=r)},[e]),null}import{Box as ft,Text as le,useInput as _i,useStdin as Li}from"ink";import{jsx as z,jsxs as un}from"react/jsx-runtime";var Ni=Fo().map(t=>t.group.toLowerCase()).join(` ${b.dot} `);function dn(){let{submitQuery:t,quitAll:e,cols:r,rows:o}=X(),{isRawModeSupported:n}=Li();_i((a,l)=>{(l.escape||l.ctrl&&a==="c")&&e()},{isActive:n});let s=r>=to+2,i=Math.max(24,Math.min(r-6,62));return un(ft,{height:Math.max(1,o-1),flexDirection:"column",justifyContent:"center",alignItems:"center",children:[s?z(At,{}):z(le,{bold:!0,color:d.accent,children:"torlink"}),z(ft,{marginTop:2,children:z(le,{color:d.text,children:"A curated, terminal-native torrent downloader."})}),z(ft,{children:z(le,{dimColor:!0,children:Ni})}),z(ft,{marginTop:1,width:i,children:z(_t,{width:i,value:"",editing:!0,placeholder:"Search or paste a magnet link\u2026",onSubmit:t})}),z(ft,{marginTop:1,children:un(le,{children:[z(le,{color:d.alt,children:"\u21B5"}),z(le,{dimColor:!0,children:" search"}),z(le,{dimColor:!0,children:` ${b.dot} `}),z(le,{dimColor:!0,children:"empty "}),z(le,{color:d.alt,children:"\u21B5"}),z(le,{dimColor:!0,children:" browse"}),z(le,{dimColor:!0,children:` ${b.dot} `}),z(le,{color:d.alt,children:"^c"}),z(le,{dimColor:!0,children:" quit"})]})})]})}import{Box as Ut,Text as Ke,useInput as Fi}from"ink";import{jsx as Te,jsxs as yr}from"react/jsx-runtime";function mn({width:t,value:e,onSubmit:r,onCancel:o}){return Fi((n,s)=>{s.escape&&o()}),yr(Ut,{flexDirection:"column",width:t,children:[Te(me,{title:"download folder",width:t,focused:!0,height:2,children:yr(Ut,{children:[Te(Ke,{color:d.accent,children:`${b.pointer} `}),Te(Ut,{flexGrow:1,minWidth:0,children:Te(Dt,{defaultValue:e,placeholder:"~/Downloads/torlink",onSubmit:r})})]})}),yr(Ut,{marginTop:1,children:[Te(Ke,{color:d.alt,children:"\u21B5"}),Te(Ke,{dimColor:!0,children:" save"}),Te(Ke,{dimColor:!0,children:` ${b.dot} `}),Te(Ke,{color:d.alt,children:"esc"}),Te(Ke,{dimColor:!0,children:" cancel"})]})]})}import{useEffect as Ui}from"react";function fn(){Ui(()=>{let{stdout:t,stdin:e}=process;t.write("\x1B[?1000h\x1B[?1006h");let r=o=>{let n=o.toString("utf8"),s=/\x1b\[<(64|65);\d+;\d+[Mm]/g,i;for(;(i=s.exec(n))!==null;){let a=i[1]==="64"?"\x1B[A":"\x1B[B";process.nextTick(()=>e.emit("data",Buffer.from(a)))}};return e.prependListener("data",r),()=>{t.write("\x1B[?1000l\x1B[?1006l"),e.removeListener("data",r)}},[])}import{jsx as N,jsxs as ht}from"react/jsx-runtime";function pn({initialMagnet:t,initialTorrent:e,onQuit:r}={}){fn();let{exit:o}=Wi(),{isRawModeSupported:n}=qi(),{stdout:s}=Vi(),[i,a]=ce({rows:s?.rows??24,cols:s?.columns??80});pt(()=>{if(!s)return;let T={rows:s.rows??24,cols:s.columns??80},E=()=>{let _={rows:s.rows??24,cols:s.columns??80};_.rows===T.rows&&_.cols===T.cols||((_.rows<T.rows||_.cols<T.cols)&&s.write("\x1B[2J\x1B[H"),T=_,a(_))};return s.on("resize",E),()=>{s.off("resize",E)}},[s]);let l=i.rows,c=i.cols,[u,p]=ce(null),[f,x]=ce(null),[v,S]=ce("splash"),[y,R]=ce(""),[k,F]=ce("all"),[L,$]=ce("content"),[I,V]=ce("none"),[D,ge]=ce(null),[ne,xe]=ce(null),[q,fe]=ce(!1),[Y,pe]=ce(!1),[ue,h]=ce(null),j=Gi(!1);pt(()=>{if(j.current)return;j.current=!0;let T=!0;return(async()=>{let E=await Br(),_=new Et;if(_.restore(qr(await Nr())),_.restoreHistory(await jr()),_.restoreSeeds(await Qr()),!T){_.suspend();return}x(E),p(_);let wt=t?Fe(t):e?await Yr(e):null;wt&&(await wr.mkdir(E.downloadDir,{recursive:!0}).catch(()=>{}),_.add({id:wt.infoHash,name:wt.name,magnet:wt.magnet},E.downloadDir),S("browser"),F("downloads"),$("content"))})(),()=>{T=!1}},[t,e]),pt(()=>{if(!u)return;let T=E=>h(`${b.done} ${J(ie(E),40)}`);return u.on("completed",T),()=>{u.off("completed",T)}},[u]),pt(()=>()=>{u?.suspend()},[u]);let C=Ie(()=>{u?.persistSync(),r?r():o()},[u,r,o]),se=Ie(T=>{x(T),Ir(T)},[]),Se=Ie(()=>{pe(!1)},[]),Xe=Ie(T=>{Se();let E=Ar(T);if(!f||!E||E===f.downloadDir){f&&E&&E===f.downloadDir&&h("Download folder unchanged.");return}(async()=>{try{await wr.mkdir(E,{recursive:!0})}catch{h(`Couldn't use folder: ${J(E,48)}`);return}se({...f,downloadDir:E}),h(`Download folder: ${J(E,48)}`)})()},[f,se,Se]),ye=Ie(T=>{!f||!u||(wr.mkdir(f.downloadDir,{recursive:!0}).catch(()=>{}),u.add(T,f.downloadDir),h(`Added: ${J(ie(T.name),40)}`),F("downloads"),$("content"))},[f,u]),xt=Ie(T=>{(async()=>{if(await Xr(T.magnet)){h(`Copied magnet: ${J(ie(T.magnet),60)}`);return}h(`Couldn't copy magnet for ${J(ie(T.name),32)}.`)})()},[]),St=Ie(T=>{let E=T.trim();if(E){let _=Fe(E);if(_){ye({id:_.infoHash,name:_.name,magnet:_.magnet}),S("browser");return}}R(E),S("browser"),k==="downloads"&&F("all"),$("content")},[k,ye]),g=Ie(async()=>{let T=(await Jr()).trim();if(!T){h("Clipboard is empty.");return}let E=T.match(/magnet:\?xt=urn:btih:[^\s"'<>]+/i)?.[0],_=E?Fe(E):null;if(_){ye({id:_.infoHash,name:_.name,magnet:_.magnet}),S("browser");return}h("No magnet link on the clipboard.")},[ye]);pt(()=>{if(!ue)return;let T=setTimeout(()=>h(null),4e3);return()=>clearTimeout(T)},[ue]);let A=l<18,O=!A,K=l>=12,ve=3+(O?1:0)+(A?0:1)+(K?1:0),yt=Math.max(6,l-1-ve),br=Math.max(4,yt),Tr=Math.max(24,c-or-3),Sn=Math.max(10,c-2),Ze=zi(()=>!u||!f?null:{config:f,setConfig:se,queue:u,view:v,setView:S,query:y,submitQuery:St,section:k,setSection:F,region:q||Y?"help":L,setRegion:$,captureMode:I,setCaptureMode:V,downloadFocus:D,setDownloadFocus:ge,seedFocus:ne,setSeedFocus:xe,startDownload:ye,copyMagnet:xt,notice:ue,setNotice:h,quitAll:C,listRows:br,compact:A,contentWidth:Tr,cols:c,rows:l},[u,f,v,y,St,k,L,q,Y,I,D,ne,ye,xt,ue,br,A,Tr,c,l,se,C]);return ji((T,E)=>{if(E.ctrl&&T==="c"){C();return}if(!Y&&I!=="text"){if(q){fe(!1);return}if(T==="?"){fe(!0);return}if(T==="o"){fe(!1),pe(!0);return}if(T==="m"){g();return}if(E.tab){$(L==="sidebar"?"content":"sidebar");return}if(E.rightArrow){L==="sidebar"&&$("content");return}if(E.leftArrow){L==="content"&&$("sidebar");return}if(E.escape){if(I==="esc")return;if(L==="content"){$("sidebar");return}S("splash");return}if(T==="q"){C();return}}},{isActive:n&&v==="browser"&&!!Ze}),Ze?v==="splash"?ht(It.Provider,{value:Ze,children:[N(Sr,{}),N(dn,{})]}):ht(It.Provider,{value:Ze,children:[N(Sr,{}),ht(Me,{flexDirection:"column",paddingX:1,children:[ht(Me,{justifyContent:"space-between",children:[N(At,{}),ue?N(Qi,{color:d.good,children:ue}):null]}),O?N(Pt,{width:Sn}):null,q?N(Me,{marginTop:1,children:N(ho,{})}):null,Y?N(Me,{marginTop:1,children:N(mn,{width:Math.max(24,Math.min(c-4,62)),value:Ze.config.downloadDir,onSubmit:Xe,onCancel:Se})}):null,ht(Me,{height:yt,marginTop:A?0:1,display:q||Y?"none":"flex",overflow:"hidden",children:[N(co,{}),N(Me,{flexGrow:1,flexDirection:"column",children:k==="downloads"?N(nn,{}):k==="seeding"?N(cn,{}):N(qo,{})})]}),K?N(Me,{display:q||Y?"none":"flex",children:N(uo,{hints:mo(L,k,D,ne)})}):null]})]}):N(Me,{height:l,justifyContent:"center",alignItems:"center",children:N($t,{label:"Starting torlink"})})}import{jsx as Ki}from"react/jsx-runtime";var Je=vr(process.argv.slice(2));Je.kind==="help"&&(console.log(Gt),process.exit(0));Je.kind==="version"&&(console.log(`torlink v${Cr}`),process.exit(0));Je.kind==="invalid"&&(console.error(`error: unknown argument '${Je.arg}'
14
+ `),console.error(Gt),process.exit(1));process.stdout.write("\x1B[?1049h\x1B[?25l\x1B[22;0t\x1B]0;torlink\x07");process.platform==="win32"&&(process.title="torlink");var hn=!1;function gt(){hn||(hn=!0,process.stdout.write("\x1B[?1000l\x1B[?1006l\x1B[?25h\x1B[23;0t\x1B[?1049l"))}var gn=!1;function zt(t=0){gn&&(gt(),process.exit(t)),gn=!0;try{xn?.unmount()}catch{}gt(),process.exit(t)}var xn=Yi(Ki(pn,{initialMagnet:Je.initialMagnet,initialTorrent:Je.initialTorrent,onQuit:()=>zt(0)}),{exitOnCtrlC:!1});xn.waitUntilExit().then(()=>zt(0)).catch(t=>{gt(),console.error(t),process.exit(1)});process.on("SIGINT",()=>zt(0));process.on("SIGTERM",()=>zt(0));process.on("exit",gt);process.on("uncaughtException",t=>{gt(),console.error(t),process.exit(1)});
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "torlnq",
3
+ "version": "0.0.1",
4
+ "description": "A sleek, zero-setup torrent finder and downloader that lives right in your terminal.",
5
+ "type": "module",
6
+ "bin": {
7
+ "torlnq": "./dist/cli.cjs"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "preview"
12
+ ],
13
+ "engines": {
14
+ "node": ">=22"
15
+ },
16
+ "scripts": {
17
+ "dev": "tsx src/index.tsx",
18
+ "build": "tsup",
19
+ "postbuild": "cp scripts/cli-entry.cjs dist/cli.cjs && chmod +x dist/cli.cjs",
20
+ "start": "node dist/index.js",
21
+ "typecheck": "tsc --noEmit",
22
+ "test": "vitest run",
23
+ "verify:seeding": "tsx scripts/verify-seeding.ts",
24
+ "previews": "tsx scripts/render-previews.tsx",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "torrent",
29
+ "torrent-client",
30
+ "torrent-search",
31
+ "downloader",
32
+ "magnet",
33
+ "magnet-links",
34
+ "p2p",
35
+ "webtorrent",
36
+ "seeding",
37
+ "tui",
38
+ "terminal",
39
+ "cli",
40
+ "ink",
41
+ "zero-configuration",
42
+ "zero-setup",
43
+ "fitgirl"
44
+ ],
45
+ "author": "bairon",
46
+ "license": "MIT",
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/bluscelabs/torlink.git"
50
+ },
51
+ "homepage": "https://github.com/bluscelabs/torlink#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/bluscelabs/torlink/issues"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "dependencies": {
59
+ "env-paths": "^4.0.0",
60
+ "ink": "^7.0.5",
61
+ "parse-torrent": "^11.0.21",
62
+ "react": "^19.2.7",
63
+ "webtorrent": "^2.4.1"
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^25.9.2",
67
+ "@types/react": "^19.2.17",
68
+ "ink-testing-library": "^4.0.0",
69
+ "tsup": "^8.5.1",
70
+ "tsx": "^4.22.4",
71
+ "typescript": "^6.0.3",
72
+ "vitest": "^4.1.8"
73
+ }
74
+ }
@@ -0,0 +1,121 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="832" height="540" viewBox="0 0 832 540" style="max-width: 832px; width: 100%; height: auto;" role="img">
3
+ <rect width="100%" height="100%" rx="14" fill="#0a0810"/>
4
+ <rect x="0.5" y="0.5" width="831" height="539" rx="14" fill="none" stroke="#2d2b31" stroke-width="1"/>
5
+ <text x="416" y="23" text-anchor="middle" font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="13" fill="#8a8a8a">torlink</text>
6
+ <g font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="16" fill="#ddd8ea">
7
+ <text x="99.2" y="84" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#5ae87a" font-weight="600">๐“</text>
8
+ <rect x="51.2" y="90" width="9.6" height="11" fill="#faf5ff"/>
9
+ <rect x="60.8" y="90" width="9.6" height="22" fill="#f5ecff"/>
10
+ <rect x="70.4" y="90" width="9.6" height="11" fill="#f0e2ff"/>
11
+ <rect x="89.6" y="90" width="9.6" height="22" fill="#e6cffe"/>
12
+ <rect x="99.2" y="90" width="9.6" height="11" fill="#e1c5fe"/>
13
+ <rect x="108.8" y="90" width="9.6" height="22" fill="#dcbcfe"/>
14
+ <rect x="128" y="90" width="9.6" height="22" fill="#d3b0fe"/>
15
+ <rect x="137.6" y="90" width="9.6" height="11" fill="#d0adfd"/>
16
+ <rect x="147.2" y="90" width="9.6" height="22" fill="#ccaafd"/>
17
+ <rect x="166.4" y="90" width="9.6" height="22" fill="#c4a4fc"/>
18
+ <rect x="204.8" y="90" width="9.6" height="22" fill="#b597fb"/>
19
+ <rect x="224" y="90" width="9.6" height="22" fill="#ae91fb"/>
20
+ <rect x="233.6" y="101" width="9.6" height="11" fill="#aa8efa"/>
21
+ <rect x="252.8" y="90" width="9.6" height="22" fill="#a487f7"/>
22
+ <rect x="272" y="90" width="9.6" height="22" fill="#9e81f3"/>
23
+ <rect x="281.6" y="101" width="9.6" height="11" fill="#9b7ef0"/>
24
+ <rect x="291.2" y="90" width="9.6" height="11" fill="#997bee"/>
25
+ <rect x="60.8" y="112" width="9.6" height="22" fill="#9375e9"/>
26
+ <rect x="89.6" y="112" width="9.6" height="22" fill="#8b6ce2"/>
27
+ <rect x="99.2" y="123" width="9.6" height="11" fill="#8869e0"/>
28
+ <rect x="108.8" y="112" width="9.6" height="22" fill="#8566de"/>
29
+ <rect x="128" y="112" width="9.6" height="22" fill="#8060d9"/>
30
+ <rect x="137.6" y="112" width="9.6" height="11" fill="#7d5dd7"/>
31
+ <rect x="147.2" y="123" width="9.6" height="11" fill="#7a5bd3"/>
32
+ <rect x="166.4" y="112" width="9.6" height="22" fill="#7456c9"/>
33
+ <rect x="176" y="123" width="9.6" height="11" fill="#7154c4"/>
34
+ <rect x="185.6" y="123" width="9.6" height="11" fill="#6e52c0"/>
35
+ <rect x="204.8" y="112" width="9.6" height="22" fill="#684eb6"/>
36
+ <rect x="224" y="112" width="9.6" height="22" fill="#6249ac"/>
37
+ <rect x="243.2" y="112" width="9.6" height="11" fill="#5b45a2"/>
38
+ <rect x="252.8" y="112" width="9.6" height="22" fill="#58439d"/>
39
+ <rect x="272" y="112" width="9.6" height="22" fill="#523e94"/>
40
+ <rect x="291.2" y="112" width="9.6" height="22" fill="#4c3a8a"/>
41
+ <text x="41.6" y="150" textLength="748.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€</text>
42
+ <rect x="41.6" y="178" width="4.8" height="22" fill="#6b6577"/>
43
+ <text x="60.8" y="194" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">All</text>
44
+ <text x="204.8" y="194" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ•ญโ”€</text>
45
+ <text x="233.6" y="194" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577" font-weight="600">Search</text>
46
+ <text x="300.8" y="194" textLength="489.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ</text>
47
+ <text x="60.8" y="216" textLength="48" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Games</text>
48
+ <rect x="208.9" y="200" width="1.4" height="22" fill="#6b6577"/>
49
+ <text x="224" y="216" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โฏ</text>
50
+ <text x="243.2" y="216" textLength="288" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Search or paste a magnet linkโ€ฆ</text>
51
+ <rect x="784.9" y="200" width="1.4" height="22" fill="#6b6577"/>
52
+ <text x="60.8" y="238" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Movies</text>
53
+ <text x="204.8" y="238" textLength="585.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ</text>
54
+ <text x="60.8" y="260" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">TV</text>
55
+ <text x="60.8" y="282" textLength="48" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Anime</text>
56
+ <text x="204.8" y="282" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ญโ”€</text>
57
+ <text x="233.6" y="282" textLength="96" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">Latest (5)</text>
58
+ <text x="339.2" y="282" textLength="451.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ</text>
59
+ <rect x="208.9" y="288" width="1.4" height="22" fill="#a78bfa"/>
60
+ <text x="224" y="304" textLength="240" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">newest across all sources</text>
61
+ <rect x="784.9" y="288" width="1.4" height="22" fill="#a78bfa"/>
62
+ <text x="60.8" y="326" textLength="86.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Downloads</text>
63
+ <rect x="208.9" y="310" width="1.4" height="22" fill="#a78bfa"/>
64
+ <rect x="784.9" y="310" width="1.4" height="22" fill="#a78bfa"/>
65
+ <text x="60.8" y="348" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Seeding</text>
66
+ <rect x="208.9" y="332" width="1.4" height="22" fill="#a78bfa"/>
67
+ <text x="252.8" y="348" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55" font-weight="600">#</text>
68
+ <text x="272" y="348" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55" font-weight="600">Name</text>
69
+ <text x="588.8" y="348" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55" font-weight="600">Size</text>
70
+ <text x="646.4" y="348" textLength="76.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55" font-weight="600">Seed:Lch</text>
71
+ <text x="742.4" y="348" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55" font-weight="600">Src</text>
72
+ <rect x="784.9" y="332" width="1.4" height="22" fill="#a78bfa"/>
73
+ <rect x="208.9" y="354" width="1.4" height="22" fill="#a78bfa"/>
74
+ <text x="224" y="370" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โฏ</text>
75
+ <text x="252.8" y="370" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1</text>
76
+ <text x="272" y="370" textLength="249.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">Oppenheimer (2023) [1080pโ€ฆ</text>
77
+ <text x="560" y="370" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1.96 GB</text>
78
+ <text x="656" y="370" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">1240:88</text>
79
+ <text x="742.4" y="370" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">YTS</text>
80
+ <rect x="784.9" y="354" width="1.4" height="22" fill="#a78bfa"/>
81
+ <rect x="208.9" y="376" width="1.4" height="22" fill="#a78bfa"/>
82
+ <text x="252.8" y="392" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">2</text>
83
+ <text x="272" y="392" textLength="249.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Dune: Part Two (2024) [21โ€ฆ</text>
84
+ <text x="560" y="392" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">7.82 GB</text>
85
+ <text x="665.6" y="392" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">910:41</text>
86
+ <text x="742.4" y="392" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2" fill-opacity="0.55">YTS</text>
87
+ <rect x="784.9" y="376" width="1.4" height="22" fill="#a78bfa"/>
88
+ <rect x="208.9" y="398" width="1.4" height="22" fill="#a78bfa"/>
89
+ <text x="252.8" y="414" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">3</text>
90
+ <text x="272" y="414" textLength="249.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Breaking Bad S05E14 1080pโ€ฆ</text>
91
+ <text x="560" y="414" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1.49 GB</text>
92
+ <text x="665.6" y="414" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">540:31</text>
93
+ <text x="732.8" y="414" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#f0c560" fill-opacity="0.55">EZTV</text>
94
+ <rect x="784.9" y="398" width="1.4" height="22" fill="#a78bfa"/>
95
+ <rect x="208.9" y="420" width="1.4" height="22" fill="#a78bfa"/>
96
+ <text x="252.8" y="436" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">4</text>
97
+ <text x="272" y="436" textLength="249.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">[Erai-raws] Jujutsu Kaiseโ€ฆ</text>
98
+ <text x="560" y="436" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1.21 GB</text>
99
+ <text x="665.6" y="436" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">320:12</text>
100
+ <text x="732.8" y="436" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#d8b4fe" fill-opacity="0.55">NYAA</text>
101
+ <rect x="784.9" y="420" width="1.4" height="22" fill="#a78bfa"/>
102
+ <rect x="208.9" y="442" width="1.4" height="22" fill="#a78bfa"/>
103
+ <text x="252.8" y="458" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">5</text>
104
+ <text x="272" y="458" textLength="192" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Frieren - 28 [1080p]</text>
105
+ <text x="560" y="458" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1.30 GB</text>
106
+ <text x="713.6" y="458" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">-</text>
107
+ <text x="742.4" y="458" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6" fill-opacity="0.55">SUB</text>
108
+ <rect x="784.9" y="442" width="1.4" height="22" fill="#a78bfa"/>
109
+ <text x="204.8" y="480" textLength="585.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ</text>
110
+ <text x="41.6" y="502" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">d</text>
111
+ <text x="60.8" y="502" textLength="76.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Download</text>
112
+ <text x="166.4" y="502" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">/</text>
113
+ <text x="185.6" y="502" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Search</text>
114
+ <text x="272" y="502" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">m</text>
115
+ <text x="291.2" y="502" textLength="115.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Paste magnet</text>
116
+ <text x="435.2" y="502" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">tab</text>
117
+ <text x="473.6" y="502" textLength="105.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Switch pane</text>
118
+ <text x="608" y="502" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">?</text>
119
+ <text x="627.2" y="502" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Keys</text>
120
+ </g>
121
+ </svg>
@@ -0,0 +1,154 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="832" height="452" viewBox="0 0 832 452" style="max-width: 832px; width: 100%; height: auto;" role="img">
3
+ <rect width="100%" height="100%" rx="14" fill="#0a0810"/>
4
+ <rect x="0.5" y="0.5" width="831" height="451" rx="14" fill="none" stroke="#2d2b31" stroke-width="1"/>
5
+ <text x="416" y="23" text-anchor="middle" font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="13" fill="#8a8a8a">torlink</text>
6
+ <g font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="16" fill="#ddd8ea">
7
+ <text x="99.2" y="84" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#5ae87a" font-weight="600">๐“</text>
8
+ <rect x="51.2" y="90" width="9.6" height="11" fill="#faf5ff"/>
9
+ <rect x="60.8" y="90" width="9.6" height="22" fill="#f5ecff"/>
10
+ <rect x="70.4" y="90" width="9.6" height="11" fill="#f0e2ff"/>
11
+ <rect x="89.6" y="90" width="9.6" height="22" fill="#e6cffe"/>
12
+ <rect x="99.2" y="90" width="9.6" height="11" fill="#e1c5fe"/>
13
+ <rect x="108.8" y="90" width="9.6" height="22" fill="#dcbcfe"/>
14
+ <rect x="128" y="90" width="9.6" height="22" fill="#d3b0fe"/>
15
+ <rect x="137.6" y="90" width="9.6" height="11" fill="#d0adfd"/>
16
+ <rect x="147.2" y="90" width="9.6" height="22" fill="#ccaafd"/>
17
+ <rect x="166.4" y="90" width="9.6" height="22" fill="#c4a4fc"/>
18
+ <rect x="204.8" y="90" width="9.6" height="22" fill="#b597fb"/>
19
+ <rect x="224" y="90" width="9.6" height="22" fill="#ae91fb"/>
20
+ <rect x="233.6" y="101" width="9.6" height="11" fill="#aa8efa"/>
21
+ <rect x="252.8" y="90" width="9.6" height="22" fill="#a487f7"/>
22
+ <rect x="272" y="90" width="9.6" height="22" fill="#9e81f3"/>
23
+ <rect x="281.6" y="101" width="9.6" height="11" fill="#9b7ef0"/>
24
+ <rect x="291.2" y="90" width="9.6" height="11" fill="#997bee"/>
25
+ <rect x="60.8" y="112" width="9.6" height="22" fill="#9375e9"/>
26
+ <rect x="89.6" y="112" width="9.6" height="22" fill="#8b6ce2"/>
27
+ <rect x="99.2" y="123" width="9.6" height="11" fill="#8869e0"/>
28
+ <rect x="108.8" y="112" width="9.6" height="22" fill="#8566de"/>
29
+ <rect x="128" y="112" width="9.6" height="22" fill="#8060d9"/>
30
+ <rect x="137.6" y="112" width="9.6" height="11" fill="#7d5dd7"/>
31
+ <rect x="147.2" y="123" width="9.6" height="11" fill="#7a5bd3"/>
32
+ <rect x="166.4" y="112" width="9.6" height="22" fill="#7456c9"/>
33
+ <rect x="176" y="123" width="9.6" height="11" fill="#7154c4"/>
34
+ <rect x="185.6" y="123" width="9.6" height="11" fill="#6e52c0"/>
35
+ <rect x="204.8" y="112" width="9.6" height="22" fill="#684eb6"/>
36
+ <rect x="224" y="112" width="9.6" height="22" fill="#6249ac"/>
37
+ <rect x="243.2" y="112" width="9.6" height="11" fill="#5b45a2"/>
38
+ <rect x="252.8" y="112" width="9.6" height="22" fill="#58439d"/>
39
+ <rect x="272" y="112" width="9.6" height="22" fill="#523e94"/>
40
+ <rect x="291.2" y="112" width="9.6" height="22" fill="#4c3a8a"/>
41
+ <text x="41.6" y="150" textLength="748.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€</text>
42
+ <text x="60.8" y="194" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">All</text>
43
+ <text x="204.8" y="194" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ญโ”€</text>
44
+ <text x="233.6" y="194" textLength="124.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">Downloads (1)</text>
45
+ <text x="368" y="194" textLength="422.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ</text>
46
+ <text x="60.8" y="216" textLength="48" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Games</text>
47
+ <rect x="208.9" y="200" width="1.4" height="22" fill="#a78bfa"/>
48
+ <text x="224" y="216" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">โฏ</text>
49
+ <text x="243.2" y="216" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ†“</text>
50
+ <text x="262.4" y="216" textLength="345.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">Dune: Part Two (2024) [2160p BluRay]</text>
51
+ <text x="656" y="216" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">7.82 GB</text>
52
+ <text x="742.4" y="216" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2">YTS</text>
53
+ <rect x="784.9" y="200" width="1.4" height="22" fill="#a78bfa"/>
54
+ <text x="60.8" y="238" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Movies</text>
55
+ <rect x="208.9" y="222" width="1.4" height="22" fill="#a78bfa"/>
56
+ <rect x="262.4" y="222" width="9.6" height="22" fill="#7c5cd6"/>
57
+ <rect x="272" y="222" width="9.6" height="22" fill="#8060d9"/>
58
+ <rect x="281.6" y="222" width="9.6" height="22" fill="#8465dd"/>
59
+ <rect x="291.2" y="222" width="9.6" height="22" fill="#8869e0"/>
60
+ <rect x="300.8" y="222" width="9.6" height="22" fill="#8c6ee4"/>
61
+ <rect x="310.4" y="222" width="9.6" height="22" fill="#9072e7"/>
62
+ <rect x="320" y="222" width="9.6" height="22" fill="#9577eb"/>
63
+ <rect x="329.6" y="222" width="9.6" height="22" fill="#997bee"/>
64
+ <rect x="339.2" y="222" width="9.6" height="22" fill="#9d80f1"/>
65
+ <rect x="348.8" y="222" width="9.6" height="22" fill="#a184f5"/>
66
+ <rect x="358.4" y="222" width="9.6" height="22" fill="#a589f8"/>
67
+ <rect x="368" y="222" width="9.6" height="22" fill="#a98dfa"/>
68
+ <rect x="377.6" y="222" width="9.6" height="22" fill="#ae91fb"/>
69
+ <rect x="387.2" y="222" width="9.6" height="22" fill="#b395fb"/>
70
+ <text x="396.8" y="238" textLength="76.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#6b6577">โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘</text>
71
+ <text x="492.8" y="238" textLength="211.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">64% 7.7 MB/s โ€ข41 6m</text>
72
+ <rect x="784.9" y="222" width="1.4" height="22" fill="#a78bfa"/>
73
+ <text x="60.8" y="260" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">TV</text>
74
+ <rect x="208.9" y="244" width="1.4" height="22" fill="#a78bfa"/>
75
+ <rect x="784.9" y="244" width="1.4" height="22" fill="#a78bfa"/>
76
+ <text x="60.8" y="282" textLength="48" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Anime</text>
77
+ <rect x="208.9" y="266" width="1.4" height="22" fill="#a78bfa"/>
78
+ <text x="224" y="282" textLength="230.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Recently downloaded (2)</text>
79
+ <rect x="784.9" y="266" width="1.4" height="22" fill="#a78bfa"/>
80
+ <rect x="208.9" y="288" width="1.4" height="22" fill="#a78bfa"/>
81
+ <text x="243.2" y="304" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2" fill-opacity="0.55">โœ“</text>
82
+ <text x="262.4" y="304" textLength="230.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Elden Ring: Shadow of tโ€ฆ</text>
83
+ <text x="521.6" y="304" textLength="76.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">50.29 GB</text>
84
+ <text x="656" y="304" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1hr ago</text>
85
+ <text x="752" y="304" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" fill-opacity="0.55">FG</text>
86
+ <rect x="784.9" y="288" width="1.4" height="22" fill="#a78bfa"/>
87
+ <rect x="41.6" y="310" width="4.8" height="22" fill="#6b6577"/>
88
+ <text x="60.8" y="326" textLength="86.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">Downloads</text>
89
+ <text x="156.8" y="326" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">(1)</text>
90
+ <rect x="208.9" y="310" width="1.4" height="22" fill="#a78bfa"/>
91
+ <text x="243.2" y="326" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#86d6a2" fill-opacity="0.55">โœ“</text>
92
+ <text x="262.4" y="326" textLength="230.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Breaking Bad S05E14 108โ€ฆ</text>
93
+ <text x="531.2" y="326" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1.49 GB</text>
94
+ <text x="627.2" y="326" textLength="96" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">1d 1hr ago</text>
95
+ <text x="732.8" y="326" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#f0c560" fill-opacity="0.55">EZTV</text>
96
+ <rect x="784.9" y="310" width="1.4" height="22" fill="#a78bfa"/>
97
+ <text x="60.8" y="348" textLength="67.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Seeding</text>
98
+ <rect x="208.9" y="332" width="1.4" height="22" fill="#a78bfa"/>
99
+ <rect x="784.9" y="332" width="1.4" height="22" fill="#a78bfa"/>
100
+ <rect x="208.9" y="354" width="1.4" height="22" fill="#a78bfa"/>
101
+ <rect x="784.9" y="354" width="1.4" height="22" fill="#a78bfa"/>
102
+ <text x="204.8" y="392" textLength="585.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ</text>
103
+ <text x="41.6" y="414" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">p</text>
104
+ <text x="60.8" y="414" textLength="48" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Pause</text>
105
+ <text x="137.6" y="414" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">c</text>
106
+ <text x="156.8" y="414" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Cancel</text>
107
+ <text x="243.2" y="414" textLength="28.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">tab</text>
108
+ <text x="281.6" y="414" textLength="105.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Switch pane</text>
109
+ <text x="416" y="414" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">?</text>
110
+ <text x="435.2" y="414" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">Keys</text>
111
+ </g>
112
+ <rect x="262.4" y="222" width="9.6" height="22" fill="#7c5cd6">
113
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#7c5cd6;#7f5fd7;#8669da;#9277de;#a18ae3;#b29ee8;#c3b3ee;#d2c5f3;#ded4f7;#e5ddfa;#e8e0fb;#e5ddfa;#ded4f7;#d2c5f3;#c3b3ee;#b29ee8;#a18ae3;#9277de;#8669da;#7f5fd7;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6;#7c5cd6" repeatCount="indefinite"/>
114
+ </rect>
115
+ <rect x="272" y="222" width="9.6" height="22" fill="#8060d9">
116
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#8060d9;#8060d9;#8060d9;#8262da;#886adc;#9377df;#a188e4;#b19ce9;#c1b0ee;#d0c2f3;#dcd2f7;#e5dcfa;#e8e1fb;#e7dffb;#e0d7f9;#d6caf5;#c8b8f1;#b8a5eb;#a891e6;#997ee1;#8c6fdd;#8465da;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9;#8060d9" repeatCount="indefinite"/>
117
+ </rect>
118
+ <rect x="281.6" y="222" width="9.6" height="22" fill="#8465dd">
119
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8566dd;#8a6cdf;#9378e2;#a088e6;#af9aea;#bfaeef;#cec0f3;#dbd0f7;#e4dbfa;#e8e1fb;#e8e0fb;#e3dafa;#d9cef7;#ccbef3;#bdacee;#ae98ea;#9f86e5;#9276e1;#896bdf;#8466dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd;#8465dd" repeatCount="indefinite"/>
120
+ </rect>
121
+ <rect x="291.2" y="222" width="9.6" height="22" fill="#8869e0">
122
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8c6ee1;#9478e4;#a087e7;#ae99eb;#beacef;#ccbef4;#d9cef7;#e3dafa;#e8e0fc;#e9e1fc;#e5dcfb;#ddd2f8;#d1c3f5;#c3b2f1;#b49fec;#a58de8;#987de5;#8f71e2;#896ae0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0;#8869e0" repeatCount="indefinite"/>
123
+ </rect>
124
+ <rect x="300.8" y="222" width="9.6" height="22" fill="#8c6ee4">
125
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8f72e5;#967ae7;#a188e9;#ae98ed;#bcaaf1;#cbbcf4;#d8ccf8;#e2d8fa;#e8e0fc;#eae2fc;#e7dffc;#e0d6fa;#d5c9f7;#c8b8f3;#b9a6f0;#ab94ec;#9e84e9;#9478e6;#8e70e4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4;#8c6ee4" repeatCount="indefinite"/>
126
+ </rect>
127
+ <rect x="310.4" y="222" width="9.6" height="22" fill="#9072e7">
128
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9274e7;#987ce9;#a188eb;#ae97ee;#bba8f1;#c9baf5;#d6caf8;#e0d7fa;#e7dffc;#eae2fd;#e8e0fc;#e2d9fb;#d9cdf8;#ccbdf5;#bfacf2;#b19bef;#a48bec;#9a7ee9;#9375e8;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7;#9072e7" repeatCount="indefinite"/>
129
+ </rect>
130
+ <rect x="320" y="222" width="9.6" height="22" fill="#9577eb">
131
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9678eb;#9b7eec;#a389ee;#ae97f0;#bba7f3;#c9b8f6;#d5c8f9;#e0d5fb;#e7defc;#eae3fd;#eae2fd;#e5dcfc;#dcd1fa;#d1c3f8;#c4b3f5;#b7a2f2;#aa92f0;#a085ed;#997cec;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb;#9577eb" repeatCount="indefinite"/>
132
+ </rect>
133
+ <rect x="329.6" y="222" width="9.6" height="22" fill="#997bee">
134
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997cee;#9d80ef;#a48af0;#af97f2;#bba6f4;#c8b6f7;#d4c6f9;#ded3fb;#e6ddfc;#eae3fd;#ebe3fd;#e7defd;#dfd5fb;#d5c8f9;#c9b8f7;#bca8f5;#b098f2;#a68bf0;#9e81ef;#9a7cee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee;#997bee" repeatCount="indefinite"/>
135
+ </rect>
136
+ <rect x="339.2" y="222" width="9.6" height="22" fill="#9d80f1">
137
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#a084f1;#a68cf2;#af97f4;#bba6f6;#c7b5f8;#d3c5fa;#ddd2fb;#e5dcfd;#eae2fd;#ebe4fe;#e8e0fd;#e2d8fc;#d9ccfb;#cebef9;#c1aef7;#b59ff5;#ab92f3;#a388f2;#9e81f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1;#9d80f1" repeatCount="indefinite"/>
138
+ </rect>
139
+ <rect x="348.8" y="222" width="9.6" height="22" fill="#a184f5">
140
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a386f5;#a88df6;#b098f7;#bba5f8;#c6b4fa;#d2c3fb;#dcd0fc;#e5dbfd;#eae2fe;#ece4fe;#eae2fe;#e5dbfd;#dcd0fc;#d2c3fb;#c6b4fa;#bba5f8;#b098f7;#a88df6;#a386f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5;#a184f5" repeatCount="indefinite"/>
141
+ </rect>
142
+ <rect x="358.4" y="222" width="9.6" height="22" fill="#a589f8">
143
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a68af8;#aa90f8;#b299f9;#bba6fa;#c6b4fb;#d1c2fc;#dbcffd;#e4dafe;#eae1fe;#ece5fe;#ebe3fe;#e7defe;#dfd4fd;#d6c8fc;#cbbafb;#c0acfa;#b69ff9;#ad94f9;#a88cf8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8;#a589f8" repeatCount="indefinite"/>
144
+ </rect>
145
+ <rect x="368" y="222" width="9.6" height="22" fill="#a98dfa">
146
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#aa8efa;#ad92fa;#b39afb;#bca6fb;#c6b3fc;#d1c1fd;#dbcefd;#e3d9fe;#e9e1fe;#ece5fe;#ece5fe;#e9e0fe;#e2d8fe;#daccfd;#cfbffd;#c5b1fc;#bba4fb;#b299fb;#ac91fa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa;#a98dfa" repeatCount="indefinite"/>
147
+ </rect>
148
+ <rect x="377.6" y="222" width="9.6" height="22" fill="#ae91fb">
149
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#b195fb;#b69cfb;#bea6fc;#c7b3fc;#d1c0fd;#dacdfe;#e3d8fe;#e9e0fe;#ece5ff;#ede5ff;#eae2fe;#e5dbfe;#ddd0fe;#d4c4fd;#cab7fd;#c1aafc;#b89ffc;#b297fb;#af92fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb;#ae91fb" repeatCount="indefinite"/>
150
+ </rect>
151
+ <rect x="387.2" y="222" width="9.6" height="22" fill="#b395fb">
152
+ <animate attributeName="fill" calcMode="discrete" dur="3.48s" values="#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b597fb;#b99efb;#c0a7fc;#c8b2fc;#d1bffd;#dacbfd;#e2d6fe;#e8dffe;#ece4ff;#ede6ff;#ece4fe;#e7ddfe;#e1d4fe;#d8c9fd;#cfbcfd;#c6b0fc;#bea5fc;#b89cfb;#b497fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb;#b395fb" repeatCount="indefinite"/>
153
+ </rect>
154
+ </svg>
@@ -0,0 +1,60 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="832" height="386" viewBox="0 0 832 386" style="max-width: 832px; width: 100%; height: auto;" role="img">
3
+ <rect width="100%" height="100%" rx="14" fill="#0a0810"/>
4
+ <rect x="0.5" y="0.5" width="831" height="385" rx="14" fill="none" stroke="#2d2b31" stroke-width="1"/>
5
+ <text x="416" y="23" text-anchor="middle" font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="13" fill="#8a8a8a">torlink</text>
6
+ <g font-family='ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace' font-size="16" fill="#ddd8ea">
7
+ <text x="339.2" y="84" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#5ae87a" font-weight="600">๐“</text>
8
+ <rect x="291.2" y="90" width="9.6" height="11" fill="#faf5ff"/>
9
+ <rect x="300.8" y="90" width="9.6" height="22" fill="#f5ecff"/>
10
+ <rect x="310.4" y="90" width="9.6" height="11" fill="#f0e2ff"/>
11
+ <rect x="329.6" y="90" width="9.6" height="22" fill="#e6cffe"/>
12
+ <rect x="339.2" y="90" width="9.6" height="11" fill="#e1c5fe"/>
13
+ <rect x="348.8" y="90" width="9.6" height="22" fill="#dcbcfe"/>
14
+ <rect x="368" y="90" width="9.6" height="22" fill="#d3b0fe"/>
15
+ <rect x="377.6" y="90" width="9.6" height="11" fill="#d0adfd"/>
16
+ <rect x="387.2" y="90" width="9.6" height="22" fill="#ccaafd"/>
17
+ <rect x="406.4" y="90" width="9.6" height="22" fill="#c4a4fc"/>
18
+ <rect x="444.8" y="90" width="9.6" height="22" fill="#b597fb"/>
19
+ <rect x="464" y="90" width="9.6" height="22" fill="#ae91fb"/>
20
+ <rect x="473.6" y="101" width="9.6" height="11" fill="#aa8efa"/>
21
+ <rect x="492.8" y="90" width="9.6" height="22" fill="#a487f7"/>
22
+ <rect x="512" y="90" width="9.6" height="22" fill="#9e81f3"/>
23
+ <rect x="521.6" y="101" width="9.6" height="11" fill="#9b7ef0"/>
24
+ <rect x="531.2" y="90" width="9.6" height="11" fill="#997bee"/>
25
+ <rect x="300.8" y="112" width="9.6" height="22" fill="#9375e9"/>
26
+ <rect x="329.6" y="112" width="9.6" height="22" fill="#8b6ce2"/>
27
+ <rect x="339.2" y="123" width="9.6" height="11" fill="#8869e0"/>
28
+ <rect x="348.8" y="112" width="9.6" height="22" fill="#8566de"/>
29
+ <rect x="368" y="112" width="9.6" height="22" fill="#8060d9"/>
30
+ <rect x="377.6" y="112" width="9.6" height="11" fill="#7d5dd7"/>
31
+ <rect x="387.2" y="123" width="9.6" height="11" fill="#7a5bd3"/>
32
+ <rect x="406.4" y="112" width="9.6" height="22" fill="#7456c9"/>
33
+ <rect x="416" y="123" width="9.6" height="11" fill="#7154c4"/>
34
+ <rect x="425.6" y="123" width="9.6" height="11" fill="#6e52c0"/>
35
+ <rect x="444.8" y="112" width="9.6" height="22" fill="#684eb6"/>
36
+ <rect x="464" y="112" width="9.6" height="22" fill="#6249ac"/>
37
+ <rect x="483.2" y="112" width="9.6" height="11" fill="#5b45a2"/>
38
+ <rect x="492.8" y="112" width="9.6" height="22" fill="#58439d"/>
39
+ <rect x="512" y="112" width="9.6" height="22" fill="#523e94"/>
40
+ <rect x="531.2" y="112" width="9.6" height="22" fill="#4c3a8a"/>
41
+ <text x="195.2" y="194" textLength="441.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#e9e4f5">A curated, terminal-native torrent downloader.</text>
42
+ <text x="262.4" y="216" textLength="316.8" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">games ยท movies ยท tv ยท anime</text>
43
+ <text x="118.4" y="260" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ญโ”€</text>
44
+ <text x="147.2" y="260" textLength="57.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa" font-weight="600">Search</text>
45
+ <text x="214.4" y="260" textLength="499.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ</text>
46
+ <rect x="122.5" y="266" width="1.4" height="22" fill="#a78bfa"/>
47
+ <text x="137.6" y="282" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โฏ</text>
48
+ <rect x="156.8" y="266" width="9.6" height="22" fill="#ddd8ea"/>
49
+ <text x="156.8" y="282" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#0a0810">S</text>
50
+ <text x="166.4" y="282" textLength="278.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">earch or paste a magnet linkโ€ฆ</text>
51
+ <rect x="708.1" y="266" width="1.4" height="22" fill="#a78bfa"/>
52
+ <text x="118.4" y="304" textLength="595.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#a78bfa">โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ</text>
53
+ <text x="233.6" y="348" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">โ†ต</text>
54
+ <text x="252.8" y="348" textLength="153.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">search ยท empty</text>
55
+ <text x="416" y="348" textLength="9.6" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">โ†ต</text>
56
+ <text x="435.2" y="348" textLength="86.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">browse ยท</text>
57
+ <text x="540.8" y="348" textLength="19.2" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill="#b9a7e6">^c</text>
58
+ <text x="569.6" y="348" textLength="38.4" lengthAdjust="spacingAndGlyphs" xml:space="preserve" fill-opacity="0.55">quit</text>
59
+ </g>
60
+ </svg>