From 523a9f41e247f1736e8d0e34c965908785606842 Mon Sep 17 00:00:00 2001 From: adogecheems Date: Sun, 8 Sep 2024 15:35:49 +0800 Subject: [PATCH] new version --- README.md | 15 +- README_en.md | 16 +- anisearch/{search => }/AniSearch.py | 4 +- anisearch/README_en.md | 206 -------------------------- anisearch/__init__.py | 30 +++- anisearch/anime/__init__.py | 0 anisearch/{search => }/cli.py | 0 anisearch/{anime => plugins}/Anime.py | 2 +- anisearch/plugins/__init__.py | 7 +- anisearch/plugins/_webget.py | 7 +- anisearch/plugins/_webget_cf.py | 6 +- anisearch/plugins/acgrip.py | 4 +- anisearch/plugins/comicat.py | 4 +- anisearch/plugins/dmhy.py | 4 +- anisearch/plugins/kisssub.py | 4 +- anisearch/plugins/miobt.py | 4 +- anisearch/plugins/nyaa.py | 4 +- anisearch/plugins/tokyotosho.py | 6 +- anisearch/search/__init__.py | 25 ---- setup.py | 4 +- 20 files changed, 79 insertions(+), 273 deletions(-) rename anisearch/{search => }/AniSearch.py (98%) delete mode 100644 anisearch/README_en.md delete mode 100644 anisearch/anime/__init__.py rename anisearch/{search => }/cli.py (100%) rename anisearch/{anime => plugins}/Anime.py (99%) delete mode 100644 anisearch/search/__init__.py diff --git a/README.md b/README.md index 8fd66e4..90a67a4 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,9 @@ AniSearch 使用基于元类的插件系统来支持不同的搜索源 非常悲哀的是,以下搜索源都需要代理 - `dmhy`: 动漫花园搜索源(速度较快) -- `comicat`: 漫猫搜索源(实现非常慢,慎用,建议只搜索季度合集) -- `kisssub`: 爱恋搜索源(同上) -- `miobt`:MioBT 搜索源(同上) +- `comicat`: [存档] 漫猫搜索源(实现非常慢,慎用,建议只搜索季度合集) +- `kisssub`: [存档] 爱恋搜索源(同上) +- `miobt`:[存档] MioBT 搜索源(同上) - `nyaa`: nyaa.si 搜索源(速度超群,不能使用季度合集搜索) - `acgrip`: acg.rip 搜索源(速度适中,不能使用季度合集搜索,由于站点的自身原因,获取的magnet是种子的下载链接) - `tokyotosho` : 东京图书馆搜索源(速度适中,不能使用季度合集搜索,绝大部分资源都需要英/日文才能搜到) @@ -121,20 +121,21 @@ AniSearch 使用基于元类的插件系统来支持不同的搜索源 ```python # 运行此代码,没有异常说明自定义插件创建成功,已经注册在插件系统中 from anisearch.plugins import BasePlugin -from anisearch.anime.Anime import Anime +from anisearch.plugins.Anime import Anime from anisearch.plugins._webget import get_html + class Custom(BasePlugin): abstract = False - + def __init__(self, parser, verify, timefmt) -> None: super().__init__(parser, verify, timefmt) def search(self, keyword, collected=True, proxies=None, system_proxy=False, **extra_options): html = get_html("", proxies=proxies, system_proxy=system_proxy, verify=self._verify) - + # 这里实现您的搜索逻辑 - + # 返回一个 Anime 对象的列表 return [Anime("2023/06/01 12:00", "Custom Anime", "1.5GB", "magnet:?xt=urn:btih:..."), ...] ``` diff --git a/README_en.md b/README_en.md index 97f77ee..80919a4 100644 --- a/README_en.md +++ b/README_en.md @@ -109,11 +109,12 @@ AniSearch uses a metaclass-based plugin system to support different search sourc - `dmhy`: Anime Garden search source (faster) -- `comicat`: Manmao search source (very slow to implement, use with caution, it is recommended to search only for quarterly collections) +- `comicat`: [achieve] Comicat search source (very slow to implement, use with caution, it is recommended to search only + for quarterly collections) -- `kisssub`: Love search source (same as above) +- `kisssub`: [achieve] KissSub search source (same as above) -- `miobt`: MioBT search source (same as above) +- `miobt`: [achieve] MioBT search source (same as above) - `nyaa`: nyaa.si search source (superb speed, can not use quarterly collection search) @@ -127,20 +128,21 @@ To create a custom plugin, you need to inherit the BasePlugin class and implemen ```python # Run this code. If there is no exception, it means that the custom plug-in is created successfully and has been registered in the plug-in system from anisearch.plugins import BasePlugin -from anisearch.anime.Anime import Anime +from anisearch.plugins.Anime import Anime from anisearch.plugins._webget import get_html + class Custom(BasePlugin): abstract = False def __init__(self, parser, verify, timefmt) -> None: super().__init__(parser, verify, timefmt) - + def search(self, keyword, collected=True, proxies=None, system_proxy=False, **extra_options): html = get_html("", proxies=proxies, system_proxy=system_proxy, verify=self._verify) - + # Implement your search logic here - + # Return a list of Anime objects return [Anime("2023/06/01 12:00", "Custom Anime", "1.5GB", "magnet:?xt=urn:btih:..."), ...] ``` diff --git a/anisearch/search/AniSearch.py b/anisearch/AniSearch.py similarity index 98% rename from anisearch/search/AniSearch.py rename to anisearch/AniSearch.py index 7eb4a82..a0e4e83 100644 --- a/anisearch/search/AniSearch.py +++ b/anisearch/AniSearch.py @@ -3,8 +3,8 @@ from typing import List, Optional from . import log -from .. import plugins -from ..anime.Anime import Anime +from . import plugins +from .plugins.Anime import Anime class AniSearch: diff --git a/anisearch/README_en.md b/anisearch/README_en.md deleted file mode 100644 index 97f77ee..0000000 --- a/anisearch/README_en.md +++ /dev/null @@ -1,206 +0,0 @@ -# Anisearch - -anisearch is a full-featured Python library for searching anime magnet links. It also provides a flexible plugin system that allows users to search animation information from different sources - -## Features - -- Support multiple search sources -- Powerful extensibility -- CSV export function -- Proxy support - -## Installation - -You can install anisearch directly using pip: - -``` -pip install Anisearch-lib -``` - -## Usage example - -Here is a basic example of using anisearch: - -```python -from anisearch import AniSearch - -# Create an AniSearch instance -searcher = AniSearch() - -# Optional parameters for the __init__() method: -# plugin_name: Search source name, defaults to 'dmhy' -# parser: beautifulsoup parser, defaults to 'lxml' in 'dmhy' -# verify: Whether to verify SSL certificates, defaults to False in 'dmhy' -# time_fmt: Time format, defaults to '%Y-%m-%d %H:%M:%S' - -# The default values of the above parameters may be different when different plug-ins are selected - -# Search animation -searcher.search('我推的孩子') - -# Optional parameters of the search() method: -# collected: Whether to search only quarterly collections, default is True -# proxies: proxy url -# -# Use proxy -# proxies = { -# 'http': 'http://10.10.1.10:3128', -# 'https': 'http://10.10.1.10:1080', -# } # Don't take it seriously, it's just an example -# searcher.search("我推的孩子", proxies=proxies) -# system_proxy: Whether to use system proxy (it seems that it always doesn't work) - -# If the search is successful, the following words will appear: -# This search is complete: 我推的孩子 - -# Output search result list -print(searcher.animes) - -# Show partial output (results in August 2024) -# [Anime('2024/03/21 13:25', '【动漫国字幕组】[【我推的孩子】][01-11][BDRip][AVC_AAC][1080P][Simplified][MP4]', '7.3GB', 'magnet:?xt=urn:btih:P76PROAB5JRUAPHIST63HGRUOMW7SEWU&dn=&tr=... - -# If everything is OK, select the first search result (you can also select others) - -searcher.select(0) - -# After selection, the anime attribute is available -print(searcher.anime.title) -print(searcher.anime.size) - -# Output: -# '【动漫国字幕组】[【我推的孩子】][01-11][BDRip][AVC_AAC][1080P][Simplified][MP4]' -# '7.3GB' -``` - -## Main components - -### AniSearch class - -`AniSearch` is the main search class, providing the following methods: - -- `search(keyword, collected=None, proxies=None, system_proxy=None, **extra_options)`: Search for animations - -- `select(index)`: Select an animation from the search results - -- `size_format(unit='MB')`: Convert the file size of the selected animation - -- `save_csv(filename)`: Save the search results to a CSV file (all results) - -** The extra_options parameter will be incorporated into the query string during crawling, which can be used to specify additional categories or options. For specific query strings, please check the search source search. url - -![querystring](https://cdn.mmoe.work/img/url.png) - -### Anime class - -The `Anime` class represents an anime entry and contains the following properties: - -- `time`: release time -- `title`: animation title -- `size`: file size -- `magnet`: magnet link - -Its __eq__ method is implemented to compare the hash values ​​of the magnet links of two Anime instances. - -### Plugin system - -AniSearch uses a metaclass-based plugin system to support different search sources - -### Implemented plugins - -- `dmhy`: Anime Garden search source (faster) - -- `comicat`: Manmao search source (very slow to implement, use with caution, it is recommended to search only for quarterly collections) - -- `kisssub`: Love search source (same as above) - -- `miobt`: MioBT search source (same as above) - -- `nyaa`: nyaa.si search source (superb speed, can not use quarterly collection search) - -- `acgrip`: acg.rip search source (moderate speed, can not use quarterly collection search, due to the site's own reasons, the magnet obtained is the download link of the seed) - -- `tokyotosho`: Tokyo Library search source (moderate speed, cannot use quarterly collection search) - -## Create a custom plugin -To create a custom plugin, you need to inherit the BasePlugin class and implement the search method. Anisearch provides a practical http request function `anisearch.plugins._webget.get_html()`, which can be used directly. Here is a simple example: - -```python -# Run this code. If there is no exception, it means that the custom plug-in is created successfully and has been registered in the plug-in system -from anisearch.plugins import BasePlugin -from anisearch.anime.Anime import Anime -from anisearch.plugins._webget import get_html - -class Custom(BasePlugin): - abstract = False - - def __init__(self, parser, verify, timefmt) -> None: - super().__init__(parser, verify, timefmt) - - def search(self, keyword, collected=True, proxies=None, system_proxy=False, **extra_options): - html = get_html("", proxies=proxies, system_proxy=system_proxy, verify=self._verify) - - # Implement your search logic here - - # Return a list of Anime objects - return [Anime("2023/06/01 12:00", "Custom Anime", "1.5GB", "magnet:?xt=urn:btih:..."), ...] -``` - -### Example of using a custom plugin - -```python -searcher_custom = AniSearch(plugin_name='custom') - -# If the file is not placed in the project plugins directory, you need to manually import it to the namespace - -# Please make sure to keep the class name (comply with the pep8 naming convention), plugin name, and file name consistent, and the case will be automatically processed - -searcher_custom.search("我推孩子") - -``` - -## Command line interface (CLI) usage - -anisearch comes with a command line interface that can be used directly in the terminal. - -### Basic usage - -``` -anisearch -k [options] -``` - -### Parameter description - -- `-k`, `--keyword`: (required) Search keyword - -- `-p`, `--plugin`: (optional) Search plugin, default is `dmhy` - -- `-c`, `--collected`: (optional) Whether to search only quarterly collections - -### Example - -1. Basic search: - -``` -anisearch -k "我推的孩子" -``` - -2. Search using a specific search plugin: - -``` -anisearch -k "我推的孩子" -p nyaa -``` - -### Usage process - -1. After running the search command, the program will display a list of search results, including serial number, title and file size -2. Users can enter the serial number of the item they want to select -3. If a valid serial number is selected, the program will display the title and magnet link of the selected item -4. Enter 0 Can opt out of the selection process - -## Contributions - -Contributions are welcome! Please feel free to submit pull requests or open issues to improve this project - -## License - -AGPLv3 \ No newline at end of file diff --git a/anisearch/__init__.py b/anisearch/__init__.py index 09716be..dbc2537 100644 --- a/anisearch/__init__.py +++ b/anisearch/__init__.py @@ -1 +1,29 @@ -from anisearch.search.AniSearch import AniSearch \ No newline at end of file +import logging + +LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s" +LOG_FILE = "search.log" + + +def setup_logger(name: str = "global", level: int = logging.DEBUG) -> logging.Logger: + logger = logging.getLogger(name) + if not logger.handlers: + logger.setLevel(level) + + try: + file_handler = logging.FileHandler(LOG_FILE, mode='w') + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(logging.Formatter(LOG_FORMAT)) + logger.addHandler(file_handler) + except Exception as e: + print(f"Failed to set up file handler: {e}") + + stream_handler = logging.StreamHandler() + stream_handler.setLevel(logging.INFO) + logger.addHandler(stream_handler) + + return logger + + +log = setup_logger() + +eval("from .AniSearch import AniSearch") diff --git a/anisearch/anime/__init__.py b/anisearch/anime/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anisearch/search/cli.py b/anisearch/cli.py similarity index 100% rename from anisearch/search/cli.py rename to anisearch/cli.py diff --git a/anisearch/anime/Anime.py b/anisearch/plugins/Anime.py similarity index 99% rename from anisearch/anime/Anime.py rename to anisearch/plugins/Anime.py index fecea7a..74e4b11 100644 --- a/anisearch/anime/Anime.py +++ b/anisearch/plugins/Anime.py @@ -1,7 +1,7 @@ import re from typing import Tuple -from ..search import log +from .. import log # Regular expression patterns size_pattern = re.compile(r'(\d+(?:\.\d+)?)\s*(\w+)') diff --git a/anisearch/plugins/__init__.py b/anisearch/plugins/__init__.py index c1102e8..7f2f3f5 100644 --- a/anisearch/plugins/__init__.py +++ b/anisearch/plugins/__init__.py @@ -1,7 +1,8 @@ import importlib -import logging from abc import ABCMeta, abstractmethod +from .. import log + class PluginMeta(ABCMeta): plugins = {} @@ -21,7 +22,7 @@ def __init__(self, parser, verify, timefmt): self._timefmt = timefmt @abstractmethod - def search(self, keyword, collected, proxies, system_proxy, extra_options): + def search(self, keyword, collected, proxies, system_proxy, **extra_options): """ Abstract method to search for a keyword. @@ -48,6 +49,6 @@ def get_plugin(name: str): try: importlib.import_module(f".{name}", package=__name__) except ImportError: - logging.info(f"The plugin {name} cannot be automatically imported, please import it manually") + log.info(f"The plugin {name} cannot be automatically imported, please import it manually") return PluginMeta.plugins.get(name.title()) diff --git a/anisearch/plugins/_webget.py b/anisearch/plugins/_webget.py index c0f4b9a..3bb116b 100644 --- a/anisearch/plugins/_webget.py +++ b/anisearch/plugins/_webget.py @@ -1,6 +1,9 @@ import os + import requests -from ..search import log + +from .. import log + def get_html(url, proxies=None, system_proxy=False, verify=True): headers = { @@ -26,4 +29,4 @@ def get_html(url, proxies=None, system_proxy=False, verify=True): except requests.RequestException as e: log.exception(f"The search was aborted due to network reasons: {e}") - raise + raise \ No newline at end of file diff --git a/anisearch/plugins/_webget_cf.py b/anisearch/plugins/_webget_cf.py index 9a50dee..135872c 100644 --- a/anisearch/plugins/_webget_cf.py +++ b/anisearch/plugins/_webget_cf.py @@ -1,7 +1,9 @@ import os -import requests + import cloudscraper -from ..search import log +import requests + +from .. import log def get_html(url, proxies=None, system_proxy=False, verify=True): diff --git a/anisearch/plugins/acgrip.py b/anisearch/plugins/acgrip.py index d812ad2..9c0737e 100644 --- a/anisearch/plugins/acgrip.py +++ b/anisearch/plugins/acgrip.py @@ -6,9 +6,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log DOMAIN = "https://acg.rip" BASE_URL = "https://acg.rip/page/{}?" diff --git a/anisearch/plugins/comicat.py b/anisearch/plugins/comicat.py index 4a5673f..7d9d18b 100644 --- a/anisearch/plugins/comicat.py +++ b/anisearch/plugins/comicat.py @@ -7,9 +7,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log DOMAIN = "https://comicat.org/" BASE_URL = "https://comicat.org/search.php?" diff --git a/anisearch/plugins/dmhy.py b/anisearch/plugins/dmhy.py index 52f899f..b51cde4 100644 --- a/anisearch/plugins/dmhy.py +++ b/anisearch/plugins/dmhy.py @@ -6,9 +6,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log BASE_URL = "https://dmhy.org/topics/list/page/{}?" diff --git a/anisearch/plugins/kisssub.py b/anisearch/plugins/kisssub.py index 02cc96c..27d3ebe 100644 --- a/anisearch/plugins/kisssub.py +++ b/anisearch/plugins/kisssub.py @@ -7,9 +7,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log DOMAIN = "https://kisssub.org/" BASE_URL = "https://kisssub.org/search.php?" diff --git a/anisearch/plugins/miobt.py b/anisearch/plugins/miobt.py index 8a752b4..71c62fa 100644 --- a/anisearch/plugins/miobt.py +++ b/anisearch/plugins/miobt.py @@ -7,9 +7,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log DOMAIN = "https://miobt.com/" BASE_URL = "https://miobt.com/search.php?" diff --git a/anisearch/plugins/nyaa.py b/anisearch/plugins/nyaa.py index 3893d53..1944deb 100644 --- a/anisearch/plugins/nyaa.py +++ b/anisearch/plugins/nyaa.py @@ -6,9 +6,9 @@ from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log BASE_URL = "https://nyaa.si/?" diff --git a/anisearch/plugins/tokyotosho.py b/anisearch/plugins/tokyotosho.py index d2b7ebe..a51228f 100644 --- a/anisearch/plugins/tokyotosho.py +++ b/anisearch/plugins/tokyotosho.py @@ -1,14 +1,14 @@ -import time import re +import time from typing import Optional, List from urllib.parse import urlencode from bs4 import BeautifulSoup from . import BasePlugin +from .Anime import Anime from ._webget import get_html -from ..anime.Anime import Anime -from ..search import log +from .. import log BASE_URL = "https://www.tokyotosho.info/search.php?" diff --git a/anisearch/search/__init__.py b/anisearch/search/__init__.py deleted file mode 100644 index 4a41582..0000000 --- a/anisearch/search/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -import logging - -LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s" -LOG_FILE = "search.log" - -def setup_logger(name: str = "global", level: int = logging.DEBUG) -> logging.Logger: - logger = logging.getLogger(name) - if not logger.handlers: # 避免重复添加处理器 - logger.setLevel(level) - - try: - file_handler = logging.FileHandler(LOG_FILE, mode='w') - file_handler.setLevel(logging.DEBUG) - file_handler.setFormatter(logging.Formatter(LOG_FORMAT)) - logger.addHandler(file_handler) - except Exception as e: - print(f"Failed to set up file handler: {e}") - - stream_handler = logging.StreamHandler() - stream_handler.setLevel(logging.INFO) - logger.addHandler(stream_handler) - - return logger - -log = setup_logger() diff --git a/setup.py b/setup.py index ae9d866..b0242d4 100644 --- a/setup.py +++ b/setup.py @@ -8,11 +8,11 @@ setup( name='Anisearch-lib', - version='1.3.2', + version='1.3.3', packages=find_packages(exclude=['tests*']), install_requires=requirements, entry_points={ - 'console_scripts': ['anisearch=anisearch.search.cli:main'], + 'console_scripts': ['anisearch=anisearch.cli:main'], }, author='adogecheems', author_email='adogecheems@outlook.com',