Add issue templates and CI workflows; remove obsolete files
- Created bug report and feature request templates for better issue tracking. - Added a build workflow for automated package management and release. - Removed outdated CodeQL analysis and Python publish workflows. - Updated project metadata in pyproject.toml and README.md. - Refactored torrent handling and site interaction modules.
This commit is contained in:
34
.gitea/ISSUE_TEMPLATE/bug.yml
Normal file
34
.gitea/ISSUE_TEMPLATE/bug.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Report a bug in this project
|
||||||
|
labels:
|
||||||
|
- kind/bug
|
||||||
|
- triage
|
||||||
|
body:
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: bug
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: |
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
What did you expect to happen? What happened instead?
|
||||||
|
Include screenshots if applicable.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduction
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: |
|
||||||
|
A clear and concise description of how to reproduce the bug.
|
||||||
|
Include steps, code snippets, or screenshots if applicable.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: additional-info
|
||||||
|
attributes:
|
||||||
|
label: Additional information
|
||||||
|
description: |
|
||||||
|
Add any other context or screenshots about the bug here.
|
||||||
|
|
||||||
|
|
||||||
23
.gitea/ISSUE_TEMPLATE/feature.yml
Normal file
23
.gitea/ISSUE_TEMPLATE/feature.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: Feature request
|
||||||
|
description: Suggest an idea for this project
|
||||||
|
labels:
|
||||||
|
- kind/feature
|
||||||
|
- triage
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: feature
|
||||||
|
attributes:
|
||||||
|
label: Describe the feature
|
||||||
|
description: |
|
||||||
|
A clear and concise description of what the feature is.
|
||||||
|
What is the problem it solves? What are you trying to accomplish?
|
||||||
|
Include screenshots if applicable.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: additional-info
|
||||||
|
attributes:
|
||||||
|
label: Additional information
|
||||||
|
description: |
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
88
.gitea/workflows/build.yml
Normal file
88
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_notes:
|
||||||
|
description: Release notes (use \n for newlines)
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
github_release:
|
||||||
|
description: 'Create Gitea Release'
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
bump:
|
||||||
|
description: 'Bump type'
|
||||||
|
required: true
|
||||||
|
default: 'patch'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'major'
|
||||||
|
- 'minor'
|
||||||
|
- 'patch'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@master
|
||||||
|
- name: Install uv
|
||||||
|
uses: astral-sh/setup-uv@v5
|
||||||
|
- name: Set up Python
|
||||||
|
run: uv python install
|
||||||
|
- name: Set Git identity
|
||||||
|
run: |
|
||||||
|
git config user.name "Gitea CI"
|
||||||
|
git config user.email "ci@git.theprivateserver.de"
|
||||||
|
- name: Bump version
|
||||||
|
id: bump
|
||||||
|
run: |
|
||||||
|
uv tool install bump-my-version
|
||||||
|
uv tool run bump-my-version bump ${{ github.event.inputs.bump }}
|
||||||
|
# echo the version to github env, the version is shown by using uv tool run bump-my-version show current_version
|
||||||
|
echo "VERSION<<EOF" >> $GITHUB_ENV
|
||||||
|
echo "$(uv tool run bump-my-version show current_version)" >> $GITHUB_ENV
|
||||||
|
echo "EOF" >> $GITHUB_ENV
|
||||||
|
- name: Push changes
|
||||||
|
uses: ad-m/github-push-action@master
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: ${{ github.ref }}
|
||||||
|
|
||||||
|
- name: Add release notes to environment
|
||||||
|
id: add_release_notes
|
||||||
|
run: |
|
||||||
|
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
|
||||||
|
echo "${{ github.event.inputs.release_notes }}" >> $GITHUB_ENV
|
||||||
|
echo "EOF" >> $GITHUB_ENV
|
||||||
|
- name: Build package
|
||||||
|
run: uv build
|
||||||
|
- name: Publish package
|
||||||
|
env:
|
||||||
|
USERNAME: ${{ github.repository_owner }}
|
||||||
|
run: uv publish --publish-url https://git.theprivateserver.de/api/packages/$USERNAME/pypi/ -t ${{ secrets.TOKEN }}
|
||||||
|
- name: Generate changelog
|
||||||
|
id: changelog
|
||||||
|
uses: metcalfc/changelog-generator@v4.6.2
|
||||||
|
with:
|
||||||
|
myToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Get the changelog
|
||||||
|
run: |
|
||||||
|
cat << "EOF"
|
||||||
|
${{ steps.changelog.outputs.changelog }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
id: create_release
|
||||||
|
if: ${{ github.event.inputs.github_release == 'true' }}
|
||||||
|
uses: softprops/action-gh-release@master
|
||||||
|
with:
|
||||||
|
tag_name: ${{ env.VERSION }}
|
||||||
|
release_name: Release ${{ env.VERSION }}
|
||||||
|
body: ${{ steps.changelog.outputs.changelog }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
make_latest: true
|
||||||
|
files: |
|
||||||
|
dist/*
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||||
70
.github/workflows/codeql-analysis.yml
vendored
70
.github/workflows/codeql-analysis.yml
vendored
@@ -1,70 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ master ]
|
|
||||||
schedule:
|
|
||||||
- cron: '38 17 * * 0'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'python' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v2
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
||||||
39
.github/workflows/python-publish.yml
vendored
39
.github/workflows/python-publish.yml
vendored
@@ -1,39 +0,0 @@
|
|||||||
# This workflow will upload a Python Package using Twine when a release is created
|
|
||||||
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
|
||||||
|
|
||||||
# This workflow uses actions that are not certified by GitHub.
|
|
||||||
# They are provided by a third-party and are governed by
|
|
||||||
# separate terms of service, privacy policy, and support
|
|
||||||
# documentation.
|
|
||||||
|
|
||||||
name: Upload Python Package
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v3
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install build
|
|
||||||
- name: Build package
|
|
||||||
run: python -m build
|
|
||||||
- name: Publish package
|
|
||||||
uses: pypa/gh-action-pypi-publish@v1.9.0
|
|
||||||
with:
|
|
||||||
user: __token__
|
|
||||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# How to contribute with this project
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
1. Star the repo, it will help me a lot.
|
|
||||||
2. Make a fork for you.
|
|
||||||
3. Clone the repo into your local machine.
|
|
||||||
4. Create a new branch for your changes.
|
|
||||||
5. Start hacking :-)
|
|
||||||
|
|
||||||
## Not familiarized with the Python workflow?
|
|
||||||
|
|
||||||
1. Be sure that you have Python 3 and virtualenv installed (if not, install them)
|
|
||||||
2. Create a new virtualenv
|
|
||||||
|
|
||||||
```
|
|
||||||
python -m virtualenv env -p python3
|
|
||||||
```
|
|
||||||
|
|
||||||
3. And activate it!
|
|
||||||
4. Now it's time to install the dependencies.
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
5. And now you're ready to hack.
|
|
||||||
|
|
||||||
## Hacking
|
|
||||||
|
|
||||||
1. Please, make sure your code is valid according the PEP8 specification
|
|
||||||
2. If you want to add a new feature, not planned yet, open an issue first.
|
|
||||||
3. Fix the issues tagged as bug, then we can fix the issues related with features and improvements.
|
|
||||||
4. Add comments to your code, don't be shy.
|
|
||||||
|
|
||||||
## Hacktoberfest plus
|
|
||||||
|
|
||||||
If this is your first time, follow this steps:
|
|
||||||
|
|
||||||
1. Go to `Getting started` and follow the instructions there.
|
|
||||||
2. Push your changes into your fork.
|
|
||||||
3. Open a PR across forks from your `dev` branch to parent's repo `dev` branch (NOT MASTER)
|
|
||||||
4. Wait for feedback
|
|
||||||
|
|
||||||
Happy coding!
|
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
# Hard Fork
|
||||||
|
## TBD
|
||||||
|
|
||||||
|
|
||||||
|
# Original Repo
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://github.com/JuanjoSalvador/NyaaPy/blob/master/nyaapy-logo.png?raw=true" />
|
<img src="https://github.com/JuanjoSalvador/NyaaPy/blob/master/nyaapy-logo.png?raw=true" />
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
|
|
||||||
def json_to_class(data):
|
|
||||||
# We check if the data passed is a list or not
|
|
||||||
if isinstance(data, list):
|
|
||||||
object_list = []
|
|
||||||
for item in data:
|
|
||||||
object_list.append(Torrent(item))
|
|
||||||
# Return a list of Torrent objects
|
|
||||||
return object_list
|
|
||||||
else:
|
|
||||||
return Torrent(data)
|
|
||||||
|
|
||||||
|
|
||||||
# This deals with converting the dict to an object
|
|
||||||
class Torrent(object):
|
|
||||||
def __init__(self, my_dict):
|
|
||||||
for key in my_dict:
|
|
||||||
setattr(self, key, my_dict[key])
|
|
||||||
|
|
||||||
|
|
||||||
class TorrentSite(Enum):
|
|
||||||
"""
|
|
||||||
Contains torrent sites
|
|
||||||
"""
|
|
||||||
|
|
||||||
NYAASI = "https://nyaa.si"
|
|
||||||
SUKEBEINYAASI = "https://sukebei.nyaa.si"
|
|
||||||
|
|
||||||
NYAALAND = "https://nyaa.land"
|
|
||||||
@@ -1,23 +1,18 @@
|
|||||||
[tool.poetry]
|
[project]
|
||||||
name = "nyaapy"
|
name = "komsuite-nyaapy"
|
||||||
version = "0.7"
|
version = "0.1.0"
|
||||||
description = "Unofficial Python wrapper for NyaaPantsu API and Nyaa.si"
|
description = "A rewritten hard fork of the original NyaaPy library."
|
||||||
authors = ["Juanjo Salvador <juanjosalvador@netc.eu>"]
|
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
authors = [{ name = "WorldTeacher", email = "coding_contact@pm.me" }]
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"bencodepy>=0.9.5",
|
||||||
|
"lxml>=5.3.1",
|
||||||
|
"regex>=2024.11.6",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = "^3.10"
|
|
||||||
requests = "^2.32.3"
|
|
||||||
lxml = "^5.2.2"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
pytest = "^8.2.2"
|
|
||||||
black = "^24.4.2"
|
|
||||||
mypy = "^1.10.1"
|
|
||||||
types-requests = "^2.32.0.20240712"
|
|
||||||
lxml-stubs = "^0.5.1"
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["hatchling"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "hatchling.build"
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
requests>=2.20.0
|
|
||||||
beautifulsoup4==4.6.0
|
|
||||||
lxml
|
|
||||||
25
setup.py
25
setup.py
@@ -1,25 +0,0 @@
|
|||||||
from setuptools import setup, find_packages # type: ignore
|
|
||||||
from os import path
|
|
||||||
|
|
||||||
currdir = path.abspath(path.dirname(__file__))
|
|
||||||
with open(path.join(currdir, "README.md"), encoding="utf-8") as f:
|
|
||||||
long_desc = f.read()
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="nyaapy",
|
|
||||||
version="0.6.3",
|
|
||||||
install_requires=[
|
|
||||||
"requests",
|
|
||||||
"lxml",
|
|
||||||
],
|
|
||||||
url="https://github.com/juanjosalvador/nyaapy",
|
|
||||||
long_description=long_desc,
|
|
||||||
long_description_content_type="text/markdown",
|
|
||||||
download_url=("https://github.com/juanjosalvador/" "nyaapy/archive/0.6.3.tar.gz"),
|
|
||||||
license="MIT",
|
|
||||||
author="Juanjo Salvador",
|
|
||||||
author_email="juanjosalvador@netc.eu",
|
|
||||||
description="Allows you to make requests on Nyaa.si and nyaa.pantsu.cat",
|
|
||||||
packages=find_packages(exclude=["tests"]),
|
|
||||||
zip_safe=False,
|
|
||||||
)
|
|
||||||
4
src/komsuite_nyaapy/__init__.py
Normal file
4
src/komsuite_nyaapy/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from .modules.anime_site import AnimeTorrentSite
|
||||||
|
from .modules.torrent import TorrentSite
|
||||||
|
from .sites.nyaa import Nyaa, SukebeiNyaa
|
||||||
|
from .modules.torrent import Torrent
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import requests
|
import requests
|
||||||
from nyaapy import torrent
|
from komsuite_nyaapy.modules import torrent
|
||||||
from nyaapy.parser import parse_nyaa, parse_single, parse_nyaa_rss
|
from komsuite_nyaapy.modules.parser import parse_nyaa, parse_single, parse_nyaa_rss
|
||||||
|
|
||||||
|
|
||||||
class AnimeTorrentSite:
|
class AnimeTorrentSite:
|
||||||
SITE = torrent.TorrentSite.NYAASI
|
SITE = torrent.TorrentSite.NYAASI
|
||||||
URL = "https://nyaa.si"
|
URL = SITE
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def last_uploads(self, number_of_results: int):
|
def last_uploads(self, number_of_results: int):
|
||||||
@@ -21,18 +21,20 @@ class AnimeTorrentSite:
|
|||||||
return torrent.json_to_class(json_data)
|
return torrent.json_to_class(json_data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search(self, keyword: str, **kwargs):
|
def search(
|
||||||
|
self,
|
||||||
|
keyword: str,
|
||||||
|
category: int = 0,
|
||||||
|
subcategory: int = 0,
|
||||||
|
filters: int = 0,
|
||||||
|
page: int = 0,
|
||||||
|
sorting: str = "id",
|
||||||
|
order: str = "desc",
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
base_url = self.URL
|
base_url = self.URL
|
||||||
|
|
||||||
user = kwargs.get("user", None)
|
user = kwargs.get("user", None)
|
||||||
category = kwargs.get("category", 0)
|
|
||||||
subcategory = kwargs.get("subcategory", 0)
|
|
||||||
filters = kwargs.get("filters", 0)
|
|
||||||
page = kwargs.get("page", 0)
|
|
||||||
sorting = kwargs.get(
|
|
||||||
"sort", "id"
|
|
||||||
) # Sorting by id = sorting by date, this is the default.
|
|
||||||
order = kwargs.get("order", "desc")
|
|
||||||
|
|
||||||
user_uri = f"user/{user}" if user else ""
|
user_uri = f"user/{user}" if user else ""
|
||||||
|
|
||||||
@@ -62,7 +64,6 @@ class AnimeTorrentSite:
|
|||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
search_uri += "&page=rss"
|
search_uri += "&page=rss"
|
||||||
|
|
||||||
http_response = requests.get(search_uri)
|
http_response = requests.get(search_uri)
|
||||||
http_response.raise_for_status()
|
http_response.raise_for_status()
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from nyaapy.magnet import magnet_builder
|
from .magnet import magnet_builder
|
||||||
from nyaapy.torrent import TorrentSite
|
from .torrent import TorrentSite
|
||||||
|
|
||||||
|
|
||||||
def nyaa_categories(b):
|
def nyaa_categories(b):
|
||||||
@@ -115,7 +115,6 @@ def parse_nyaa(request_text, limit, site):
|
|||||||
|
|
||||||
for td in tr.xpath("./td"):
|
for td in tr.xpath("./td"):
|
||||||
for link in td.xpath("./a"):
|
for link in td.xpath("./a"):
|
||||||
|
|
||||||
href = link.attrib.get("href").split("/")[-1]
|
href = link.attrib.get("href").split("/")[-1]
|
||||||
|
|
||||||
# Only caring about non-comment pages.
|
# Only caring about non-comment pages.
|
||||||
155
src/komsuite_nyaapy/modules/torrent.py
Normal file
155
src/komsuite_nyaapy/modules/torrent.py
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from dataclasses import field
|
||||||
|
import os
|
||||||
|
import bencodepy
|
||||||
|
import regex
|
||||||
|
from typing import Optional
|
||||||
|
import loguru
|
||||||
|
import sys
|
||||||
|
|
||||||
|
log = loguru.logger
|
||||||
|
log.remove()
|
||||||
|
log.add("cli.log", rotation="1 week", retention="1 month")
|
||||||
|
log.add(sys.stdout, level="INFO")
|
||||||
|
|
||||||
|
|
||||||
|
def json_to_class(data):
|
||||||
|
# We check if the data passed is a list or not
|
||||||
|
if isinstance(data, list):
|
||||||
|
object_list = []
|
||||||
|
for item in data:
|
||||||
|
object_list.append(Torrent(**item))
|
||||||
|
# Return a list of Torrent objects
|
||||||
|
return object_list
|
||||||
|
else:
|
||||||
|
return [Torrent(**data)]
|
||||||
|
|
||||||
|
|
||||||
|
# This deals with converting the dict to an object
|
||||||
|
@dataclass
|
||||||
|
class Torrent:
|
||||||
|
id: int = 0
|
||||||
|
category: Optional[str] = None
|
||||||
|
category: Optional[str] = None
|
||||||
|
url: Optional[str] = None
|
||||||
|
name: Optional[str] = None
|
||||||
|
download_url: Optional[str] = None
|
||||||
|
magnet: Optional[str] = None
|
||||||
|
size: Optional[str] = None
|
||||||
|
seeders: int = 0
|
||||||
|
leechers: int = 0
|
||||||
|
completed_downloads: int = 0
|
||||||
|
date: Optional[str] = None
|
||||||
|
type: Optional[str] = None
|
||||||
|
volumes: list[int] = field(default_factory=list)
|
||||||
|
contents: list[str] = field(default_factory=list)
|
||||||
|
filetypes: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
self.get_contents
|
||||||
|
self.seeders = int(self.seeders)
|
||||||
|
self.leechers = int(self.leechers) if self.leechers is not None else 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filesizes(self):
|
||||||
|
data_count = self.size.split(" ")[0]
|
||||||
|
data_value = self.size.split(" ")[1]
|
||||||
|
mib = 1
|
||||||
|
kib = 2
|
||||||
|
gib = 3
|
||||||
|
|
||||||
|
return float(data_count) * (
|
||||||
|
1024
|
||||||
|
** (mib if data_value == "MiB" else kib if data_value == "KiB" else gib)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_contents(self):
|
||||||
|
os.system(f"wget {self.download_url}> /dev/null 2>&1")
|
||||||
|
with open(f"{self.download_url.split('/')[-1]}", "rb") as f:
|
||||||
|
data = bencodepy.decode(f.read())
|
||||||
|
|
||||||
|
info = data[b"info"]
|
||||||
|
filetypes: list[str] = []
|
||||||
|
|
||||||
|
# For multi-file torrents
|
||||||
|
if b"files" in info:
|
||||||
|
files: list[str] = []
|
||||||
|
for file in info[b"files"]: # type: ignore
|
||||||
|
path_parts = [part.decode("utf-8") for part in file[b"path"]] # type: ignore
|
||||||
|
files.append("/".join(path_parts)) # type: ignore
|
||||||
|
filetypes.append(path_parts[-1].split(".")[-1]) # type: ignore
|
||||||
|
self.filetypes = list(set(filetypes))
|
||||||
|
self.contents = files
|
||||||
|
# check each file for the presence of r"^(.*?)\s(vol\.\s\d{2})|(v\d{2,3})"
|
||||||
|
volumes: list[int] = []
|
||||||
|
for file in files:
|
||||||
|
match = regex.findall(
|
||||||
|
r"(vol\.?\s*\d{1,3}|v\d{1,3}(?:[-v]\d{1,3})?)",
|
||||||
|
file,
|
||||||
|
regex.IGNORECASE,
|
||||||
|
)
|
||||||
|
if match:
|
||||||
|
match = (
|
||||||
|
"".join(match[0])
|
||||||
|
.strip()
|
||||||
|
.replace("vol", "")
|
||||||
|
.replace("v", "")
|
||||||
|
.replace(".", "")
|
||||||
|
)
|
||||||
|
if "-" in match:
|
||||||
|
match = match.split("-")
|
||||||
|
# if difference between numbers is greater than 1, add missing numbers to volumes
|
||||||
|
if int(match[1]) - int(match[0]) > 1:
|
||||||
|
for i in range(int(match[0]) - 1, int(match[1]) + 1):
|
||||||
|
volumes.append(i)
|
||||||
|
else:
|
||||||
|
volumes.append(int(match[0]))
|
||||||
|
volumes.append(int(match[1]))
|
||||||
|
else:
|
||||||
|
if match.isdigit():
|
||||||
|
volumes.append(int(match))
|
||||||
|
|
||||||
|
volumes = sorted(volumes)
|
||||||
|
self.volumes = volumes
|
||||||
|
|
||||||
|
# For single-file torrents
|
||||||
|
# elif b"name" in info:
|
||||||
|
# return [info[b"name"].decode("utf-8")]
|
||||||
|
else:
|
||||||
|
self.volumes = [0]
|
||||||
|
# log.debug("Filetypes: {}, Volumes: {}".format(self.filetypes, self.volumes)) #! enable for debug
|
||||||
|
os.remove(f"{self.download_url.split('/')[-1]}")
|
||||||
|
|
||||||
|
|
||||||
|
class TorrentSite(Enum):
|
||||||
|
"""
|
||||||
|
Contains torrent sites
|
||||||
|
"""
|
||||||
|
|
||||||
|
NYAASI = "https://nyaa.si"
|
||||||
|
SUKEBEINYAASI = "https://sukebei.nyaa.si"
|
||||||
|
|
||||||
|
NYAALAND = "https://nyaa.land"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list_sites(cls):
|
||||||
|
return [site.value for site in cls]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_site(cls, site):
|
||||||
|
if isinstance(site, TorrentSite):
|
||||||
|
return site.value
|
||||||
|
for s in cls:
|
||||||
|
if s.value == site:
|
||||||
|
return s
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_site_url(cls, site):
|
||||||
|
return cls.site.value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def nyaa(cls):
|
||||||
|
return (cls.NYAASI, cls.NYAASI.value)
|
||||||
11
src/komsuite_nyaapy/sites/nyaa.py
Normal file
11
src/komsuite_nyaapy/sites/nyaa.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from komsuite_nyaapy import AnimeTorrentSite, TorrentSite
|
||||||
|
|
||||||
|
|
||||||
|
class SukebeiNyaa(AnimeTorrentSite):
|
||||||
|
SITE = TorrentSite.SUKEBEINYAASI
|
||||||
|
URL = TorrentSite.get_site(SITE)
|
||||||
|
|
||||||
|
|
||||||
|
class Nyaa(AnimeTorrentSite):
|
||||||
|
SITE = TorrentSite.NYAASI
|
||||||
|
URL = TorrentSite.get_site(SITE)
|
||||||
Reference in New Issue
Block a user