7 Commits
0.1.1 ... 0.1.3

Author SHA1 Message Date
Gitea CI
25ed12fdf9 Bump version: 0.1.2 → 0.1.3 2025-07-04 14:24:50 +00:00
d29938bcf5 .
Merge branch 'master' of https://git.theprivateserver.de/KomSuite/KomSuite-NyaaPy
2025-07-04 16:20:13 +02:00
df256f5be2 refactor: do not download torrent file to identify contents 2025-07-04 16:17:17 +02:00
Gitea CI
126747a77e Bump version: 0.1.1 → 0.1.2 2025-06-29 12:26:14 +00:00
a6ffbd59f8 iuntegrate bumpversion into pyproject, change workflow 2025-06-29 14:25:23 +02:00
bfaad4de0d add async api 2025-06-29 14:20:10 +02:00
b5cdabf0f6 add httpx dependencies 2025-06-29 14:19:41 +02:00
7 changed files with 174 additions and 57 deletions

View File

@@ -1,21 +0,0 @@
[tool.bumpversion]
current_version = "0.1.0"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
search = "{current_version}"
replace = "{new_version}"
regex = false
ignore_missing_version = false
ignore_missing_files = false
tag = false
sign_tags = false
tag_name = "v{new_version}"
tag_message = "Bump version: {current_version} → {new_version}"
allow_dirty = false
commit = false
message = "Bump version: {current_version} → {new_version}"
moveable_tags = []
commit_args = ""
setup_hooks = []
pre_commit_hooks = []
post_commit_hooks = []

View File

@@ -25,10 +25,16 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@master uses: actions/checkout@master
with:
fetch-depth: 0
fetch-tags: true
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v5
- name: Set up Python - name: Set up Python
run: uv python install run: uv python install
with:
python-version-file: "pyproject.toml"
- name: Set Git identity - name: Set Git identity
run: | run: |
git config user.name "Gitea CI" git config user.name "Gitea CI"

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "komsuite-nyaapy" name = "komsuite-nyaapy"
version = "0.1.0" version = "0.1.3"
description = "A rewritten hard fork of the original NyaaPy library." description = "A rewritten hard fork of the original NyaaPy library."
license = "MIT" license = "MIT"
readme = "README.md" readme = "README.md"
@@ -8,6 +8,8 @@ authors = [{ name = "WorldTeacher", email = "coding_contact@pm.me" }]
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"bencodepy>=0.9.5", "bencodepy>=0.9.5",
"httpx>=0.28.1",
"httpx-retries>=0.3.2",
"lxml>=5.3.1", "lxml>=5.3.1",
"regex>=2024.11.6", "regex>=2024.11.6",
] ]
@@ -16,3 +18,25 @@ dependencies = [
[build-system] [build-system]
requires = ["hatchling"] requires = ["hatchling"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[tool.bumpversion]
current_version = "0.1.3"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
search = "{current_version}"
replace = "{new_version}"
regex = false
ignore_missing_version = false
ignore_missing_files = false
tag = true
sign_tags = false
tag_name = "v{new_version}"
tag_message = "Bump version: {current_version} → {new_version}"
allow_dirty = true
commit = true
message = "Bump version: {current_version} → {new_version}"
moveable_tags = []
commit_args = ""
setup_hooks = []
pre_commit_hooks = []
post_commit_hooks = []

View File

@@ -1,4 +1,4 @@
from .modules.anime_site import AnimeTorrentSite from .modules.anime_site import AnimeTorrentSite, AnimeTorrentSiteAsync
from .modules.torrent import TorrentSite from .modules.torrent import TorrentSite
from .sites.nyaa import Nyaa, SukebeiNyaa from .sites.nyaa import Nyaa, SukebeiNyaa
from .modules.torrent import Torrent from .modules.torrent import Torrent

View File

@@ -1,4 +1,4 @@
import requests import httpx
from komsuite_nyaapy.modules import torrent from komsuite_nyaapy.modules import torrent
from komsuite_nyaapy.modules.parser import parse_nyaa, parse_single, parse_nyaa_rss from komsuite_nyaapy.modules.parser import parse_nyaa, parse_single, parse_nyaa_rss
@@ -8,21 +8,20 @@ class AnimeTorrentSite:
URL = SITE URL = SITE
@classmethod @classmethod
def last_uploads(self, number_of_results: int): def last_uploads(cls, number_of_results: int):
r = requests.get(self.URL) with httpx.Client() as client:
r = client.get(cls.URL)
r.raise_for_status()
# If anything up with nyaa servers let the user know. json_data = parse_nyaa(
r.raise_for_status() request_text=r.text, limit=number_of_results, site=cls.SITE
)
json_data = parse_nyaa(
request_text=r.text, limit=number_of_results, site=self.SITE
)
return torrent.json_to_class(json_data) return torrent.json_to_class(json_data)
@classmethod @classmethod
def search( def search(
self, cls,
keyword: str, keyword: str,
category: int = 0, category: int = 0,
subcategory: int = 0, subcategory: int = 0,
@@ -32,10 +31,9 @@ class AnimeTorrentSite:
order: str = "desc", order: str = "desc",
**kwargs, **kwargs,
): ):
base_url = self.URL base_url = cls.URL
user = kwargs.get("user", None) user = kwargs.get("user", None)
user_uri = f"user/{user}" if user else "" user_uri = f"user/{user}" if user else ""
if page > 0: if page > 0:
@@ -64,34 +62,134 @@ class AnimeTorrentSite:
if not user: if not user:
search_uri += "&page=rss" search_uri += "&page=rss"
http_response = requests.get(search_uri)
http_response.raise_for_status()
if user: with httpx.Client() as client:
http_response = client.get(search_uri)
http_response.raise_for_status()
if user:
json_data = parse_nyaa(
request_text=http_response.content, limit=None, site=cls.SITE
)
else:
json_data = parse_nyaa_rss(
request_text=http_response.content, limit=None, site=cls.SITE
)
return torrent.json_to_class(json_data)
@classmethod
def get(cls, view_id: int):
with httpx.Client() as client:
r = client.get(f"{cls.URL}/view/{view_id}")
r.raise_for_status()
json_data = parse_single(request_text=r.content, site=cls.SITE)
return torrent.json_to_class(json_data)
@classmethod
def get_from_user(cls, username):
with httpx.Client() as client:
r = client.get(f"{cls.URL}/user/{username}")
r.raise_for_status()
json_data = parse_nyaa(request_text=r.content, limit=None, site=cls.SITE)
return torrent.json_to_class(json_data)
class AnimeTorrentSiteAsync:
SITE = torrent.TorrentSite.NYAASI
URL = SITE
@classmethod
async def last_uploads(cls, number_of_results: int):
async with httpx.AsyncClient() as client:
r = await client.get(cls.URL)
r.raise_for_status()
json_data = parse_nyaa( json_data = parse_nyaa(
request_text=http_response.content, limit=None, site=self.SITE request_text=r.text, limit=number_of_results, site=cls.SITE
)
return torrent.json_to_class(json_data)
@classmethod
async def search(
cls,
keyword: str,
category: int = 0,
subcategory: int = 0,
filters: int = 0,
page: int = 0,
sorting: str = "id",
order: str = "desc",
**kwargs,
):
base_url = cls.URL
user = kwargs.get("user", None)
user_uri = f"user/{user}" if user else ""
if page > 0:
search_uri = "{}/{}?f={}&c={}_{}&q={}&p={}&s={}&o={}".format(
base_url,
user_uri,
filters,
category,
subcategory,
keyword,
page,
sorting,
order,
) )
else: else:
json_data = parse_nyaa_rss( search_uri = "{}/{}?f={}&c={}_{}&q={}&s={}&o={}".format(
request_text=http_response.content, limit=None, site=self.SITE base_url,
user_uri,
filters,
category,
subcategory,
keyword,
sorting,
order,
) )
# Convert JSON data to a class object if not user:
return torrent.json_to_class(json_data) search_uri += "&page=rss"
@classmethod async with httpx.AsyncClient() as client:
def get(self, view_id: int): http_response = await client.get(search_uri)
r = requests.get(f"{self.URL}/view/{view_id}") http_response.raise_for_status()
r.raise_for_status()
json_data = parse_single(request_text=r.content, site=self.SITE) if user:
json_data = parse_nyaa(
request_text=http_response.content, limit=None, site=cls.SITE
)
else:
json_data = parse_nyaa_rss(
request_text=http_response.content, limit=None, site=cls.SITE
)
return torrent.json_to_class(json_data) return torrent.json_to_class(json_data)
@classmethod @classmethod
def get_from_user(self, username): async def get(cls, view_id: int):
r = requests.get(f"{self.URL}/user/{username}") async with httpx.AsyncClient() as client:
r.raise_for_status() r = await client.get(f"{cls.URL}/view/{view_id}")
r.raise_for_status()
json_data = parse_single(request_text=r.content, site=cls.SITE)
return torrent.json_to_class(json_data)
@classmethod
async def get_from_user(cls, username):
async with httpx.AsyncClient() as client:
r = await client.get(f"{cls.URL}/user/{username}")
r.raise_for_status()
json_data = parse_nyaa(request_text=r.content, limit=None, site=cls.SITE)
json_data = parse_nyaa(request_text=r.content, limit=None, site=self.SITE)
return torrent.json_to_class(json_data) return torrent.json_to_class(json_data)

View File

@@ -7,6 +7,7 @@ import regex
from typing import Optional from typing import Optional
import loguru import loguru
import sys import sys
import requests
log = loguru.logger log = loguru.logger
log.remove() log.remove()
@@ -66,10 +67,11 @@ class Torrent:
@property @property
def get_contents(self): def get_contents(self):
os.system(f"wget {self.download_url}> /dev/null 2>&1") resp = requests.get(self.download_url, timeout=15)
with open(f"{self.download_url.split('/')[-1]}", "rb") as f: resp.raise_for_status() # raises for HTTP 4xx/5xx
data = bencodepy.decode(f.read())
# 2. Decode directly from bytes
data = bencodepy.decode(resp.content)
info = data[b"info"] info = data[b"info"]
filetypes: list[str] = [] filetypes: list[str] = []
@@ -120,7 +122,6 @@ class Torrent:
else: else:
self.volumes = [0] self.volumes = [0]
# log.debug("Filetypes: {}, Volumes: {}".format(self.filetypes, self.volumes)) #! enable for debug # log.debug("Filetypes: {}, Volumes: {}".format(self.filetypes, self.volumes)) #! enable for debug
os.remove(f"{self.download_url.split('/')[-1]}")
class TorrentSite(Enum): class TorrentSite(Enum):

View File

@@ -1,4 +1,4 @@
from komsuite_nyaapy import AnimeTorrentSite, TorrentSite from komsuite_nyaapy import AnimeTorrentSite, TorrentSite, AnimeTorrentSiteAsync
class SukebeiNyaa(AnimeTorrentSite): class SukebeiNyaa(AnimeTorrentSite):
@@ -9,3 +9,12 @@ class SukebeiNyaa(AnimeTorrentSite):
class Nyaa(AnimeTorrentSite): class Nyaa(AnimeTorrentSite):
SITE = TorrentSite.NYAASI SITE = TorrentSite.NYAASI
URL = TorrentSite.get_site(SITE) URL = TorrentSite.get_site(SITE)
class SukebiNyaaAsync(AnimeTorrentSiteAsync):
SITE = TorrentSite.SUKEBEINYAASI
URL = TorrentSite.get_site(SITE)
class NyaaAsync(AnimeTorrentSiteAsync):
SITE = TorrentSite.NYAASI
URL = TorrentSite.get_site(SITE)