Differential 0.6.5.1__py3-none-any.whl
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.
- differential/__init__.py +0 -0
- differential/base_plugin.py +687 -0
- differential/commands.py +29 -0
- differential/constants.py +63 -0
- differential/main.py +47 -0
- differential/plugin_loader.py +49 -0
- differential/plugin_register.py +44 -0
- differential/plugins/__init__.py +0 -0
- differential/plugins/chdbits.py +17 -0
- differential/plugins/chdbits_encode.py +210 -0
- differential/plugins/gazelle.py +18 -0
- differential/plugins/greatposterwall.py +21 -0
- differential/plugins/hdbits.py +39 -0
- differential/plugins/league_official.py +134 -0
- differential/plugins/lemonhd.py +19 -0
- differential/plugins/nexusphp.py +18 -0
- differential/plugins/pterclub.py +21 -0
- differential/plugins/ptp.py +20 -0
- differential/plugins/unit3d.py +18 -0
- differential/tools/BDinfoCli.0.7.3/BDInfo.exe +0 -0
- differential/tools/BDinfoCli.0.7.3/DiscUtils.Common.dll +0 -0
- differential/tools/BDinfoCli.0.7.3/DiscUtils.dll +0 -0
- differential/tools/BDinfoCli.0.7.3/Microsoft.WindowsAPICodePack.Shell.dll +0 -0
- differential/tools/BDinfoCli.0.7.3/Microsoft.WindowsAPICodePack.ShellExtensions.dll +0 -0
- differential/tools/BDinfoCli.0.7.3/Microsoft.WindowsAPICodePack.dll +0 -0
- differential/tools/BDinfoCli.0.7.3/ZedGraph.dll +0 -0
- differential/tools/__init__.py +0 -0
- differential/torrent.py +134 -0
- differential/utils/__init__.py +0 -0
- differential/utils/binary.py +106 -0
- differential/utils/browser.py +23 -0
- differential/utils/config.py +51 -0
- differential/utils/image/__init__.py +19 -0
- differential/utils/image/byr.py +68 -0
- differential/utils/image/chevereto.py +139 -0
- differential/utils/image/cloudinary.py +57 -0
- differential/utils/image/hdbits.py +105 -0
- differential/utils/image/imgbox.py +135 -0
- differential/utils/image/imgurl.py +51 -0
- differential/utils/image/ptpimg.py +39 -0
- differential/utils/image/smms.py +49 -0
- differential/utils/image/types.py +30 -0
- differential/utils/mediainfo.py +211 -0
- differential/utils/mediainfo_handler.py +190 -0
- differential/utils/nfo.py +12 -0
- differential/utils/parse.py +30 -0
- differential/utils/ptgen/bangumi.py +71 -0
- differential/utils/ptgen/base.py +50 -0
- differential/utils/ptgen/douban.py +137 -0
- differential/utils/ptgen/epic.py +50 -0
- differential/utils/ptgen/imdb.py +124 -0
- differential/utils/ptgen/indienova.py +72 -0
- differential/utils/ptgen/parser.py +33 -0
- differential/utils/ptgen/steam.py +54 -0
- differential/utils/ptgen_handler.py +83 -0
- differential/utils/screenshot_handler.py +180 -0
- differential/utils/torrent.py +69 -0
- differential/utils/uploader/__init__.py +2 -0
- differential/utils/uploader/auto_feed.py +134 -0
- differential/utils/uploader/easy_upload.py +65 -0
- differential/version.py +1 -0
- differential-0.6.5.1.dist-info/METADATA +134 -0
- differential-0.6.5.1.dist-info/RECORD +66 -0
- differential-0.6.5.1.dist-info/WHEEL +4 -0
- differential-0.6.5.1.dist-info/entry_points.txt +6 -0
- differential-0.6.5.1.dist-info/licenses/LICENSE +21 -0
differential/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import json
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from itertools import chain
|
|
7
|
+
from urllib.parse import quote
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
|
|
10
|
+
from loguru import logger
|
|
11
|
+
|
|
12
|
+
from differential.plugin_register import PluginRegister
|
|
13
|
+
from differential.torrent import TorrnetBase
|
|
14
|
+
from differential.constants import ImageHosting
|
|
15
|
+
from differential.utils.browser import open_link
|
|
16
|
+
from differential.utils.torrent import make_torrent
|
|
17
|
+
from differential.utils.parse import parse_encoder_log
|
|
18
|
+
from differential.utils.uploader import EasyUpload, AutoFeed
|
|
19
|
+
from differential.utils.mediainfo_handler import MediaInfoHandler
|
|
20
|
+
from differential.utils.ptgen_handler import PTGenHandler
|
|
21
|
+
from differential.utils.screenshot_handler import ScreenshotHandler
|
|
22
|
+
from differential.utils.nfo import generate_nfo
|
|
23
|
+
from differential.utils.ptgen.base import PTGenData, DataType
|
|
24
|
+
from differential.utils.ptgen.imdb import IMDBData
|
|
25
|
+
from differential.utils.ptgen.douban import DoubanData
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Base(ABC, TorrnetBase, metaclass=PluginRegister):
|
|
29
|
+
@classmethod
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def add_parser(cls, parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"-c",
|
|
34
|
+
"--config",
|
|
35
|
+
type=str,
|
|
36
|
+
help="配置文件的路径,默认为config.ini",
|
|
37
|
+
default="config.ini",
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"-l", "--log", type=str, help="log文件的路径", default=argparse.SUPPRESS
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"-f",
|
|
44
|
+
"--folder",
|
|
45
|
+
type=str,
|
|
46
|
+
help="种子文件夹的路径",
|
|
47
|
+
default=argparse.SUPPRESS,
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"-u", "--url", type=str, help="豆瓣链接", default=argparse.SUPPRESS
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"-uu",
|
|
54
|
+
"--upload-url",
|
|
55
|
+
type=str,
|
|
56
|
+
help="PT站点上传的路径,一般为https://xxxxx.com/upload.php",
|
|
57
|
+
default=argparse.SUPPRESS,
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"-t",
|
|
61
|
+
"--make-torrent",
|
|
62
|
+
action="store_true",
|
|
63
|
+
help="是否制种,默认否",
|
|
64
|
+
default=argparse.SUPPRESS,
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"-n",
|
|
68
|
+
"--generate-nfo",
|
|
69
|
+
action="store_true",
|
|
70
|
+
help="是否用MediaInfo生成NFO文件,默认否",
|
|
71
|
+
default=argparse.SUPPRESS,
|
|
72
|
+
)
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"-s",
|
|
75
|
+
"--screenshot-count",
|
|
76
|
+
type=int,
|
|
77
|
+
help="截图数量,默认为0,即不生成截图",
|
|
78
|
+
default=argparse.SUPPRESS,
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--screenshot-path",
|
|
82
|
+
type=str,
|
|
83
|
+
help="截图文件夹,会在提供的文件夹中查找图片并上传,不会再生成截图",
|
|
84
|
+
default=argparse.SUPPRESS,
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--create-folder",
|
|
88
|
+
action="store_true",
|
|
89
|
+
dest="create_folder",
|
|
90
|
+
help="如果目标为文件,创建文件夹并把目标文件放入其中",
|
|
91
|
+
default=argparse.SUPPRESS,
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"--use-short-bdinfo",
|
|
95
|
+
action="store_true",
|
|
96
|
+
help="使用QUICK SUMMARY作为BDInfo,默认使用完整BDInfo",
|
|
97
|
+
default=argparse.SUPPRESS,
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--no-scan-bdinfo",
|
|
101
|
+
action="store_false",
|
|
102
|
+
dest="scan_bdinfo",
|
|
103
|
+
help="如果为原盘,跳过扫描BDInfo",
|
|
104
|
+
default=argparse.SUPPRESS,
|
|
105
|
+
)
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"--optimize-screenshot",
|
|
108
|
+
action="store_true",
|
|
109
|
+
help="是否压缩截图(无损),默认压缩",
|
|
110
|
+
default=argparse.SUPPRESS,
|
|
111
|
+
)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
"--image-hosting",
|
|
114
|
+
type=ImageHosting,
|
|
115
|
+
help=f"图床的类型,现在支持{','.join(i.value for i in ImageHosting)}",
|
|
116
|
+
default=argparse.SUPPRESS,
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--ptpimg-api-key",
|
|
120
|
+
type=str,
|
|
121
|
+
help="PTPIMG的API Key",
|
|
122
|
+
default=argparse.SUPPRESS,
|
|
123
|
+
)
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"--hdbits-cookie",
|
|
126
|
+
type=str,
|
|
127
|
+
help="HDBits的Cookie",
|
|
128
|
+
default=argparse.SUPPRESS,
|
|
129
|
+
)
|
|
130
|
+
parser.add_argument(
|
|
131
|
+
"--hdbits-thumb-size",
|
|
132
|
+
type=str,
|
|
133
|
+
help="HDBits图床缩略图的大小,默认w300",
|
|
134
|
+
default=argparse.SUPPRESS,
|
|
135
|
+
)
|
|
136
|
+
parser.add_argument(
|
|
137
|
+
"--chevereto-hosting-url",
|
|
138
|
+
type=str,
|
|
139
|
+
help="自建chevereto图床的地址",
|
|
140
|
+
default=argparse.SUPPRESS,
|
|
141
|
+
)
|
|
142
|
+
parser.add_argument(
|
|
143
|
+
"--chevereto-api-key",
|
|
144
|
+
type=str,
|
|
145
|
+
help="自建Chevereto的API Key,详情见https://v3-docs.chevereto.com/api/#api-call",
|
|
146
|
+
default=argparse.SUPPRESS,
|
|
147
|
+
)
|
|
148
|
+
parser.add_argument(
|
|
149
|
+
"--chevereto-username",
|
|
150
|
+
type=str,
|
|
151
|
+
help="如果自建Chevereto的API未开放,请设置username和password",
|
|
152
|
+
default=argparse.SUPPRESS,
|
|
153
|
+
)
|
|
154
|
+
parser.add_argument(
|
|
155
|
+
"--chevereto-password",
|
|
156
|
+
type=str,
|
|
157
|
+
help="如果自建Chevereto的API未开放,请设置username和password",
|
|
158
|
+
default=argparse.SUPPRESS,
|
|
159
|
+
)
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
"--imgurl-api-key",
|
|
162
|
+
type=str,
|
|
163
|
+
help="Imgurl的API Key",
|
|
164
|
+
default=argparse.SUPPRESS,
|
|
165
|
+
)
|
|
166
|
+
parser.add_argument(
|
|
167
|
+
"--smms-api-key", type=str, help="SM.MS的API Key", default=argparse.SUPPRESS
|
|
168
|
+
)
|
|
169
|
+
parser.add_argument(
|
|
170
|
+
"--byr-cookie",
|
|
171
|
+
type=str,
|
|
172
|
+
help="BYR的Cookie,可登录后访问任意页面F12查看",
|
|
173
|
+
default=argparse.SUPPRESS,
|
|
174
|
+
)
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
"--byr-alternative-url",
|
|
177
|
+
type=str,
|
|
178
|
+
help="BYR反代地址(如有),可为空",
|
|
179
|
+
default=argparse.SUPPRESS,
|
|
180
|
+
)
|
|
181
|
+
parser.add_argument(
|
|
182
|
+
"--cloudinary-cloud-name",
|
|
183
|
+
type=str,
|
|
184
|
+
help="Cloudinary的cloud name",
|
|
185
|
+
default=argparse.SUPPRESS,
|
|
186
|
+
)
|
|
187
|
+
parser.add_argument(
|
|
188
|
+
"--cloudinary-api-key",
|
|
189
|
+
type=str,
|
|
190
|
+
help="Cloudinary的api key",
|
|
191
|
+
default=argparse.SUPPRESS,
|
|
192
|
+
)
|
|
193
|
+
parser.add_argument(
|
|
194
|
+
"--cloudinary-api-secret",
|
|
195
|
+
type=str,
|
|
196
|
+
help="Cloudinary的api secret",
|
|
197
|
+
default=argparse.SUPPRESS,
|
|
198
|
+
)
|
|
199
|
+
parser.add_argument(
|
|
200
|
+
"--imgbox-username",
|
|
201
|
+
type=str,
|
|
202
|
+
help="Imgbox图床登录用户名,留空则匿名上传",
|
|
203
|
+
default=argparse.SUPPRESS,
|
|
204
|
+
)
|
|
205
|
+
parser.add_argument(
|
|
206
|
+
"--imgbox-password",
|
|
207
|
+
type=str,
|
|
208
|
+
help="Imgbox图床登录密码,留空则匿名上传",
|
|
209
|
+
default=argparse.SUPPRESS,
|
|
210
|
+
)
|
|
211
|
+
parser.add_argument(
|
|
212
|
+
"--imgbox-thumbnail-size",
|
|
213
|
+
type=str,
|
|
214
|
+
help="Imgbox图床缩略图的大小,默认300r",
|
|
215
|
+
default=argparse.SUPPRESS,
|
|
216
|
+
)
|
|
217
|
+
parser.add_argument(
|
|
218
|
+
"--imgbox-family-safe",
|
|
219
|
+
action="store_true",
|
|
220
|
+
dest="imgbox_family_safe",
|
|
221
|
+
help="Imgbox图床是否是非成人内容",
|
|
222
|
+
default=argparse.SUPPRESS,
|
|
223
|
+
)
|
|
224
|
+
parser.add_argument(
|
|
225
|
+
"--imgbox-not-family-safe",
|
|
226
|
+
action="store_false",
|
|
227
|
+
dest="imgbox_family_safe",
|
|
228
|
+
help="Imgbox图床是否是成人内容",
|
|
229
|
+
default=argparse.SUPPRESS,
|
|
230
|
+
)
|
|
231
|
+
parser.add_argument(
|
|
232
|
+
"--ptgen-url", type=str, help="自定义PTGEN的地址", default=argparse.SUPPRESS
|
|
233
|
+
)
|
|
234
|
+
parser.add_argument(
|
|
235
|
+
"--ptgen-retry",
|
|
236
|
+
type=int,
|
|
237
|
+
help="PTGEN重试次数,默认为3次",
|
|
238
|
+
default=argparse.SUPPRESS,
|
|
239
|
+
)
|
|
240
|
+
parser.add_argument(
|
|
241
|
+
"--announce-url",
|
|
242
|
+
type=str,
|
|
243
|
+
help="制种时announce地址",
|
|
244
|
+
default=argparse.SUPPRESS,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
parser.add_argument(
|
|
248
|
+
"--encoder-log", type=str, help="压制log的路径", default=argparse.SUPPRESS
|
|
249
|
+
)
|
|
250
|
+
upload_option_group = parser.add_mutually_exclusive_group()
|
|
251
|
+
upload_option_group.add_argument(
|
|
252
|
+
"--easy-upload",
|
|
253
|
+
action="store_true",
|
|
254
|
+
help="使用树大Easy Upload插件自动填充",
|
|
255
|
+
dest="easy_upload",
|
|
256
|
+
default=argparse.SUPPRESS,
|
|
257
|
+
)
|
|
258
|
+
upload_option_group.add_argument(
|
|
259
|
+
"--auto-feed",
|
|
260
|
+
action="store_true",
|
|
261
|
+
help="使用明日大Auto Feed插件自动填充",
|
|
262
|
+
dest="auto_feed",
|
|
263
|
+
default=argparse.SUPPRESS,
|
|
264
|
+
)
|
|
265
|
+
parser.add_argument(
|
|
266
|
+
"--trim-description",
|
|
267
|
+
action="store_true",
|
|
268
|
+
help="是否在生成的链接中省略种子描述,该选项主要是为了解决浏览器限制URL长度的问题,默认关闭",
|
|
269
|
+
default=argparse.SUPPRESS,
|
|
270
|
+
)
|
|
271
|
+
parser.add_argument(
|
|
272
|
+
"--use-short-url",
|
|
273
|
+
action="store_true",
|
|
274
|
+
help="是否缩短生成的上传链接",
|
|
275
|
+
default=argparse.SUPPRESS,
|
|
276
|
+
)
|
|
277
|
+
parser.add_argument(
|
|
278
|
+
"--no-reuse-torrent",
|
|
279
|
+
action="store_false",
|
|
280
|
+
dest="reuse_torrent",
|
|
281
|
+
help="是否直接在差速器已经制作的种子基础上重新制种",
|
|
282
|
+
default=argparse.SUPPRESS,
|
|
283
|
+
)
|
|
284
|
+
parser.add_argument(
|
|
285
|
+
"--from-torrent",
|
|
286
|
+
type=str,
|
|
287
|
+
help="提供种子,在此基础上,直接洗种生成新种子",
|
|
288
|
+
default=argparse.SUPPRESS,
|
|
289
|
+
)
|
|
290
|
+
return parser
|
|
291
|
+
|
|
292
|
+
def __init__(
|
|
293
|
+
self,
|
|
294
|
+
folder: str,
|
|
295
|
+
url: str,
|
|
296
|
+
upload_url: str,
|
|
297
|
+
screenshot_count: int = 0,
|
|
298
|
+
screenshot_path: str = None,
|
|
299
|
+
optimize_screenshot: bool = True,
|
|
300
|
+
create_folder: bool = False,
|
|
301
|
+
use_short_bdinfo: bool = False,
|
|
302
|
+
scan_bdinfo: bool = True,
|
|
303
|
+
image_hosting: ImageHosting = ImageHosting.PTPIMG,
|
|
304
|
+
chevereto_hosting_url: str = "",
|
|
305
|
+
imgurl_hosting_url: str = "",
|
|
306
|
+
ptpimg_api_key: str = None,
|
|
307
|
+
hdbits_cookie: str = None,
|
|
308
|
+
hdbits_thumb_size: str = "w300",
|
|
309
|
+
chevereto_api_key: str = None,
|
|
310
|
+
chevereto_username: str = None,
|
|
311
|
+
chevereto_password: str = None,
|
|
312
|
+
cloudinary_cloud_name: str = None,
|
|
313
|
+
cloudinary_api_key: str = None,
|
|
314
|
+
cloudinary_api_secret: str = None,
|
|
315
|
+
imgurl_api_key: str = None,
|
|
316
|
+
smms_api_key: str = None,
|
|
317
|
+
byr_cookie: str = None,
|
|
318
|
+
byr_alternative_url: str = None,
|
|
319
|
+
imgbox_username: str = None,
|
|
320
|
+
imgbox_password: str = None,
|
|
321
|
+
imgbox_thumbnail_size: str = "300r",
|
|
322
|
+
imgbox_family_safe: bool = True,
|
|
323
|
+
ptgen_url: str = "https://ptgen.lgto.workers.dev",
|
|
324
|
+
second_ptgen_url: str = "https://api.slyw.me",
|
|
325
|
+
announce_url: str = "https://example.com",
|
|
326
|
+
ptgen_retry: int = 3,
|
|
327
|
+
generate_nfo: bool = False,
|
|
328
|
+
make_torrent: bool = False,
|
|
329
|
+
easy_upload: bool = False,
|
|
330
|
+
auto_feed: bool = False,
|
|
331
|
+
trim_description: bool = False,
|
|
332
|
+
use_short_url: bool = False,
|
|
333
|
+
encoder_log: str = "",
|
|
334
|
+
reuse_torrent: bool = True,
|
|
335
|
+
from_torrent: str = None,
|
|
336
|
+
**kwargs,
|
|
337
|
+
):
|
|
338
|
+
self.folder = Path(folder)
|
|
339
|
+
self.url = url
|
|
340
|
+
self.upload_url = upload_url
|
|
341
|
+
|
|
342
|
+
self.announce_url = announce_url
|
|
343
|
+
self.generate_nfo = generate_nfo
|
|
344
|
+
self.make_torrent = make_torrent
|
|
345
|
+
self.easy_upload = easy_upload
|
|
346
|
+
self.auto_feed = auto_feed
|
|
347
|
+
self.trim_description = trim_description
|
|
348
|
+
self.use_short_url = use_short_url
|
|
349
|
+
self.encoder_log = encoder_log
|
|
350
|
+
self.reuse_torrent = reuse_torrent
|
|
351
|
+
self.from_torrent = from_torrent
|
|
352
|
+
|
|
353
|
+
self.mediainfo_handler = MediaInfoHandler(
|
|
354
|
+
folder=self.folder,
|
|
355
|
+
create_folder=create_folder,
|
|
356
|
+
use_short_bdinfo=use_short_bdinfo,
|
|
357
|
+
scan_bdinfo=scan_bdinfo,
|
|
358
|
+
)
|
|
359
|
+
self.ptgen_handler = PTGenHandler(
|
|
360
|
+
url=self.url,
|
|
361
|
+
ptgen_url=ptgen_url,
|
|
362
|
+
second_ptgen_url=second_ptgen_url,
|
|
363
|
+
ptgen_retry=ptgen_retry,
|
|
364
|
+
)
|
|
365
|
+
self.screenshot_handler = ScreenshotHandler(
|
|
366
|
+
folder=self.folder,
|
|
367
|
+
screenshot_count=screenshot_count,
|
|
368
|
+
screenshot_path=screenshot_path,
|
|
369
|
+
optimize_screenshot=optimize_screenshot,
|
|
370
|
+
image_hosting=image_hosting,
|
|
371
|
+
chevereto_hosting_url=chevereto_hosting_url,
|
|
372
|
+
imgurl_hosting_url=imgurl_hosting_url,
|
|
373
|
+
ptpimg_api_key=ptpimg_api_key,
|
|
374
|
+
hdbits_cookie=hdbits_cookie,
|
|
375
|
+
hdbits_thumb_size=hdbits_thumb_size,
|
|
376
|
+
chevereto_username=chevereto_username,
|
|
377
|
+
chevereto_password=chevereto_password,
|
|
378
|
+
chevereto_api_key=chevereto_api_key,
|
|
379
|
+
cloudinary_cloud_name=cloudinary_cloud_name,
|
|
380
|
+
cloudinary_api_key=cloudinary_api_key,
|
|
381
|
+
cloudinary_api_secret=cloudinary_api_secret,
|
|
382
|
+
imgurl_api_key=imgurl_api_key,
|
|
383
|
+
smms_api_key=smms_api_key,
|
|
384
|
+
byr_cookie=byr_cookie,
|
|
385
|
+
byr_alternative_url=byr_alternative_url,
|
|
386
|
+
imgbox_username=imgbox_username,
|
|
387
|
+
imgbox_password=imgbox_password,
|
|
388
|
+
imgbox_thumbnail_size=imgbox_thumbnail_size,
|
|
389
|
+
imgbox_family_safe=imgbox_family_safe,
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
self.main_file: Optional[Path] = None
|
|
393
|
+
self.ptgen: Optional[PTGenData] = None
|
|
394
|
+
self.douban: Optional[DoubanData] = None
|
|
395
|
+
self.imdb: Optional[IMDBData] = None
|
|
396
|
+
|
|
397
|
+
def upload(self):
|
|
398
|
+
self._prepare()
|
|
399
|
+
if self.easy_upload:
|
|
400
|
+
torrent_info = self.easy_upload_torrent_info
|
|
401
|
+
if self.trim_description:
|
|
402
|
+
# 直接打印简介部分来绕过浏览器的链接长度限制
|
|
403
|
+
torrent_info["description"] = ""
|
|
404
|
+
logger.trace(f"torrent_info: {torrent_info}")
|
|
405
|
+
link = f"{self.upload_url}#torrentInfo={quote(json.dumps(torrent_info))}"
|
|
406
|
+
logger.trace(f"已生成自动上传链接:{link}")
|
|
407
|
+
if self.trim_description:
|
|
408
|
+
logger.info(f"种子描述:\n{self.description}")
|
|
409
|
+
open_link(link, self.use_short_url)
|
|
410
|
+
elif self.auto_feed:
|
|
411
|
+
link = f"{self.upload_url}#{self.auto_feed_info}"
|
|
412
|
+
# if self.trim_description:
|
|
413
|
+
# logger.info(f"种子描述:\n{self.description}")
|
|
414
|
+
logger.trace(f"已生成自动上传链接:{link}")
|
|
415
|
+
open_link(link, self.use_short_url)
|
|
416
|
+
else:
|
|
417
|
+
logger.info(
|
|
418
|
+
"\n"
|
|
419
|
+
f"标题: {self.title}\n"
|
|
420
|
+
f"副标题: {self.subtitle}\n"
|
|
421
|
+
f"豆瓣: {self.douban_url}\n"
|
|
422
|
+
f"IMDB: {self.imdb_url}\n"
|
|
423
|
+
f"视频编码: {self.video_codec} 音频编码: {self.audio_codec} 分辨率: {self.resolution}\n"
|
|
424
|
+
f"描述:\n{self.description}"
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
def _prepare(self):
|
|
428
|
+
self.main_file = self.mediainfo_handler.find_mediainfo()
|
|
429
|
+
self.ptgen, self.douban, self.imdb = self.ptgen_handler.fetch_ptgen_info()
|
|
430
|
+
self.screenshot_handler.collect_screenshots(
|
|
431
|
+
self.main_file,
|
|
432
|
+
self.mediainfo_handler.resolution,
|
|
433
|
+
self.mediainfo_handler.duration,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
if self.generate_nfo:
|
|
437
|
+
generate_nfo(self.folder, self.mediainfo_handler.media_info)
|
|
438
|
+
|
|
439
|
+
if self.make_torrent:
|
|
440
|
+
make_torrent(
|
|
441
|
+
self.folder,
|
|
442
|
+
self.announce_url,
|
|
443
|
+
self.__class__.__name__,
|
|
444
|
+
self.reuse_torrent,
|
|
445
|
+
self.from_torrent,
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def parsed_encoder_log(self):
|
|
450
|
+
return parse_encoder_log(self.encoder_log)
|
|
451
|
+
|
|
452
|
+
@property
|
|
453
|
+
def title(self):
|
|
454
|
+
# TODO: Either use file name or generate from mediainfo and ptgen
|
|
455
|
+
temp_name = (
|
|
456
|
+
self.folder.name if self.folder.is_dir() else self.folder.stem
|
|
457
|
+
).replace(".", " ")
|
|
458
|
+
temp_name = re.sub(r"(?<=5|7)( )1(?=.*$)", ".1", temp_name)
|
|
459
|
+
return temp_name
|
|
460
|
+
|
|
461
|
+
@property
|
|
462
|
+
def subtitle(self):
|
|
463
|
+
if not self.douban:
|
|
464
|
+
return self.ptgen.subtitle
|
|
465
|
+
return self.douban.subtitle
|
|
466
|
+
|
|
467
|
+
@property
|
|
468
|
+
def media_info(self):
|
|
469
|
+
return self.mediainfo_handler.media_info
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def media_infos(self):
|
|
473
|
+
return []
|
|
474
|
+
|
|
475
|
+
@property
|
|
476
|
+
def description(self):
|
|
477
|
+
return "{}\n\n[quote]{}{}[/quote]\n\n{}".format(
|
|
478
|
+
self.ptgen.format,
|
|
479
|
+
self.media_info,
|
|
480
|
+
"\n\n" + self.parsed_encoder_log if self.parsed_encoder_log else "",
|
|
481
|
+
"\n".join(
|
|
482
|
+
[f"{uploaded}" for uploaded in self.screenshot_handler.screenshots]
|
|
483
|
+
),
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
@property
|
|
487
|
+
def original_description(self):
|
|
488
|
+
return ""
|
|
489
|
+
|
|
490
|
+
@property
|
|
491
|
+
def douban_url(self):
|
|
492
|
+
if self.douban:
|
|
493
|
+
return f"https://movie.douban.com/subject/{self.douban.sid}"
|
|
494
|
+
return ""
|
|
495
|
+
|
|
496
|
+
@property
|
|
497
|
+
def douban_info(self):
|
|
498
|
+
return ""
|
|
499
|
+
|
|
500
|
+
@property
|
|
501
|
+
def imdb_url(self):
|
|
502
|
+
return getattr(self.ptgen, "imdb_link", "")
|
|
503
|
+
|
|
504
|
+
@property
|
|
505
|
+
def screenshots(self):
|
|
506
|
+
return [u.url for u in self.screenshot_handler.screenshots]
|
|
507
|
+
|
|
508
|
+
@property
|
|
509
|
+
def poster(self):
|
|
510
|
+
return getattr(self.ptgen, "poster")
|
|
511
|
+
|
|
512
|
+
@property
|
|
513
|
+
def year(self):
|
|
514
|
+
return (
|
|
515
|
+
self.imdb.year
|
|
516
|
+
if self.imdb
|
|
517
|
+
else self.douban.year if self.douban else getattr(self.ptgen, "year", "")
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
@property
|
|
521
|
+
def category(self):
|
|
522
|
+
if self.douban:
|
|
523
|
+
if "演唱会" in self.douban.genre and "音乐" in self.douban.genre:
|
|
524
|
+
return "concert"
|
|
525
|
+
if self.imdb:
|
|
526
|
+
if "Documentary" in self.imdb.genre:
|
|
527
|
+
return "documentary"
|
|
528
|
+
if self.imdb.type_ == DataType.MOVIE:
|
|
529
|
+
return "movie"
|
|
530
|
+
if self.imdb.type_ == DataType.TV_SERIES:
|
|
531
|
+
return "tvPack"
|
|
532
|
+
return self.ptgen.type_
|
|
533
|
+
|
|
534
|
+
@property
|
|
535
|
+
def video_type(self):
|
|
536
|
+
if "webdl" in self.folder.name.lower() or "web-dl" in self.folder.name.lower():
|
|
537
|
+
return "web"
|
|
538
|
+
elif "remux" in self.folder.name.lower():
|
|
539
|
+
return "remux"
|
|
540
|
+
elif "hdtv" in self.folder.name.lower():
|
|
541
|
+
return "hdtv"
|
|
542
|
+
elif any(e in self.folder.name.lower() for e in ("x264", "x265")):
|
|
543
|
+
return "encode"
|
|
544
|
+
elif "bluray" in self.folder.name.lower() and not any(
|
|
545
|
+
e in self.folder.name.lower() for e in ("x264", "x265")
|
|
546
|
+
):
|
|
547
|
+
return "bluray"
|
|
548
|
+
elif "uhd" in self.folder.name.lower():
|
|
549
|
+
return "uhdbluray"
|
|
550
|
+
for track in self.mediainfo_handler.tracks:
|
|
551
|
+
if track.track_type == "Video":
|
|
552
|
+
if track.encoding_settings:
|
|
553
|
+
return "encode"
|
|
554
|
+
return ""
|
|
555
|
+
|
|
556
|
+
@property
|
|
557
|
+
def format(self):
|
|
558
|
+
# TODO: Maybe read from mediainfo
|
|
559
|
+
return self.main_file.suffix
|
|
560
|
+
|
|
561
|
+
@property
|
|
562
|
+
def source(self):
|
|
563
|
+
return ""
|
|
564
|
+
|
|
565
|
+
@property
|
|
566
|
+
def video_codec(self):
|
|
567
|
+
for track in self.mediainfo_handler.mediainfo.tracks:
|
|
568
|
+
if track.track_type == "Video":
|
|
569
|
+
if track.encoded_library_name:
|
|
570
|
+
return track.encoded_library_name
|
|
571
|
+
if track.commercial_name == "AVC":
|
|
572
|
+
return "h264"
|
|
573
|
+
if track.commercial_name == "HEVC":
|
|
574
|
+
return "hevc"
|
|
575
|
+
# h264: "AVC/H.264",
|
|
576
|
+
# hevc: "HEVC",
|
|
577
|
+
# x264: "x264",
|
|
578
|
+
# x265: "x265",
|
|
579
|
+
# h265: "HEVC",
|
|
580
|
+
# mpeg2: "MPEG-2",
|
|
581
|
+
# mpeg4: "AVC/H.264",
|
|
582
|
+
# vc1: "VC-1",
|
|
583
|
+
# dvd: "MPEG"
|
|
584
|
+
return ""
|
|
585
|
+
|
|
586
|
+
@property
|
|
587
|
+
def audio_codec(self):
|
|
588
|
+
codec_map = {
|
|
589
|
+
"AAC": "aac",
|
|
590
|
+
"Dolby Digital Plus": "dd+",
|
|
591
|
+
"Dolby Digital": "dd",
|
|
592
|
+
"DTS-HD Master Audio": "dtshdma",
|
|
593
|
+
"Dolby Digital Plus with Dolby Atmos": "atmos",
|
|
594
|
+
"Dolby TrueHD": "truehd",
|
|
595
|
+
"Dolby TrueHD with Dolby Atmos": "truehd",
|
|
596
|
+
}
|
|
597
|
+
for track in self.mediainfo_handler.mediainfo.tracks:
|
|
598
|
+
if track.track_type == "Audio":
|
|
599
|
+
if track.format_info == "Audio Coding 3":
|
|
600
|
+
return "ac3"
|
|
601
|
+
if track.format_info == "Free Lossless Audio Codec":
|
|
602
|
+
return "flac"
|
|
603
|
+
if track.commercial_name in codec_map:
|
|
604
|
+
return codec_map.get(track.commercial_name)
|
|
605
|
+
# TODO: other formats
|
|
606
|
+
# dts: "3",
|
|
607
|
+
# lpcm: "21",
|
|
608
|
+
# dtsx: "3",
|
|
609
|
+
# ape: "2",
|
|
610
|
+
# wav: "22",
|
|
611
|
+
# mp3: "4",
|
|
612
|
+
# m4a: "5",
|
|
613
|
+
# other: "7"
|
|
614
|
+
return ""
|
|
615
|
+
|
|
616
|
+
@property
|
|
617
|
+
def resolution(self):
|
|
618
|
+
for track in self.mediainfo_handler.mediainfo.tracks:
|
|
619
|
+
if track.track_type == "Video":
|
|
620
|
+
if track.height <= 480:
|
|
621
|
+
return "480p"
|
|
622
|
+
elif track.height <= 576:
|
|
623
|
+
return "576p"
|
|
624
|
+
elif track.height <= 720:
|
|
625
|
+
return "720p"
|
|
626
|
+
elif track.height <= 1080:
|
|
627
|
+
if getattr(track, "scan_type__store_method") == "InterleavedFields":
|
|
628
|
+
return "1080i"
|
|
629
|
+
return "1080p"
|
|
630
|
+
elif track.height <= 2160:
|
|
631
|
+
return "2160p"
|
|
632
|
+
elif track.height <= 4320:
|
|
633
|
+
return "4320p"
|
|
634
|
+
return ""
|
|
635
|
+
|
|
636
|
+
@property
|
|
637
|
+
def area(self):
|
|
638
|
+
if self.douban:
|
|
639
|
+
return self.douban.area
|
|
640
|
+
return ""
|
|
641
|
+
|
|
642
|
+
@property
|
|
643
|
+
def movie_name(self):
|
|
644
|
+
if self.imdb:
|
|
645
|
+
return self.imdb.name
|
|
646
|
+
if self.douban:
|
|
647
|
+
return next(iter(self.douban.aka), "")
|
|
648
|
+
return ""
|
|
649
|
+
|
|
650
|
+
@property
|
|
651
|
+
def movie_aka_name(self):
|
|
652
|
+
return ""
|
|
653
|
+
|
|
654
|
+
@property
|
|
655
|
+
def size(self):
|
|
656
|
+
for track in self.mediainfo_handler.tracks:
|
|
657
|
+
if track.track_type == "General":
|
|
658
|
+
return track.file_size
|
|
659
|
+
return ""
|
|
660
|
+
|
|
661
|
+
@property
|
|
662
|
+
def tags(self):
|
|
663
|
+
tags = {}
|
|
664
|
+
for track in self.mediainfo_handler.tracks:
|
|
665
|
+
if track.track_type == "General":
|
|
666
|
+
if track.audio_language_list and "Chinese" in track.audio_language_list:
|
|
667
|
+
tags["chinese_audio"] = True
|
|
668
|
+
if track.text_language_list and "Chinese" in track.text_language_list:
|
|
669
|
+
tags["chinese_subtitle"] = True
|
|
670
|
+
# TODO: hdr, hdr10_plus, dolby_vision, diy, cantonese_audio, false,dts_x, dolby_atoms
|
|
671
|
+
return tags
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def other_tags(self):
|
|
675
|
+
return []
|
|
676
|
+
|
|
677
|
+
@property
|
|
678
|
+
def comparisons(self):
|
|
679
|
+
return []
|
|
680
|
+
|
|
681
|
+
@property
|
|
682
|
+
def easy_upload_torrent_info(self):
|
|
683
|
+
return EasyUpload(plugin=self).torrent_info
|
|
684
|
+
|
|
685
|
+
@property
|
|
686
|
+
def auto_feed_info(self):
|
|
687
|
+
return AutoFeed(plugin=self).info
|