torrra 0.1.0__tar.gz
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.
- torrra-0.1.0/.github/workflows/release.yml +28 -0
- torrra-0.1.0/.gitignore +10 -0
- torrra-0.1.0/.pre-commit-config.yaml +7 -0
- torrra-0.1.0/.python-version +1 -0
- torrra-0.1.0/PKG-INFO +105 -0
- torrra-0.1.0/README.md +93 -0
- torrra-0.1.0/pyproject.toml +25 -0
- torrra-0.1.0/requirements.txt +82 -0
- torrra-0.1.0/src/torrra/__init__.py +3 -0
- torrra-0.1.0/src/torrra/cli/__init__.py +0 -0
- torrra-0.1.0/src/torrra/cli/main.py +69 -0
- torrra-0.1.0/src/torrra/downloader.py +77 -0
- torrra-0.1.0/src/torrra/indexers/__init__.py +1 -0
- torrra-0.1.0/src/torrra/indexers/base.py +20 -0
- torrra-0.1.0/src/torrra/indexers/yts_mx.py +56 -0
- torrra-0.1.0/src/torrra/types.py +13 -0
- torrra-0.1.0/src/torrra/utils/__init__.py +0 -0
- torrra-0.1.0/src/torrra/utils/html.py +8 -0
- torrra-0.1.0/uv.lock +213 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
name: Publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: pypi
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv and setup the python version
|
|
19
|
+
uses: astral-sh/setup-uv@v5
|
|
20
|
+
|
|
21
|
+
- name: Install the project
|
|
22
|
+
run: uv sync --all-groups
|
|
23
|
+
|
|
24
|
+
- name: Build wheel
|
|
25
|
+
run: uv build
|
|
26
|
+
|
|
27
|
+
- name: Publish package
|
|
28
|
+
run: uv publish
|
torrra-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
torrra-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: torrra
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI-based torrent search and downloader
|
|
5
|
+
Author: stabldev
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: httpx>=0.28.1
|
|
8
|
+
Requires-Dist: questionary>=2.1.0
|
|
9
|
+
Requires-Dist: rich>=14.0.0
|
|
10
|
+
Requires-Dist: selectolax>=0.3.31
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# torrra 🎯
|
|
14
|
+
|
|
15
|
+
> CLI-based torrent search and downloader
|
|
16
|
+
|
|
17
|
+
`torrra` is a sleek and minimal command-line tool to search torrents from various indexers and download them- all from your terminal.
|
|
18
|
+
|
|
19
|
+
## ✨ Features
|
|
20
|
+
|
|
21
|
+
- Search torrents from multiple indexers (`YTS` supported; more coming)
|
|
22
|
+
- Fetch magnet links directly
|
|
23
|
+
- Download torrents via libtorrent
|
|
24
|
+
- Pretty CLI with Rich-powered progress bars
|
|
25
|
+
- Modular and easily extensible indexer architecture
|
|
26
|
+
|
|
27
|
+
## 📦 Installation
|
|
28
|
+
|
|
29
|
+
> Requires Python 3.11+ and [libtorrent-rasterbar](https://libtorrent.org/).
|
|
30
|
+
|
|
31
|
+
### 1. Install `libtorrent`
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Linux (Arch)
|
|
35
|
+
sudo pacman -S libtorrent-rasterbar
|
|
36
|
+
# Linux (Debian/Ubuntu)
|
|
37
|
+
sudo apt install python3-libtorrent
|
|
38
|
+
|
|
39
|
+
# macOS (Homebrew)
|
|
40
|
+
brew install libtorrent-rasterbar
|
|
41
|
+
|
|
42
|
+
# Windows/macOS (Python wheels)
|
|
43
|
+
pip install python-libtorrent
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
> Note: For Windows users, the `python-libtorrent` wheel includes all dependencies and is the recommended method.
|
|
47
|
+
|
|
48
|
+
### 2. Install `torrra`
|
|
49
|
+
```bash
|
|
50
|
+
pip install torrra
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### OR: compile from source (advanced)
|
|
54
|
+
|
|
55
|
+
See libtorrent's build guide:
|
|
56
|
+
https://libtorrent.org/building.html
|
|
57
|
+
|
|
58
|
+
For local development, fork the repo, then:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/yourusername/torrra
|
|
62
|
+
cd torrra
|
|
63
|
+
uv sync
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 💡 Usage
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
torrra
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Follow the prompts:
|
|
73
|
+
|
|
74
|
+
1. Enter search query
|
|
75
|
+
2. Pick an indexer
|
|
76
|
+
3. Select a torrent
|
|
77
|
+
4. Choose quality / magnet link
|
|
78
|
+
5. Pick a download folder
|
|
79
|
+
|
|
80
|
+
## 🧩 Indexer Support
|
|
81
|
+
|
|
82
|
+
Currently supported:
|
|
83
|
+
|
|
84
|
+
- YTS (movies)
|
|
85
|
+
|
|
86
|
+
Planned:
|
|
87
|
+
|
|
88
|
+
- 1337x
|
|
89
|
+
- GLodls
|
|
90
|
+
- Nyaa (anime-only, optional)
|
|
91
|
+
- Community-driven additions
|
|
92
|
+
|
|
93
|
+
## 🛠️ Dev Notes
|
|
94
|
+
|
|
95
|
+
- Modular indexer structure (`torrra/indexers`)
|
|
96
|
+
- Extend `BaseIndexer` to add new sources
|
|
97
|
+
- Built using:
|
|
98
|
+
- `httpx` + `selectolax` for scraping
|
|
99
|
+
- `libtorrent` for torrenting
|
|
100
|
+
- `rich` for CLI visuals
|
|
101
|
+
- `questionary` for input prompts
|
|
102
|
+
|
|
103
|
+
## 📜 License
|
|
104
|
+
|
|
105
|
+
MIT © [stabldev](https://github.com/stabldev)
|
torrra-0.1.0/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# torrra 🎯
|
|
2
|
+
|
|
3
|
+
> CLI-based torrent search and downloader
|
|
4
|
+
|
|
5
|
+
`torrra` is a sleek and minimal command-line tool to search torrents from various indexers and download them- all from your terminal.
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- Search torrents from multiple indexers (`YTS` supported; more coming)
|
|
10
|
+
- Fetch magnet links directly
|
|
11
|
+
- Download torrents via libtorrent
|
|
12
|
+
- Pretty CLI with Rich-powered progress bars
|
|
13
|
+
- Modular and easily extensible indexer architecture
|
|
14
|
+
|
|
15
|
+
## 📦 Installation
|
|
16
|
+
|
|
17
|
+
> Requires Python 3.11+ and [libtorrent-rasterbar](https://libtorrent.org/).
|
|
18
|
+
|
|
19
|
+
### 1. Install `libtorrent`
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Linux (Arch)
|
|
23
|
+
sudo pacman -S libtorrent-rasterbar
|
|
24
|
+
# Linux (Debian/Ubuntu)
|
|
25
|
+
sudo apt install python3-libtorrent
|
|
26
|
+
|
|
27
|
+
# macOS (Homebrew)
|
|
28
|
+
brew install libtorrent-rasterbar
|
|
29
|
+
|
|
30
|
+
# Windows/macOS (Python wheels)
|
|
31
|
+
pip install python-libtorrent
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
> Note: For Windows users, the `python-libtorrent` wheel includes all dependencies and is the recommended method.
|
|
35
|
+
|
|
36
|
+
### 2. Install `torrra`
|
|
37
|
+
```bash
|
|
38
|
+
pip install torrra
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### OR: compile from source (advanced)
|
|
42
|
+
|
|
43
|
+
See libtorrent's build guide:
|
|
44
|
+
https://libtorrent.org/building.html
|
|
45
|
+
|
|
46
|
+
For local development, fork the repo, then:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/yourusername/torrra
|
|
50
|
+
cd torrra
|
|
51
|
+
uv sync
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 💡 Usage
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
torrra
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Follow the prompts:
|
|
61
|
+
|
|
62
|
+
1. Enter search query
|
|
63
|
+
2. Pick an indexer
|
|
64
|
+
3. Select a torrent
|
|
65
|
+
4. Choose quality / magnet link
|
|
66
|
+
5. Pick a download folder
|
|
67
|
+
|
|
68
|
+
## 🧩 Indexer Support
|
|
69
|
+
|
|
70
|
+
Currently supported:
|
|
71
|
+
|
|
72
|
+
- YTS (movies)
|
|
73
|
+
|
|
74
|
+
Planned:
|
|
75
|
+
|
|
76
|
+
- 1337x
|
|
77
|
+
- GLodls
|
|
78
|
+
- Nyaa (anime-only, optional)
|
|
79
|
+
- Community-driven additions
|
|
80
|
+
|
|
81
|
+
## 🛠️ Dev Notes
|
|
82
|
+
|
|
83
|
+
- Modular indexer structure (`torrra/indexers`)
|
|
84
|
+
- Extend `BaseIndexer` to add new sources
|
|
85
|
+
- Built using:
|
|
86
|
+
- `httpx` + `selectolax` for scraping
|
|
87
|
+
- `libtorrent` for torrenting
|
|
88
|
+
- `rich` for CLI visuals
|
|
89
|
+
- `questionary` for input prompts
|
|
90
|
+
|
|
91
|
+
## 📜 License
|
|
92
|
+
|
|
93
|
+
MIT © [stabldev](https://github.com/stabldev)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "torrra"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "CLI-based torrent search and downloader"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "stabldev" }]
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"httpx>=0.28.1",
|
|
10
|
+
"questionary>=2.1.0",
|
|
11
|
+
"rich>=14.0.0",
|
|
12
|
+
"selectolax>=0.3.31",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
torrra = "torrra:main"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["hatchling"]
|
|
20
|
+
build-backend = "hatchling.build"
|
|
21
|
+
|
|
22
|
+
[dependency-groups]
|
|
23
|
+
dev = [
|
|
24
|
+
"libtorrent>=2.0.11",
|
|
25
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# This file was autogenerated by uv via the following command:
|
|
2
|
+
# uv export --frozen --output-file=requirements.txt
|
|
3
|
+
-e .
|
|
4
|
+
anyio==4.9.0 \
|
|
5
|
+
--hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \
|
|
6
|
+
--hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c
|
|
7
|
+
# via httpx
|
|
8
|
+
certifi==2025.6.15 \
|
|
9
|
+
--hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \
|
|
10
|
+
--hash=sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b
|
|
11
|
+
# via
|
|
12
|
+
# httpcore
|
|
13
|
+
# httpx
|
|
14
|
+
h11==0.16.0 \
|
|
15
|
+
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
|
|
16
|
+
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
|
17
|
+
# via httpcore
|
|
18
|
+
httpcore==1.0.9 \
|
|
19
|
+
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
|
|
20
|
+
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
|
|
21
|
+
# via httpx
|
|
22
|
+
httpx==0.28.1 \
|
|
23
|
+
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
|
24
|
+
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
|
25
|
+
# via torrra
|
|
26
|
+
idna==3.10 \
|
|
27
|
+
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
|
|
28
|
+
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
|
|
29
|
+
# via
|
|
30
|
+
# anyio
|
|
31
|
+
# httpx
|
|
32
|
+
libtorrent==2.0.11 \
|
|
33
|
+
--hash=sha256:474e792c52319cc918a007aa61cb34fb7f9236fa6c9603953e8c0fb3e6d922c7 \
|
|
34
|
+
--hash=sha256:51daa58d0958ac99d88a1749d6848c6023ea899da98e503b12a1a311189d79fd \
|
|
35
|
+
--hash=sha256:55aa67cdc8cbf777e41998d5432a3ab01f198c955ec6d2fb14c500b309db3f37 \
|
|
36
|
+
--hash=sha256:63fcb829d2b9fed566771426c7b1473a4acb7ccb4957ef07793b28de8468cd3e \
|
|
37
|
+
--hash=sha256:758662c88a186c6018e4062d1b1b5e58ed55e17189ad4a7389c87b8b2b5efeb4 \
|
|
38
|
+
--hash=sha256:8be0e27f40594bfee42e60e7785261834fdaf938267dceee8a08eae08a12a3c2 \
|
|
39
|
+
--hash=sha256:e234f665c987262d4102f6d2e099d76b12dfa20bcc77b77891184b075ab84ea8 \
|
|
40
|
+
--hash=sha256:f4489732bbc44114c7fb1893b71c578052d1aca352852002938b23ac8a6fb5c3 \
|
|
41
|
+
--hash=sha256:f72f0075b84aa18d25ee3ab3c39ba5193777d34d016c9a38294c92ffc60f6225
|
|
42
|
+
markdown-it-py==3.0.0 \
|
|
43
|
+
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
|
|
44
|
+
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
|
|
45
|
+
# via rich
|
|
46
|
+
mdurl==0.1.2 \
|
|
47
|
+
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
|
48
|
+
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
|
49
|
+
# via markdown-it-py
|
|
50
|
+
prompt-toolkit==3.0.51 \
|
|
51
|
+
--hash=sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07 \
|
|
52
|
+
--hash=sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed
|
|
53
|
+
# via questionary
|
|
54
|
+
pygments==2.19.2 \
|
|
55
|
+
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
|
|
56
|
+
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
|
|
57
|
+
# via rich
|
|
58
|
+
questionary==2.1.0 \
|
|
59
|
+
--hash=sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec \
|
|
60
|
+
--hash=sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587
|
|
61
|
+
# via torrra
|
|
62
|
+
rich==14.0.0 \
|
|
63
|
+
--hash=sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0 \
|
|
64
|
+
--hash=sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725
|
|
65
|
+
# via torrra
|
|
66
|
+
selectolax==0.3.31 \
|
|
67
|
+
--hash=sha256:0f3b32d50c663b27d5b59c303c1aef1b4a3ae654b5e6921e17f25ed6f09a6d95 \
|
|
68
|
+
--hash=sha256:1427c2c7d83e8ca04fde77cae3222ab3f97b9f98db1ada06ceb93682b3cf202d \
|
|
69
|
+
--hash=sha256:68fdf557b6ebbb55f28b3747f29591694d12eec16f56cb8a5f8f4fab04b4fa0a \
|
|
70
|
+
--hash=sha256:90b63149e1e44e4b8fcd06669f30a7c68062bfb264d8c621d03fdc4850e6e5c9 \
|
|
71
|
+
--hash=sha256:c8937b21aef5c752b03368a88c6c889bc1557299926194cf248ed16f64617e6c \
|
|
72
|
+
--hash=sha256:e1985c95c91c1244d99ce5ec3284a1256a2da75232cdfde6932f3bdb469a7a8d \
|
|
73
|
+
--hash=sha256:ee1414a76142c3474f26df0140cda1edb92cc5f44d995de88bcf48982dc6c986
|
|
74
|
+
# via torrra
|
|
75
|
+
sniffio==1.3.1 \
|
|
76
|
+
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
|
|
77
|
+
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
|
|
78
|
+
# via anyio
|
|
79
|
+
wcwidth==0.2.13 \
|
|
80
|
+
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
|
|
81
|
+
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
|
|
82
|
+
# via prompt-toolkit
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from prompt_toolkit.shortcuts import CompleteStyle
|
|
3
|
+
import questionary
|
|
4
|
+
from questionary import Choice
|
|
5
|
+
from typing import List
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from torrra.downloader import download_magnet
|
|
9
|
+
from torrra.indexers import INDEXERS
|
|
10
|
+
from torrra.types import Magnet, Torrent
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main() -> None:
|
|
16
|
+
query = questionary.text("Search:").ask()
|
|
17
|
+
|
|
18
|
+
if not query:
|
|
19
|
+
console.print("[red]No query entered. Exiting...[/red]")
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
indexer_name = questionary.select(
|
|
23
|
+
"Choose an indexer:", choices=list(INDEXERS.keys())
|
|
24
|
+
).ask()
|
|
25
|
+
indexer_module_path = INDEXERS[indexer_name]
|
|
26
|
+
indexer = importlib.import_module(indexer_module_path).Indexer()
|
|
27
|
+
|
|
28
|
+
with console.status(
|
|
29
|
+
f"[bold green]Searching {indexer_name} for '{query}'...[/bold green]"
|
|
30
|
+
):
|
|
31
|
+
torrents: List[Torrent] = indexer.search(query)
|
|
32
|
+
|
|
33
|
+
if not torrents:
|
|
34
|
+
console.print("[yellow]Could not find any torrents. Exiting...[/yellow]")
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
torrent_choices = [
|
|
38
|
+
Choice(title=torrent.title, value=torrent) for torrent in torrents
|
|
39
|
+
]
|
|
40
|
+
selected_torrent: Torrent | None = questionary.select(
|
|
41
|
+
"Select a torrent:", choices=torrent_choices
|
|
42
|
+
).ask()
|
|
43
|
+
|
|
44
|
+
if not selected_torrent:
|
|
45
|
+
console.print("[yellow]No torrent selected. Exiting...[/yellow]")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
with console.status(
|
|
49
|
+
f"[bold green]Fetching magnet links for '{selected_torrent.title}'...[/bold green]"
|
|
50
|
+
):
|
|
51
|
+
magnets: List[Magnet] = indexer.get_magnets(selected_torrent.link)
|
|
52
|
+
|
|
53
|
+
if not magnets:
|
|
54
|
+
console.print("[yellow]No magnet links found. Exiting...[/yellow]")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
magnet_choices = [Choice(title=magnet.title, value=magnet) for magnet in magnets]
|
|
58
|
+
selected_magnet: Magnet | None = questionary.select(
|
|
59
|
+
"Select:", choices=magnet_choices
|
|
60
|
+
).ask()
|
|
61
|
+
|
|
62
|
+
if not selected_magnet:
|
|
63
|
+
console.print("[yellow]No magnet selected. Exiting...[/yellow]")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
save_path = questionary.path(
|
|
67
|
+
"Download path:", only_directories=True, complete_style=CompleteStyle.COLUMN
|
|
68
|
+
).ask()
|
|
69
|
+
download_magnet(selected_magnet.magnet_uri, save_path)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import libtorrent as lt
|
|
2
|
+
import time
|
|
3
|
+
from rich.progress import (
|
|
4
|
+
Progress,
|
|
5
|
+
BarColumn,
|
|
6
|
+
TransferSpeedColumn,
|
|
7
|
+
TimeRemainingColumn,
|
|
8
|
+
TextColumn,
|
|
9
|
+
TaskProgressColumn,
|
|
10
|
+
DownloadColumn,
|
|
11
|
+
)
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def download_magnet(magnet_uri: str, save_path: str):
|
|
18
|
+
ses = lt.session()
|
|
19
|
+
ses.listen_on(6881, 6891)
|
|
20
|
+
|
|
21
|
+
params = {
|
|
22
|
+
"save_path": save_path,
|
|
23
|
+
"storage_mode": lt.storage_mode_t(2),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
handle = lt.add_magnet_uri(ses, magnet_uri, params)
|
|
27
|
+
|
|
28
|
+
console.print("[bold green]Downloading metadata...[/bold green]")
|
|
29
|
+
while not handle.has_metadata():
|
|
30
|
+
time.sleep(0.5)
|
|
31
|
+
|
|
32
|
+
torrent_info = handle.get_torrent_info()
|
|
33
|
+
total_size = torrent_info.total_size()
|
|
34
|
+
file_count = torrent_info.num_files()
|
|
35
|
+
|
|
36
|
+
console.print(
|
|
37
|
+
f"[bold green]Starting download: [cyan]{handle.name()}[/cyan][/bold green]"
|
|
38
|
+
)
|
|
39
|
+
console.print(
|
|
40
|
+
f"[yellow]Size:[/yellow] {total_size/(1024*1024):.2f} MB | [yellow]Files:[/yellow] {file_count}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
with Progress(
|
|
44
|
+
TextColumn("[bold blue]{task.fields[filename]}"),
|
|
45
|
+
BarColumn(),
|
|
46
|
+
TaskProgressColumn(),
|
|
47
|
+
DownloadColumn(),
|
|
48
|
+
TransferSpeedColumn(),
|
|
49
|
+
TimeRemainingColumn(),
|
|
50
|
+
console=console,
|
|
51
|
+
) as progress:
|
|
52
|
+
task = progress.add_task(
|
|
53
|
+
"download", filename=handle.name(), peers=0, total=total_size
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
prev_downloaded = 0
|
|
57
|
+
prev_time = time.time()
|
|
58
|
+
|
|
59
|
+
while not handle.is_seed():
|
|
60
|
+
s = handle.status()
|
|
61
|
+
|
|
62
|
+
# calculate real-time download speed
|
|
63
|
+
cur_time = time.time()
|
|
64
|
+
downloaded = s.total_done
|
|
65
|
+
elapsed = cur_time - prev_time
|
|
66
|
+
speed = (downloaded - prev_downloaded) / elapsed if elapsed > 0 else 0
|
|
67
|
+
|
|
68
|
+
progress.update(task, completed=downloaded, speed=speed)
|
|
69
|
+
|
|
70
|
+
prev_downloaded = downloaded
|
|
71
|
+
prev_time = cur_time
|
|
72
|
+
time.sleep(0.5)
|
|
73
|
+
|
|
74
|
+
console.print(
|
|
75
|
+
f"\n[bold green]✓ Download complete: [cyan]{handle.name()}[/cyan][/bold green]"
|
|
76
|
+
)
|
|
77
|
+
console.print(f"[green]Saved to: [underline]{save_path}[/underline][/green]")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
INDEXERS = {"yts.mx": "torrra.indexers.yts_mx"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from selectolax.parser import HTMLParser
|
|
3
|
+
|
|
4
|
+
from torrra.types import Magnet, Torrent
|
|
5
|
+
from torrra.utils.html import parse_html
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BaseIndexer(ABC):
|
|
10
|
+
def _get_parser(self, url: str) -> HTMLParser:
|
|
11
|
+
html = parse_html(url)
|
|
12
|
+
return HTMLParser(html)
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def search(self, query: str) -> List[Torrent]:
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def get_magnets(self, link: str) -> List[Magnet]:
|
|
20
|
+
pass
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from torrra.indexers.base import BaseIndexer
|
|
4
|
+
from torrra.types import Magnet, Torrent
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Indexer(BaseIndexer):
|
|
8
|
+
def search(self, query: str) -> List[Torrent]:
|
|
9
|
+
url = f"https://yts.mx/browse-movies/{query}/all/all/0/latest/0/all"
|
|
10
|
+
parser = self._get_parser(url)
|
|
11
|
+
res = []
|
|
12
|
+
|
|
13
|
+
nodes = parser.css(
|
|
14
|
+
"div.browse-content div.browse-movie-wrap div.browse-movie-bottom"
|
|
15
|
+
)
|
|
16
|
+
for node in nodes:
|
|
17
|
+
title_node = node.css_first("a.browse-movie-title")
|
|
18
|
+
year_node = node.css_first("div.browse-movie-year")
|
|
19
|
+
|
|
20
|
+
title = title_node.text(strip=True) if title_node else ""
|
|
21
|
+
link = title_node.attributes.get("href") if title_node else ""
|
|
22
|
+
|
|
23
|
+
if query not in title.lower() or link is None:
|
|
24
|
+
continue
|
|
25
|
+
|
|
26
|
+
year = year_node.text(strip=True) if year_node else ""
|
|
27
|
+
|
|
28
|
+
torrent_title = f"{title} {year}".strip()
|
|
29
|
+
res.append(Torrent(title=torrent_title, link=link))
|
|
30
|
+
return res
|
|
31
|
+
|
|
32
|
+
def get_magnets(self, link: str) -> List[Magnet]:
|
|
33
|
+
parser = self._get_parser(link)
|
|
34
|
+
res = []
|
|
35
|
+
|
|
36
|
+
nodes = parser.css("div.modal div.modal-torrent")
|
|
37
|
+
for node in nodes:
|
|
38
|
+
resolution_node = node.css_first("div.modal-quality span")
|
|
39
|
+
resolution = resolution_node.text(strip=True) if resolution_node else ""
|
|
40
|
+
|
|
41
|
+
quality_info = resolution
|
|
42
|
+
|
|
43
|
+
quality_size_nodes = node.css("p.quality-size")
|
|
44
|
+
if len(quality_size_nodes) >= 2:
|
|
45
|
+
source = quality_size_nodes[0].text(strip=True)
|
|
46
|
+
size = quality_size_nodes[1].text(strip=True)
|
|
47
|
+
quality_info = f"{source} {resolution} {size}"
|
|
48
|
+
|
|
49
|
+
magnet_node = node.css_first("a.magnet")
|
|
50
|
+
magnet_uri = magnet_node.attributes.get("href") if magnet_node else ""
|
|
51
|
+
|
|
52
|
+
if not magnet_uri:
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
res.append(Magnet(title=quality_info, magnet_uri=magnet_uri))
|
|
56
|
+
return res
|
|
File without changes
|
torrra-0.1.0/uv.lock
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 2
|
|
3
|
+
requires-python = ">=3.13"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "anyio"
|
|
7
|
+
version = "4.9.0"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
dependencies = [
|
|
10
|
+
{ name = "idna" },
|
|
11
|
+
{ name = "sniffio" },
|
|
12
|
+
]
|
|
13
|
+
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
|
|
14
|
+
wheels = [
|
|
15
|
+
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[[package]]
|
|
19
|
+
name = "certifi"
|
|
20
|
+
version = "2025.6.15"
|
|
21
|
+
source = { registry = "https://pypi.org/simple" }
|
|
22
|
+
sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" }
|
|
23
|
+
wheels = [
|
|
24
|
+
{ url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" },
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[[package]]
|
|
28
|
+
name = "h11"
|
|
29
|
+
version = "0.16.0"
|
|
30
|
+
source = { registry = "https://pypi.org/simple" }
|
|
31
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
|
32
|
+
wheels = [
|
|
33
|
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "httpcore"
|
|
38
|
+
version = "1.0.9"
|
|
39
|
+
source = { registry = "https://pypi.org/simple" }
|
|
40
|
+
dependencies = [
|
|
41
|
+
{ name = "certifi" },
|
|
42
|
+
{ name = "h11" },
|
|
43
|
+
]
|
|
44
|
+
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
|
45
|
+
wheels = [
|
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[[package]]
|
|
50
|
+
name = "httpx"
|
|
51
|
+
version = "0.28.1"
|
|
52
|
+
source = { registry = "https://pypi.org/simple" }
|
|
53
|
+
dependencies = [
|
|
54
|
+
{ name = "anyio" },
|
|
55
|
+
{ name = "certifi" },
|
|
56
|
+
{ name = "httpcore" },
|
|
57
|
+
{ name = "idna" },
|
|
58
|
+
]
|
|
59
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
|
60
|
+
wheels = [
|
|
61
|
+
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[[package]]
|
|
65
|
+
name = "idna"
|
|
66
|
+
version = "3.10"
|
|
67
|
+
source = { registry = "https://pypi.org/simple" }
|
|
68
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
|
|
69
|
+
wheels = [
|
|
70
|
+
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[[package]]
|
|
74
|
+
name = "libtorrent"
|
|
75
|
+
version = "2.0.11"
|
|
76
|
+
source = { registry = "https://pypi.org/simple" }
|
|
77
|
+
wheels = [
|
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/92/74/b689c070c1649c69b6f70c27cd9f3418fb3cba7532b6b5f857c1689edcdc/libtorrent-2.0.11-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:f4489732bbc44114c7fb1893b71c578052d1aca352852002938b23ac8a6fb5c3", size = 5555119, upload-time = "2025-01-29T11:34:57.644Z" },
|
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/c1/b8/24e072c2270fc0193332987f1c3082a1cc8276bc462167b3e45fa0bb9a07/libtorrent-2.0.11-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:758662c88a186c6018e4062d1b1b5e58ed55e17189ad4a7389c87b8b2b5efeb4", size = 5654645, upload-time = "2025-01-29T11:35:00.79Z" },
|
|
80
|
+
{ url = "https://files.pythonhosted.org/packages/07/62/5e3bbebfcf19c963f3f960b8a28ad2bf8cad1e56d8dce3ff9387084ef705/libtorrent-2.0.11-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:55aa67cdc8cbf777e41998d5432a3ab01f198c955ec6d2fb14c500b309db3f37", size = 5653493, upload-time = "2025-01-29T11:35:03.139Z" },
|
|
81
|
+
{ url = "https://files.pythonhosted.org/packages/5c/85/e067ca5544e79525b80a7a986cb58e28977f274c4f341d1294c0ea35d7c7/libtorrent-2.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:474e792c52319cc918a007aa61cb34fb7f9236fa6c9603953e8c0fb3e6d922c7", size = 8251482, upload-time = "2025-01-29T11:35:05.522Z" },
|
|
82
|
+
{ url = "https://files.pythonhosted.org/packages/a4/4c/86d834a8bbdd34276e4d87400d105ddab1dd4b8938f2c1229accc03a5b0d/libtorrent-2.0.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e234f665c987262d4102f6d2e099d76b12dfa20bcc77b77891184b075ab84ea8", size = 8514771, upload-time = "2025-01-29T11:35:09.604Z" },
|
|
83
|
+
{ url = "https://files.pythonhosted.org/packages/f6/7e/e369802ae56bad9de629d9ad7c719dc4328aecf9aac8f61d33755d20b269/libtorrent-2.0.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8be0e27f40594bfee42e60e7785261834fdaf938267dceee8a08eae08a12a3c2", size = 12076824, upload-time = "2025-01-29T11:35:12.773Z" },
|
|
84
|
+
{ url = "https://files.pythonhosted.org/packages/51/c6/b78e0f1515e65ca1a22383124cd867a1c9eee40053e7971064dd937c4802/libtorrent-2.0.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51daa58d0958ac99d88a1749d6848c6023ea899da98e503b12a1a311189d79fd", size = 12065489, upload-time = "2025-01-29T11:35:16.533Z" },
|
|
85
|
+
{ url = "https://files.pythonhosted.org/packages/db/4a/cac02c0d907ec37f22131207f69e78a97045d8e8cab6c6b0a29647dbf732/libtorrent-2.0.11-cp313-cp313-win32.whl", hash = "sha256:63fcb829d2b9fed566771426c7b1473a4acb7ccb4957ef07793b28de8468cd3e", size = 1772278, upload-time = "2025-01-29T11:35:19.333Z" },
|
|
86
|
+
{ url = "https://files.pythonhosted.org/packages/3d/7b/49ebb7df766398d49d59335481dafd7f4a3e8669a1aee5a6d22f9338b09c/libtorrent-2.0.11-cp313-cp313-win_amd64.whl", hash = "sha256:f72f0075b84aa18d25ee3ab3c39ba5193777d34d016c9a38294c92ffc60f6225", size = 1973890, upload-time = "2025-01-29T11:35:22.157Z" },
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[[package]]
|
|
90
|
+
name = "markdown-it-py"
|
|
91
|
+
version = "3.0.0"
|
|
92
|
+
source = { registry = "https://pypi.org/simple" }
|
|
93
|
+
dependencies = [
|
|
94
|
+
{ name = "mdurl" },
|
|
95
|
+
]
|
|
96
|
+
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
|
|
97
|
+
wheels = [
|
|
98
|
+
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[[package]]
|
|
102
|
+
name = "mdurl"
|
|
103
|
+
version = "0.1.2"
|
|
104
|
+
source = { registry = "https://pypi.org/simple" }
|
|
105
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
|
106
|
+
wheels = [
|
|
107
|
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[[package]]
|
|
111
|
+
name = "prompt-toolkit"
|
|
112
|
+
version = "3.0.51"
|
|
113
|
+
source = { registry = "https://pypi.org/simple" }
|
|
114
|
+
dependencies = [
|
|
115
|
+
{ name = "wcwidth" },
|
|
116
|
+
]
|
|
117
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" }
|
|
118
|
+
wheels = [
|
|
119
|
+
{ url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" },
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[[package]]
|
|
123
|
+
name = "pygments"
|
|
124
|
+
version = "2.19.2"
|
|
125
|
+
source = { registry = "https://pypi.org/simple" }
|
|
126
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
127
|
+
wheels = [
|
|
128
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
[[package]]
|
|
132
|
+
name = "questionary"
|
|
133
|
+
version = "2.1.0"
|
|
134
|
+
source = { registry = "https://pypi.org/simple" }
|
|
135
|
+
dependencies = [
|
|
136
|
+
{ name = "prompt-toolkit" },
|
|
137
|
+
]
|
|
138
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/b8/d16eb579277f3de9e56e5ad25280fab52fc5774117fb70362e8c2e016559/questionary-2.1.0.tar.gz", hash = "sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587", size = 26775, upload-time = "2024-12-29T11:49:17.802Z" }
|
|
139
|
+
wheels = [
|
|
140
|
+
{ url = "https://files.pythonhosted.org/packages/ad/3f/11dd4cd4f39e05128bfd20138faea57bec56f9ffba6185d276e3107ba5b2/questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec", size = 36747, upload-time = "2024-12-29T11:49:16.734Z" },
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
[[package]]
|
|
144
|
+
name = "rich"
|
|
145
|
+
version = "14.0.0"
|
|
146
|
+
source = { registry = "https://pypi.org/simple" }
|
|
147
|
+
dependencies = [
|
|
148
|
+
{ name = "markdown-it-py" },
|
|
149
|
+
{ name = "pygments" },
|
|
150
|
+
]
|
|
151
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
|
|
152
|
+
wheels = [
|
|
153
|
+
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
[[package]]
|
|
157
|
+
name = "selectolax"
|
|
158
|
+
version = "0.3.31"
|
|
159
|
+
source = { registry = "https://pypi.org/simple" }
|
|
160
|
+
sdist = { url = "https://files.pythonhosted.org/packages/14/38/27c125553ead2b003b8deb0e0d6a2a9c0fab8a33dee71dc492f710c2b911/selectolax-0.3.31.tar.gz", hash = "sha256:1427c2c7d83e8ca04fde77cae3222ab3f97b9f98db1ada06ceb93682b3cf202d", size = 4705062, upload-time = "2025-07-01T13:12:55.372Z" }
|
|
161
|
+
wheels = [
|
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/f5/4a/b57fb6d4d6f7dbdf46538fa8bbcdf23d038fa5e38f6b3d568bac4c29b59b/selectolax-0.3.31-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68fdf557b6ebbb55f28b3747f29591694d12eec16f56cb8a5f8f4fab04b4fa0a", size = 2075492, upload-time = "2025-07-01T13:12:32.078Z" },
|
|
163
|
+
{ url = "https://files.pythonhosted.org/packages/b2/1c/eafcfb255b3fa7eb0d4a563c789fc17540e89da303c3da642f906cc6718d/selectolax-0.3.31-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c8937b21aef5c752b03368a88c6c889bc1557299926194cf248ed16f64617e6c", size = 2069797, upload-time = "2025-07-01T13:12:33.696Z" },
|
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/b3/0b/75ebd89e4391bc959a0d66ae18c3be274fa3542cba7bf64c1d9c8f4370c4/selectolax-0.3.31-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1414a76142c3474f26df0140cda1edb92cc5f44d995de88bcf48982dc6c986", size = 5746598, upload-time = "2025-07-01T13:12:35.496Z" },
|
|
165
|
+
{ url = "https://files.pythonhosted.org/packages/da/d3/0d9ae2678597f2073507b2762ab9854c2cd2564912510618595be645f89e/selectolax-0.3.31-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90b63149e1e44e4b8fcd06669f30a7c68062bfb264d8c621d03fdc4850e6e5c9", size = 5781753, upload-time = "2025-07-01T13:12:37.118Z" },
|
|
166
|
+
{ url = "https://files.pythonhosted.org/packages/53/49/b96bd5ccb0e3a22c968b1a4780396e68d69288187185dac5cec344eada65/selectolax-0.3.31-cp313-cp313-win_amd64.whl", hash = "sha256:0f3b32d50c663b27d5b59c303c1aef1b4a3ae654b5e6921e17f25ed6f09a6d95", size = 1789255, upload-time = "2025-07-01T13:12:38.607Z" },
|
|
167
|
+
{ url = "https://files.pythonhosted.org/packages/f0/41/d94e2608bcbda96605d888ba02668c6d1fc56fd7ef8b39b4d0f0f235b283/selectolax-0.3.31-cp313-cp313-win_arm64.whl", hash = "sha256:e1985c95c91c1244d99ce5ec3284a1256a2da75232cdfde6932f3bdb469a7a8d", size = 1734157, upload-time = "2025-07-01T13:12:39.934Z" },
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
[[package]]
|
|
171
|
+
name = "sniffio"
|
|
172
|
+
version = "1.3.1"
|
|
173
|
+
source = { registry = "https://pypi.org/simple" }
|
|
174
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
|
175
|
+
wheels = [
|
|
176
|
+
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
[[package]]
|
|
180
|
+
name = "torrra"
|
|
181
|
+
version = "0.1.0"
|
|
182
|
+
source = { editable = "." }
|
|
183
|
+
dependencies = [
|
|
184
|
+
{ name = "httpx" },
|
|
185
|
+
{ name = "questionary" },
|
|
186
|
+
{ name = "rich" },
|
|
187
|
+
{ name = "selectolax" },
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
[package.dev-dependencies]
|
|
191
|
+
dev = [
|
|
192
|
+
{ name = "libtorrent" },
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
[package.metadata]
|
|
196
|
+
requires-dist = [
|
|
197
|
+
{ name = "httpx", specifier = ">=0.28.1" },
|
|
198
|
+
{ name = "questionary", specifier = ">=2.1.0" },
|
|
199
|
+
{ name = "rich", specifier = ">=14.0.0" },
|
|
200
|
+
{ name = "selectolax", specifier = ">=0.3.31" },
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
[package.metadata.requires-dev]
|
|
204
|
+
dev = [{ name = "libtorrent", specifier = ">=2.0.11" }]
|
|
205
|
+
|
|
206
|
+
[[package]]
|
|
207
|
+
name = "wcwidth"
|
|
208
|
+
version = "0.2.13"
|
|
209
|
+
source = { registry = "https://pypi.org/simple" }
|
|
210
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" }
|
|
211
|
+
wheels = [
|
|
212
|
+
{ url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" },
|
|
213
|
+
]
|