From 1c240f9d767b19804cbe5557f4fa8f507cc21281 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 24 Jun 2024 17:06:56 +0800 Subject: [PATCH 1/6] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d314cc41..fbb76010 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # MoviePilot +![GitHub Repo stars](https://img.shields.io/github/stars/jxxghp/MoviePilot?style=for-the-badge) +![GitHub forks](https://img.shields.io/github/forks/jxxghp/MoviePilot?style=for-the-badge) +![GitHub contributors](https://img.shields.io/github/contributors/jxxghp/MoviePilot?style=for-the-badge) +![GitHub repo size](https://img.shields.io/github/repo-size/jxxghp/MoviePilot?style=for-the-badge) +![GitHub issues](https://img.shields.io/github/issues/jxxghp/MoviePilot?style=for-the-badge) +![Docker Pulls](https://img.shields.io/docker/pulls/jxxghp/moviepilot?style=for-the-badge) +![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20Synology-blue?style=for-the-badge) + + 基于 [NAStool](https://github.com/NAStool/nas-tools) 部分代码重新设计,聚焦自动化核心需求,减少问题同时更易于扩展和维护。 # 仅用于学习交流使用,请勿在任何国内平台宣传该项目! @@ -20,4 +29,4 @@ - \ No newline at end of file + From 93b8f24ec715ed143b239109e974db2f0bc6ca91 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 24 Jun 2024 17:13:50 +0800 Subject: [PATCH 2/6] v1.9.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复阿里云盘无法整理备份盘的问题 - 修复手动整理时fanart图片文件不全的问题 - 修复了通过远程消息下载时不会自动分类的问题 - 修复登录失败时的提示信息 - 修复有的场景下订阅重复下载问题 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 4551da43..9b695438 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -APP_VERSION = 'v1.9.8-beta' +APP_VERSION = 'v1.9.8' From fd2682bc6a45b23f7d81f54dee3c4c5d3a46db9b Mon Sep 17 00:00:00 2001 From: thsrite Date: Tue, 25 Jun 2024 10:03:29 +0800 Subject: [PATCH 3/6] =?UTF-8?q?add=20=E5=88=A0=E9=99=A4=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E3=80=81=E5=88=A0=E9=99=A4=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8E=86=E5=8F=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/db/downloadhistory_oper.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/db/downloadhistory_oper.py b/app/db/downloadhistory_oper.py index 8770b28e..a7fe1b64 100644 --- a/app/db/downloadhistory_oper.py +++ b/app/db/downloadhistory_oper.py @@ -139,3 +139,15 @@ class DownloadHistoryOper(DbOper): return DownloadHistory.list_by_type(db=self._db, mtype=mtype, days=days) + + def delete_history(self, historyid): + """ + 删除下载记录 + """ + DownloadHistory.delete(self._db, historyid) + + def delete_downloadfile(self, downloadfileid): + """ + 删除下载文件记录 + """ + DownloadFiles.delete(self._db, downloadfileid) From 2d0b21d3f2e1192629d3bda285e6895f51e41127 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 25 Jun 2024 16:29:57 +0800 Subject: [PATCH 4/6] fix #2418 fix #2421 fix #2412 --- app/modules/themoviedb/scraper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/modules/themoviedb/scraper.py b/app/modules/themoviedb/scraper.py index a38f0369..757d51c3 100644 --- a/app/modules/themoviedb/scraper.py +++ b/app/modules/themoviedb/scraper.py @@ -168,7 +168,7 @@ class TmdbScraper: if self._force_nfo or not file_path.with_name("season.nfo").exists(): self.__gen_tv_season_nfo_file(seasoninfo=seasoninfo, season=meta.begin_season, - season_path=file_path) + season_path=file_path.parent) # TMDB季图片 poster_name, poster_url = self.get_season_poster(seasoninfo, meta.begin_season) if poster_name and poster_url: From 9dcfb6dc1e23d456184c9b6d252734caadc03e60 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 25 Jun 2024 16:32:45 +0800 Subject: [PATCH 5/6] v1.9.8-1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复剧集自动刮削报错问题 --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 9b695438..cf2211b5 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -APP_VERSION = 'v1.9.8' +APP_VERSION = 'v1.9.8-1' From ad378956bf4337bef2ee0f072a7038d2c729daab Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 26 Jun 2024 09:08:18 +0800 Subject: [PATCH 6/6] support haidan index --- app/modules/indexer/__init__.py | 6 ++ app/modules/indexer/haidan.py | 167 ++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 app/modules/indexer/haidan.py diff --git a/app/modules/indexer/__init__.py b/app/modules/indexer/__init__.py index 5ea82f24..9a100cbb 100644 --- a/app/modules/indexer/__init__.py +++ b/app/modules/indexer/__init__.py @@ -9,6 +9,7 @@ from app.db.sitestatistic_oper import SiteStatisticOper from app.helper.sites import SitesHelper from app.log import logger from app.modules import _ModuleBase +from app.modules.indexer.haidan import HaiDanSpider from app.modules.indexer.mtorrent import MTorrentSpider from app.modules.indexer.spider import TorrentSpider from app.modules.indexer.tnode import TNodeSpider @@ -118,6 +119,11 @@ class IndexerModule(_ModuleBase): mtype=mtype, page=page ) + elif site.get('parser') == "Haidan": + error_flag, result = HaiDanSpider(site).search( + keyword=search_word, + mtype=mtype + ) else: error_flag, result = self.__spider_search( search_word=search_word, diff --git a/app/modules/indexer/haidan.py b/app/modules/indexer/haidan.py new file mode 100644 index 00000000..5aabfd13 --- /dev/null +++ b/app/modules/indexer/haidan.py @@ -0,0 +1,167 @@ +import urllib.parse +from typing import Tuple, List + +from ruamel.yaml import CommentedMap + +from app.core.config import settings +from app.db.systemconfig_oper import SystemConfigOper +from app.log import logger +from app.schemas import MediaType +from app.utils.http import RequestUtils +from app.utils.string import StringUtils + + +class HaiDanSpider: + """ + haidan.video API + """ + _indexerid = None + _domain = None + _url = None + _name = "" + _proxy = None + _cookie = None + _ua = None + _size = 100 + _searchurl = "%storrents.php" + _detailurl = "%sdetails.php?group_id=%s" + _timeout = 15 + + # 电影分类 + _movie_category = ['401', '404', '405'] + _tv_category = ['402', '403', '404', '405'] + + # 足销状态 1-普通,2-免费,3-2X,4-2X免费,5-50%,6-2X50%,7-30% + _dl_state = { + "1": 1, + "2": 0, + "3": 1, + "4": 0, + "5": 0.5, + "6": 0.5, + "7": 0.3 + } + _up_state = { + "1": 1, + "2": 1, + "3": 2, + "4": 2, + "5": 1, + "6": 2, + "7": 1 + } + + def __init__(self, indexer: CommentedMap): + self.systemconfig = SystemConfigOper() + if indexer: + self._indexerid = indexer.get('id') + self._url = indexer.get('domain') + self._domain = StringUtils.get_url_domain(self._url) + self._searchurl = self._searchurl % self._url + self._name = indexer.get('name') + if indexer.get('proxy'): + self._proxy = settings.PROXY + self._cookie = indexer.get('cookie') + self._ua = indexer.get('ua') + self._timeout = indexer.get('timeout') or 15 + + def search(self, keyword: str, mtype: MediaType = None) -> Tuple[bool, List[dict]]: + """ + 搜索 + """ + + def __dict_to_query(_params: dict): + """ + 将数组转换为逗号分隔的字符串 + """ + for key, value in _params.items(): + if isinstance(value, list): + _params[key] = ','.join(map(str, value)) + return urllib.parse.urlencode(params) + + # 检查cookie + if not self._cookie: + return True, [] + + if not mtype: + categories = [] + elif mtype == MediaType.TV: + categories = self._tv_category + else: + categories = self._movie_category + + # 搜索类型 + if keyword.startswith('tt'): + search_area = '4' + else: + search_area = '0' + + params = { + "isapi": "1", + "search_area": search_area, # 0-标题 1-简介(较慢)3-发种用户名 4-IMDb + "search": keyword, + "search_mode": "0", # 0-与 1-或 2-精准 + "cat": categories + } + res = RequestUtils( + cookies=self._cookie, + ua=self._ua, + proxies=self._proxy, + timeout=self._timeout + ).get_res(url=f"{self._searchurl}?{__dict_to_query(params)}") + torrents = [] + if res and res.status_code == 200: + result = res.json() + code = result.get('code') + if code != 0: + logger.warn(f"{self._name} 搜索失败:{result.get('msg')}") + return True, [] + data = result.get('data') or {} + for tid, item in data.items(): + category_value = result.get('category') + if category_value in self._tv_category \ + and category_value not in self._movie_category: + category = MediaType.TV.value + elif category_value in self._movie_category: + category = MediaType.MOVIE.value + else: + category = MediaType.UNKNOWN.value + torrent = { + 'title': item.get('name'), + 'description': item.get('small_descr'), + 'enclosure': item.get('url'), + 'pubdate': StringUtils.format_timestamp(item.get('added')), + 'size': int(item.get('size') or '0'), + 'seeders': int(item.get('seeders') or '0'), + 'peers': int(item.get("leechers") or '0'), + 'grabs': int(item.get("times_completed") or '0'), + 'downloadvolumefactor': self.__get_downloadvolumefactor(item.get('sp_state')), + 'uploadvolumefactor': self.__get_uploadvolumefactor(item.get('sp_state')), + 'page_url': self._detailurl % (self._url, item.get('group_id')), + 'labels': [], + 'category': category + } + torrents.append(torrent) + elif res is not None: + logger.warn(f"{self._name} 搜索失败,错误码:{res.status_code}") + return True, [] + else: + logger.warn(f"{self._name} 搜索失败,无法连接 {self._domain}") + return True, [] + return False, torrents + + def __get_downloadvolumefactor(self, discount: str) -> float: + """ + 获取下载系数 + """ + if discount: + return self._dl_state.get(discount, 1) + return 1 + + def __get_uploadvolumefactor(self, discount: str) -> float: + """ + 获取上传系数 + """ + if discount: + return self._up_state.get(discount, 1) + return 1