├── LICENSE
├── README.md
├── javsdt
├── Class
│ ├── JavFile.py
│ └── Settings.py
├── CreateIni.py
├── Functions
│ ├── Baidu.py
│ ├── Car.py
│ ├── Genre.py
│ ├── Picture.py
│ ├── Process.py
│ ├── Record.py
│ ├── Requests
│ │ ├── ArzonReq.py
│ │ ├── Download.py
│ │ ├── Jav321Req.py
│ │ ├── JavbusReq.py
│ │ ├── JavdbReq.py
│ │ └── JavlibraryReq.py
│ ├── Standard.py
│ ├── Status.py
│ ├── User.py
│ └── XML.py
├── Jav321.py
├── JavbusWuma.py
├── JavbusYouma.py
├── JavdbFc2.py
├── StaticFiles
│ ├── divulge.png
│ ├── emby.ico
│ ├── ini.ico
│ ├── javbus.ico
│ ├── javdb.ico
│ ├── javlibrary.ico
│ ├── javsdt.ico
│ ├── subtitle.png
│ ├── suren.ico
│ └── update.ico
├── Update.py
├── divulge.png
├── emby_actors.py
├── javlibrary.py
├── subtitle.png
├── 【特征对照表】.xlsx
└── 【素人车牌】.txt
├── requirements.txt
├── 检查更新.json
└── 测试影片.zip
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 junerain123
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Adult Video Scraper for JAV 日本AV(JAV)刮削整理
2 | 原作者暂停更新和修复bug。开此分支用于维护javsdt并且继续开发,接受pull request,欢迎提交新功能和修复bug。
3 |
4 | 为了维护及开发新功能,欢迎各位加入TG群https://t.me/javsdtool
5 |
6 | Todo:
7 | - [ ] 由于缺少相关背景,需要有会使用Emby API的大佬帮助整合进入Emby。(参考Javscraper: https://github.com/JavScraper/Emby.Plugins.JavScraper 和jellyfin-plugin-avdc:https://github.com/xjasonlyu/jellyfin-plugin-avdc)
8 |
9 | ## 源码使用方法,
10 | 1、先安装[Python3](https://www.python.org/downloads/)和[Node.js](https://nodejs.org/zh-cn/download/)最新版本。
11 |
12 | 2、进入[Release](https://github.com/fanza1/Fake_javsdt/releases),下载最新版本源码
13 |
14 | 3、找到根目录下的requirements.txt,然后运行pip install安装执行环境
15 | ```
16 | pip install -r .\requirements.txt
17 | pip install -U cfscrape
18 | ```
19 | 4、然后进入javsdt目录执行CreateIni.py
20 |
21 | 5、接下来按需求执行如JavbusYouma.py
22 |
23 | ## 常见问题
24 | * 注意,执行方法可以打开cmd或PowerShell使用命令行如
25 | ```
26 | pip install -r .\requirements.txt
27 | pip install -U cfscrape
28 | python CreateIni.py
29 | python JavbusYouma.py
30 | ```
31 | 对于windows用户也可以直接双击运行,选择python执行
32 |
33 | * javlibrary免翻墙刮削出错建议更换网址,图书馆官方网址发布:http://www.javlibrary.com/cn/publictopic.php?id=13483
34 |
35 | ## Log 记录
36 | - [x] 21.6.7 fix JavBus图片刮削
37 | - [x] 21.2.25 fix JavBus有码无法刮削genre和tag
38 | - [x] 21.3.4 fix JavBus无码无法刮削genre和tag
39 | - [x] 21.4.2 fix javlibrary评分错乱的问题,移除作者瞎搞的评分算法,忠于图书馆的评分。修复由于cf造成的无法获取javlibrary网页的问题,但需要用户安装最新版node.js并且在命令行执行
40 | ```
41 | pip install -U cfscrape
42 | ```
43 | - [x] 21.4.2 new feature 增加避免小众高分影片霸榜的算法
44 |
45 |
46 | # 以下为原repo的Readme
47 | ## jav-standard-tool 简称javsdt
48 | ## 作者为生活所迫,已经跑路...
49 | 简介:收集影视元数据,并规范本地文件(夹)的格式,收集演员头像,为emby、kodi、jellyfin、极影派等影片管理软件铺路。
50 |
51 |
52 | ## 1、【一般用户】下载及群链接:
53 | 目前2021年2月7日更新的1.1.5版本 推荐使用win10 64位
54 | [从蓝奏云下载](https://junerain.lanzous.com/ivp8Plg6wza) 或者 [从github下载](https://github.com/javsdt/javsdt/releases/tag/V1.1.5)
55 |
56 | [前往下载演员头像](https://github.com/javsdt/javsdt/releases/tag/女优头像)
57 |
58 | [企鹅群](https://jq.qq.com/?_wv=1027&k=5CbWOpV)(需要付费1人民币扩群)
59 | [电报群](https://t.me/joinchat/PaHhgBaleu_qEgFy_NJlIA)(尽量进企鹅群,电报群真的没时间去了)
60 |
61 | ## 2、[使用说明(还没写完)](https://github.com/javsdt/javsdt/wiki)
62 | [旧版的使用说明从蓝奏云下载](https://www.lanzous.com/ib0qozg)
63 |
64 | ## 3、【其他开发者】运行环境:
65 | python3.7.6 发行版是pyinstaller打包的exe
66 | pip install requests==2.20.0(安装2.25.1报错ProxyError无法使用http代理)
67 | pip install Pillow
68 | pip install baidu-aip
69 | pip install pysocks
70 | pip install [cloudscraper](https://github.com/VeNoMouS/cloudscraper)(目前版本暂时不需要)
71 | pip install xlrd==1.2.0(安装2.2.1无法读取xlsx)
72 | 几个jav的py都是独立执行的,加了很多很多注释,希望能理解其中踩过的坑。
73 |
74 | ## 4、工作流程:
75 | (1)用户选择文件夹,遍历路径下的所有文件。
76 | (2)文件是jav,取车牌号,到javXXX网站搜索影片找到对应网页。
77 | (3)获取网页源码找出“标题”“导演”“发行日期”等信息和DVD封面url。
78 | (4)重命名影片文件。
79 | (5)重命名文件夹或建立独立文件夹。
80 | (6)保存信息写入nfo。
81 | (7)下载封面url作fanart.jpg,裁剪右半边作poster.jpg。
82 | (8)移动文件夹,完成归类。
83 |
84 | ## 5、目标效果:
85 | 效果图不放了
86 | !=[image](https://github.com/javsdt/images/blob/master/jav/javsdt/readme/%E7%9B%AE%E6%A0%87%E6%95%88%E6%9E%9C1.png?raw=false)
87 | !=[image](https://github.com/javsdt/images/blob/master/jav/javsdt/readme/%E7%9B%AE%E6%A0%87%E6%95%88%E6%9E%9C2.png?raw=false)
88 | !=[image](https://github.com/javsdt/images/blob/master/jav/javsdt/readme/%E7%9B%AE%E6%A0%87%E6%95%88%E6%9E%9C3.jpg?raw=false)
89 |
90 | ## 6、ini中的用户设置:
91 | 
92 |
93 | ## 7、其他说明:
94 | (1)不需要赞助;
95 | (2)允许对软件进行任何形式的转载;
96 | (3)代码及软件使用“MIT许可证”,他人可以修改代码、发布分支,允许闭源、商业化,但造成后果与本作者无关。
97 |
--------------------------------------------------------------------------------
/javsdt/Class/JavFile.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import sep
3 |
4 |
5 | # 每一部jav的“结构体”
6 | class JavFile(object):
7 | def __init__(self, file_raw, root, car, episode, subtitle, num_current):
8 | self.name = file_raw # 文件名带文件扩展名 ABC-123.mp4
9 | self.root = root # 视频所在文件夹的路径
10 | self.car = car # 车牌
11 | self.episode = episode # 第几集 1 2 3集
12 | self.subtitle = subtitle # 字幕文件名 ABC-123.srt
13 | self.type = '.' + file_raw.split('.')[-1].lower() # 视频文件扩展名 .mp4
14 | self.subtitle_type = '.' + subtitle.split('.')[-1].lower() # 字幕扩展名 .srt
15 | self.number = num_current # 当前处理的视频在所有视频中的编号
16 |
17 | # 视频文件完整路径
18 | @property
19 | def path(self):
20 | return self.root + sep + self.name
21 |
22 | # 视频文件完整路径,但不带文件扩展名
23 | @property
24 | def name_no_ext(self):
25 | return self.name[:-len(self.type)]
26 |
27 | # 所在文件夹名称
28 | @property
29 | def folder(self):
30 | return self.root.split(sep)[-1]
31 |
32 | # 字幕文件完整路径
33 | @property
34 | def path_subtitle(self):
35 | return self.root + sep + self.subtitle
--------------------------------------------------------------------------------
/javsdt/Class/Settings.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from configparser import RawConfigParser
3 | from os import system
4 | from os.path import exists
5 | from aip import AipBodyAnalysis
6 |
7 |
8 | # 设置
9 | class Settings(object):
10 | def __init__(self, av_type):
11 | config_settings = RawConfigParser()
12 | config_settings.read('【点我设置整理规则】.ini', encoding='utf-8-sig')
13 | ####################################################### nfo ###################################################
14 | # 是否 跳过已存在nfo的文件夹,不处理已有nfo的文件夹
15 | self.bool_skip = True if config_settings.get("收集nfo", "是否跳过已存在nfo的文件夹?") == '是' else False
16 | # 是否 收集nfo
17 | self.bool_nfo = True if config_settings.get("收集nfo", "是否收集nfo?") == '是' else False
18 | # 自定义 nfo中title的格式
19 | self._custom_nfo_title = config_settings.get("收集nfo", "nfo中title的格式")
20 | # 是否 去除 标题 末尾可能存在的演员姓名
21 | self.bool_strip_actors = True if config_settings.get("收集nfo", "是否去除标题末尾的演员姓名?") == '是' else False
22 | # 自定义 将系列、片商等元素作为特征,因为emby不会直接在影片介绍页面上显示片商,也不会读取系列set
23 | self._custom_genres = config_settings.get("收集nfo", "额外将以下元素添加到特征中")
24 | # ?是否将“系列”写入到特征中
25 | self.bool_write_series = True if '系列' in self._custom_genres else False
26 | # ?是否将“片商”写入到特征中
27 | self.bool_write_studio = True if '片商' in self._custom_genres else False
28 | # 是否 将特征保存到风格中
29 | self.bool_genre = True if config_settings.get("收集nfo", "是否将特征保存到genre?") == '是' else False
30 | # 是否 将 片商 作为特征
31 | self.bool_tag = True if config_settings.get("收集nfo", "是否将特征保存到tag?") == '是' else False
32 | ####################################################### 重命名 #################################################
33 | # 是否 重命名 视频
34 | self.bool_rename_video = True if config_settings.get("重命名影片", "是否重命名影片?") == '是' else False
35 | # 自定义 重命名 视频
36 | self._custom_video = config_settings.get("重命名影片", "重命名影片的格式")
37 | # 是否 重命名视频所在文件夹,或者为它创建独立文件夹
38 | self._bool_rename_folder = True if config_settings.get("修改文件夹", "是否重命名或创建独立文件夹?") == '是' else False
39 | # 自定义 新的文件夹名
40 | self._custom_folder = config_settings.get("修改文件夹", "新文件夹的格式")
41 | ########################################################## 归类 ################################################
42 | # 是否 归类jav
43 | self.bool_classify = True if config_settings.get("归类影片", "是否归类影片?") == '是' else False
44 | # 是否 针对“文件夹”归类jav,“否”即针对“文件”
45 | self.bool_classify_folder = True if config_settings.get("归类影片", "针对文件还是文件夹?") == '文件夹' else False
46 | # 自定义 路径 归类的jav放到哪
47 | self._custom_root = config_settings.get("归类影片", "归类的根目录")
48 | # 自定义 jav按什么类别标准来归类
49 | self._custom_classify_basis = config_settings.get("归类影片", "归类的标准")
50 | ######################################################## 图片 ################################################
51 | # 是否 下载图片
52 | self.bool_jpg = True if config_settings.get("下载封面", "是否下载封面海报?") == '是' else False
53 | # 自定义 命名 大封面fanart
54 | self._custom_fanart = config_settings.get("下载封面", "DVD封面的格式")
55 | # 自定义 命名 小海报poster
56 | self._custom_poster = config_settings.get("下载封面", "海报的格式")
57 | # 是否 如果视频有“中字”,给poster的左上角加上“中文字幕”的斜杠
58 | self.bool_watermark_subtitle = True if config_settings.get("下载封面", "是否为海报加上中文字幕条幅?") == '是' else False
59 | # 是否 如果视频是“无码流出”,给poster的右上角加上“无码流出”的斜杠
60 | self.bool_watermark_divulge = True if config_settings.get("下载封面", "是否为海报加上无码流出条幅?") == '是' else False
61 | ###################################################### 字幕 #######################################################
62 | # 是否 重命名用户已拥有的字幕
63 | self.bool_rename_subtitle = True if config_settings.get("字幕文件", "是否重命名已有的字幕文件?") == '是' else False
64 | ###################################################### kodi #######################################################
65 | # 是否 收集演员头像
66 | self.bool_sculpture = True if config_settings.get("kodi专用", "是否收集演员头像?") == '是' else False
67 | # 是否 对于多cd的影片,kodi只需要一份图片和nfo
68 | self.bool_cd_only = True if config_settings.get("kodi专用", "是否对多cd只收集一份图片和nfo?") == '是' else False
69 | ###################################################### 代理 ########################################################
70 | # 是否 使用局部代理
71 | self._bool_proxy = True if config_settings.get("局部代理", "是否使用局部代理?") == '是' else False
72 | # 是否 使用http代理,否 就是socks5
73 | self._bool_http = True if config_settings.get("局部代理", "http还是socks5?") == 'http' else False
74 | # 代理端口
75 | self._custom_proxy = config_settings.get("局部代理", "代理端口")
76 | # 是否 代理javlibrary
77 | self._bool_library_proxy = True if config_settings.get("局部代理", "是否代理javlibrary(有问题)?") == '是' else False
78 | # 是否 代理javbus,还有代理javbus上的图片cdnbus
79 | self._bool_bus_proxy = True if config_settings.get("局部代理", "是否代理javbus?") == '是' else False
80 | # 是否 代理javbus,还有代理javbus上的图片cdnbus
81 | self._bool_321_proxy = True if config_settings.get("局部代理", "是否代理jav321?") == '是' else False
82 | # 是否 代理javdb,还有代理javdb上的图片
83 | self._bool_db_proxy = True if config_settings.get("局部代理", "是否代理javdb?") == '是' else False
84 | # 是否 代理arzon
85 | self._bool_arzon_proxy = True if config_settings.get("局部代理", "是否代理arzon?") == '是' else False
86 | # 是否 代理dmm图片,javlibrary和javdb上的有码图片几乎都是直接引用dmm
87 | self._bool_dmm_proxy = True if config_settings.get("局部代理", "是否代理dmm图片?") == '是' else False
88 | #################################################### 原影片文件的性质 ################################################
89 | # 自定义 无视的字母数字 去除影响搜索结果的字母数字 xhd1080、mm616、FHD-1080
90 | self._custom_surplus_words_youma_in_filename = config_settings.get("原影片文件的性质", "有码素人无视多余的字母数字")
91 | # 自定义 无视的字母数字 去除影响搜索结果的字母数字 full、tokyohot、
92 | self._custom_surplus_words_wuma_in_filename = config_settings.get("原影片文件的性质", "无码无视多余的字母数字")
93 | # 自定义 原影片性质 影片有中文,体现在视频名称中包含这些字符
94 | self._custom_subtitle_words_in_filename = config_settings.get("原影片文件的性质", "是否中字即文件名包含")
95 | # 自定义 是否中字 这个元素的表现形式
96 | self.custom_subtitle_expression = config_settings.get("原影片文件的性质", "是否中字的表现形式")
97 | # 自定义 原影片性质 影片是无码流出片,体现在视频名称中包含这些字符
98 | self._custom_divulge_words_in_filename = config_settings.get("原影片文件的性质", "是否流出即文件名包含")
99 | # 自定义 是否流出 这个元素的表现形式
100 | self.custom_divulge_expression = config_settings.get("原影片文件的性质", "是否流出的表现形式")
101 | # 自定义 原影片性质 有码
102 | self._av_type = config_settings.get("原影片文件的性质", av_type)
103 | ##################################################### 信息来源 ##################################################
104 | # 是否 收集javlibrary下方用户超过10个人点赞的评论
105 | self.bool_review = True if config_settings.get("信息来源", "是否用javlibrary整理影片时收集网友的热评?") == '是' else False
106 | # 是否 收集javlibrary下方用户超过10个人点赞的评论
107 | self.bool_bus_first = True if config_settings.get("信息来源", "是否用javlibrary整理影片时优先从javbus下载图片?") == '是' else False
108 | ################################################### 其他设置 ####################################################
109 | # 是否 使用简体中文 简介翻译的结果和jav特征会变成“简体”还是“繁体”
110 | self.bool_zh = True if config_settings.get("其他设置", "简繁中文?") == '简' else False
111 | # 网址 javlibrary
112 | self._url_library = config_settings.get("其他设置", "javlibrary网址")
113 | # 网址 javbus
114 | self._url_bus = config_settings.get("其他设置", "javbus网址")
115 | # 网址 javdb
116 | self._url_db = config_settings.get("其他设置", "javdb网址")
117 | # 自定义 文件类型 只有列举出的视频文件类型,才会被处理
118 | self._custom_file_type = config_settings.get("其他设置", "扫描文件类型")
119 | # 自定义 命名格式中“标题”的长度 windows只允许255字符,所以限制长度,但nfo中的标题是全部
120 | self.int_title_len = int(config_settings.get("其他设置", "重命名中的标题长度(50~150)"))
121 | ######################################## 百度翻译API ####################################################
122 | # 是否 需要简介
123 | self.bool_plot = True if config_settings.get("百度翻译API", "是否需要日语简介?") == '是' else False
124 | # 是否 把日语简介翻译为中文
125 | self.bool_tran = True if config_settings.get("百度翻译API", "是否翻译为中文?") == '是' else False
126 | # 账户 百度翻译api
127 | self._tran_id = config_settings.get("百度翻译API", "APP ID")
128 | self._tran_sk = config_settings.get("百度翻译API", "密钥")
129 | ######################################## 百度人体分析 ####################################################
130 | # 是否 需要准确定位人脸的poster
131 | self.bool_face = True if config_settings.get("百度人体分析", "是否需要准确定位人脸的poster?") == '是' else False
132 | # 账户 百度人体分析
133 | self._al_id = config_settings.get("百度人体分析", "appid")
134 | self._ai_ak = config_settings.get("百度人体分析", "api key")
135 | self._al_sk = config_settings.get("百度人体分析", "secret key")
136 |
137 | ##########################################################################################################
138 | # 是否 重命名视频所在文件夹,或者为它创建独立文件夹
139 | self.bool_rename_folder = self.judge_need_rename_folder()
140 |
141 | # ######################[收集nfo]#####################################
142 | # 命名nfo中title的格式
143 | def formula_name_nfo_title(self):
144 | # 给用户命名用的标题可能是删减的,nfo中的标题是完整标题
145 | return self._custom_nfo_title.replace('标题', '完整标题', 1).split('+')
146 |
147 | # 额外放入特征风格中的元素
148 | def list_extra_genre(self):
149 | list_extra_genres = self._custom_genres.split('、') if self._custom_genres else [] # 需要的额外特征
150 | list_extra_genres = [i for i in list_extra_genres if i != '系列' and i != '片商']
151 | return list_extra_genres
152 |
153 | # #########################[重命名影片]##############################
154 | # 得到视频命名格式list
155 | def formula_rename_video(self):
156 | return self._custom_video.split('+')
157 |
158 | # #########################[修改文件夹]##############################
159 | # 是否需要重命名文件夹或者创建新的文件夹
160 | def judge_need_rename_folder(self):
161 | if self.bool_classify: # 如果需要归类
162 | if self.bool_classify_folder: # 并且是针对文件夹
163 | return True # 那么必须重命名文件夹或者创建新的文件夹
164 | else:
165 | return False # 否则不会操作新文件夹
166 | else: # 不需要归类
167 | if self._bool_rename_folder: # 但是用户本来就在ini中写了要重命名文件夹
168 | return True
169 | else:
170 | return False
171 |
172 | # 得到文件夹命名格式list 示例:['车牌', '【', '全部演员', '】']
173 | def formula_rename_folder(self):
174 | return self._custom_folder.split('+')
175 |
176 | # #########################[归类影片]##############################
177 | # 功能:检查 归类根目录 的合法性
178 | # 参数:用户自定义的归类根目录,用户选择整理的文件夹路径
179 | # 返回:归类根目录路径
180 | # 辅助:os.sep,os.system
181 | def check_classify_root(self, root_choose, sep):
182 | if self.bool_classify:
183 | custom_root = self._custom_root.rstrip(sep)
184 | # 用户使用默认的“所选文件夹”
185 | if custom_root == '所选文件夹':
186 | return root_choose + sep + '归类完成'
187 | # 归类根目录 是 用户输入的路径c:\a,继续核实合法性
188 | else:
189 | # 用户输入的路径 不是 所选文件夹root_choose
190 | if custom_root != root_choose:
191 | if custom_root[:2] != root_choose[:2]:
192 | print('归类的根目录“', custom_root, '”和所选文件夹不在同一磁盘无法归类!请修正!')
193 | system('pause')
194 | if not exists(custom_root):
195 | print('归类的根目录“', custom_root, '”不存在!无法归类!请修正!')
196 | system('pause')
197 | return custom_root
198 | # 用户输入的路径 就是 所选文件夹root_choose
199 | else:
200 | return root_choose + sep + '归类完成'
201 | else:
202 | return ''
203 |
204 | # 归类标准 比如:影片类型\全部演员
205 | def custom_classify_basis(self):
206 | return self._custom_classify_basis
207 |
208 | # #########################[下载封面]##############################
209 | # 命名fanart的格式
210 | def formula_name_fanart(self):
211 | return self._custom_fanart.split('+')
212 |
213 | # 命名poster的格式
214 | def formula_name_poster(self):
215 | return self._custom_poster.split('+')
216 |
217 | # #########################[局部代理]##############################
218 | # 得到proxy
219 | def get_proxy(self):
220 | if self._bool_proxy and self._custom_proxy:
221 | if self._bool_http:
222 | proxies = {"http": "http://" + self._custom_proxy,
223 | "https": "https://" + self._custom_proxy}
224 | else:
225 | proxies = {"http": "socks5://" + self._custom_proxy,
226 | "https": "socks5://" + self._custom_proxy}
227 | proxy_library = proxies if self._bool_library_proxy else {} # 请求javlibrary时传递的参数
228 | proxy_bus = proxies if self._bool_bus_proxy else {} # 请求javbus时传递的参数
229 | proxy_321 = proxies if self._bool_321_proxy else {} # 请求jav321时传递的参数
230 | proxy_db = proxies if self._bool_db_proxy else {} # 请求javdb时传递的参数
231 | proxy_arzon = proxies if self._bool_arzon_proxy else {} # 请求arzon时传递的参数
232 | proxy_dmm = proxies if self._bool_dmm_proxy else {} # 请求dmm图片时传递的参数
233 | else:
234 | proxy_library = {}
235 | proxy_bus = {}
236 | proxy_321 = {}
237 | proxy_db = {}
238 | proxy_arzon = {}
239 | proxy_dmm = {}
240 | return proxy_library, proxy_bus, proxy_321, proxy_db, proxy_arzon, proxy_dmm
241 |
242 | # #########################[原影片文件的性质]##############################
243 | # 得到代表中字的文字list
244 | def list_subtitle_word_in_filename(self):
245 | return self._custom_subtitle_words_in_filename.upper().split('、')
246 |
247 | # 得到代表流出的文字list
248 | def list_divulge_word_in_filename(self):
249 | return self._custom_divulge_words_in_filename.upper().split('、')
250 |
251 | # 得到干扰车牌选择的文字list
252 | def list_surplus_word_in_filename(self, av_type):
253 | if av_type == '有码':
254 | return self._custom_surplus_words_youma_in_filename.upper().split('、')
255 | else:
256 | return self._custom_surplus_words_wuma_in_filename.upper().split('、')
257 |
258 | # 自定义有码、无码、素人、FC2的对应称谓
259 | def av_type(self):
260 | return self._av_type
261 |
262 | # #########################[信息来源]##############################
263 |
264 | # #########################[其他设置]##############################
265 | # javlibrary网址,是简体还是繁体
266 | def get_url_library(self):
267 | url_library = self._url_library
268 | if not url_library.endswith('/'):
269 | url_library += '/'
270 | return url_library + 'cn/'
271 |
272 | # javbus网址
273 | def get_url_bus(self):
274 | if not self._url_bus.endswith('/'):
275 | url_web_bus = self._url_bus + '/'
276 | else:
277 | url_web_bus = self._url_bus
278 | return url_web_bus
279 |
280 | # jav321网址
281 | def get_url_321(self):
282 | if self.bool_zh:
283 | url_search_321 = 'https://www.jav321.com/search'
284 | url_web_321 = 'https://www.jav321.com/'
285 | else:
286 | url_search_321 = 'https://tw.jav321.com/search'
287 | url_web_321 = 'https://tw.jav321.com/'
288 | return url_search_321, url_web_321
289 |
290 | # javdb网址
291 | def get_url_db(self):
292 | if not self._url_db.endswith('/'):
293 | url_db = self._url_db + '/'
294 | else:
295 | url_db = self._url_db
296 | return url_db
297 |
298 | # 得到扫描文件类型
299 | def tuple_video_type(self):
300 | return tuple(self._custom_file_type.upper().split('、'))
301 |
302 | # #########################[百度翻译API]##############################
303 | # 百度翻译的目标语言、翻译账户
304 | def get_translate_account(self):
305 | if self.bool_zh:
306 | to_language = 'zh' # 目标语言,zh是简体中文,cht是繁体中文
307 | else:
308 | to_language = 'cht'
309 | return to_language, self._tran_id, self._tran_sk
310 |
311 | # #########################[百度人体分析]##############################
312 | def start_body_analysis(self):
313 | if self.bool_face:
314 | return AipBodyAnalysis(self._al_id, self._ai_ak, self._al_sk)
315 | else:
316 | return None
317 |
--------------------------------------------------------------------------------
/javsdt/CreateIni.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import system
3 | from configparser import RawConfigParser
4 | from traceback import format_exc
5 |
6 | try:
7 | print('>>正在重写ini文件...')
8 | config_settings = RawConfigParser()
9 | config_settings.add_section("收集nfo")
10 | config_settings.set("收集nfo", "是否跳过已存在nfo的文件夹?", "否")
11 | config_settings.set("收集nfo", "是否收集nfo?", "是")
12 | config_settings.set("收集nfo", "nfo中title的格式", "车牌+空格+标题")
13 | config_settings.set("收集nfo", "是否去除标题末尾的演员姓名?", "否")
14 | config_settings.set("收集nfo", "额外将以下元素添加到特征中", "系列、片商")
15 | config_settings.set("收集nfo", "是否将特征保存到genre?", "是")
16 | config_settings.set("收集nfo", "是否将特征保存到tag?", "是")
17 | config_settings.add_section("重命名影片")
18 | config_settings.set("重命名影片", "是否重命名影片?", "是")
19 | config_settings.set("重命名影片", "重命名影片的格式", "车牌+空格+标题")
20 | config_settings.add_section("修改文件夹")
21 | config_settings.set("修改文件夹", "是否重命名或创建独立文件夹?", "是")
22 | config_settings.set("修改文件夹", "新文件夹的格式", "【+全部演员+】+车牌")
23 | config_settings.add_section("归类影片")
24 | config_settings.set("归类影片", "是否归类影片?", "否")
25 | config_settings.set("归类影片", "针对文件还是文件夹?", "文件夹")
26 | config_settings.set("归类影片", "归类的根目录", "所选文件夹")
27 | config_settings.set("归类影片", "归类的标准", "影片类型\全部演员")
28 | config_settings.add_section("下载封面")
29 | config_settings.set("下载封面", "是否下载封面海报?", "是")
30 | config_settings.set("下载封面", "DVD封面的格式", "视频+-fanart.jpg")
31 | config_settings.set("下载封面", "海报的格式", "视频+-poster.jpg")
32 | config_settings.set("下载封面", "是否为海报加上中文字幕条幅?", "否")
33 | config_settings.set("下载封面", "是否为海报加上无码流出条幅?", "否")
34 | config_settings.add_section("字幕文件")
35 | config_settings.set("字幕文件", "是否重命名已有的字幕文件?", "是")
36 | config_settings.set("字幕文件", "是否跳过已有字幕的影片?", "是")
37 | config_settings.add_section("kodi专用")
38 | config_settings.set("kodi专用", "是否收集演员头像?", "否")
39 | config_settings.set("kodi专用", "是否对多cd只收集一份图片和nfo?", "否")
40 | config_settings.add_section("emby/jellyfin")
41 | config_settings.set("emby/jellyfin", "网址", "http://localhost:8096/")
42 | config_settings.set("emby/jellyfin", "API ID", "b55d950becc74bbebbf4698d995db826")
43 | config_settings.set("emby/jellyfin", "是否覆盖以前上传的头像?", "否")
44 | config_settings.add_section("局部代理")
45 | config_settings.set("局部代理", "是否使用局部代理?", "否")
46 | config_settings.set("局部代理", "http还是socks5?", "http")
47 | config_settings.set("局部代理", "代理端口", "127.0.0.1:10809")
48 | config_settings.set("局部代理", "是否代理javlibrary(有问题)?", "否")
49 | config_settings.set("局部代理", "是否代理javbus?", "否")
50 | config_settings.set("局部代理", "是否代理jav321?", "否")
51 | config_settings.set("局部代理", "是否代理javdb?", "否")
52 | config_settings.set("局部代理", "是否代理arzon?", "否")
53 | config_settings.set("局部代理", "是否代理dmm图片?", "否")
54 | # config_settings.set("其他设置", "是否将全部演员(多个)表现为“n人共演?", "否")
55 | config_settings.add_section("原影片文件的性质")
56 | config_settings.set("原影片文件的性质", "有码素人无视多余的字母数字", "xhd1080、mm616、fhd-1080")
57 | config_settings.set("原影片文件的性质", "无码无视多余的字母数字", "1080p、caribbean、carib、1pondo、1pon、fhd、all、tokyo-hot、tokyohot、3xplanet、full")
58 | config_settings.set("原影片文件的性质", "是否中字即文件名包含", "-C、_C、中字、中文字幕、字幕")
59 | config_settings.set("原影片文件的性质", "是否中字的表现形式", "㊥")
60 | config_settings.set("原影片文件的性质", "是否流出即文件名包含", "流出")
61 | config_settings.set("原影片文件的性质", "是否流出的表现形式", "无码流出")
62 | config_settings.set("原影片文件的性质", "有码", "有码")
63 | config_settings.set("原影片文件的性质", "无码", "无码")
64 | config_settings.set("原影片文件的性质", "素人", "素人")
65 | config_settings.set("原影片文件的性质", "FC2", "FC2")
66 | config_settings.add_section("信息来源")
67 | config_settings.set("信息来源", "是否用javlibrary整理影片时收集网友的热评?", "是")
68 | config_settings.set("信息来源", "是否用javlibrary整理影片时优先从javbus下载图片?", "否")
69 | config_settings.add_section("其他设置")
70 | config_settings.set("其他设置", "简繁中文?", "简")
71 | config_settings.set("其他设置", "javlibrary网址", "http://www.f50q.com/")
72 | config_settings.set("其他设置", "javbus网址", "https://www.buscdn.me")
73 | config_settings.set("其他设置", "javdb网址", "https://javdb6.com/")
74 | config_settings.set("其他设置", "扫描文件类型", "mp4、mkv、avi、wmv、iso、rmvb、flv、ts")
75 | config_settings.set("其他设置", "重命名中的标题长度(50~150)", "50")
76 | config_settings.add_section("百度翻译API")
77 | config_settings.set("百度翻译API", "是否需要日语简介?", "是")
78 | config_settings.set("百度翻译API", "是否翻译为中文?", "否")
79 | config_settings.set("百度翻译API", "app id", "")
80 | config_settings.set("百度翻译API", "密钥", "")
81 | config_settings.add_section("百度人体分析")
82 | config_settings.set("百度人体分析", "是否需要准确定位人脸的poster?", "否")
83 | config_settings.set("百度人体分析", "appid", "")
84 | config_settings.set("百度人体分析", "api key", "")
85 | config_settings.set("百度人体分析", "secret key", "")
86 | config_settings.write(open('【点我设置整理规则】.ini', "w", encoding='utf-8-sig'))
87 | print(' >“【点我设置整理规则】.ini”重写成功!')
88 | ####################################################################################################################
89 | config_actor = RawConfigParser()
90 | config_actor.add_section("缺失的演员头像")
91 | config_actor.set("缺失的演员头像", "演员姓名", "N(次数)")
92 | config_actor.add_section("说明")
93 | config_actor.set("说明", "上面的“演员姓名 = N(次数)”的表达式", "后面的N数字表示你有N部(次)影片都在找她的头像,可惜找不到")
94 | config_actor.set("说明", "你可以去保存一下她的头像jpg到“演员头像”文件夹", "以后就能保存她的头像到影片的文件夹了")
95 | config_actor.write(open('actors_for_kodi.ini', "w", encoding='utf-8-sig'))
96 | print(' >“actors_for_kodi.ini”重写成功!')
97 | system('pause')
98 | except:
99 | print(format_exc())
100 | print('\n创建ini失败,解决上述问题后,重新打开exe创建ini!')
101 | system('pause')
102 |
--------------------------------------------------------------------------------
/javsdt/Functions/Baidu.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import requests
3 | from os import system
4 | from time import sleep, time
5 | from hashlib import md5
6 | from json import loads
7 | # from traceback import format_exc
8 |
9 |
10 | # 功能:调用百度翻译API接口,翻译日语简介
11 | # 参数:百度翻译api账户api_id, api_key,需要翻译的内容word,目标语言to_lang
12 | # 返回:中文简介string
13 | # 辅助:os.system, hashlib.md5,time.time,requests.get,json.loads
14 | def translate(api_id, api_key, word, to_lang):
15 | for retry in range(10):
16 | # 把账户、翻译的内容、时间 混合md5加密,传给百度验证
17 | salt = str(time())[:10]
18 | final_sign = api_id + word + salt + api_key
19 | final_sign = md5(final_sign.encode("utf-8")).hexdigest()
20 | # 表单paramas
21 | paramas = {
22 | 'q': word,
23 | 'from': 'jp',
24 | 'to': to_lang,
25 | 'appid': '%s' % api_id,
26 | 'salt': '%s' % salt,
27 | 'sign': '%s' % final_sign
28 | }
29 | try:
30 | response = requests.get('http://api.fanyi.baidu.com/api/trans/vip/translate', params=paramas, timeout=(6, 7))
31 | except:
32 | print(' >百度翻译拉闸了...重新翻译...')
33 | continue
34 | content = str(response.content, encoding="utf-8")
35 | # 百度返回为空
36 | if not content:
37 | print(' >百度翻译返回为空...重新翻译...')
38 | sleep(1)
39 | continue
40 | # 百度返回了dict json
41 | json_reads = loads(content)
42 | # print(json_reads)
43 | if 'error_code' in json_reads: # 返回错误码
44 | error_code = json_reads['error_code']
45 | if error_code == '54003':
46 | print(' >请求百度翻译太快...技能冷却1秒...')
47 | sleep(1)
48 | elif error_code == '54005':
49 | print(' >发送了太多超长的简介给百度翻译...技能冷却3秒...')
50 | sleep(3)
51 | elif error_code == '52001':
52 | print(' >连接百度翻译超时...重新翻译...')
53 | elif error_code == '52002':
54 | print(' >百度翻译拉闸了...重新翻译...')
55 | elif error_code == '54003':
56 | print(' >使用过于频繁,百度翻译不想给你用了...')
57 | system('pause')
58 | elif error_code == '52003':
59 | print(' >请正确输入百度翻译API账号,请阅读【使用说明】!')
60 | print('>>javsdt已停止工作...')
61 | system('pause')
62 | elif error_code == '58003':
63 | print(' >你的百度翻译API账户被百度封禁了,请联系作者,告诉你解封办法!“')
64 | print('>>javsdt已停止工作...')
65 | system('pause')
66 | elif error_code == '90107':
67 | print(' >你的百度翻译API账户还未通过认证或者失效,请前往API控制台解决问题!“')
68 | print('>>javsdt已停止工作...')
69 | system('pause')
70 | else:
71 | print(' >百度翻译error_code!请截图联系作者!', error_code)
72 | continue
73 | else: # 返回正确信息
74 | return json_reads['trans_result'][0]['dst']
75 | print(' >翻译简介失败...请截图联系作者...')
76 | return '【百度翻译出错】' + word
77 |
78 |
79 |
--------------------------------------------------------------------------------
/javsdt/Functions/Car.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import re
3 | from os import system
4 |
5 |
6 | # 功能:发现用于javlibrary的有码车牌,因为T28-、ID比较特殊在
7 | # 参数:大写后的视频文件名file,素人车牌list_suren_car 示例:AVOP-127.MP4 ['LUXU', 'MIUM']
8 | # 返回:发现的车牌 示例:AVOP-127
9 | # 辅助:re.search
10 | def find_car_library(file, list_suren_car):
11 | # car_pref 车牌前缀 ABP-,带横杠;car_suf,车牌后缀 123。
12 | # 先处理特例 T28 车牌
13 | if re.search(r'[^A-Z]?T28[-_ ]*\d\d+', file):
14 | car_pref = 'T-28'
15 | car_suf = re.search(r'T28[-_ ]*(\d\d+)', file).group(1)
16 | # 特例 ID 车牌,在javlibrary上,20ID-020是ID-20020
17 | elif re.search(r'[^\d]?\d\dID[-_ ]*\d\d+', file):
18 | carg = re.search(r'[^\d]?(\d\d)ID[-_ ]*(\d\d+)', file)
19 | car_pref = 'ID-' + carg.group(1)
20 | car_suf = carg.group(2)
21 | # 一般车牌
22 | elif re.search(r'[A-Z][A-Z]+[-_ ]*\d\d+', file):
23 | carg = re.search(r'([A-Z][A-Z]+)[-_ ]*(\d\d+)', file)
24 | car_pref = carg.group(1)
25 | # 如果是素人或无码车牌,不处理
26 | if car_pref in list_suren_car or car_pref in ['HEYZO', 'PONDO', 'CARIB', 'OKYOHOT']:
27 | return ''
28 | car_pref = car_pref + '-'
29 | car_suf = carg.group(2)
30 | else:
31 | return ''
32 | # 去掉太多的0,AVOP00127 => AVOP-127
33 | if len(car_suf) > 3:
34 | car_suf = car_suf[:-3].lstrip('0') + car_suf[-3:]
35 | return car_pref + car_suf
36 |
37 |
38 | # 功能:发现原视频文件名中用于javbus的有码车牌
39 | # 参数:大写后的视频文件名,素人车牌list_suren_car 示例:AVOP-127.MP4 ['LUXU', 'MIUM']
40 | # 返回:发现的车牌 示例:AVOP-127
41 | # 辅助:re.search
42 | def find_car_bus(file, list_suren_car):
43 | # car_pref 车牌前缀 ABP-,带横杠;car_suf,车牌后缀 123。
44 | # 先处理特例 T28 车牌
45 | if re.search(r'[^A-Z]?T28[-_ ]*\d\d+', file):
46 | car_pref = 'T28-'
47 | car_suf = re.search(r'T28[-_ ]*(\d\d+)', file).group(1)
48 | # 以javbus上记录的20ID-020为标准
49 | elif re.search(r'[^\d]?\d\dID[-_ ]*\d\d+', file):
50 | carg = re.search(r'(\d\d)ID[-_ ]*(\d\d+)', file)
51 | car_pref = carg.group(1) + 'ID-'
52 | car_suf = carg.group(2)
53 | # 一般车牌
54 | elif re.search(r'[A-Z]+[-_ ]*\d\d+', file):
55 | carg = re.search(r'([A-Z]+)[-_ ]*(\d\d+)', file)
56 | car_pref = carg.group(1)
57 | if car_pref in list_suren_car or car_pref in ['HEYZO', 'PONDO', 'CARIB', 'OKYOHOT']:
58 | return ''
59 | car_pref = car_pref + '-'
60 | car_suf = carg.group(2)
61 | else:
62 | return ''
63 | # 去掉太多的0,avop00127 => avop-127
64 | if len(car_suf) > 3:
65 | car_suf = car_suf[:-3].lstrip('0') + car_suf[-3:]
66 | return car_pref + car_suf
67 |
68 |
69 | # 功能:发现原视频文件名中的无码车牌
70 | # 参数:被大写后的视频文件名,素人车牌list_suren_car 示例:ABC123ABC123.MP4 ['LUXU', 'MIUM']
71 | # 返回:发现的车牌 示例:ABC123ABC123,只要是字母数字,全拿着
72 | # 辅助:re.search
73 | def find_car_wuma(file, list_suren_car):
74 | # N12345
75 | if re.search(r'[^A-Z]?N\d\d+', file):
76 | car_pref = 'N'
77 | car_suf = re.search(r'N(\d\d+)', file).group(1)
78 | # 123-12345
79 | elif re.search(r'\d+[-_ ]\d\d+', file):
80 | carg = re.search(r'(\d+)[-_ ](\d\d+)', file)
81 | car_pref = carg.group(1) + '-'
82 | car_suf = carg.group(2)
83 | # 只要是字母数字-_,全拿着
84 | elif re.search(r'[A-Z0-9]+[-_ ]?[A-Z0-9]+', file):
85 | carg = re.search(r'([A-Z0-9]+)([-_ ]*)([A-Z0-9]+)', file)
86 | car_pref = carg.group(1)
87 | # print(car_pref)
88 | if car_pref in list_suren_car:
89 | return ''
90 | car_pref = car_pref + carg.group(2)
91 | car_suf = carg.group(3)
92 | # 下面是处理和一般有码车牌差不多的无码车牌,拿到的往往是错误的,仅在1.0.4版本使用过,宁可不整理也不识别个错的
93 | # elif search(r'[A-Z]+[-_ ]?\d+', file):
94 | # carg = search(r'([A-Z]+)([-_ ]?)(\d+)', file)
95 | # car_pref = carg.group(1)
96 | # if car_pref in list_suren_car:
97 | # return ''
98 | # car_pref = car_pref + carg.group(2)
99 | # car_suf = carg.group(3)
100 | else:
101 | return ''
102 | # 无码就不去0了,去了0和不去0,可能是不同结果
103 | # if len(car_suf) > 3:
104 | # car_suf = car_suf[:-3].lstrip('0') + car_suf[-3:]
105 | return car_pref + car_suf
106 |
107 |
108 | # 功能:发现素人车牌,直接从已记录的list_suren_car中来对比
109 | # 参数:大写后的视频文件名,素人车牌list_suren_car 示例:LUXU-123.MP4 ['LUXU', 'MIUM']
110 | # 返回:发现的车牌 示例:LUXU-123
111 | # 辅助:re.search
112 | def find_car_suren(file, list_suren_car):
113 | carg = re.search(r'([A-Z][A-Z]+)[-_ ]*(\d\d+)', file) # 匹配字幕车牌
114 | if str(carg) != 'None':
115 | car_pref = carg.group(1)
116 | # 如果用户把视频文件名指定为jav321上的网址,让该视频通过
117 | if car_pref not in list_suren_car and '三二一' not in file:
118 | return ''
119 | car_suf = carg.group(2)
120 | # 去掉太多的0,avop00127
121 | if len(car_suf) > 3:
122 | car_suf = car_suf[:-3].lstrip('0') + car_suf[-3:]
123 | return car_pref + '-' + car_suf
124 | else:
125 | return ''
126 |
127 |
128 | # 功能:得到素人车牌集合
129 | # 参数:无
130 | # 返回:素人车牌list
131 | # 辅助:无
132 | def list_suren_car():
133 | try:
134 | with open('【素人车牌】.txt', 'r', encoding="utf-8") as f:
135 | list_suren_cars = list(f)
136 | except:
137 | print('【素人车牌】.txt读取失败!停止工作!')
138 | system('pause')
139 | list_suren_cars = [i.strip().upper() for i in list_suren_cars if i != '\n']
140 | # print(list_suren_cars)
141 | return list_suren_cars
142 |
--------------------------------------------------------------------------------
/javsdt/Functions/Genre.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import xlrd
3 |
4 |
5 | # 功能:得到优化的特征字典
6 | # 参数:用户在用哪个exe(对应sheet_name) ,简繁中文to_language 示例:Javbus有码 ,zh
7 | # 返回:优化的特征字典
8 | # 辅助:xlrd
9 | def better_dict_genre(sheet_name, to_language):
10 | dict = {}
11 | # 打开Excel文件
12 | excel = xlrd.open_workbook('【特征对照表】.xlsx',)
13 | # 定位excel中的某一sheet
14 | sheet = excel.sheet_by_name(sheet_name)
15 | row = sheet.nrows # 总行数
16 | for i in range(1, row):
17 | list_row = sheet.row_values(i) # i行的list
18 | if to_language == 'zh':
19 | dict[list_row[0]] = list_row[1]
20 | elif to_language == 'cht':
21 | dict[list_row[0]] = list_row[2]
22 | else:
23 | dict[list_row[0]] = list_row[1]
24 | # print(dict)
25 | return dict
26 |
27 |
28 | # print(better_dict_genre('Javlibrary', 'cht'))
29 |
--------------------------------------------------------------------------------
/javsdt/Functions/Picture.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import system
3 | from PIL import Image
4 |
5 |
6 | # 功能:查看图片是否存在,能否打开,有没有损坏
7 | # 参数:图片路径path_picture
8 | # 返回:True
9 | # 辅助:Image.open
10 | def check_picture(path_picture):
11 | try:
12 | img = Image.open(path_picture)
13 | img.load()
14 | return True
15 | except (FileNotFoundError, OSError):
16 | # print('文件损坏')
17 | return False
18 |
19 |
20 | # 功能:调用百度AL人体分析,分析图片中的人体
21 | # 参数:图片路径,百度人体分析client
22 | # 返回:鼻子的x坐标
23 | # 辅助:os.system, cli.bodyAnalysis
24 | def image_cut(path, client):
25 | # if bool_face: # 启动人体分析的这两行代码在settings.py中
26 | # client = AipBodyAnalysis(al_id, ai_ak, al_sk)
27 | for retry in range(10):
28 | with open(path, 'rb') as fp:
29 | image = fp.read()
30 | try:
31 | result = client.bodyAnalysis(image)
32 | return int(result["person_info"][0]['body_parts']['nose']['x'])
33 | except:
34 | print(' >人体分析出现错误,请对照“人体分析错误表格”:', result)
35 | print(' >正在尝试重新人体检测...')
36 | continue
37 | print(' >人体分析无法使用...请先解决人体分析的问题,或截图联系作者...')
38 | system('pause')
39 |
40 |
41 | # 功能:裁剪有码的fanart封面作为poster,一般fanart是800*538,把右边的379*538裁剪下来
42 | # 参数:已下载的fanart路径,目标poster路径
43 | # 返回:无
44 | # 辅助:Image.open
45 | def crop_poster_youma(path_fanart, path_poster):
46 | img = Image.open(path_fanart)
47 | wf, hf = img.size # fanart的宽 高
48 | wide = int(hf / 1.42) # 理想中海报的宽(应该是379),应该是fanart的高/1.42,1.42来源于(538/379)
49 | # 如果fanart不是正常的800*576的横向图,而是非常“瘦”的图
50 | if wf < wide:
51 | poster = img.crop((0, 0, wf, int(wf * 1.42)))
52 | poster.save(path_poster, quality=95) # quality=95 是无损crop,如果不设置,默认75
53 | print(' >poster.jpg裁剪成功')
54 | else:
55 | x_left = wf - wide
56 | poster = img.crop((x_left, 0, wf, hf)) # poster在fanart的 左上角(x_left, 0),右下角(x_left + wide, hf)
57 | poster.save(path_poster, quality=95) # 坐标轴的Y轴是反的
58 | print(' >poster.jpg裁剪成功')
59 |
60 |
61 | # 功能:不使用人体分析,裁剪fanart封面作为poster,裁剪中间,或者裁剪右边
62 | # 参数:已下载的fanart路径,目标poster路径, 选择模式int_pattern(无码是裁剪fanart右边,FC2和素人是裁剪fanart中间)
63 | # 返回:无
64 | # 辅助:Image.open
65 | def crop_poster_default(path_fanart, path_poster, int_pattern):
66 | img = Image.open(path_fanart)
67 | wf, hf = img.size # fanart的宽 高
68 | wide = int(hf * 2 / 3) # 理想中海报的宽,应该是fanart的高的三分之二
69 | # 如果fanart特别“瘦”(宽不到高的三分之二),则以fanart现在的宽作为poster的宽,未来的高为宽的二分之三。
70 | if wf < wide:
71 | poster = img.crop((0, 0, wf, wf * 1.5))
72 | poster.save(path_poster, quality=95) # quality=95 是无损crop,如果不设置,默认75
73 | print(' >poster.jpg裁剪成功')
74 | else:
75 | x_left = (wf - wide) / int_pattern # / 2,poster裁剪fanart中间;/ 1,poster裁剪fanart右边。
76 | # crop
77 | try:
78 | poster = img.crop((x_left, 0, x_left + wide, hf)) # poster在fanart的 左上角(x_left, 0),右下角(x_left + wide, hf)
79 | except:
80 | raise
81 | poster.save(path_poster, quality=95)
82 | print(' >poster.jpg裁剪成功')
83 |
84 |
85 | # 功能:使用人体分析,裁剪fanart封面作为poster,围绕鼻子坐标进行裁剪
86 | # 参数:已下载的fanart路径,目标poster路径, 百度人体分析client
87 | # 返回:无
88 | # 辅助:Image.open, image_cut()
89 | def crop_poster_baidu(path_fanart, path_poster, client):
90 | img = Image.open(path_fanart)
91 | wf, hf = img.size # fanart的宽 高
92 | wide = int(hf * 2 / 3) # 理想中海报的宽,应该是fanart的高的三分之二
93 | # 如果fanart特别“瘦”,宽不到高的三分之二。以fanart的宽作为poster的宽。
94 | if wf < wide:
95 | poster = img.crop((0, 0, wf, wf * 1.5))
96 | poster.save(path_poster, quality=95) # quality=95 是无损crop,如果不设置,默认75
97 | print(' >poster.jpg裁剪成功')
98 | else:
99 | wide_half = wide / 2
100 | # 使用人体分析,得到鼻子x坐标
101 | x_nose = image_cut(path_fanart, client) # 鼻子的x坐标
102 | # 围绕鼻子进行裁剪,先来判断一下鼻子是不是太靠左或者太靠右
103 | if x_nose + wide_half > wf: # 鼻子 + 一半poster宽超出fanart右边
104 | x_left = wf - wide # 以右边为poster
105 | elif x_nose - wide_half < 0: # 鼻子 - 一半poster宽超出fanart左边
106 | x_left = 0 # 以左边为poster
107 | else: # 不会超出poster
108 | x_left = x_nose - wide_half # 以鼻子为中心向两边扩展
109 | # crop
110 | poster = img.crop((x_left, 0, x_left + wide, hf)) # poster在fanart的 左上角(x_left, 0),右下角(x_left + wide, hf),
111 | poster.save(path_poster, quality=95) # 坐标轴的Y轴是反的
112 | print(' >poster.jpg裁剪成功')
113 |
114 |
115 | # 功能:给poster的左上方加上“中文字幕”的红色条幅
116 | # 参数:poster路径
117 | # 返回:无
118 | # 辅助:Image.open
119 | def add_watermark_subtitle(path_poster):
120 | # 打开poster,“中文字幕”条幅的宽高是poster的宽的四分之一
121 | img_poster = Image.open(path_poster)
122 | scroll_wide = int(img_poster.height/4)
123 | # 打开“中文字幕”条幅,缩小到合适poster的尺寸
124 | watermark_subtitle = Image.open('StaticFiles/subtitle.png')
125 | watermark_subtitle = watermark_subtitle.resize((scroll_wide, scroll_wide), Image.ANTIALIAS)
126 | r, g, b, a = watermark_subtitle.split() # 获取颜色通道,保持png的透明性
127 | # 条幅在poster上摆放的位置。左上角(0,0)
128 | img_poster.paste(watermark_subtitle, (0, 0), mask=a)
129 | img_poster.save(path_poster, quality=95)
130 | print(' >poster加上中文字幕条幅')
131 |
132 |
133 | # 功能:给poster的右上方加上“无码流出”的红色条幅
134 | # 参数:poster路径
135 | # 返回:无
136 | # 辅助:Image.open
137 | def add_watermark_divulge(path_poster):
138 | # 打开poster,条幅的宽高是poster的宽的四分之一
139 | img_poster = Image.open(path_poster)
140 | w, h = img_poster.size
141 | scroll_wide = int(h/4)
142 | # 打开条幅,缩小到合适poster的尺寸
143 | watermark_divulge = Image.open('StaticFiles/divulge.png')
144 | watermark_divulge = watermark_divulge.resize((scroll_wide, scroll_wide), Image.ANTIALIAS)
145 | r, g, b, a = watermark_divulge.split() # 获取颜色通道,保持png的透明性
146 | # 条幅在poster上摆放的位置。左上角(x_left,0)
147 | x_left = w - scroll_wide
148 | img_poster.paste(watermark_divulge, (x_left, 0), mask=a)
149 | img_poster.save(path_poster, quality=95)
150 | print(' >poster加上无码流出红幅')
--------------------------------------------------------------------------------
/javsdt/Functions/Process.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import sep
3 | from os.path import exists
4 | from xml.etree.ElementTree import parse, ParseError
5 |
6 |
7 | # 功能:完善用于命名的dict_data,如果用户自定义的各种命名公式中有dict_data未包含的元素,则添加进dict_data。
8 | # 将可能比较复杂的list_classify_basis按“+”“\”切割好,准备用于组装后面的归类路径。
9 | # 参数:用户自定义的各种命名公式list
10 | # 返回:存储命名信息的dict_data, 切割好的归类标准list_classify_basis
11 | # 辅助:os.sep
12 | def perfect_dict_data(list_extra_genres, list_rename_video, list_rename_folder, list_name_nfo_title, list_name_fanart, list_name_poster, custom_classify_basis, dict_data):
13 | for i in list_extra_genres:
14 | if i not in dict_data:
15 | dict_data[i] = i
16 | for i in list_rename_video:
17 | if i not in dict_data:
18 | dict_data[i] = i
19 | for i in list_rename_folder:
20 | if i not in dict_data:
21 | dict_data[i] = i
22 | for i in list_name_nfo_title:
23 | if i not in dict_data:
24 | dict_data[i] = i
25 | for i in list_name_fanart:
26 | if i not in dict_data:
27 | dict_data[i] = i
28 | for i in list_name_poster:
29 | if i not in dict_data:
30 | dict_data[i] = i
31 | list_classify_basis = []
32 | for i in custom_classify_basis.split('\\'):
33 | for j in i.split('+'):
34 | if j not in dict_data:
35 | dict_data[j] = j
36 | list_classify_basis.append(j)
37 | list_classify_basis.append(sep)
38 | return dict_data, list_classify_basis
39 |
40 |
41 | # 功能:根据【原文件名】和《已存在的、之前整理的nfo》,判断当前jav是否有“中文字幕”
42 | # 参数:①当前jav所处文件夹路径root_jav ②jav文件名不带格式后缀name_no_extension,
43 | # ③如果【原文件名】包含list_subtitle_character中的元素即判断有“中文字幕”,
44 | # 返回:True
45 | # 辅助:os.path.exists,xml.etree.ElementTree.parse,xml.etree.ElementTree.ParseError
46 | def judge_exist_subtitle(root_jav, name_no_extension, list_subtitle_character):
47 | # 去除 '-CD' 和 '-CARIB'对 '-C'判断中字的影响
48 | name_no_extension = name_no_extension.upper().replace('-CD', '').replace('-CARIB', '')
49 | # 如果原文件名包含“-c、-C、中字”这些字符
50 | for i in list_subtitle_character:
51 | if i in name_no_extension:
52 | return True
53 | # 先前整理过的nfo中有 ‘中文字幕’这个Genre
54 | path_old_nfo = root_jav + sep + name_no_extension + '.nfo'
55 | if exists(path_old_nfo):
56 | try:
57 | tree = parse(path_old_nfo)
58 | except ParseError: # nfo可能损坏
59 | return False
60 | for child in tree.getroot():
61 | if child.text == '中文字幕':
62 | return True
63 | return False
64 |
65 |
66 | # 功能:根据【原文件名】和《已存在的、之前整理的nfo》,判断当前jav是否有“无码流出”
67 | # 参数:①当前jav所处文件夹路径root_jav ②jav文件名不带格式后缀name_no_extension,
68 | # ③如果【原文件名】包含list_divulge_character中的元素即判断有“中文字幕”,
69 | # 返回:True
70 | # 辅助:os.path.exists,xml.etree.ElementTree.parse,xml.etree.ElementTree.ParseError
71 | def judge_exist_divulge(root_jav, name_no_extension, list_divulge_character):
72 | # 如果原文件名包含“-c、-C、中字”这些字符
73 | for i in list_divulge_character:
74 | if i in name_no_extension:
75 | return True
76 | # 先前整理过的nfo中有 ‘中文字幕’这个Genre
77 | path_old_nfo = root_jav + sep + name_no_extension + '.nfo'
78 | if exists(path_old_nfo):
79 | try:
80 | tree = parse(path_old_nfo)
81 | except ParseError: # nfo可能损坏
82 | return False
83 | for child in tree.getroot():
84 | if child.text == '无码流出':
85 | return True
86 | return False
--------------------------------------------------------------------------------
/javsdt/Functions/Record.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from time import strftime, localtime, time
3 |
4 |
5 | # 功能:记录整理的文件夹、整理的时间
6 | # 参数:错误信息
7 | # 返回:无
8 | # 辅助:os.strftime, os.localtime, os.time,
9 | def record_start(root_choose):
10 | msg = '已选择文件夹:' + root_choose + ' ' + strftime('%Y-%m-%d %H:%M:%S', localtime(time())) + '\n'
11 | txt = open('【可删除】失败记录.txt', 'a', encoding="utf-8")
12 | txt.write(msg)
13 | txt.close()
14 | txt = open('【可删除】警告信息.txt', 'a', encoding="utf-8")
15 | txt.write(msg)
16 | txt.close()
17 | txt = open('【可删除】新旧文件名清单.txt', 'a', encoding="utf-8")
18 | txt.write(msg)
19 | txt.close()
20 |
21 |
22 | # 功能:记录错误信息
23 | # 参数:错误信息
24 | # 返回:无
25 | # 辅助:无
26 | def record_fail(fail_msg):
27 | print(fail_msg, end='')
28 | txt = open('【可删除】失败记录.txt', 'a', encoding="utf-8")
29 | txt.write(fail_msg)
30 | txt.close()
31 |
32 |
33 | # 功能:记录警告信息
34 | # 参数:警告信息
35 | # 返回:无
36 | # 辅助:无
37 | def record_warn(warn_msg):
38 | txt = open('【可删除】警告信息.txt', 'a', encoding="utf-8")
39 | txt.write(warn_msg)
40 | txt.close()
41 |
42 |
43 | # 功能:记录旧文件名
44 | # 参数:新文件名,旧文件名
45 | # 返回:无
46 | # 辅助:无
47 | def record_video_old(name_new, name_old):
48 | txt = open('【可删除】新旧文件名清单.txt', 'a', encoding="utf-8")
49 | txt.write('<<<< ' + name_old + '\n')
50 | txt.write('>>>> ' + name_new + '\n')
51 | txt.close()
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/ArzonReq.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import requests, re
3 | from os import system
4 | # from traceback import format_exc
5 |
6 |
7 | # 功能:获取一个arzon_cookie
8 | # 参数:代理proxy
9 | # 返回:cookies
10 | def steal_arzon_cookies(proxy):
11 | print('\n正在尝试通过 https://www.arzon.jp 的成人验证...')
12 | for retry in range(10):
13 | try: # 当初费尽心机,想办法如何通过页面上的成人验证,结果在一个C#开发的jav爬虫项目,看到它请求以下网址,再跳转到arzon主页,所得到的的cookie即是合法的cookie
14 | if proxy:
15 | session = requests.Session()
16 | session.get('https://www.arzon.jp/index.php?action=adult_customer_agecheck&agecheck=1&redirect=https%3A%2F%2Fwww.arzon.jp%2F', proxies=proxy, timeout=(12, 7))
17 | print('通过arzon的成人验证!\n')
18 | return session.cookies.get_dict()
19 | else:
20 | session = requests.Session()
21 | session.get('https://www.arzon.jp/index.php?action=adult_customer_agecheck&agecheck=1&redirect=https%3A%2F%2Fwww.arzon.jp%2F', timeout=(12, 7))
22 | print('通过arzon的成人验证!\n')
23 | return session.cookies.get_dict()
24 | except requests.exceptions.ProxyError:
25 | # print(format_exc())
26 | print(' >通过局部代理失败,重新尝试...')
27 | continue
28 | except:
29 | # print(format_exc())
30 | print('通过失败,重新尝试...')
31 | continue
32 | print('>>请检查你的网络环境是否可以打开:https://www.arzon.jp/')
33 | system('pause')
34 |
35 |
36 | # 功能:搜索arzon,或请求arzon上jav所在网页
37 | # 参数:网址url,请求头部header/cookies,代理proxy
38 | # 返回:网页html
39 | def get_arzon_html(url, cookies, proxy):
40 | # print('代理:', proxy)
41 | for retry in range(10):
42 | try:
43 | if proxy:
44 | rqs = requests.get(url, cookies=cookies, proxies=proxy, timeout=(12, 7))
45 | else:
46 | rqs = requests.get(url, cookies=cookies, timeout=(12, 7))
47 | except requests.exceptions.ProxyError:
48 | # print(format_exc())
49 | print(' >通过局部代理失败,重新尝试...')
50 | continue
51 | except:
52 | print(' >打开网页失败,重新尝试...')
53 | continue
54 | rqs.encoding = 'utf-8'
55 | rqs_content = rqs.text
56 | if re.search(r'arzon', rqs_content):
57 | return rqs_content
58 | else:
59 | print(' >打开网页失败,空返回...重新尝试...')
60 | continue
61 | print('>>请检查你的网络环境是否可以打开:', url)
62 | system('pause')
63 |
64 |
65 | # 功能:从arzon上查找简介
66 | # 参数:车牌car,cookies,proxy
67 | # 返回:简介,执行完成状态码,cookies
68 | def find_plot_arzon(car, cookies, proxy):
69 | for retry in range(2):
70 | url_search_arzon = 'https://www.arzon.jp/itemlist.html?t=&m=all&s=&q=' + car.replace('-', '')
71 | print(' >查找简介:', url_search_arzon)
72 | # 得到arzon的搜索结果页面
73 | html_search_arzon = get_arzon_html(url_search_arzon, cookies, proxy)
74 | #
获取简介:', url_on_arzon)
81 | # 打开arzon上每一个搜索结果的页面
82 | html_arzon = get_arzon_html(url_on_arzon, cookies, proxy)
83 | # 在该url_on_arzon网页上查找简介
84 | plotg = re.search(r'h2>作品紹介([\s\S]*?)', html_arzon)
85 | # 成功找到plot
86 | if str(plotg) != 'None':
87 | plot_br = plotg.group(1)
88 | plot = ''
89 | for line in plot_br.split('
'):
90 | line = line.strip()
91 | plot += line
92 | return plot, 0, cookies
93 | # 几个搜索结果查找完了,也没有找到简介
94 | return '【arzon有该影片,但找不到简介】', 1, cookies
95 | # 没有搜索结果
96 | else:
97 | # arzon返回的页面实际是18岁验证
98 | adultg = re.search(r'18歳未満', html_search_arzon)
99 | if str(adultg) != 'None':
100 | cookies = steal_arzon_cookies(proxy)
101 | continue
102 | # 不是成人验证,也没有简介
103 | else:
104 | return '【影片下架,暂无简介】', 2, cookies
105 | print('>>请检查你的网络环境是否可以通过成人验证:https://www.arzon.jp/')
106 | system('pause')
107 | return '', 3, cookies
108 |
109 |
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/Download.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import requests
3 | from PIL import Image
4 |
5 |
6 | # 下载图片,无返回
7 | # 参数:图片地址,存放路径,代理
8 | def download_pic(url, path, proxy):
9 | for retry in range(5):
10 | try:
11 | if proxy:
12 | r = requests.get(url, proxies=proxy, stream=True, timeout=(6, 10))
13 | with open(path, 'wb') as pic:
14 | for chunk in r:
15 | pic.write(chunk)
16 | else:
17 | r = requests.get(url, stream=True, timeout=(6, 10))
18 | with open(path, 'wb') as pic:
19 | for chunk in r:
20 | pic.write(chunk)
21 | except requests.exceptions.ProxyError:
22 | # print(format_exc())
23 | print(' >通过局部代理失败,重新尝试...')
24 | continue
25 | except:
26 | # print(format_exc())
27 | print(' >下载失败,重新下载...')
28 | continue
29 | # 如果下载的图片打不开,则重新下载
30 | try:
31 | img = Image.open(path)
32 | img.load()
33 | return
34 | except OSError:
35 | print(' >下载失败,重新下载....')
36 | continue
37 | raise Exception(' >下载多次,仍然失败!')
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/Jav321Req.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import re, requests
3 | from os import system
4 | # from traceback import format_exc
5 |
6 |
7 | # 用户指定jav321的网址后,请求jav所在网页,返回html
8 | def get_321_html(url, proxy):
9 | for retry in range(10):
10 | try:
11 | if proxy:
12 | rqs = requests.get(url, proxies=proxy, timeout=(6, 7))
13 | else:
14 | rqs = requests.get(url, timeout=(6, 7))
15 | except requests.exceptions.ProxyError:
16 | # print(format_exc())
17 | print(' >通过局部代理失败...')
18 | continue
19 | except:
20 | print(' >打开网页失败,重新尝试...')
21 | continue
22 | rqs.encoding = 'utf-8'
23 | rqs_content = rqs.text
24 | if re.search(r'JAV321', rqs_content):
25 | return rqs_content
26 | else:
27 | print(' >打开网页失败,空返回...重新尝试...')
28 | continue
29 | print('>>请检查你的网络环境是否可以打开:', url)
30 | system('pause')
31 |
32 |
33 | # 向jav321 post车牌,得到jav所在网页,也可能是无结果的网页,返回html
34 | def post_321_html(url, data, proxy):
35 | for retry in range(10):
36 | try:
37 | if proxy:
38 | rqs = requests.post(url, data=data, proxies=proxy, timeout=(6, 7))
39 | else:
40 | rqs = requests.post(url, data=data, timeout=(6, 7))
41 | except requests.exceptions.ProxyError:
42 | # print(format_exc())
43 | print(' >通过局部代理失败,重新尝试...')
44 | continue
45 | except:
46 | # print(format_exc())
47 | print(' >打开网页失败,重新尝试...')
48 | continue
49 | rqs.encoding = 'utf-8'
50 | rqs_content = rqs.text
51 | if re.search(r'JAV321', rqs_content):
52 | return rqs_content
53 | else:
54 | print(' >打开网页失败,空返回...重新尝试...')
55 | continue
56 | print('>>请检查你的网络环境是否可以打开:', url)
57 | system('pause')
58 |
59 |
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/JavbusReq.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import re, os, requests
3 | # from traceback import format_exc
4 |
5 | # 功能:请求各大jav网站和arzon的网页
6 | # 参数:网址url,请求头部header/cookies,代理proxy
7 | # 返回:网页html,请求头部
8 |
9 |
10 | # 搜索javbus,或请求javbus上jav所在网页,返回html
11 | def get_bus_html(url, proxy):
12 | for retry in range(10):
13 | try:
14 | if proxy: # existmag=all为了 获得所有影片,而不是默认的有磁力的链接
15 | rqs = requests.get(url, proxies=proxy, timeout=(6, 7), headers={'Cookie': 'existmag=all'})
16 | else:
17 | rqs = requests.get(url, timeout=(6, 7), headers={'Cookie': 'existmag=all'})
18 | except requests.exceptions.ProxyError:
19 | # print(format_exc())
20 | print(' >通过局部代理失败,重新尝试...')
21 | continue
22 | except:
23 | # print(format_exc())
24 | print(' >打开网页失败,重新尝试...')
25 | continue
26 | rqs.encoding = 'utf-8'
27 | rqs_content = rqs.text
28 | if re.search(r'JavBus', rqs_content):
29 | return rqs_content
30 | else:
31 | print(' >打开网页失败,空返回...重新尝试...')
32 | continue
33 | print('>>请检查你的网络环境是否可以打开:', url)
34 | os.system('pause')
35 |
36 |
37 | # 去javbus搜寻系列、在javbus的封面链接
38 | # 返回:系列名称,图片链接,状态码
39 | def find_series_cover_bus(car, url_bus, proxy):
40 | # 需要这两个东西
41 | series = url_cover_bus = ''
42 | # 状态码,标记是否在javbus上搜索到多个结果(如果有多个结果,javlibrary整理时还是从javlibrary上下载封面)
43 | status = 0 # 0表示javbus是唯一的搜索结果
44 | # jav在javbus上的url,一般就是javbus网址+车牌
45 | url_on_bus = url_bus + car
46 | print(' >获取系列:', url_on_bus)
47 | # 获得影片在javbus上的网页
48 | html_bus = get_bus_html(url_on_bus, proxy)
49 | if not re.search(r'404 Page', html_bus):
50 | # DVD封面cover
51 | coverg = re.search(r'bigImage" href="(.+?)">', html_bus)
52 | if str(coverg) != 'None':
53 | url_cover_bus = coverg.group(1)
54 | # 系列: 悪質シロウトナンパ
55 | seriesg = re.search(r'系列: (.+?)', html_bus)
56 | if str(seriesg) != 'None':
57 | series = seriesg.group(1)
58 | # 这部jav在javbus的网址不简单
59 | else:
60 | # 还是老老实实去搜索
61 | url_search_bus = url_bus + 'search/' + car.replace('-', '') + '&type=1&parent=ce'
62 | print(' >搜索javbus:', url_search_bus)
63 | html_bus = get_bus_html(url_search_bus, proxy)
64 | # 搜索结果的网页,大部分情况一个结果,也有可能是多个结果的网页
65 | # 尝试找movie-box
66 | list_search_results = re.findall(r'movie-box" href="(.+?)">', html_bus) # 匹配处理“标题”
67 | if list_search_results:
68 | jav_pref = car.split('-')[0] # 匹配车牌的前缀字母
69 | jav_suf = car.split('-')[-1].lstrip('0') # 当前车牌的后缀数字 去除多余的0
70 | list_fit_results = [] # 存放,车牌符合的结果
71 | for i in list_search_results:
72 | url_end = i.split('/')[-1].upper()
73 | url_suf = re.search(r'[-_](\d+)', url_end).group(1).lstrip('0') # 匹配box上影片url,车牌的后缀数字,去除多余的0
74 | if jav_suf == url_suf: # 数字相同
75 | url_pref = re.search(r'([A-Z]+2?8?)', url_end).group(1).upper() # 匹配处理url所带车牌前面的字母“n”
76 | if jav_pref == url_pref: # 数字相同的基础下,字母也相同,即可能车牌相同
77 | list_fit_results.append(i)
78 | # 有结果
79 | if list_fit_results:
80 | # 有多个结果,发个状态码,警告一下用户
81 | if len(list_fit_results) > 1:
82 | status = 1
83 | # 默认用第一个搜索结果
84 | url_first_result = list_fit_results[0]
85 | print(' >获取系列:', url_first_result)
86 | html_bus = get_bus_html(url_first_result, proxy)
87 | # DVD封面cover
88 | coverg = re.search(r'bigImage" href="(.+?)">', html_bus)
89 | if str(coverg) != 'None':
90 | url_cover_bus = coverg.group(1)
91 | # 系列: 悪質シロウトナンパ
92 | seriesg = re.search(r'系列: (.+?)', html_bus)
93 | if str(seriesg) != 'None':
94 | series = seriesg.group(1)
95 | return series, url_cover_bus, status
96 |
97 |
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/JavdbReq.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import re, os, requests, time
3 | # from traceback import format_exc
4 |
5 | # 功能:请求各大jav网站和arzon的网页
6 | # 参数:网址url,请求头部header/cookies,代理proxy
7 | # 返回:网页html,请求头部
8 |
9 |
10 | #################################################### javdb ########################################################
11 | # 搜索javdb,得到搜索结果网页,返回html。
12 | def get_search_db_html(url, cookies, proxy):
13 | for retry in range(1, 11):
14 | if retry % 4 == 0:
15 | print(' >睡眠5分钟...')
16 | time.sleep(300)
17 | try:
18 | if proxy:
19 | rqs = requests.get(url, cookies=cookies, proxies=proxy, timeout=(6, 7))
20 | else:
21 | rqs = requests.get(url, cookies=cookies, timeout=(6, 7))
22 | except requests.exceptions.ProxyError:
23 | # print(format_exc())
24 | print(' >通过局部代理失败,重新尝试...')
25 | continue
26 | except:
27 | # print(format_exc())
28 | print(' >打开网页失败,重新尝试...')
29 | continue
30 | rqs.encoding = 'utf-8'
31 | rqs_content = rqs.text
32 | if re.search(r'JavDB', rqs_content):
33 | if re.search(r'搜索結果', rqs_content):
34 | return rqs_content, cookies
35 | elif re.search(r'登入 | JavDB', rqs_content):
36 | cfduid = input('请输入cfduid:')
37 | jdb_session = input('请输入jdb_session:')
38 | cookies = {
39 | "__cfduid": cfduid,
40 | "_jdb_session": jdb_session,
41 | }
42 | else:
43 | print(' >睡眠5分钟...')
44 | time.sleep(300)
45 | continue
46 | else:
47 | print(' >打开网页失败,空返回...重新尝试...')
48 | continue
49 | print('>>请检查你的网络环境是否可以打开:', url)
50 | os.system('pause')
51 |
52 |
53 | # 请求jav在javdb上的网页,返回html
54 | def get_db_html(url, cookies, proxy):
55 | for retry in range(1, 11):
56 | if retry % 4 == 0:
57 | print(' >睡眠5分钟...')
58 | time.sleep(300)
59 | try:
60 | if proxy:
61 | rqs = requests.get(url, cookies=cookies, proxies=proxy, timeout=(6, 7))
62 | else:
63 | rqs = requests.get(url, cookies=cookies, timeout=(6, 7))
64 | except requests.exceptions.ProxyError:
65 | # print(format_exc())
66 | print(' >通过局部代理失败,重新尝试...')
67 | continue
68 | except:
69 | # print(format_exc())
70 | print(' >打开网页失败,重新尝试...')
71 | continue
72 | rqs.encoding = 'utf-8'
73 | rqs_content = rqs.text
74 | # print(rqs_content)
75 | if re.search(r'JavDB', rqs_content):
76 | if re.search(r'link rel="canonical"', rqs_content):
77 | return rqs_content, cookies
78 | elif re.search(r'登入 | JavDB', rqs_content):
79 | cfduid = input('请粘贴cfduid:')
80 | jdb_session = input('请粘贴jdb_session:')
81 | cookies = {
82 | "__cfduid": cfduid,
83 | "_jdb_session": jdb_session,
84 | }
85 | else:
86 | print(' >睡眠5分钟...')
87 | time.sleep(300)
88 | continue
89 | else:
90 | print(' >打开网页失败,空返回...重新尝试...')
91 | continue
92 | print('>>请检查你的网络环境是否可以打开:', url)
93 | os.system('pause')
94 |
95 |
--------------------------------------------------------------------------------
/javsdt/Functions/Requests/JavlibraryReq.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import re, os, requests
3 | # from traceback import format_exc
4 | import cfscrape
5 | # 功能:请求各大jav网站和arzon的网页
6 | # 参数:网址url,请求头部header/cookies,代理proxy
7 | # 返回:网页html,请求头部
8 |
9 |
10 | #################################################### javlibrary ########################################################
11 | # 搜索javlibrary,或请求javlibrary上jav所在网页,返回html
12 | def get_library_html(url, proxy):
13 | for retry in range(10):
14 | try:
15 | if proxy:
16 | rqs = requests.get(url, proxies=proxy, timeout=(6, 7))
17 | else:
18 | rqs = requests.get(url, timeout=(6, 7))
19 | except requests.exceptions.ProxyError:
20 | # print(format_exc())
21 | print(' >通过局部代理失败,重新尝试...')
22 | continue
23 | except:
24 | # print(format_exc())
25 | print(' >打开网页失败,重新尝试...')
26 | continue
27 | rqs.encoding = 'utf-8'
28 | rqs_content = rqs.text
29 | # print(rqs_content)
30 | if re.search(r'JAVLibrary', rqs_content): # 得到想要的网页,直接返回
31 | return rqs_content
32 | else: # 代理工具返回的错误信息
33 | print(' >打开网页失败,空返回...尝试cfscrape...')
34 | #print(url)
35 | scraper = cfscrape.create_scraper()
36 | web_data = scraper.get(url).text
37 | #print(web_data)
38 | if re.search(r'JAVLibrary', web_data):
39 | return web_data
40 | else:
41 | continue
42 | print('>>请检查你的网络环境是否可以打开:', url)
43 | os.system('pause')
44 |
45 |
--------------------------------------------------------------------------------
/javsdt/Functions/Standard.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import sep, makedirs, rename, rmdir, listdir
3 | from os.path import exists
4 | from configparser import RawConfigParser
5 | from shutil import copyfile
6 |
7 | from Functions.Record import record_video_old, record_fail
8 |
9 |
10 | # 功能:1重命名视频
11 | # 参数:设置settings,重命名视频的命名公式list_name_video,命名信息dict_data,第几集str_cd,处理的影片jav,已失败次数num_fail,视频的相对路径path_relative
12 | # 返回:命名信息dict_data(dict_data['视频']可能改变)、处理的影片jav(文件名改变)、已发生的失败次数num_fail
13 | # 辅助:os.exists, os.rename, record_video_old, record_fail
14 | def rename_mp4(jav, num_fail, settings, dict_data, list_name_video, path_relative, str_cd):
15 | if settings.bool_rename_video:
16 | # 构造新文件名,不带文件类型后缀
17 | name_without_ext = ''
18 | for j in list_name_video:
19 | name_without_ext += dict_data[j]
20 | name_without_ext = name_without_ext.rstrip() + str_cd # 去除末尾空格,否则windows会自动删除空格,导致程序仍以为带空格
21 | path_new = jav.root + sep + name_without_ext + jav.type # 【临时变量】path_new 视频文件的新路径
22 | # 一般情况,不存在同名视频文件
23 | if not exists(path_new):
24 | rename(jav.path, path_new)
25 | record_video_old(jav.path, path_new)
26 | # 已存在目标文件,但就是现在的文件
27 | elif jav.path.upper() == path_new.upper():
28 | try:
29 | rename(jav.path, path_new)
30 | # windows本地磁盘,“abc-123.mp4”重命名为“abc-123.mp4”或“ABC-123.mp4”没问题,但有用户反映,挂载的磁盘会报错“file exists error”
31 | except:
32 | num_fail += 1
33 | record_fail(' >第' + str(num_fail) + '个失败!请自行重命名大小写:' + path_relative + '\n')
34 | # 存在目标文件,不是现在的文件。
35 | else:
36 | num_fail += 1
37 | record_fail(
38 | ' >第' + str(num_fail) + '个失败!重命名影片失败,重复的影片,已经有相同文件名的视频了:' + path_new + '\n')
39 | raise FileExistsError # 【终止对该jav的整理】
40 | dict_data['视频'] = name_without_ext # 【更新】 dict_data['视频']
41 | jav.name = name_without_ext + jav.type # 【更新】jav.name,重命名操作可能不成功,但之后的操作仍然围绕成功的jav.name来命名
42 | print(' >修改文件名' + str_cd + '完成')
43 | # 重命名字幕
44 | if jav.subtitle and settings.bool_rename_subtitle:
45 | subtitle_new = name_without_ext + jav.subtitle_type # 【临时变量】subtitle_new
46 | path_subtitle_new = jav.root + sep + subtitle_new # 【临时变量】path_subtitle_new
47 | if jav.path_subtitle != path_subtitle_new:
48 | rename(jav.path_subtitle, path_subtitle_new)
49 | jav.subtitle = subtitle_new # 【更新】 jav.subtitle 字幕完整文件名
50 | print(' >修改字幕名完成')
51 | return dict_data, jav, num_fail
52 |
53 |
54 | # 功能:2归类影片,只针对视频文件和字幕文件,无视它们当前所在文件夹
55 | # 参数:设置settings,归类的目标目录路径root_classify,归类标准组合公式list_classify_basis,命名信息dict_data,处理的影片jav,已失败次数num_fail
56 | # 返回:处理的影片jav(所在文件夹路径改变)、已失败次数num_fail
57 | # 辅助:os.exists, os.rename, os.makedirs,
58 | def classify_files(jav, num_fail, settings, dict_data, list_classify_basis, root_classify):
59 | # 如果需要归类,且不是针对文件夹来归类
60 | if settings.bool_classify and not settings.bool_classify_folder:
61 | # 移动的目标文件夹路径
62 | root_dest = root_classify + sep
63 | for j in list_classify_basis:
64 | root_dest += dict_data[j].rstrip() # 【临时变量】归类的目标文件夹路径 C:\Users\JuneRain\Desktop\测试文件夹\葵司\
65 | # 还不存在该文件夹,新建
66 | if not exists(root_dest):
67 | makedirs(root_dest)
68 | path_new = root_dest + sep + jav.name # 【临时变量】新的影片路径
69 | # 目标文件夹没有相同的影片,防止用户已经有一个“avop-127.mp4”,现在又来一个
70 | if not exists(path_new):
71 | rename(jav.path, path_new)
72 | print(' >归类视频文件完成')
73 | # 移动字幕
74 | if jav.subtitle:
75 | path_subtitle_new = root_dest + sep + jav.subtitle # 【临时变量】新的字幕路径
76 | if jav.path_subtitle != path_subtitle_new:
77 | rename(jav.path_subtitle, path_subtitle_new)
78 | # 不再更新 jav.path_subtitle,下面不会再操作 字幕文件
79 | print(' >归类字幕文件完成')
80 | jav.root = root_dest # 【更新】jav.root
81 | else:
82 | num_fail += 1
83 | record_fail(' >第' + str(num_fail) + '个失败!归类失败,重复的影片,归类的目标文件夹已经存在相同的影片:' + path_new + '\n')
84 | raise FileExistsError # 【终止对该jav的整理】
85 | return jav, num_fail
86 |
87 |
88 | # 功能:3重命名文件夹【相同】如果已进行第2操作,第3操作不会进行,因为用户只需要归类视频文件,不需要管文件夹。
89 | # 参数:设置settings,重命名文件夹的公式list_name_folder,命名信息dict_data,是否是独立文件夹bool_separate_folder,
90 | # 处理的影片jav,该车牌总共多少cd num_all_episodes,已失败次数num_fail
91 | # 返回:处理的影片jav(所在文件夹路径改变)、已失败次数num_fail
92 | # 辅助:os.exists, os.rename, os.makedirs,record_fail
93 | def rename_folder(jav, num_fail, settings, dict_data, list_name_folder, bool_separate_folder, num_all_episodes):
94 | if settings.bool_rename_folder:
95 | # 构造 新文件夹名folder_new
96 | folder_new = ''
97 | for j in list_name_folder:
98 | folder_new += (dict_data[j])
99 | folder_new = folder_new.rstrip(' .') # 【临时变量】新的所在文件夹。去除末尾空格和“.”
100 | # 是独立文件夹,才会重命名文件夹
101 | if bool_separate_folder:
102 | # 当前视频是该车牌的最后一集,他的兄弟姐妹已经处理完成,才会重命名它们的“家”。
103 | if jav.episode == num_all_episodes:
104 | list_root_now = jav.root.split(sep)
105 | del list_root_now[-1]
106 | root_new = sep.join(list_root_now) + sep + folder_new # 【临时变量】新的影片所在文件夹路径。
107 | # 想要重命名的目标影片文件夹不存在
108 | if not exists(root_new):
109 | rename(jav.root, root_new)
110 | jav.root = root_new # 【更新】jav.root
111 | # 目标影片文件夹存在,但就是现在的文件夹,即新旧相同
112 | elif jav.root == root_new:
113 | pass
114 | # 真的有一个同名的文件夹了
115 | else:
116 | num_fail += 1
117 | record_fail(' >第' + str(num_fail) + '个失败!重命名文件夹失败,已存在相同文件夹:' + root_new + '\n')
118 | raise FileExistsError # 【终止对该jav的整理】
119 | print(' >重命名文件夹完成')
120 | # 不是独立的文件夹,建立独立的文件夹
121 | else:
122 | path_separate_folder = jav.root + sep + folder_new # 【临时变量】需要创建的的影片所在文件夹。
123 | # 确认没有同名文件夹
124 | if not exists(path_separate_folder):
125 | makedirs(path_separate_folder)
126 | path_new = path_separate_folder + sep + jav.name # 【临时变量】新的影片路径
127 | # 如果这个文件夹是现成的,在它内部确认有没有“abc-123.mp4”。
128 | if not exists(path_new):
129 | rename(jav.path, path_new)
130 | # 移动字幕
131 | if jav.subtitle:
132 | path_subtitle_new = path_separate_folder + sep + jav.subtitle # 【临时变量】新的字幕路径
133 | rename(jav.path_subtitle, path_subtitle_new)
134 | # 下面不会操作 字幕文件 了,jav.path_subtitle不再更新
135 | print(' >移动字幕到独立文件夹')
136 | jav.root = path_separate_folder # 【更新】jav.root
137 | # 里面已有“avop-127.mp4”,这不是它的家。
138 | else:
139 | num_fail += 1
140 | record_fail(' >第' + str(num_fail) + '个失败!创建独立文件夹失败,已存在相同的视频文件:' + path_new + '\n')
141 | raise FileExistsError # 【终止对该jav的整理】
142 | return jav, num_fail
143 |
144 |
145 | # 功能:6为当前jav收集演员头像到“.actors”文件夹中
146 | # 参数:演员们 list_actors,jav当前所处文件夹的路径root_now
147 | # 返回:无
148 | # 辅助:os.path.exists,os.makedirs, configparser.RawConfigParser, shutil.copyfile
149 | def collect_sculpture(list_actors, root_now):
150 | for each_actor in list_actors:
151 | path_exist_actor = '演员头像' + sep + each_actor[0] + sep + each_actor # 事先准备好的演员头像路径
152 | if exists(path_exist_actor + '.jpg'):
153 | pic_type = '.jpg'
154 | elif exists(path_exist_actor + '.png'):
155 | pic_type = '.png'
156 | else:
157 | config_actor = RawConfigParser()
158 | config_actor.read('【缺失的演员头像统计For Kodi】.ini', encoding='utf-8-sig')
159 | try:
160 | each_actor_times = config_actor.get('缺失的演员头像', each_actor)
161 | config_actor.set("缺失的演员头像", each_actor, str(int(each_actor_times) + 1))
162 | except:
163 | config_actor.set("缺失的演员头像", each_actor, '1')
164 | config_actor.write(open('【缺失的演员头像统计For Kodi】.ini', "w", encoding='utf-8-sig'))
165 | continue
166 | # 已经收录了这个演员头像
167 | root_dest_actor = root_now + sep + '.actors' + sep # 头像的目标文件夹
168 | if not exists(root_dest_actor):
169 | makedirs(root_dest_actor)
170 | # 复制一份到“.actors”
171 | copyfile(path_exist_actor + pic_type, root_dest_actor + each_actor + pic_type)
172 | print(' >演员头像收集完成:', each_actor)
173 |
174 |
175 | # 功能:7归类影片,针对文件夹(如果已进行第2操作,第7操作不会进行,因为用户只需要归类视频文件,不需要管文件夹)
176 | # 参数:设置settings,处理的影片jav,该车牌总共多少cd num_all_episodes,是否是独立文件夹bool_separate_folder,
177 | # 归类的目标目录路径root_classify,当前处理的文件夹路径root,命名信息dict_data
178 | # 返回:处理的影片jav(所在文件夹路径改变)、已失败次数num_fail
179 | # 辅助:os.exists, os.rename, os.makedirs,
180 | def classify_folder(jav, num_fail, settings, dict_data, list_classify_basis, root_classify, root, bool_separate_folder, num_all_episodes):
181 | if settings.bool_classify and settings.bool_classify_folder and jav.episode == num_all_episodes: # 需要移动文件夹,且,是该影片的最后一集
182 | # 用户选择的文件夹是一部影片的独立文件夹,为了避免在这个文件夹里又生成新的归类文件夹
183 | if bool_separate_folder and root_classify.startswith(root):
184 | print(' >无法归类,请选择该文件夹的上级文件夹作它的归类根目录')
185 | return num_fail
186 | # 归类放置的目标文件夹
187 | root_dest = root_classify + sep
188 | # 移动的目标文件夹
189 | for j in list_classify_basis:
190 | root_dest += dict_data[j].rstrip(' .') # 【临时变量】 文件夹移动的目标上级文件夹 C:\Users\JuneRain\Desktop\测试文件夹\1\葵司\
191 | root_new = root_dest + sep + jav.folder # 【临时变量】 文件夹移动的目标路径 C:\Users\JuneRain\Desktop\测试文件夹\1\葵司\【葵司】AVOP-127\
192 | # print(root_new)
193 | # 还不存在归类的目标文件夹
194 | if not exists(root_new):
195 | makedirs(root_new)
196 | # 把现在文件夹里的东西都搬过去
197 | jav_files = listdir(jav.root)
198 | for i in jav_files:
199 | rename(jav.root + sep + i, root_new + sep + i)
200 | # 删除“旧房子”,这是javsdt唯一的删除操作,而且os.rmdir只能删除空文件夹
201 | rmdir(jav.root)
202 | print(' >归类文件夹完成')
203 | # 用户已经有了这个文件夹,可能以前处理过同车牌的视频
204 | else:
205 | num_fail += 1
206 | record_fail(' >第' + str(num_fail) + '个失败!归类失败,归类的目标位置已存在相同文件夹:' + root_new + '\n')
207 | raise FileExistsError
208 | return num_fail
209 |
--------------------------------------------------------------------------------
/javsdt/Functions/Status.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | from os import sep, system, walk
3 | from os.path import exists
4 | from shutil import copyfile
5 |
6 |
7 | # 功能:如果需要为kodi整理头像,则先检查“演员头像for kodi.ini”、“演员头像”文件夹是否存在
8 | # 参数:是否需要整理头像
9 | # 返回:无
10 | # 辅助:os.path.exists,os.system,shutil.copyfile
11 | def check_actors(bool_sculpture):
12 | if bool_sculpture:
13 | if not exists('演员头像'):
14 | print('\n“演员头像”文件夹丢失!请把它放进exe的文件夹中!\n')
15 | system('pause')
16 | if not exists('【缺失的演员头像统计For Kodi】.ini'):
17 | if exists('actors_for_kodi.ini'):
18 | copyfile('actors_for_kodi.ini', '【缺失的演员头像统计For Kodi】.ini')
19 | print('\n“【缺失的演员头像统计For Kodi】.ini”成功!')
20 | else:
21 | print('\n请打开“【ini】重新创建ini.exe”创建丢失的程序组件!')
22 | system('pause')
23 |
24 |
25 | # 功能:检查 归类根目录 是否存在,是不是和视频在同一个磁盘……
26 | # 参数:用户自定义的归类根目录,用户选择整理的文件夹路径
27 | # 返回:归类根目录路径
28 | # 辅助:os.sep,os.system
29 | def check_classify_root(root_custom, root_choose):
30 | # 用户使用默认的“所选文件夹”
31 | if root_custom == '所选文件夹':
32 | return root_choose + sep + '归类完成'
33 | # 归类根目录 是 用户输入的路径c:\a,继续核实合法性
34 | else:
35 | root_custom = root_custom.rstrip(sep)
36 | # 用户输入的路径 不是 所选文件夹root_choose
37 | if root_custom != root_choose:
38 | if root_custom[:2] != root_choose[:2]:
39 | print('归类的根目录“', root_custom, '”和所选文件夹不在同一磁盘无法归类!请修正!')
40 | system('pause')
41 | if not exists(root_custom):
42 | print('归类的根目录“', root_custom, '”不存在!无法归类!请修正!')
43 | system('pause')
44 | return root_custom
45 | # 用户输入的路径 就是 所选文件夹root_choose
46 | else:
47 | return root_choose + sep + '归类完成'
48 |
49 |
50 | # 功能:所选文件夹总共有多少个视频文件
51 | # 参数:用户选择整理的文件夹路径root_choose,视频类型后缀集合tuple_video_type
52 | # 返回:无
53 | # 辅助:os.walk
54 | def count_num_videos(root_choose, tuple_video_type):
55 | num_videos = 0
56 | for root, dirs, files in walk(root_choose):
57 | for file_raw in files:
58 | file_temp = file_raw.upper()
59 | if file_temp.endswith(tuple_video_type) and not file_temp.startswith('.'):
60 | num_videos += 1
61 | return num_videos
62 |
63 |
64 | # 功能:判断当前一级文件夹是否含有nfo文件
65 | # 参数:这层文件夹下的文件们
66 | # 返回:True
67 | # 辅助:无
68 | def judge_exist_nfo(list_files):
69 | for file in list_files[::-1]:
70 | if file.endswith('.nfo'):
71 | return True
72 | return False
73 |
74 |
75 | # 功能:判断是否有除了“.actors”"extrafanrt”外的其他文件夹(如果有的话,说明当前文件夹不是jav的独立文件夹)
76 | # 参数:文件夹list
77 | # 返回:True
78 | # 辅助:无
79 | def judge_exist_extra_folders(list_folders):
80 | for folder in list_folders:
81 | if folder != '.actors' and folder != 'extrafanart':
82 | return True
83 | return False
84 |
--------------------------------------------------------------------------------
/javsdt/Functions/User.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import sys
3 | from os import sep, system
4 | from os.path import exists, isdir
5 | from time import sleep
6 | from tkinter import filedialog, Tk, TclError
7 |
8 |
9 | # 功能:获取用户选取的文件夹路径
10 | # 参数:无
11 | # 返回:路径str
12 | # 辅助:tkinter.Tk,tkinter.filedialog,os.sep,sys
13 | def choose_directory():
14 | # 用户:选择需要整理的文件夹
15 | print('请选择要整理的文件夹:', end='')
16 | for i in range(2):
17 | try:
18 | directory_root = Tk()
19 | directory_root.withdraw()
20 | path_work = filedialog.askdirectory()
21 | if path_work == '':
22 | print('你没有选择目录! 请重新选:')
23 | sleep(2)
24 | continue
25 | else:
26 | # askdirectory 获得是 正斜杠 路径C:/,所以下面要把 / 换成 反斜杠\
27 | return path_work.replace('/', sep)
28 | except TclError: # 来自@BlueSkyBot
29 | try:
30 | path_work = input("请输入你需要整理的文件夹路径: ")
31 | except KeyboardInterrupt:
32 | sys.exit('输入终止,马上退出!')
33 | if not exists(path_work) or not isdir(path_work):
34 | print('\"{0}\" 不存在当前目录或者输入错误,请重新输入!'.format(path_work))
35 | sleep(2)
36 | continue
37 | else:
38 | return path_work
39 | print('你可能不需要我了,请关闭我吧!')
40 | system('pause')
--------------------------------------------------------------------------------
/javsdt/Functions/XML.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 |
4 | # 功能:去除xml文档不允许的特殊字符 &<>
5 | # 参数:(文件名、简介、标题)str
6 | # 返回:str
7 | # 辅助:无
8 | def replace_xml(name):
9 | # 替换xml中的不允许的特殊字符 .replace('\'', ''').replace('\"', '"')
10 | # .replace('&', '&').replace('<', '<').replace('>', '>') nfo基于xml,xml中不允许这5个字符,但实际测试nfo只不允许左边3个
11 | return name.replace('&', '&').replace('<', '<').replace('>', '>')\
12 | .replace('\n', '').replace('\t', '').replace('\r', '').rstrip()
13 |
14 |
15 | # 功能:去除xml文档和windows路径不允许的特殊字符 &<> \/:*?"<>|
16 | # 参数:(文件名、简介、标题)str
17 | # 返回:str
18 | # 辅助:无
19 | def replace_xml_win(name):
20 | # 替换windows路径不允许的特殊字符 \/:*?"<>|
21 | return name.replace('&', '&').replace('<', '<').replace('>', '>')\
22 | .replace('\n', '').replace('\t', '').replace('\r', '')\
23 | .replace("\\", "#").replace("/", "#").replace(":", ":").replace("*", "#")\
24 | .replace("?", "?").replace("\"", "#").replace("|", "#").rstrip()
25 |
--------------------------------------------------------------------------------
/javsdt/Jav321.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import os
3 | import re
4 | from shutil import copyfile
5 | from traceback import format_exc
6 |
7 | from Class.JavFile import JavFile
8 | ########################################################################################################################
9 | from Class.Settings import Settings
10 | from Functions.Baidu import translate
11 | from Functions.Car import find_car_suren, list_suren_car
12 | from Functions.Picture import add_watermark_divulge, crop_poster_default
13 | from Functions.Picture import check_picture, add_watermark_subtitle
14 | # ################################################## 不同 ##########################################################
15 | from Functions.Process import judge_exist_divulge
16 | from Functions.Process import judge_exist_subtitle
17 | from Functions.Process import perfect_dict_data
18 | from Functions.Record import record_start, record_fail
19 | from Functions.Requests.Download import download_pic
20 | from Functions.Requests.Jav321Req import get_321_html, post_321_html
21 | from Functions.Standard import rename_mp4, rename_folder, classify_files, classify_folder
22 | from Functions.Status import check_actors
23 | from Functions.Status import judge_exist_nfo, judge_exist_extra_folders, count_num_videos
24 | from Functions.User import choose_directory
25 | from Functions.XML import replace_xml, replace_xml_win
26 |
27 |
28 | # main开始
29 | print('1、请开启代理,建议美国节点,访问“https://www.jav321.com/”\n'
30 | '2、影片信息没有导演,没有演员头像,可能没有演员姓名\n'
31 | '3、只能整理列出车牌的素人影片\n'
32 | ' 如有素人车牌识别不出,请在ini中添加该车牌,或者告知作者\n')
33 |
34 | # 读取配置文件,这个ini文件用来给用户设置
35 | print('正在读取ini中的设置...', end='')
36 | try:
37 | settings = Settings('素人')
38 | except:
39 | settings = None
40 | print(format_exc())
41 | print('\n无法读取ini文件,请修改它为正确格式,或者打开“【ini】重新创建ini.exe”创建全新的ini!')
42 | os.system('pause')
43 | print('\n读取ini文件成功!\n')
44 |
45 | # 路径分隔符:当前系统的路径分隔符 windows是“\”,linux和mac是“/”
46 | sep = os.sep
47 |
48 | # 检查头像:如果需要为kodi整理头像,先检查演员头像ini、头像文件夹是否存在。
49 | check_actors(settings.bool_sculpture)
50 |
51 | # 局部代理:哪些站点需要代理。
52 | proxy_library, proxy_bus, proxy_321, proxy_db, proxy_arzon, proxy_dmm = settings.get_proxy()
53 | # jav321网址 搜索网址 https://www.jav321.com/search https://www.jav321.com/
54 | url_search_321, url_321 = settings.get_url_321()
55 |
56 | # 选择简繁中文以及百度翻译账户:需要简体中文还是繁体中文,影响影片特征和简介。
57 | to_language, tran_id, tran_sk = settings.get_translate_account()
58 |
59 | # 信息字典:存放影片信息,用于给用户自定义各种命名。
60 | dict_data = {'车牌': 'ABC-123',
61 | '车牌前缀': 'ABC',
62 | '标题': '素人标题',
63 | '完整标题': '完整素人标题',
64 | '导演': '素人导演',
65 | '片商': '素人片商',
66 | '评分': '0',
67 | '片长': '0',
68 | '系列': '素人系列',
69 | '发行年月日': '1970-01-01', '发行年份': '1970', '月': '01', '日': '01',
70 | '首个演员': '素人演员', '全部演员': '素人演员',
71 | '空格': ' ',
72 | '\\': sep, '/': sep, # 文件路径分隔符
73 | '是否中字': '',
74 | '是否流出': '',
75 | '影片类型': settings.av_type(),
76 | '视频': 'ABC-123', # 当前及未来的视频文件名,不带ext
77 | '原文件名': 'ABC-123', '原文件夹名': 'ABC-123', }
78 |
79 | # nfo中title的写法。
80 | list_name_nfo_title = settings.formula_name_nfo_title()
81 | # 额外将哪些元素放入特征中
82 | list_extra_genres = settings.list_extra_genre()
83 | # 重命名视频的格式
84 | list_name_video = settings.formula_rename_video()
85 | # 重命名文件夹的格式
86 | list_name_folder = settings.formula_rename_folder()
87 |
88 | # fanart的格式
89 | list_name_fanart = settings.formula_name_fanart()
90 | # poster的格式
91 | list_name_poster = settings.formula_name_poster()
92 |
93 | # 视频文件名包含哪些多余的字母数字,需要无视
94 | list_surplus_words_in_filename = settings.list_surplus_word_in_filename('素人')
95 | # 文件名包含哪些特殊含义的文字,判断是否中字
96 | list_subtitle_words_in_filename = settings.list_subtitle_word_in_filename()
97 | # 文件名包含哪些特殊含义的文字,判断是否是无码流出片
98 | list_divulge_words_in_filename = settings.list_divulge_word_in_filename()
99 |
100 | # 素人番号:得到事先设置的素人番号,让程序能跳过它们
101 | list_suren_cars = list_suren_car()
102 |
103 | # 需要扫描的文件的类型
104 | tuple_video_types = settings.tuple_video_type()
105 |
106 | # 完善dict_data,如果用户自定义了一些文字,不在元素中,需要将它们添加进dict_data;list_classify_basis,归类标准,归类目标文件夹的组成公式。
107 | dict_data, list_classify_basis = perfect_dict_data(list_extra_genres, list_name_video, list_name_folder,
108 | list_name_nfo_title, list_name_fanart, list_name_poster,
109 | settings.custom_classify_basis(), dict_data)
110 |
111 | # 用户输入“回车”就继续选择文件夹整理
112 | input_start_key = ''
113 | while input_start_key == '':
114 | # 用户:选择需要整理的文件夹
115 | print('请选择要整理的文件夹:', end='')
116 | root_choose = choose_directory()
117 | print(root_choose)
118 | # 日志:在txt中记录一下用户的这次操作,在某个时间选择了某个文件夹
119 | record_start(root_choose)
120 | # 归类:用户自定义的归类根目录,如果不需要归类则为空
121 | root_classify = settings.check_classify_root(root_choose, sep)
122 | # 计数:失败次数及进度
123 | num_fail = 0 # 已经或可能导致致命错误,比如整理未完成,同车牌有不同视频
124 | num_all_videos = count_num_videos(root_choose, tuple_video_types) # 所选文件夹总共有多少个视频文件
125 | num_current = 0 # 当前视频的编号
126 | print('...文件扫描开始...如果时间过长...请避开夜晚高峰期...\n')
127 | # root【当前根目录】 dirs【子文件夹】 files【文件】,root是str,后两个是list
128 | for root, dirs, files in os.walk(root_choose):
129 | # 什么文件都没有
130 | if not files:
131 | continue
132 | # 当前root是已归类的目录,无需处理
133 | if '归类完成' in root.replace(root_choose, ''):
134 | continue
135 | # 跳过已存在nfo的文件夹,判断这一层文件夹中有没有nfo
136 | if settings.bool_skip and judge_exist_nfo(files):
137 | continue
138 | # 对这一层文件夹进行评估,有多少视频,有多少同车牌视频,是不是独立文件夹
139 | list_jav_struct = [] # 存放:需要整理的jav的结构体
140 | dict_car_pref = {} # 存放:每一车牌的集数, 例如{'abp-123': 1, avop-789': 2}是指 abp-123只有一集,avop-789有cd1、cd2
141 | num_videos_include = 0 # 计数:当前文件夹中视频的数量,可能有视频不是jav
142 | dict_subtitle_files = {} # 存放:jav的字幕文件和车牌对应关系 {'c:\a\abc_123.srt': 'abc-123'}
143 | # 判断文件是不是字幕文件,放入dict_subtitle_files中
144 | for file_raw in files:
145 | file_temp = file_raw.upper()
146 | if file_temp.endswith(('.SRT', '.VTT', '.ASS', '.SSA', '.SUB', '.SMI',)):
147 | # 当前模式不处理FC2
148 | if 'FC2' in file_temp:
149 | continue
150 | # 去除用户设置的、干扰车牌的文字
151 | for word in list_surplus_words_in_filename:
152 | file_temp = file_temp.replace(word, '')
153 | # 得到字幕文件名中的车牌
154 | subtitle_car = find_car_suren(file_temp, list_suren_cars)
155 | # 将该字幕文件和其中的车牌对应到dict_subtitle_files中
156 | if subtitle_car:
157 | dict_subtitle_files[file_raw] = subtitle_car
158 | # print(dict_subtitle_files)
159 | # 判断文件是不是视频,放入list_jav_struct中
160 | for file_raw in files:
161 | file_temp = file_raw.upper()
162 | if file_temp.endswith(tuple_video_types) and not file_temp.startswith('.'):
163 | num_videos_include += 1
164 | num_current += 1
165 | if 'FC2' in file_temp:
166 | continue
167 | for word in list_surplus_words_in_filename:
168 | file_temp = file_temp.replace(word, '')
169 | # 得到视频中的车牌
170 | car = find_car_suren(file_temp, list_suren_cars)
171 | if car:
172 | try:
173 | dict_car_pref[car] += 1 # 已经有这个车牌了,加一集cd
174 | except KeyError:
175 | dict_car_pref[car] = 1 # 这个新车牌有了第一集
176 | # 这个车牌在dict_subtitle_files中,有它的字幕。
177 | if car in dict_subtitle_files.values():
178 | subtitle_file = list(dict_subtitle_files.keys())[list(dict_subtitle_files.values()).index(car)]
179 | del dict_subtitle_files[subtitle_file]
180 | else:
181 | subtitle_file = ''
182 | # 将该jav的各种属性打包好,包括原文件名带扩展名、所在文件夹路径、第几集、所属字幕文件名
183 | jav_struct = JavFile(file_raw, root, car, dict_car_pref[car], subtitle_file, num_current)
184 | list_jav_struct.append(jav_struct)
185 | else:
186 | print('>>无法处理:', root.replace(root_choose, '') + sep + file_raw)
187 |
188 | # 判定影片所在文件夹是否是独立文件夹,独立文件夹是指该文件夹仅用来存放该影片,而不是大杂烩文件夹
189 | # 这一层文件夹下有jav
190 | if dict_car_pref:
191 | # 当前文件夹下,车牌不止一个;还有其他非jav视频;有其他文件夹,除了演员头像文件夹“.actors”和额外剧照文件夹“extrafanart”;
192 | if len(dict_car_pref) > 1 or num_videos_include > len(list_jav_struct) or judge_exist_extra_folders(dirs):
193 | bool_separate_folder = False # 不是独立的文件夹
194 | else:
195 | bool_separate_folder = True # 这一层文件夹是这部jav的独立文件夹
196 | else:
197 | continue
198 |
199 | # 开始处理每一部jav
200 | for jav in list_jav_struct:
201 | # 告诉用户进度
202 | print('>> [' + str(jav.number) + '/' + str(num_all_videos) + ']:', jav.name)
203 | print(' >发现车牌:', jav.car)
204 |
205 | # 判断是否有中字的特征,条件有三满足其一即可:1有外挂字幕 2文件名中含有“-C”之类的字眼 3旧的nfo中已经记录了它的中字特征
206 | if jav.subtitle:
207 | bool_subtitle = True # 判定成功
208 | dict_data['是否中字'] = settings.custom_subtitle_expression # '是否中字'这一命名元素被激活
209 | else:
210 | bool_subtitle = judge_exist_subtitle(root, jav.name_no_ext, list_subtitle_words_in_filename)
211 | dict_data['是否中字'] = settings.custom_subtitle_expression if bool_subtitle else ''
212 | # 判断是否是无码流出的作品,同理
213 | bool_divulge = judge_exist_divulge(root, jav.name_no_ext, list_divulge_words_in_filename)
214 | dict_data['是否流出'] = settings.custom_divulge_expression if bool_divulge else ''
215 |
216 | # 影片的相对于所选文件夹的路径,用于报错
217 | path_relative = sep + jav.path.replace(root_choose, '')
218 |
219 | # 获取nfo信息的jav321网页
220 | try:
221 | # 用户指定了网址,则直接得到jav所在网址
222 | if '图书馆' in jav.name:
223 | url_appointg = re.search(r'三二一(.+?)\.', jav.name)
224 | if str(url_appointg) != 'None':
225 | url_on_web = url_321 + 'video/' + url_appointg.group(1)
226 | print(' >获取信息:', url_on_web)
227 | html_web = get_321_html(url_on_web, proxy_321)
228 | # 尝试找标题,jav321上的标题不包含车牌,title_only表示单纯的标题
229 | titleg = re.search(r'(.+?) ', html_web) # 匹配处理“标题”
230 | # 搜索结果就是AV的页面
231 | if str(titleg) != 'None':
232 | title_only = titleg.group(1)
233 | print(title_only)
234 | # 找不到标题,jav321找不到影片
235 | else:
236 | # print(html_web)
237 | num_fail += 1
238 | record_fail(' >第' + str(num_fail) + '个失败!你指定的jav321网址找不到影片:' + path_relative + '\n')
239 | continue # 【退出对该jav的整理】
240 | else:
241 | num_fail += 1
242 | record_fail(' >第' + str(num_fail) + '个失败!你指定的jav321网址有错误:' + path_relative + '\n')
243 | continue # 【退出对该jav的整理】
244 | # 用户没有指定网址,则去搜索
245 | else:
246 | # 得到jav321搜索网页html
247 | print(' >搜索车牌:', url_search_321)
248 | html_web = post_321_html(url_search_321, {'sn': jav.car}, proxy_321)
249 | # print(html_web)
250 | # 尝试找标题
251 | titleg = re.search(r'h3>(.+?) ', html_web) # 匹配处理“标题”
252 | # 找得到,搜索结果就是AV的页面
253 | if str(titleg) != 'None':
254 | title_only = titleg.group(1)
255 | # print(title_only)
256 | # 找不到标题,jav321找不到影片
257 | else:
258 | num_fail += 1
259 | record_fail(' >第' + str(
260 | num_fail) + '个失败!jav321找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
261 | continue # 【退出对该jav的整理】
262 |
263 | # 去除xml文档和windows路径不允许的特殊字符 &<> \/:*?"<>|
264 | title_only = replace_xml_win(title_only)
265 | # 正则匹配 影片信息 开始!
266 | # 有大部分信息的html_web
267 | html_web = re.search(r'(h3>.+?)async', html_web).group(1)
268 | print(html_web)
269 | # 车牌
270 | dict_data['车牌'] = car = re.search(r'番.?: (.+?)
', html_web).group(1).upper()
271 | dict_data['车牌前缀'] = car.split('-')[0]
272 | # jav321上素人的title开头不是车牌
273 | title = car + ' ' + title_only
274 | # 给用户重命名用的标题是“短标题”,nfo中是“完整标题”,但用户在ini中只用写“标题”
275 | dict_data['完整标题'] = title_only
276 | # 处理影片的标题过长
277 | if len(title_only) > settings.int_title_len:
278 | dict_data['标题'] = title_only[:settings.int_title_len]
279 | else:
280 | dict_data['标题'] = title_only
281 | print(' >影片标题:', title)
282 | # DVD封面cover
283 | coverg = re.search(r'poster="(.+?)">: (\d\d\d\d-\d\d-\d\d)
', html_web)
304 | if str(premieredg) != 'None':
305 | dict_data['发行年月日'] = time_premiered = premieredg.group(1)
306 | dict_data['发行年份'] = time_premiered[0:4]
307 | dict_data['月'] = time_premiered[5:7]
308 | dict_data['日'] = time_premiered[8:10]
309 | else:
310 | dict_data['发行年月日'] = time_premiered = '1970-01-01'
311 | dict_data['发行年份'] = '1970'
312 | dict_data['月'] = '01'
313 | dict_data['日'] = '01'
314 | # 片长 150 分钟 |
315 | runtimeg = re.search(r'播放..: (\d+)', html_web)
316 | if str(runtimeg) != 'None':
317 | dict_data['片长'] = runtimeg.group(1)
318 | else:
319 | dict_data['片长'] = '0'
320 | # 片商: プレステージプレミアム(PRESTIGE PREMIUM)
321 | studiog = re.search(r'片商: (.+?)', html_web)
322 | if str(studiog) != 'None':
323 | dict_data['片商'] = studio = replace_xml_win(studiog.group(1))
324 | else:
325 | dict_data['片商'] = '素人片商'
326 | studio = ''
327 | # 演员们 和 # 第一个演员 演员: 花音さん 21歳 床屋さん(家族経営)  
328 | actorg = re.search(r'small>(.+?)', html_web)
329 | if str(actorg) != 'None':
330 | actor_only = actorg.group(1)
331 | list_actor = actor_only.replace('/', ' ').split(
332 | ' ') # luxu-071 松波優 29歳 システムエンジニア
333 | list_actor = [i for i in list_actor if i]
334 | if len(list_actor) > 3:
335 | dict_data['首个演员'] = list_actor[1] + ' ' + list_actor[2] + ' ' + list_actor[3]
336 | elif len(list_actor) > 1:
337 | del list_actor[0]
338 | dict_data['首个演员'] = ' '.join(list_actor)
339 | else:
340 | dict_data['首个演员'] = '素人'
341 | dict_data['全部演员'] = dict_data['首个演员']
342 | else:
343 | dict_data['首个演员'] = dict_data['全部演员'] = '素人'
344 | # 特点
345 | genres = re.findall(r'genre.+?">(.+?)', html_web)
346 | genres = [i for i in genres if i != '标签' and i != '標籤' and i != '素人'] # 这些特征 没有参考意义,为用户删去
347 | if bool_subtitle: # 有“中字“,加上特征”中文字幕”
348 | genres.append('中文字幕')
349 | if bool_divulge: # 是流出无码片,加上特征'无码流出'
350 | genres.append('无码流出')
351 | # print(genres)
352 | # 评分
353 | scoreg = re.search(r'评分: (\d\.\d)
', html_web)
354 | if str(scoreg) != 'None':
355 | float_score = float(scoreg.group(1))
356 | float_score = (float_score - 2) * 10 / 3
357 | if float_score >= 0:
358 | score = '%.1f' % float_score
359 | else:
360 | score = '0'
361 | else:
362 | scoreg = re.search(r'"img/(\d\d)\.gif', html_web)
363 | if str(scoreg) != 'None':
364 | float_score = float(scoreg.group(1)) / 10
365 | float_score = (float_score - 2) * 10 / 3
366 | if float_score >= 0:
367 | score = '%.1f' % float_score
368 | else:
369 | score = '0'
370 | else:
371 | score = '0'
372 | dict_data['评分'] = score
373 | # 烂番茄评分 用上面的评分*10
374 | criticrating = str(float(score) * 10)
375 | #######################################################################
376 | # 简介
377 | if settings.bool_nfo:
378 | plotg = re.search(r'md-12">([^<].+?)', html_web)
379 | if str(plotg) != 'None':
380 | plot = plotg.group(1)
381 | else:
382 | plot = ''
383 | plot = title_only + plot
384 | if settings.bool_tran:
385 | plot = translate(tran_id, tran_sk, plot, to_language)
386 | if plot.startswith('【百度'):
387 | num_fail += 1
388 | record_fail(' >第' + str(num_fail) + '个失败!翻译简介失败:' + path_relative + '\n')
389 | plot = replace_xml(plot)
390 | else:
391 | plot = ''
392 | # print(plot)
393 | #######################################################################
394 | dict_data['视频'] = dict_data['原文件名'] = jav.name_no_ext # dict_data['视频'],先定义为原文件名,即将发生变化。
395 | dict_data['原文件夹名'] = jav.folder
396 | # 是CD1还是CDn?
397 | num_all_episodes = dict_car_pref[jav.car] # 该车牌总共多少集
398 | if num_all_episodes > 1:
399 | str_cd = '-cd' + str(jav.episode)
400 | else:
401 | str_cd = ''
402 |
403 | # 1重命名视频【相同】
404 | try:
405 | dict_data, jav, num_temp = rename_mp4(jav, num_fail, settings, dict_data, list_name_video,
406 | path_relative, str_cd)
407 | num_fail = num_temp
408 | except FileExistsError:
409 | num_fail += 1
410 | continue
411 |
412 | # 2 归类影片【相同】只针对视频文件和字幕文件。注意:第2操作和下面(第3操作+第7操作)互斥,只能执行第2操作或(第3操作+第7操作),归类影片是针对“文件”还是“文件夹”。
413 | try:
414 | jav, num_temp = classify_files(jav, num_fail, settings, dict_data, list_classify_basis,
415 | root_classify)
416 | num_fail = num_temp
417 | except FileExistsError:
418 | num_fail += 1
419 | continue
420 |
421 | # 3重命名文件夹【相同】如果是针对“文件”归类,这一步会被跳过。 因为用户只需要归类视频文件,不需要管文件夹。
422 | try:
423 | jav, num_temp = rename_folder(jav, num_fail, settings, dict_data, list_name_folder,
424 | bool_separate_folder, num_all_episodes)
425 | num_fail = num_temp
426 | except FileExistsError:
427 | num_fail += 1
428 | continue
429 |
430 | # 更新一下path_relative
431 | path_relative = sep + jav.path.replace(root_choose, '') # 影片的相对于所选文件夹的路径,用于报错
432 |
433 | # 4写入nfo【独特】
434 | if settings.bool_nfo:
435 | # 如果是为空地准备的nfo,不需要多cd
436 | if settings.bool_cd_only:
437 | path_nfo = jav.root + sep + jav.name_no_ext.replace(str_cd, '') + '.nfo'
438 | else:
439 | path_nfo = jav.root + sep + jav.name_no_ext + '.nfo'
440 | # nfo中tilte的写法
441 | title_in_nfo = ''
442 | for i in list_name_nfo_title:
443 | title_in_nfo += dict_data[i]
444 | # 开始写入nfo,这nfo格式是参考的kodi的nfo
445 | f = open(path_nfo, 'w', encoding="utf-8")
446 | f.write("\n"
447 | "\n"
448 | " " + plot + "\n"
449 | " " + title_in_nfo + "\n"
450 | " " + title + "\n"
451 | " " + score + "\n"
452 | " " + criticrating + "\n"
453 | " " + dict_data['发行年份'] + "\n"
454 | " NC-17\n"
455 | " NC-17\n"
456 | " JP\n"
457 | " " + time_premiered + "\n"
458 | " " + time_premiered + "\n"
459 | " " + dict_data['片长'] + "\n"
460 | " 日本\n"
461 | " " + studio + "\n"
462 | " " + car + "\n"
463 | " " + car + "\n")
464 | # 需要将特征写入genre
465 | if settings.bool_genre:
466 | for i in genres:
467 | f.write(" " + i + "\n")
468 | if settings.bool_write_studio and studio:
469 | f.write(" 片商:" + studio + "\n")
470 | if list_extra_genres:
471 | for i in list_extra_genres:
472 | f.write(" " + dict_data[i] + "\n")
473 | # 需要将特征写入tag
474 | if settings.bool_tag:
475 | for i in genres:
476 | f.write(" " + i + "\n")
477 | if settings.bool_write_studio and studio:
478 | f.write(" 片商:" + studio + "\n")
479 | if list_extra_genres:
480 | for i in list_extra_genres:
481 | f.write(" " + dict_data[i] + "\n")
482 | # 写入演员
483 | f.write(
484 | " \n " + dict_data['首个演员'] + "\n Actor\n \n")
485 | f.write("\n")
486 | f.close()
487 | print(' >nfo收集完成')
488 |
489 | # 5需要两张封面图片【独特】
490 | if settings.bool_jpg:
491 | # 下载海报的地址 cover
492 | # fanart和poster路径
493 | path_fanart = jav.root + sep
494 | path_poster = jav.root + sep
495 | for i in list_name_fanart:
496 | path_fanart += dict_data[i]
497 | for i in list_name_poster:
498 | path_poster += dict_data[i]
499 | # kodi只需要一份图片,图片路径唯一
500 | if settings.bool_cd_only:
501 | path_fanart = path_fanart.replace(str_cd, '')
502 | path_poster = path_poster.replace(str_cd, '')
503 | # emby需要多份,现在不是第一集,直接复制第一集的图片
504 | elif jav.episode != 1:
505 | try:
506 | copyfile(path_fanart.replace(str_cd, '-cd1'), path_fanart)
507 | print(' >fanart.jpg复制成功')
508 | copyfile(path_poster.replace(str_cd, '-cd1'), path_poster)
509 | print(' >poster.jpg复制成功')
510 | except FileNotFoundError:
511 | pass
512 | # kodi或者emby需要的第一份图片
513 | if check_picture(path_fanart):
514 | # print(' >已有fanart.jpg')
515 | pass
516 | else:
517 | # 下载封面
518 | print(' >从jav321下载封面:', url_cover)
519 | try:
520 | download_pic(url_cover, path_fanart, proxy_321)
521 | print(' >fanart.jpg下载成功')
522 | except:
523 | num_fail += 1
524 | record_fail(' >第' + str(
525 | num_fail) + '个失败!下载fanart.jpg失败:' + url_cover + ',' + path_relative + '\n')
526 | continue # 退出对该jav的整理
527 | # 下载海报
528 | if check_picture(path_poster):
529 | # print(' >已有poster.jpg')
530 | pass
531 | elif url_cover == url_poster: # 有些素人片,没有fanart和poster之分,只有一张接近正方形的图片
532 | # 裁剪生成 poster
533 | crop_poster_default(path_fanart, path_poster, 2)
534 | # 需要加上条纹
535 | if settings.bool_watermark_subtitle and bool_subtitle:
536 | add_watermark_subtitle(path_poster)
537 | if settings.bool_watermark_divulge and bool_divulge:
538 | add_watermark_divulge(path_poster)
539 | else:
540 | # 下载poster.jpg
541 | print(' >从jav321下载poster:', url_poster)
542 | try:
543 | download_pic(url_poster, path_poster, proxy_321)
544 | print(' >poster.jpg下载成功')
545 | # 需要加上条纹
546 | if settings.bool_watermark_subtitle and bool_subtitle:
547 | add_watermark_subtitle(path_poster)
548 | if settings.bool_watermark_divulge and bool_divulge:
549 | add_watermark_divulge(path_poster)
550 | except:
551 | num_fail += 1
552 | record_fail(
553 | ' >第' + str(num_fail) + '个失败!poster下载失败:' + url_poster + ',' + path_relative + '\n')
554 | continue
555 |
556 | # 6收集演员头像【相同】
557 |
558 | # 7归类影片,针对文件夹【相同】
559 | try:
560 | num_temp = classify_folder(jav, num_fail, settings, dict_data, list_classify_basis, root_classify,
561 | root, bool_separate_folder, num_all_episodes)
562 | num_fail = num_temp
563 | except FileExistsError:
564 | num_fail += 1
565 | continue
566 |
567 | except:
568 | num_fail += 1
569 | record_fail(' >第' + str(
570 | num_fail) + '个失败!发生错误,如一直在该影片报错请截图并联系作者:' + path_relative + '\n' + format_exc() + '\n')
571 | continue # 【退出对该jav的整理】
572 |
573 | # 完结撒花
574 | print('\n当前文件夹完成,', end='')
575 | if num_fail > 0:
576 | print('失败', num_fail, '个! ', root_choose, '\n')
577 | line = -1
578 | with open('【可删除】失败记录.txt', 'r', encoding="utf-8") as f:
579 | content = list(f)
580 | while 1:
581 | if content[line].startswith('已'):
582 | break
583 | line -= 1
584 | for i in range(line + 1, 0):
585 | print(content[i], end='')
586 | print('\n“【可删除】失败记录.txt”已记录错误\n')
587 | else:
588 | print(' “0”失败! ', root_choose, '\n')
589 | # os.system('pause')
590 | input_start_key = input('回车继续选择文件夹整理:')
591 |
--------------------------------------------------------------------------------
/javsdt/JavbusWuma.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import os, re
3 | from shutil import copyfile
4 | from traceback import format_exc
5 | ########################################################################################################################
6 | from Class.Settings import Settings
7 | from Class.JavFile import JavFile
8 | from Functions.Status import judge_exist_nfo, judge_exist_extra_folders, count_num_videos
9 | from Functions.User import choose_directory
10 | from Functions.Record import record_start, record_fail
11 | from Functions.Process import perfect_dict_data
12 | from Functions.Standard import rename_mp4, rename_folder, classify_files, classify_folder
13 | from Functions.XML import replace_xml_win
14 | from Functions.Process import judge_exist_subtitle
15 | from Functions.Picture import check_picture, add_watermark_subtitle
16 | from Functions.Requests.Download import download_pic
17 | from Functions.Genre import better_dict_genre
18 | # ################################################## 不同 ##########################################################
19 | from Functions.Status import check_actors
20 | from Functions.Car import find_car_wuma, list_suren_car
21 | from Functions.Standard import collect_sculpture
22 | from Functions.Picture import crop_poster_baidu, crop_poster_default
23 | from Functions.Requests.JavbusReq import get_bus_html
24 |
25 |
26 | # main开始
27 | print('1、避开21:00-1:00,访问javbus很慢\n'
28 | '2、若一直连不上javbus,请在ini中更新防屏蔽网址\n'
29 | '3、找不到AV信息,请在javbus上确认,再修改本地视频文件名,如:\n'
30 | ' 1)多余的字母数字:[JAV] [Uncensored] HEYZO 2171 [1080p].mp4 => HEYZO 2171.mp4\n'
31 | ' 112314-742-carib-1080p.mp4 => 112314-742.mp4\n'
32 | ' Heyzo_HD_0733_full.mp4 => Heyzo_0733.mp4\n'
33 | ' 2)多余的横杠:sr-131.mp4 => sr131.mp4\n'
34 | ' 3)干扰车牌的分集:Heyzo_0733_01.mp4 => Heyzo_0733啊.mp4\n'
35 | ' Heyzo_0733_02.mp4 => Heyzo_0733吧.mp4\n')
36 |
37 | # 读取配置文件,这个ini文件用来给用户设置
38 | print('正在读取ini中的设置...', end='')
39 | try:
40 | settings = Settings('无码')
41 | except:
42 | settings = None
43 | print(format_exc())
44 | print('\n无法读取ini文件,请修改它为正确格式,或者打开“【ini】重新创建ini.exe”创建全新的ini!')
45 | os.system('pause')
46 | print('\n读取ini文件成功!\n')
47 |
48 | # 路径分隔符:当前系统的路径分隔符 windows是“\”,linux和mac是“/”
49 | sep = os.sep
50 |
51 | # 检查头像:如果需要为kodi整理头像,先检查演员头像ini、头像文件夹是否存在。
52 | check_actors(settings.bool_sculpture)
53 |
54 | # 局部代理:哪些站点需要代理。
55 | proxy_library, proxy_bus, proxy_321, proxy_db, proxy_arzon, proxy_dmm = settings.get_proxy()
56 |
57 | # javbus网址 https://www.buscdn.work/
58 | url_bus = settings.get_url_bus()
59 |
60 | # 选择简繁中文以及百度翻译账户:需要简体中文还是繁体中文,影响影片特征和简介。
61 | to_language, tran_id, tran_sk = settings.get_translate_account()
62 |
63 | # 信息字典:存放影片信息,用于给用户自定义各种命名。
64 | dict_data = {'车牌': 'CBA-123',
65 | '车牌前缀': 'CBA',
66 | '标题': '无码标题',
67 | '完整标题': '完整无码标题',
68 | '导演': '无码导演',
69 | '片商': '无码片商',
70 | '评分': '0',
71 | '片长': '0',
72 | '系列': '无码系列',
73 | '发行年月日': '1970-01-01', '发行年份': '1970', '月': '01', '日': '01',
74 | '首个演员': '无码演员', '全部演员': '无码演员',
75 | '空格': ' ',
76 | '\\': sep, '/': sep, # 文件路径分隔符
77 | '是否中字': '',
78 | '是否流出': '',
79 | '影片类型': settings.av_type(),
80 | '视频': 'CBA-123', # 当前及未来的视频文件名,不带ext
81 | '原文件名': 'CBA-123', '原文件夹名': 'CBA-123', }
82 |
83 | # nfo中title的写法。
84 | list_name_nfo_title = settings.formula_name_nfo_title()
85 | # 额外将哪些元素放入特征中
86 | list_extra_genres = settings.list_extra_genre()
87 | # 重命名视频的格式
88 | list_name_video = settings.formula_rename_video()
89 | # 重命名文件夹的格式
90 | list_name_folder = settings.formula_rename_folder()
91 |
92 | # fanart的格式
93 | list_name_fanart = settings.formula_name_fanart()
94 | # poster的格式
95 | list_name_poster = settings.formula_name_poster()
96 |
97 | # 视频文件名包含哪些多余的字母数字,需要无视
98 | list_surplus_words_in_filename = settings.list_surplus_word_in_filename('无码')
99 | # 文件名包含哪些特殊含义的文字,判断是否中字
100 | list_subtitle_words_in_filename = settings.list_subtitle_word_in_filename()
101 |
102 | # 素人番号:得到事先设置的素人番号,让程序能跳过它们
103 | list_suren_cars = list_suren_car()
104 |
105 | # 需要扫描的文件的类型
106 | tuple_video_types = settings.tuple_video_type()
107 |
108 | # 完善dict_data,如果用户自定义了一些文字,不在元素中,需要将它们添加进dict_data;list_classify_basis,归类标准,归类目标文件夹的组成公式。
109 | dict_data, list_classify_basis = perfect_dict_data(list_extra_genres, list_name_video, list_name_folder,
110 | list_name_nfo_title, list_name_fanart, list_name_poster,
111 | settings.custom_classify_basis(), dict_data)
112 |
113 | # 准备工作:使用人体分析,与百度al建立联系
114 | client = settings.start_body_analysis()
115 |
116 | # 优化特征的字典
117 | dict_genre = better_dict_genre('Javbus无码', to_language)
118 |
119 | # 用户输入“回车”就继续选择文件夹整理
120 | input_start_key = ''
121 | while input_start_key == '':
122 | # 用户:选择需要整理的文件夹
123 | print('请选择要整理的文件夹:', end='')
124 | root_choose = choose_directory()
125 | print(root_choose)
126 | # 日志:在txt中记录一下用户的这次操作,在某个时间选择了某个文件夹
127 | record_start(root_choose)
128 | # 归类:用户自定义的归类根目录,如果不需要归类则为空
129 | root_classify = settings.check_classify_root(root_choose, sep)
130 | # 计数:失败次数及进度
131 | num_fail = 0 # 已经或可能导致致命错误,比如整理未完成,同车牌有不同视频
132 | num_all_videos = count_num_videos(root_choose, tuple_video_types) # 所选文件夹总共有多少个视频文件
133 | num_current = 0 # 当前视频的编号
134 | print('...文件扫描开始...如果时间过长...请避开夜晚高峰期...\n')
135 | # root【当前根目录】 dirs【子文件夹】 files【文件】,root是str,后两个是list
136 | for root, dirs, files in os.walk(root_choose):
137 | # 什么文件都没有
138 | if not files:
139 | continue
140 | # 当前root是已归类的目录,无需处理
141 | if '归类完成' in root.replace(root_choose, ''):
142 | continue
143 | # 跳过已存在nfo的文件夹,判断这一层文件夹中有没有nfo
144 | if settings.bool_skip and judge_exist_nfo(files):
145 | continue
146 | # 对这一层文件夹进行评估,有多少视频,有多少同车牌视频,是不是独立文件夹
147 | list_jav_struct = [] # 存放:需要整理的jav的结构体
148 | dict_car_pref = {} # 存放:每一车牌的集数, 例如{'abp-123': 1, avop-789': 2}是指 abp-123只有一集,avop-789有cd1、cd2
149 | num_videos_include = 0 # 计数:当前文件夹中视频的数量,可能有视频不是jav
150 | dict_subtitle_files = {} # 存放:jav的字幕文件和车牌对应关系 {'c:\a\abc_123.srt': 'abc-123'}
151 | # 判断文件是不是字幕文件,放入dict_subtitle_files中
152 | for file_raw in files:
153 | file_temp = file_raw.upper()
154 | if file_temp.endswith(('.SRT', '.VTT', '.ASS', '.SSA', '.SUB', '.SMI',)):
155 | # 当前模式不处理FC2
156 | if 'FC2' in file_temp:
157 | continue
158 | # 去除用户设置的、干扰车牌的文字
159 | for word in list_surplus_words_in_filename:
160 | file_temp = file_temp.replace(word, '')
161 | # 得到字幕文件名中的车牌
162 | subtitle_car = find_car_wuma(file_temp, list_suren_cars)
163 | # 将该字幕文件和其中的车牌对应到dict_subtitle_files中
164 | if subtitle_car:
165 | dict_subtitle_files[file_raw] = subtitle_car
166 | # print(dict_subtitle_files)
167 | # 判断文件是不是视频,放入list_jav_struct中
168 | for file_raw in files:
169 | file_temp = file_raw.upper()
170 | if file_temp.endswith(tuple_video_types) and not file_temp.startswith('.'):
171 | num_videos_include += 1
172 | num_current += 1
173 | if 'FC2' in file_temp:
174 | continue
175 | for word in list_surplus_words_in_filename:
176 | file_temp = file_temp.replace(word, '')
177 | # 得到视频中的车牌
178 | car = find_car_wuma(file_temp, list_suren_cars)
179 | if car:
180 | try:
181 | dict_car_pref[car] += 1 # 已经有这个车牌了,加一集cd
182 | except KeyError:
183 | dict_car_pref[car] = 1 # 这个新车牌有了第一集
184 | # 这个车牌在dict_subtitle_files中,有它的字幕。
185 | if car in dict_subtitle_files.values():
186 | subtitle_file = list(dict_subtitle_files.keys())[list(dict_subtitle_files.values()).index(car)]
187 | del dict_subtitle_files[subtitle_file]
188 | else:
189 | subtitle_file = ''
190 | # 将该jav的各种属性打包好,包括原文件名带扩展名、所在文件夹路径、第几集、所属字幕文件名
191 | jav_struct = JavFile(file_raw, root, car, dict_car_pref[car], subtitle_file, num_current)
192 | list_jav_struct.append(jav_struct)
193 | else:
194 | print('>>无法处理:', root.replace(root_choose, '') + sep + file_raw)
195 |
196 | # 判定影片所在文件夹是否是独立文件夹,独立文件夹是指该文件夹仅用来存放该影片,而不是大杂烩文件夹
197 | # 这一层文件夹下有jav
198 | if dict_car_pref:
199 | # 当前文件夹下,车牌不止一个;还有其他非jav视频;有其他文件夹,除了演员头像文件夹“.actors”和额外剧照文件夹“extrafanart”;
200 | if len(dict_car_pref) > 1 or num_videos_include > len(list_jav_struct) or judge_exist_extra_folders(dirs):
201 | bool_separate_folder = False # 不是独立的文件夹
202 | else:
203 | bool_separate_folder = True # 这一层文件夹是这部jav的独立文件夹
204 | else:
205 | continue
206 |
207 | # 开始处理每一部jav
208 | for jav in list_jav_struct:
209 | # 告诉用户进度
210 | print('>> [' + str(jav.number) + '/' + str(num_all_videos) + ']:', jav.name)
211 | print(' >发现车牌:', jav.car)
212 |
213 | # 判断是否有中字的特征,条件有三满足其一即可:1有外挂字幕 2文件名中含有“-C”之类的字眼 3旧的nfo中已经记录了它的中字特征
214 | if jav.subtitle:
215 | bool_subtitle = True # 判定成功
216 | dict_data['是否中字'] = settings.custom_subtitle_expression # '是否中字'这一命名元素被激活
217 | else:
218 | bool_subtitle = judge_exist_subtitle(root, jav.name_no_ext, list_subtitle_words_in_filename)
219 | dict_data['是否中字'] = settings.custom_subtitle_expression if bool_subtitle else ''
220 |
221 | # 影片的相对于所选文件夹的路径,用于报错
222 | path_relative = sep + jav.path.replace(root_choose, '')
223 |
224 | # 获取nfo信息的javbus网页
225 | try:
226 | # 用户指定了网址,则直接得到jav所在网址
227 | if '公交车' in jav.name:
228 | url_appointg = re.search(r'公交车(.+?)\.', jav.name)
229 | if str(url_appointg) != 'None':
230 | url_on_web = url_bus + url_appointg.group(1)
231 | else:
232 | num_fail += 1
233 | record_fail(' >第' + str(num_fail) + '个失败!你指定的javbus网址有错误:' + path_relative + '\n')
234 | continue # 【退出对该jav的整理】
235 | # 用户没有指定网址,则去搜索
236 | else:
237 | url_search_web = url_bus + 'uncensored/search/' + jav.car.replace('-', '%20').replace('_',
238 | '%20').replace(
239 | ' ', '%20') + '&type=&parent=uc'
240 | print(' >搜索车牌:', url_search_web)
241 | # 得到javbus搜索网页html
242 | html_web = get_bus_html(url_search_web, proxy_bus)
243 | # 尝试找movie-box
244 | list_search_results = re.findall(r'movie-box" href="(.+?)">', html_web) # 匹配处理“标题”
245 | if list_search_results: # 搜索结果页面只有一个box
246 | # print(list_search_results)
247 | # print(' >正在核查搜索结果...')
248 | jav_prefg = re.search(r'([A-Z0-9]+)[-_]?', jav.car)
249 | jav_pref = jav_prefg.group(1) if str(jav_prefg) != 'None' else ''
250 | jav_sufg = re.search(r'[^\d](\d\d+)', jav.car)
251 | jav_suf = jav_sufg.group(1).lstrip('0') if str(jav_sufg) != 'None' else ''
252 | # print(jav_pref, jav_suf)
253 | list_fit_results = [] # 存放,车牌符合的结果
254 | for i in list_search_results:
255 | url_end = i.split('/')[-1].upper()
256 | url_sufg = re.search(r'[^\d](\d\d+)', url_end)
257 | url_suf = url_sufg.group(1).lstrip('0') if str(
258 | url_sufg) != 'None' else '' # 匹配box上影片url,车牌的后缀数字,去除多余的0
259 | # print(url_end, url_suf)
260 | if jav_suf == url_suf: # 数字相同
261 | url_prefg = re.search(r'([A-Z0-9]+)[-_]?', url_end)
262 | url_pref = url_prefg.group(1).upper() if str(url_prefg) != 'None' else ''
263 | if jav_pref == url_pref: # 数字相同的基础下,字母也相同,即可能车牌相同
264 | list_fit_results.append(i)
265 | # 无码搜索的结果一个都匹配不上
266 | if not list_fit_results:
267 | num_fail += 1
268 | record_fail(' >第' + str(
269 | num_fail) + '个失败!javbus无码找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
270 | continue # 【退出对该jav的整理】
271 | # 默认用第一个搜索结果
272 | url_on_web = list_fit_results[0]
273 | # print('最终链接:', url_on_web)
274 | # print('最终list:', list_fit_results)
275 | if len(list_fit_results) > 1:
276 | num_fail += 1
277 | record_fail(' >第' + str(
278 | num_fail) + '个警告!javbus搜索到同车牌的不同视频:' + jav.car + ',' + path_relative + '\n')
279 | # 找不到box
280 | else:
281 | num_fail += 1
282 | record_fail(' >第' + str(
283 | num_fail) + '个失败!javbus无码找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
284 | continue # 【跳出对该jav的整理】
285 | # 经过上面的三种情况,可能找到了jav在bus上的网页链接url_on_web
286 | print(' >获取信息:', url_on_web)
287 | # 得到最终的jav所在网页
288 | html_web = get_bus_html(url_on_web, proxy_bus)
289 |
290 | # 开始匹配信息
291 | # 有大部分信息的html_web
292 | html_web = re.search(r'(h3>[\s\S]*?)磁力連結投稿', html_web, re.DOTALL).group(1)
293 | # 标题
294 | title = re.search(r'h3>(.+?)
\/:*?"<>|
296 | title = replace_xml_win(title)
297 | print(' >影片标题:', title)
298 | # 正则匹配 影片信息 开始!
299 | # title的开头是车牌号,想要后面的纯标题
300 | car_titleg = re.search(r'(.+?) (.+)', title)
301 | # 车牌号
302 | dict_data['车牌'] = car = car_titleg.group(1)
303 | dict_data['车牌前缀'] = car.split('-')[0]
304 | # 给用户重命名用的标题是“短标题”,nfo中是“完整标题”,但用户在ini中只用写“标题”
305 | title_only = car_titleg.group(2)
306 | # DVD封面cover
307 | coverg = re.search(r'bigImage" href="(.+?)">', html_web) # 封面图片的正则对象
308 | if str(coverg) != 'None':
309 | url_cover = coverg.group(1)
310 | else:
311 | url_cover = ''
312 | # 发行日期
313 | premieredg = re.search(r'發行日期: (.+?)', html_web)
314 | if str(premieredg) != 'None':
315 | dict_data['发行年月日'] = time_premiered = premieredg.group(1)
316 | dict_data['发行年份'] = time_premiered[0:4]
317 | dict_data['月'] = time_premiered[5:7]
318 | dict_data['日'] = time_premiered[8:10]
319 | else:
320 | dict_data['发行年月日'] = time_premiered = '1970-01-01'
321 | dict_data['发行年份'] = '1970'
322 | dict_data['月'] = '01'
323 | dict_data['日'] = '01'
324 | # 片长 150 分钟 |
325 | runtimeg = re.search(r'長度: (.+?)分鐘', html_web)
326 | if str(runtimeg) != 'None':
327 | dict_data['片长'] = runtimeg.group(1)
328 | else:
329 | dict_data['片长'] = '0'
330 | # 导演
331 | directorg = re.search(r'導演: (.+?)<', html_web)
332 | if str(directorg) != 'None':
333 | dict_data['导演'] = replace_xml_win(directorg.group(1))
334 | else:
335 | dict_data['导演'] = '无码导演'
336 | # 片商 制作商
337 | studiog = re.search(r'製作商: (.+?)', html_web)
338 | if str(studiog) != 'None':
339 | dict_data['片商'] = studio = replace_xml_win(studiog.group(1))
340 | else:
341 | dict_data['片商'] = '有码片商'
342 | studio = ''
343 | # 系列: 悪質シロウトナンパ
344 | seriesg = re.search(r'系列: (.+?)', html_web) # 封面图片的正则对象
345 | if str(seriesg) != 'None':
346 | dict_data['系列'] = series = seriesg.group(1).replace(sep, '#')
347 | else:
348 | dict_data['系列'] = '无码系列'
349 | series = ''
350 | # 演员们 和 # 第一个演员
351 | actors = re.findall(r'star/.+?">
', html_web)
352 | if actors:
353 | if len(actors) > 7:
354 | dict_data['全部演员'] = ' '.join(actors[:7])
355 | else:
356 | dict_data['全部演员'] = ' '.join(actors)
357 | dict_data['首个演员'] = actors[0]
358 | # 有些用户需要删去 标题 末尾可能存在的 演员姓名
359 | if settings.bool_strip_actors and title_only.endswith(dict_data['全部演员']):
360 | title_only = title_only[:-len(dict_data['全部演员'])].rstrip()
361 | else:
362 | actors = ['有码演员']
363 | dict_data['首个演员'] = dict_data['全部演员'] = '无码演员'
364 | # 处理影片的标题过长
365 | dict_data['完整标题'] = title_only
366 | if len(title_only) > settings.int_title_len:
367 | dict_data['标题'] = title_only[:settings.int_title_len]
368 | else:
369 | dict_data['标题'] = title_only
370 | # 特点
371 | genres = re.findall(r'genre">', html_web)
372 | if bool_subtitle: # 有“中字“,加上特征”中文字幕”
373 | genres.append('中文字幕')
374 | try:
375 | genres = [dict_genre[i] for i in genres if dict_genre[i] != '删除']
376 | except KeyError as error:
377 | num_fail += 1
378 | record_fail(' >第' + str(num_fail) + '个失败!发现新的特征需要添加至【特征对照表】:' + str(error) + '\n')
379 | continue
380 | # print(genres)
381 | #######################################################################
382 | dict_data['视频'] = dict_data['原文件名'] = jav.name_no_ext # dict_data['视频'],先定义为原文件名,即将发生变化。
383 | dict_data['原文件夹名'] = jav.folder
384 | # 是CD1还是CDn?
385 | num_all_episodes = dict_car_pref[jav.car] # 该车牌总共多少集
386 | if num_all_episodes > 1:
387 | str_cd = '-cd' + str(jav.episode)
388 | else:
389 | str_cd = ''
390 |
391 | # 1重命名视频【相同】
392 | try:
393 | dict_data, jav, num_temp = rename_mp4(jav, num_fail, settings, dict_data, list_name_video,
394 | path_relative, str_cd)
395 | num_fail = num_temp
396 | except FileExistsError:
397 | num_fail += 1
398 | continue
399 |
400 | # 2 归类影片【相同】只针对视频文件和字幕文件。注意:第2操作和下面(第3操作+第7操作)互斥,只能执行第2操作或(第3操作+第7操作),归类影片是针对“文件”还是“文件夹”。
401 | try:
402 | jav, num_temp = classify_files(jav, num_fail, settings, dict_data, list_classify_basis,
403 | root_classify)
404 | num_fail = num_temp
405 | except FileExistsError:
406 | num_fail += 1
407 | continue
408 |
409 | # 3重命名文件夹【相同】如果是针对“文件”归类,这一步会被跳过。 因为用户只需要归类视频文件,不需要管文件夹。
410 | try:
411 | jav, num_temp = rename_folder(jav, num_fail, settings, dict_data, list_name_folder,
412 | bool_separate_folder, num_all_episodes)
413 | num_fail = num_temp
414 | except FileExistsError:
415 | num_fail += 1
416 | continue
417 |
418 | # 更新一下path_relative
419 | path_relative = sep + jav.path.replace(root_choose, '') # 影片的相对于所选文件夹的路径,用于报错
420 |
421 | # 4写入nfo【独特】
422 | if settings.bool_nfo:
423 | if settings.bool_cd_only:
424 | path_nfo = jav.root + sep + jav.name_no_ext.replace(str_cd, '') + '.nfo'
425 | else:
426 | path_nfo = jav.root + sep + jav.name_no_ext + '.nfo'
427 | title_in_nfo = ''
428 | for i in list_name_nfo_title:
429 | title_in_nfo += dict_data[i] # nfo中tilte的写法
430 | # 开始写入nfo,这nfo格式是参考的kodi的nfo
431 | f = open(path_nfo, 'w', encoding="utf-8")
432 | f.write("\n"
433 | "\n"
434 | " " + title_in_nfo + "\n"
435 | " " + title + "\n"
436 | " " + dict_data['导演'] + "\n"
437 | " " + dict_data['发行年份'] + "\n"
438 | " NC-17\n"
439 | " NC-17\n"
440 | " JP\n"
441 | " " + time_premiered + "\n"
442 | " " + time_premiered + "\n"
443 | " " + dict_data['片长'] + "\n"
444 | " 日本\n"
445 | " " + studio + "\n"
446 | " " + car + "\n"
447 | " " + car + "\n"
448 | " " + series + "\n") # emby不管set系列,kodi可以
449 | # 需要将特征写入genre
450 | if settings.bool_genre:
451 | for i in genres:
452 | f.write(" " + i + "\n")
453 | if settings.bool_write_series and series:
454 | f.write(" 系列:" + series + "\n")
455 | if settings.bool_write_studio and studio:
456 | f.write(" 片商:" + studio + "\n")
457 | if list_extra_genres:
458 | for i in list_extra_genres:
459 | f.write(" " + dict_data[i] + "\n")
460 | # 需要将特征写入tag
461 | if settings.bool_tag:
462 | for i in genres:
463 | f.write(" " + i + "\n")
464 | if settings.bool_write_series and series:
465 | f.write(" 系列:" + series + "\n")
466 | if settings.bool_write_studio and studio:
467 | f.write(" 片商:" + studio + "\n")
468 | if list_extra_genres:
469 | for i in list_extra_genres:
470 | f.write(" " + dict_data[i] + "\n")
471 | # 写入演员
472 | for i in actors:
473 | f.write(" \n " + i + "\n Actor\n \n")
474 | f.write("\n")
475 | f.close()
476 | print(' >nfo收集完成')
477 |
478 | # 5需要两张封面图片【独特】
479 | if settings.bool_jpg:
480 | # fanart和poster路径
481 | path_fanart = jav.root + sep
482 | path_poster = jav.root + sep
483 | for i in list_name_fanart:
484 | path_fanart += dict_data[i]
485 | for i in list_name_poster:
486 | path_poster += dict_data[i]
487 | # print(path_fanart)
488 | # kodi只需要一份图片,图片路径唯一
489 | if settings.bool_cd_only:
490 | path_fanart = path_fanart.replace(str_cd, '')
491 | path_poster = path_poster.replace(str_cd, '')
492 | # emby需要多份,现在不是第一集,直接复制第一集的图片
493 | elif jav.episode != 1:
494 | try:
495 | copyfile(path_fanart.replace(str_cd, '-cd1'), path_fanart)
496 | print(' >fanart.jpg复制成功')
497 | copyfile(path_poster.replace(str_cd, '-cd1'), path_poster)
498 | print(' >poster.jpg复制成功')
499 | except FileNotFoundError:
500 | pass
501 | # kodi或者emby需要的第一份图片
502 | if check_picture(path_fanart):
503 | # print(' >已有fanart.jpg')
504 | pass
505 | else:
506 | # 下载封面
507 | print(' >从javbus下载封面:', url_cover)
508 | try:
509 | download_pic(url_cover, path_fanart, proxy_bus)
510 | print(' >fanart.jpg下载成功')
511 | except:
512 | num_fail += 1
513 | record_fail(' >第' + str(
514 | num_fail) + '个失败!下载fanart.jpg失败:' + url_cover + ',' + path_relative + '\n')
515 | continue # 退出对该jav的整理
516 | # 裁剪生成 poster
517 | if check_picture(path_poster):
518 | # print(' >已有poster.jpg')
519 | pass
520 | elif settings.bool_face:
521 | crop_poster_baidu(path_fanart, path_poster, client)
522 | # 需要加上条纹
523 | if settings.bool_watermark_subtitle and bool_subtitle:
524 | add_watermark_subtitle(path_poster)
525 | else:
526 | crop_poster_default(path_fanart, path_poster, 1)
527 | if settings.bool_watermark_subtitle and bool_subtitle:
528 | add_watermark_subtitle(path_poster)
529 |
530 | # 6收集演员头像【相同】
531 | if settings.bool_sculpture and jav.episode == 1:
532 | if actors[0] == '有码演员':
533 | print(' >未知演员,无法收集头像')
534 | else:
535 | collect_sculpture(actors, jav.root)
536 |
537 | # 7归类影片,针对文件夹【相同】
538 | try:
539 | num_temp = classify_folder(jav, num_fail, settings, dict_data, list_classify_basis, root_classify,
540 | root, bool_separate_folder, num_all_episodes)
541 | num_fail = num_temp
542 | except FileExistsError:
543 | num_fail += 1
544 | continue
545 |
546 | except:
547 | num_fail += 1
548 | record_fail(' >第' + str(
549 | num_fail) + '个失败!发生错误,如一直在该影片报错请截图并联系作者:' + path_relative + '\n' + format_exc() + '\n')
550 | continue # 【退出对该jav的整理】
551 |
552 | # 完结撒花
553 | print('\n当前文件夹完成,', end='')
554 | if num_fail > 0:
555 | print('失败', num_fail, '个! ', root_choose, '\n')
556 | line = -1
557 | with open('【可删除】失败记录.txt', 'r', encoding="utf-8") as f:
558 | content = list(f)
559 | while 1:
560 | if content[line].startswith('已'):
561 | break
562 | line -= 1
563 | for i in range(line + 1, 0):
564 | print(content[i], end='')
565 | print('\n“【可删除】失败记录.txt”已记录错误\n')
566 | else:
567 | print(' “0”失败! ', root_choose, '\n')
568 | # os.system('pause')
569 | input_start_key = input('回车继续选择文件夹整理:')
570 |
--------------------------------------------------------------------------------
/javsdt/JavbusYouma.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import os, re
3 | from shutil import copyfile
4 | from traceback import format_exc
5 | ########################################################################################################################
6 | from Class.Settings import Settings
7 | from Class.JavFile import JavFile
8 | from Functions.Status import judge_exist_nfo, judge_exist_extra_folders, count_num_videos
9 | from Functions.User import choose_directory
10 | from Functions.Record import record_start, record_fail, record_warn
11 | from Functions.Process import perfect_dict_data
12 | from Functions.Standard import rename_mp4, rename_folder, classify_files, classify_folder
13 | from Functions.XML import replace_xml, replace_xml_win
14 | from Functions.Process import judge_exist_subtitle
15 | from Functions.Picture import check_picture, add_watermark_subtitle
16 | from Functions.Requests.Download import download_pic
17 | from Functions.Genre import better_dict_genre
18 | # ################################################## 不同 ##########################################################
19 | from Functions.Process import judge_exist_divulge
20 | from Functions.Status import check_actors
21 | from Functions.Car import find_car_bus, list_suren_car
22 | from Functions.Standard import collect_sculpture
23 | from Functions.Baidu import translate
24 | from Functions.Picture import add_watermark_divulge, crop_poster_youma
25 | from Functions.Requests.JavbusReq import get_bus_html
26 | from Functions.Requests.ArzonReq import steal_arzon_cookies, find_plot_arzon
27 |
28 |
29 | # main开始
30 | print('1、避开21:00-1:00,访问javbus和arzon很慢。\n'
31 | '2、若一直打不开javbus,请在ini中更新防屏蔽网址\n')
32 |
33 | # 读取配置文件,这个ini文件用来给用户设置
34 | print('正在读取ini中的设置...', end='')
35 | try:
36 | settings = Settings('有码')
37 | except:
38 | settings = None
39 | print(format_exc())
40 | print('\n无法读取ini文件,请修改它为正确格式,或者打开“【ini】重新创建ini.exe”创建全新的ini!')
41 | os.system('pause')
42 | print('\n读取ini文件成功!\n')
43 |
44 |
45 | # 路径分隔符:当前系统的路径分隔符 windows是“\”,linux和mac是“/”
46 | sep = os.sep
47 |
48 | # 检查头像:如果需要为kodi整理头像,先检查演员头像ini、头像文件夹是否存在。
49 | check_actors(settings.bool_sculpture)
50 |
51 | # 局部代理:哪些站点需要代理。
52 | proxy_library, proxy_bus, proxy_321, proxy_db, proxy_arzon, proxy_dmm = settings.get_proxy()
53 |
54 | # arzon通行证:如果需要在nfo中写入日语简介,需要先获得合法的arzon网站的cookie,用于通过成人验证。
55 | cookie_arzon = steal_arzon_cookies(proxy_arzon) if settings.bool_plot and settings.bool_nfo else {}
56 |
57 | # javbus网址 https://www.buscdn.work/
58 | url_bus = settings.get_url_bus()
59 |
60 | # 选择简繁中文以及百度翻译账户:需要简体中文还是繁体中文,影响影片特征和简介。
61 | to_language, tran_id, tran_sk = settings.get_translate_account()
62 |
63 | # 信息字典:存放影片信息,用于给用户自定义各种命名。
64 | dict_data = {'车牌': 'ABC-123',
65 | '车牌前缀': 'ABC',
66 | '标题': '有码标题',
67 | '完整标题': '完整有码标题',
68 | '导演': '有码导演',
69 | '片商': '有码片商',
70 | '评分': '0',
71 | '片长': '0',
72 | '系列': '有码系列',
73 | '发行年月日': '1970-01-01', '发行年份': '1970', '月': '01', '日': '01',
74 | '首个演员': '有码演员', '全部演员': '有码演员',
75 | '空格': ' ',
76 | '\\': sep, '/': sep, # 文件路径分隔符
77 | '是否中字': '',
78 | '是否流出': '',
79 | '影片类型': settings.av_type(),
80 | '视频': 'ABC-123', # 当前及未来的视频文件名,不带ext
81 | '原文件名': 'ABC-123', '原文件夹名': 'ABC-123', }
82 |
83 | # nfo中title的写法。
84 | list_name_nfo_title = settings.formula_name_nfo_title()
85 | # 额外将哪些元素放入特征中
86 | list_extra_genres = settings.list_extra_genre()
87 | # 重命名视频的格式
88 | list_name_video = settings.formula_rename_video()
89 | # 重命名文件夹的格式
90 | list_name_folder = settings.formula_rename_folder()
91 |
92 | # fanart的格式
93 | list_name_fanart = settings.formula_name_fanart()
94 | # poster的格式
95 | list_name_poster = settings.formula_name_poster()
96 |
97 | # 视频文件名包含哪些多余的字母数字,需要无视
98 | list_surplus_words_in_filename = settings.list_surplus_word_in_filename('有码')
99 | # 文件名包含哪些特殊含义的文字,判断是否中字
100 | list_subtitle_words_in_filename = settings.list_subtitle_word_in_filename()
101 | # 文件名包含哪些特殊含义的文字,判断是否是无码流出片
102 | list_divulge_words_in_filename = settings.list_divulge_word_in_filename()
103 |
104 | # 素人番号:得到事先设置的素人番号,让程序能跳过它们
105 | list_suren_cars = list_suren_car()
106 |
107 | # 需要扫描的文件的类型
108 | tuple_video_types = settings.tuple_video_type()
109 |
110 | # 完善dict_data,如果用户自定义了一些文字,不在元素中,需要将它们添加进dict_data;list_classify_basis,归类标准,归类目标文件夹的组成公式。
111 | dict_data, list_classify_basis = perfect_dict_data(list_extra_genres, list_name_video, list_name_folder, list_name_nfo_title, list_name_fanart, list_name_poster, settings.custom_classify_basis(), dict_data)
112 |
113 | # 优化特征的字典
114 | dict_genre = better_dict_genre('Javbus有码', to_language)
115 |
116 | # 用户输入“回车”就继续选择文件夹整理
117 | input_start_key = ''
118 | while input_start_key == '':
119 | # 用户:选择需要整理的文件夹
120 | print('请选择要整理的文件夹:', end='')
121 | root_choose = choose_directory()
122 | print(root_choose)
123 | # 日志:在txt中记录一下用户的这次操作,在某个时间选择了某个文件夹
124 | record_start(root_choose)
125 | # 归类:用户自定义的归类根目录,如果不需要归类则为空
126 | root_classify = settings.check_classify_root(root_choose, sep)
127 | # 计数:失败次数及进度
128 | num_fail = 0 # 已经或可能导致致命错误,比如整理未完成,同车牌有不同视频
129 | num_warn = 0 # 对整理结果不致命的问题,比如找不到简介
130 | num_all_videos = count_num_videos(root_choose, tuple_video_types) # 所选文件夹总共有多少个视频文件
131 | num_current = 0 # 当前视频的编号
132 | print('...文件扫描开始...如果时间过长...请避开夜晚高峰期...\n')
133 | # root【当前根目录】 dirs【子文件夹】 files【文件】,root是str,后两个是list
134 | for root, dirs, files in os.walk(root_choose):
135 | # 什么文件都没有
136 | if not files:
137 | continue
138 | # 当前root是已归类的目录,无需处理
139 | if '归类完成' in root.replace(root_choose, ''):
140 | continue
141 | # 跳过已存在nfo的文件夹,判断这一层文件夹中有没有nfo
142 | if settings.bool_skip and judge_exist_nfo(files):
143 | continue
144 | # 对这一层文件夹进行评估,有多少视频,有多少同车牌视频,是不是独立文件夹
145 | list_jav_struct = [] # 存放:需要整理的jav的结构体
146 | dict_car_pref = {} # 存放:每一车牌的集数, 例如{'abp-123': 1, avop-789': 2}是指 abp-123只有一集,avop-789有cd1、cd2
147 | num_videos_include = 0 # 计数:当前文件夹中视频的数量,可能有视频不是jav
148 | dict_subtitle_files = {} # 存放:jav的字幕文件和车牌对应关系 {'c:\a\abc_123.srt': 'abc-123'}
149 | # 判断文件是不是字幕文件,放入dict_subtitle_files中
150 | for file_raw in files:
151 | file_temp = file_raw.upper()
152 | if file_temp.endswith(('.SRT', '.VTT', '.ASS', '.SSA', '.SUB', '.SMI',)):
153 | # 当前模式不处理FC2
154 | if 'FC2' in file_temp:
155 | continue
156 | # 去除用户设置的、干扰车牌的文字
157 | for word in list_surplus_words_in_filename:
158 | file_temp = file_temp.replace(word, '')
159 | # 得到字幕文件名中的车牌
160 | subtitle_car = find_car_bus(file_temp, list_suren_cars)
161 | # 将该字幕文件和其中的车牌对应到dict_subtitle_files中
162 | if subtitle_car:
163 | dict_subtitle_files[file_raw] = subtitle_car
164 | # print(dict_subtitle_files)
165 | # 判断文件是不是视频,放入list_jav_struct中
166 | for file_raw in files:
167 | file_temp = file_raw.upper()
168 | if file_temp.endswith(tuple_video_types) and not file_temp.startswith('.'):
169 | num_videos_include += 1
170 | num_current += 1
171 | if 'FC2' in file_temp:
172 | continue
173 | for word in list_surplus_words_in_filename:
174 | file_temp = file_temp.replace(word, '')
175 | # 得到视频中的车牌
176 | car = find_car_bus(file_temp, list_suren_cars)
177 | if car:
178 | try:
179 | dict_car_pref[car] += 1 # 已经有这个车牌了,加一集cd
180 | except KeyError:
181 | dict_car_pref[car] = 1 # 这个新车牌有了第一集
182 | # 这个车牌在dict_subtitle_files中,有它的字幕。
183 | if car in dict_subtitle_files.values():
184 | subtitle_file = list(dict_subtitle_files.keys())[list(dict_subtitle_files.values()).index(car)]
185 | del dict_subtitle_files[subtitle_file]
186 | else:
187 | subtitle_file = ''
188 | # 将该jav的各种属性打包好,包括原文件名带扩展名、所在文件夹路径、第几集、所属字幕文件名
189 | jav_struct = JavFile(file_raw, root, car, dict_car_pref[car], subtitle_file, num_current)
190 | list_jav_struct.append(jav_struct)
191 | else:
192 | print('>>无法处理:', root.replace(root_choose, '') + sep + file_raw)
193 |
194 | # 判定影片所在文件夹是否是独立文件夹,独立文件夹是指该文件夹仅用来存放该影片,而不是大杂烩文件夹
195 | # 这一层文件夹下有jav
196 | if dict_car_pref:
197 | # 当前文件夹下,车牌不止一个;还有其他非jav视频;有其他文件夹,除了演员头像文件夹“.actors”和额外剧照文件夹“extrafanart”;
198 | if len(dict_car_pref) > 1 or num_videos_include > len(list_jav_struct) or judge_exist_extra_folders(dirs):
199 | bool_separate_folder = False # 不是独立的文件夹
200 | else:
201 | bool_separate_folder = True # 这一层文件夹是这部jav的独立文件夹
202 | else:
203 | continue
204 |
205 | # 开始处理每一部jav
206 | for jav in list_jav_struct:
207 | # 告诉用户进度
208 | print('>> [' + str(jav.number) + '/' + str(num_all_videos) + ']:', jav.name)
209 | print(' >发现车牌:', jav.car)
210 |
211 | # 判断是否有中字的特征,条件有三满足其一即可:1有外挂字幕 2文件名中含有“-C”之类的字眼 3旧的nfo中已经记录了它的中字特征
212 | if jav.subtitle:
213 | bool_subtitle = True # 判定成功
214 | dict_data['是否中字'] = settings.custom_subtitle_expression # '是否中字'这一命名元素被激活
215 | else:
216 | bool_subtitle = judge_exist_subtitle(root, jav.name_no_ext, list_subtitle_words_in_filename)
217 | dict_data['是否中字'] = settings.custom_subtitle_expression if bool_subtitle else ''
218 | # 判断是否是无码流出的作品,同理
219 | bool_divulge = judge_exist_divulge(root, jav.name_no_ext, list_divulge_words_in_filename)
220 | dict_data['是否流出'] = settings.custom_divulge_expression if bool_divulge else ''
221 |
222 | # 影片的相对于所选文件夹的路径,用于报错
223 | path_relative = sep + jav.path.replace(root_choose, '')
224 |
225 | # 获取nfo信息的javbus网页
226 | try:
227 | # 用户指定了网址,则直接得到jav所在网址
228 | if '公交车' in jav.name:
229 | url_appointg = re.search(r'公交车(.+?)\.', jav.name)
230 | if str(url_appointg) != 'None':
231 | url_on_web = url_bus + url_appointg.group(1)
232 | else:
233 | num_fail += 1
234 | record_fail(' >第' + str(num_fail) + '个失败!你指定的javbus网址有错误:' + path_relative + '\n')
235 | continue # 【退出对该jav的整理】
236 | # 用户没有指定网址,则去搜索
237 | else:
238 | url_search_web = url_bus + 'search/' + jav.car + '&type=1&parent=ce'
239 | print(' >搜索车牌:', url_search_web)
240 | # 得到javbus搜索网页html
241 | html_web = get_bus_html(url_search_web, proxy_bus)
242 | # 尝试找movie-box
243 | list_search_results = re.findall(r'movie-box" href="(.+?)">', html_web) # 匹配处理“标题”
244 | if list_search_results: # 搜索页面有结果
245 | # print(list_search_results)
246 | # print(' >正在核查搜索结果...')
247 | jav_pref = jav.car.split('-')[0] # 匹配车牌的前缀字母
248 | jav_suf = jav.car.split('-')[-1].lstrip('0') # 当前车牌的后缀数字 去除多余的0
249 | list_fit_results = [] # 存放,车牌符合的结果
250 | for i in list_search_results:
251 | url_end = i.split('/')[-1].upper()
252 | url_suf = re.search(r'[-_](\d+)', url_end).group(1).lstrip('0') # 匹配box上影片url,车牌的后缀数字,去除多余的0
253 | if jav_suf == url_suf: # 数字相同
254 | url_pref = re.search(r'([A-Z0-9]+)[-_]', url_end).group(1).upper() # 匹配处理url所带车牌前面的字母“n”
255 | if jav_pref == url_pref: # 数字相同的基础下,字母也相同,即可能车牌相同
256 | list_fit_results.append(i)
257 | # 有码搜索的结果一个都匹配不上
258 | if not list_fit_results:
259 | num_fail += 1
260 | record_fail(' >第' + str(
261 | num_fail) + '个失败!javbus有码找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
262 | continue # 【跳出对该jav的整理】
263 | # 默认用第一个搜索结果
264 | url_on_web = list_fit_results[0]
265 | if len(list_fit_results) > 1:
266 | num_fail += 1
267 | record_fail(' >第' + str(
268 | num_fail) + '个警告!javbus搜索到同车牌的不同视频:' + jav.car + ',' + path_relative + '\n')
269 | # 找不到box
270 | else:
271 | num_fail += 1
272 | record_fail(' >第' + str(
273 | num_fail) + '个失败!javbus有码找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
274 | continue # 【跳出对该jav的整理】
275 | # 经过上面的三种情况,可能找到了jav在bus上的网页链接url_on_web
276 | print(' >获取信息:', url_on_web)
277 | # 得到最终的jav所在网页
278 | html_web = get_bus_html(url_on_web, proxy_bus)
279 |
280 | # 开始匹配信息
281 | # 有大部分信息的html_web
282 | html_web = re.search(r'(h3>[\s\S]*?)磁力連結投稿', html_web, re.DOTALL).group(1)
283 | # 标题
284 | title = re.search(r'h3>(.+?) \/:*?"<>|
286 | title = replace_xml_win(title)
287 | print(' >影片标题:', title)
288 | # 正则匹配 影片信息 开始!
289 | # title的开头是车牌号,想要后面的纯标题
290 | car_titleg = re.search(r'(.+?) (.+)', title)
291 | # 车牌号
292 | dict_data['车牌'] = car = car_titleg.group(1)
293 | dict_data['车牌前缀'] = car.split('-')[0]
294 | # 给用户重命名用的标题是“短标题”,nfo中是“完整标题”,但用户在ini中只用写“标题”
295 | title_only = car_titleg.group(2)
296 | # DVD封面cover
297 | coverg = re.search(r'bigImage" href="(.+?)">', html_web) # 封面图片的正则对象
298 | if str(coverg) != 'None':
299 | url_cover = url_bus + coverg.group(1)
300 | else:
301 | url_cover = ''
302 | # 发行日期
303 | premieredg = re.search(r'發行日期: (.+?)', html_web)
304 | if str(premieredg) != 'None':
305 | dict_data['发行年月日'] = time_premiered = premieredg.group(1)
306 | dict_data['发行年份'] = time_premiered[0:4]
307 | dict_data['月'] = time_premiered[5:7]
308 | dict_data['日'] = time_premiered[8:10]
309 | else:
310 | dict_data['发行年月日'] = time_premiered = '1970-01-01'
311 | dict_data['发行年份'] = '1970'
312 | dict_data['月'] = '01'
313 | dict_data['日'] = '01'
314 | # 片长 150 分钟 |
315 | runtimeg = re.search(r'長度: (.+?)分鐘', html_web)
316 | if str(runtimeg) != 'None':
317 | dict_data['片长'] = runtimeg.group(1)
318 | else:
319 | dict_data['片长'] = '0'
320 | # 导演
321 | directorg = re.search(r'導演: (.+?)<', html_web)
322 | if str(directorg) != 'None':
323 | dict_data['导演'] = replace_xml_win(directorg.group(1))
324 | else:
325 | dict_data['导演'] = '有码导演'
326 | # 片商 制作商
327 | studiog = re.search(r'製作商: (.+?)', html_web)
328 | if str(studiog) != 'None':
329 | dict_data['片商'] = studio = replace_xml_win(studiog.group(1))
330 | else:
331 | dict_data['片商'] = '有码片商'
332 | studio = ''
333 | # 系列: 悪質シロウトナンパ
334 | seriesg = re.search(r'系列: (.+?)', html_web) # 封面图片的正则对象
335 | if str(seriesg) != 'None':
336 | dict_data['系列'] = series = seriesg.group(1).replace(sep, '#')
337 | else:
338 | dict_data['系列'] = '有码系列'
339 | series = ''
340 | # 演员们 和 # 第一个演员
341 | actors = re.findall(r'star/.+?">
', html_web)
342 | if actors:
343 | if len(actors) > 7:
344 | dict_data['全部演员'] = ' '.join(actors[:7])
345 | else:
346 | dict_data['全部演员'] = ' '.join(actors)
347 | dict_data['首个演员'] = actors[0]
348 | # 有些用户需要删去 标题 末尾可能存在的 演员姓名
349 | if settings.bool_strip_actors and title_only.endswith(dict_data['全部演员']):
350 | title_only = title_only[:-len(dict_data['全部演员'])].rstrip()
351 | else:
352 | actors = ['有码演员']
353 | dict_data['首个演员'] = dict_data['全部演员'] = '有码演员'
354 | # 处理影片的标题过长
355 | dict_data['完整标题'] = title_only
356 | if len(title_only) > settings.int_title_len:
357 | dict_data['标题'] = title_only[:settings.int_title_len]
358 | else:
359 | dict_data['标题'] = title_only
360 | # 特点
361 | genres = re.findall(r'genre">', html_web)
362 | if bool_subtitle: # 有“中字“,加上特征”中文字幕”
363 | genres.append('中文字幕')
364 | if bool_divulge: # 是流出无码片,加上特征'无码流出'
365 | genres.append('无码流出')
366 | try:
367 | genres = [dict_genre[i] for i in genres if dict_genre[i] != '删除']
368 | except KeyError as error:
369 | num_fail += 1
370 | record_fail(' >第' + str(num_fail) + '个失败!发现新的特征需要添加至【特征对照表】:' + str(error) + '\n')
371 | continue
372 | # print(genres)
373 | # arzon的简介 #########################################################
374 | # 去arzon找简介
375 | if settings.bool_nfo and settings.bool_plot and jav.episode == 1:
376 | plot, status_arzon, acook = find_plot_arzon(car, cookie_arzon, proxy_arzon)
377 | if status_arzon == 0:
378 | pass
379 | elif status_arzon == 1:
380 | num_warn += 1
381 | record_warn(' >第' + str(num_warn) + '个失败!找不到简介,尽管arzon上有搜索结果:' + path_relative + '\n')
382 | else:
383 | num_warn += 1
384 | record_warn(' >第' + str(num_warn) + '个失败!找不到简介,影片被arzon下架:' + path_relative + '\n')
385 | # 需要翻译简介
386 | if settings.bool_tran:
387 | plot = translate(tran_id, tran_sk, plot, to_language)
388 | if plot.startswith('【百度'):
389 | num_fail += 1
390 | record_fail(' >第' + str(num_fail) + '个失败!翻译简介失败:' + path_relative + '\n')
391 | # 去除xml文档不允许的特殊字符 &<> \/:*?"<>|
392 | plot = replace_xml(plot)
393 | # print(plot)
394 | else:
395 | plot = ''
396 | #######################################################################
397 | dict_data['视频'] = dict_data['原文件名'] = jav.name_no_ext # dict_data['视频'],先定义为原文件名,即将发生变化。
398 | dict_data['原文件夹名'] = jav.folder
399 | # 是CD1还是CDn?
400 | num_all_episodes = dict_car_pref[jav.car] # 该车牌总共多少集
401 | if num_all_episodes > 1:
402 | str_cd = '-cd' + str(jav.episode)
403 | else:
404 | str_cd = ''
405 |
406 | # 1重命名视频【相同】
407 | try:
408 | dict_data, jav, num_temp = rename_mp4(jav, num_fail, settings, dict_data, list_name_video,
409 | path_relative, str_cd)
410 | num_fail = num_temp
411 | except FileExistsError:
412 | num_fail += 1
413 | continue
414 |
415 | # 2 归类影片【相同】只针对视频文件和字幕文件。注意:第2操作和下面(第3操作+第7操作)互斥,只能执行第2操作或(第3操作+第7操作),归类影片是针对“文件”还是“文件夹”。
416 | try:
417 | jav, num_temp = classify_files(jav, num_fail, settings, dict_data, list_classify_basis,
418 | root_classify)
419 | num_fail = num_temp
420 | except FileExistsError:
421 | num_fail += 1
422 | continue
423 |
424 | # 3重命名文件夹【相同】如果是针对“文件”归类,这一步会被跳过。 因为用户只需要归类视频文件,不需要管文件夹。
425 | try:
426 | jav, num_temp = rename_folder(jav, num_fail, settings, dict_data, list_name_folder,
427 | bool_separate_folder, num_all_episodes)
428 | num_fail = num_temp
429 | except FileExistsError:
430 | num_fail += 1
431 | continue
432 |
433 | # 更新一下path_relative
434 | path_relative = sep + jav.path.replace(root_choose, '') # 影片的相对于所选文件夹的路径,用于报错
435 |
436 | # 4写入nfo【独特】
437 | if settings.bool_nfo:
438 | if settings.bool_cd_only:
439 | path_nfo = jav.root + sep + jav.name_no_ext.replace(str_cd, '') + '.nfo'
440 | else:
441 | path_nfo = jav.root + sep + jav.name_no_ext + '.nfo'
442 | title_in_nfo = ''
443 | for i in list_name_nfo_title:
444 | title_in_nfo += dict_data[i] # nfo中tilte的写法
445 | # 开始写入nfo,这nfo格式是参考的kodi的nfo
446 | f = open(path_nfo, 'w', encoding="utf-8")
447 | f.write("\n"
448 | "\n"
449 | " " + plot + "\n"
450 | " " + title_in_nfo + "\n"
451 | " " + title + "\n"
452 | " " + dict_data['导演'] + "\n"
453 | " " + dict_data['发行年份'] + "\n"
454 | " NC-17\n"
455 | " NC-17\n"
456 | " JP\n"
457 | " " + time_premiered + "\n"
458 | " " + time_premiered + "\n"
459 | " " + dict_data['片长'] + "\n"
460 | " 日本\n"
461 | " " + studio + "\n"
462 | " " + car + "\n"
463 | " " + car + "\n"
464 | " " + series + "\n") # emby不管set系列,kodi可以
465 | # 需要将特征写入genre
466 | if settings.bool_genre:
467 | for i in genres:
468 | f.write(" " + i + "\n")
469 | if settings.bool_write_series and series:
470 | f.write(" 系列:" + series + "\n")
471 | if settings.bool_write_studio and studio:
472 | f.write(" 片商:" + studio + "\n")
473 | if list_extra_genres:
474 | for i in list_extra_genres:
475 | f.write(" " + dict_data[i] + "\n")
476 | # 需要将特征写入tag
477 | if settings.bool_tag:
478 | for i in genres:
479 | f.write(" " + i + "\n")
480 | if settings.bool_write_series and series:
481 | f.write(" 系列:" + series + "\n")
482 | if settings.bool_write_studio and studio:
483 | f.write(" 片商:" + studio + "\n")
484 | if list_extra_genres:
485 | for i in list_extra_genres:
486 | f.write(" " + dict_data[i] + "\n")
487 | # 写入演员
488 | for i in actors:
489 | f.write(" \n " + i + "\n Actor\n \n")
490 | f.write("\n")
491 | f.close()
492 | print(' >nfo收集完成')
493 |
494 | # 5需要两张封面图片【独特】
495 | if settings.bool_jpg:
496 | # fanart和poster路径
497 | path_fanart = jav.root + sep
498 | path_poster = jav.root + sep
499 | for i in list_name_fanart:
500 | path_fanart += dict_data[i]
501 | for i in list_name_poster:
502 | path_poster += dict_data[i]
503 | # print(path_fanart)
504 | # kodi只需要一份图片,图片路径唯一
505 | if settings.bool_cd_only:
506 | path_fanart = path_fanart.replace(str_cd, '')
507 | path_poster = path_poster.replace(str_cd, '')
508 | # emby需要多份,现在不是第一集,直接复制第一集的图片
509 | elif jav.episode != 1:
510 | try:
511 | copyfile(path_fanart.replace(str_cd, '-cd1'), path_fanart)
512 | print(' >fanart.jpg复制成功')
513 | copyfile(path_poster.replace(str_cd, '-cd1'), path_poster)
514 | print(' >poster.jpg复制成功')
515 | except FileNotFoundError:
516 | pass
517 | # kodi或者emby需要的第一份图片
518 | if check_picture(path_fanart):
519 | # print(' >已有fanart.jpg')
520 | pass
521 | else:
522 | # 下载封面
523 | print(' >从javbus下载封面:', url_cover)
524 | try:
525 | download_pic(url_cover, path_fanart, proxy_bus)
526 | print(' >fanart.jpg下载成功')
527 | except:
528 | num_fail += 1
529 | record_fail(' >第' + str(
530 | num_fail) + '个失败!下载fanart.jpg失败:' + url_cover + ',' + path_relative + '\n')
531 | continue # 退出对该jav的整理
532 | # 裁剪生成 poster
533 | if check_picture(path_poster):
534 | # print(' >已有poster.jpg')
535 | pass
536 | else:
537 | crop_poster_youma(path_fanart, path_poster)
538 | # 需要加上条纹
539 | if settings.bool_watermark_subtitle and bool_subtitle:
540 | add_watermark_subtitle(path_poster)
541 | if settings.bool_watermark_divulge and bool_divulge:
542 | add_watermark_divulge(path_poster)
543 |
544 | # 6收集演员头像【相同】
545 | if settings.bool_sculpture and jav.episode == 1:
546 | if actors[0] == '有码演员':
547 | print(' >未知演员,无法收集头像')
548 | else:
549 | collect_sculpture(actors, jav.root)
550 |
551 | # 7归类影片,针对文件夹【相同】
552 | try:
553 | num_temp = classify_folder(jav, num_fail, settings, dict_data, list_classify_basis, root_classify,
554 | root, bool_separate_folder, num_all_episodes)
555 | num_fail = num_temp
556 | except FileExistsError:
557 | num_fail += 1
558 | continue
559 |
560 | except:
561 | num_fail += 1
562 | record_fail(' >第' + str(num_fail) + '个失败!发生错误,如一直在该影片报错请截图并联系作者:' + path_relative + '\n' + format_exc() + '\n')
563 | continue # 【退出对该jav的整理】
564 |
565 | # 完结撒花
566 | print('\n当前文件夹完成,', end='')
567 | if num_fail > 0:
568 | print('失败', num_fail, '个! ', root_choose, '\n')
569 | line = -1
570 | with open('【可删除】失败记录.txt', 'r', encoding="utf-8") as f:
571 | content = list(f)
572 | while 1:
573 | if content[line].startswith('已'):
574 | break
575 | line -= 1
576 | for i in range(line+1, 0):
577 | print(content[i], end='')
578 | print('\n“【可删除】失败记录.txt”已记录错误\n')
579 | else:
580 | print(' “0”失败! ', root_choose, '\n')
581 | if num_warn > 0:
582 | print('“警告信息.txt”还记录了', num_warn, '个警告信息!\n')
583 | # os.system('pause')
584 | input_start_key = input('回车继续选择文件夹整理:')
585 |
--------------------------------------------------------------------------------
/javsdt/JavdbFc2.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import os, re
3 | from shutil import copyfile
4 | from traceback import format_exc
5 | ########################################################################################################################
6 | from Class.Settings import Settings
7 | from Class.JavFile import JavFile
8 | from Functions.Status import judge_exist_nfo, judge_exist_extra_folders, count_num_videos
9 | from Functions.User import choose_directory
10 | from Functions.Record import record_start, record_fail
11 | from Functions.Process import perfect_dict_data
12 | from Functions.Standard import rename_mp4, rename_folder, classify_files, classify_folder
13 | from Functions.XML import replace_xml_win
14 | from Functions.Process import judge_exist_subtitle
15 | from Functions.Picture import check_picture, add_watermark_subtitle
16 | from Functions.Requests.Download import download_pic
17 | from Functions.Genre import better_dict_genre
18 | # ################################################## 不同 ##########################################################
19 | from Functions.Process import judge_exist_divulge
20 | from Functions.Status import check_actors
21 | from Functions.Picture import add_watermark_divulge, crop_poster_baidu, crop_poster_default
22 | from Functions.Requests.JavdbReq import get_db_html, get_search_db_html
23 |
24 |
25 | # main开始
26 | print('1、若一直连不上javdb,请在ini中更新防屏蔽网址\n'
27 | '2、javdb限制搜索次数,5分钟只能搜索12次左右,然后睡眠5分钟,建议挂机整理!\n'
28 | ' 如果刚启动整理就睡眠,请检查当前网络环境能否访问javdb!\n'
29 | '4、整理FC2,fc2的信息非常非常少,大概只有个标题、卖家(片商)\n')
30 |
31 | # 读取配置文件,这个ini文件用来给用户设置
32 | print('正在读取ini中的设置...', end='')
33 | try:
34 | settings = Settings('fc2')
35 | except:
36 | settings = None
37 | print(format_exc())
38 | print('\n无法读取ini文件,请修改它为正确格式,或者打开“【ini】重新创建ini.exe”创建全新的ini!')
39 | os.system('pause')
40 | print('\n读取ini文件成功!\n')
41 |
42 |
43 | print('进入javdb网站 => 点击主页上的FC2,登录账号 => 键盘按“F12”再按“F5” => 点击“fc2”,复制cfduid和jdb_session')
44 | print('需要看护值守,及时更新它们')
45 | cfduid = input('请粘贴cfduid:')
46 | jdb_session = input('请粘贴jdb_session:')
47 | cookies = {
48 | "__cfduid": cfduid,
49 | "_jdb_session": jdb_session,
50 | }
51 |
52 | # 路径分隔符:当前系统的路径分隔符 windows是“\”,linux和mac是“/”
53 | sep = os.sep
54 |
55 | # 检查头像:如果需要为kodi整理头像,先检查演员头像ini、头像文件夹是否存在。
56 | check_actors(settings.bool_sculpture)
57 |
58 | # 局部代理:哪些站点需要代理。
59 | proxy_library, proxy_bus, proxy_321, proxy_db, proxy_arzon, proxy_dmm = settings.get_proxy()
60 |
61 | # javdb网址:
62 | url_db = settings.get_url_db()
63 |
64 | # 选择简繁中文以及百度翻译账户:需要简体中文还是繁体中文,影响影片特征和简介。
65 | to_language, tran_id, tran_sk = settings.get_translate_account()
66 |
67 | # 信息字典:存放影片信息,用于给用户自定义各种命名。
68 | dict_data = {'车牌': 'FC2-123',
69 | '车牌前缀': 'FC2',
70 | '标题': 'FC2标题',
71 | '完整标题': '完整FC2标题',
72 | '导演': 'FC2导演',
73 | '片商': 'FC2片商',
74 | '评分': '0',
75 | '片长': '0',
76 | '系列': 'FC2系列',
77 | '发行年月日': '1970-01-01', '发行年份': '1970', '月': '01', '日': '01',
78 | '首个演员': 'FC2演员', '全部演员': 'FC2演员',
79 | '空格': ' ',
80 | '\\': sep, '/': sep, # 文件路径分隔符
81 | '是否中字': '',
82 | '是否流出': '',
83 | '影片类型': settings.av_type(),
84 | '视频': 'FC2-123', # 当前及未来的视频文件名,不带ext
85 | '原文件名': 'FC2-123', '原文件夹名': 'FC2-123', }
86 |
87 | # nfo中title的写法。
88 | list_name_nfo_title = settings.formula_name_nfo_title()
89 | # 额外将哪些元素放入特征中
90 | list_extra_genres = settings.list_extra_genre()
91 | # 重命名视频的格式
92 | list_name_video = settings.formula_rename_video()
93 | # 重命名文件夹的格式
94 | list_name_folder = settings.formula_rename_folder()
95 |
96 | # fanart的格式
97 | list_name_fanart = settings.formula_name_fanart()
98 | # poster的格式
99 | list_name_poster = settings.formula_name_poster()
100 |
101 | # 视频文件名包含哪些多余的字母数字,需要无视
102 | list_surplus_words_in_filename = settings.list_surplus_word_in_filename('有码')
103 | # 文件名包含哪些特殊含义的文字,判断是否中字
104 | list_subtitle_words_in_filename = settings.list_subtitle_word_in_filename()
105 | # 文件名包含哪些特殊含义的文字,判断是否是无码流出片
106 | list_divulge_words_in_filename = settings.list_divulge_word_in_filename()
107 |
108 | # 需要扫描的文件的类型
109 | tuple_video_types = settings.tuple_video_type()
110 |
111 | # 完善dict_data,如果用户自定义了一些文字,不在元素中,需要将它们添加进dict_data;list_classify_basis,归类标准,归类目标文件夹的组成公式。
112 | dict_data, list_classify_basis= perfect_dict_data(list_extra_genres, list_name_video, list_name_folder, list_name_nfo_title, list_name_fanart, list_name_poster, settings.custom_classify_basis(), dict_data)
113 |
114 | # 准备工作:使用人体分析,与百度al建立联系
115 | client = settings.start_body_analysis()
116 |
117 | # 优化特征的字典
118 | dict_genre = better_dict_genre('JavdbFc2', to_language)
119 |
120 | # 用户输入“回车”就继续选择文件夹整理
121 | input_start_key = ''
122 | while input_start_key == '':
123 | # 用户:选择需要整理的文件夹
124 | print('请选择要整理的文件夹:', end='')
125 | root_choose = choose_directory()
126 | print(root_choose)
127 | # 日志:在txt中记录一下用户的这次操作,在某个时间选择了某个文件夹
128 | record_start(root_choose)
129 | # 归类:用户自定义的归类根目录,如果不需要归类则为空
130 | root_classify = settings.check_classify_root(root_choose, sep)
131 | # 计数:失败次数及进度
132 | num_fail = 0 # 已经或可能导致致命错误,比如整理未完成,同车牌有不同视频
133 | num_all_videos = count_num_videos(root_choose, tuple_video_types) # 所选文件夹总共有多少个视频文件
134 | num_current = 0 # 当前视频的编号
135 | print('...文件扫描开始...如果时间过长...请避开夜晚高峰期...\n')
136 | # root【当前根目录】 dirs【子文件夹】 files【文件】,root是str,后两个是list
137 | for root, dirs, files in os.walk(root_choose):
138 | # 什么文件都没有
139 | if not files:
140 | continue
141 | # 当前root是已归类的目录,无需处理
142 | if '归类完成' in root.replace(root_choose, ''):
143 | continue
144 | # 跳过已存在nfo的文件夹,判断这一层文件夹中有没有nfo
145 | if settings.bool_skip and judge_exist_nfo(files):
146 | continue
147 | # 对这一层文件夹进行评估,有多少视频,有多少同车牌视频,是不是独立文件夹
148 | list_jav_struct = [] # 存放:需要整理的jav的结构体
149 | dict_car_pref = {} # 存放:每一车牌的集数, 例如{'abp-123': 1, avop-789': 2}是指 abp-123只有一集,avop-789有cd1、cd2
150 | num_videos_include = 0 # 计数:当前文件夹中视频的数量,可能有视频不是jav
151 | dict_subtitle_files = {} # 存放:jav的字幕文件和车牌对应关系 {'c:\a\abc_123.srt': 'abc-123'}
152 | # 判断文件是不是字幕文件,放入dict_subtitle_files中
153 | for file_raw in files:
154 | file_temp = file_raw.upper()
155 | if file_temp.endswith(('.SRT', '.VTT', '.ASS', '.SSA', '.SUB', '.SMI',)):
156 | # 仅处理fc2
157 | if 'FC2' not in file_temp:
158 | continue # 【跳出2】
159 | subtitle_carg = re.search(r'FC2[^\d]*(\d+)', file_temp) # 匹配字幕车牌
160 | if str(subtitle_carg) != 'None':
161 | subtitle_car = 'FC2-' + subtitle_carg.group(1)
162 | dict_subtitle_files[file_raw] = subtitle_car
163 | # print(dict_subtitle_files)
164 | # 判断文件是不是视频,放入list_jav_struct中
165 | for file_raw in files:
166 | file_temp = file_raw.upper()
167 | if file_temp.endswith(tuple_video_types) and not file_temp.startswith('.'):
168 | num_videos_include += 1
169 | num_current += 1
170 | # 仅处理fc2
171 | if 'FC2' not in file_temp:
172 | # print('>>无法处理:' + root.replace(root_choose, '') + sep + file_raw)
173 | continue # 【跳出2】
174 | video_numg = re.search(r'FC2[^\d]*(\d+)', file_temp) # 匹配视频车牌
175 | if str(video_numg) != 'None':
176 | car = 'FC2-' + video_numg.group(1)
177 | # 这个车牌有几集?
178 | try:
179 | dict_car_pref[car] += 1 # 已经有这个车牌了,加一集cd
180 | except KeyError:
181 | dict_car_pref[car] = 1 # 这个新车牌有了第一集
182 | # 这个车牌在dict_subtitle_files中,有它的字幕。
183 | if car in dict_subtitle_files.values():
184 | subtitle_file = list(dict_subtitle_files.keys())[list(dict_subtitle_files.values()).index(car)]
185 | del dict_subtitle_files[subtitle_file]
186 | else:
187 | subtitle_file = ''
188 | # 将该jav的各种属性打包好,包括原文件名带扩展名、所在文件夹路径、第几集、所属字幕文件名
189 | jav_struct = JavFile(file_raw, root, car, dict_car_pref[car], subtitle_file, num_current)
190 | list_jav_struct.append(jav_struct)
191 | else:
192 | print('>>无法处理:', root.replace(root_choose, '') + sep + file_raw)
193 |
194 | # 判定影片所在文件夹是否是独立文件夹,独立文件夹是指该文件夹仅用来存放该影片,而不是大杂烩文件夹
195 | # 这一层文件夹下有jav
196 | if dict_car_pref:
197 | # 当前文件夹下,车牌不止一个;还有其他非jav视频;有其他文件夹,除了演员头像文件夹“.actors”和额外剧照文件夹“extrafanart”;
198 | if len(dict_car_pref) > 1 or num_videos_include > len(list_jav_struct) or judge_exist_extra_folders(dirs):
199 | bool_separate_folder = False # 不是独立的文件夹
200 | else:
201 | bool_separate_folder = True # 这一层文件夹是这部jav的独立文件夹
202 | else:
203 | continue
204 |
205 | # 开始处理每一部jav
206 | for jav in list_jav_struct:
207 | # 告诉用户进度
208 | print('>> [' + str(jav.number) + '/' + str(num_all_videos) + ']:', jav.name)
209 | print(' >发现车牌:', jav.car)
210 |
211 | # 判断是否有中字的特征,条件有三满足其一即可:1有外挂字幕 2文件名中含有“-C”之类的字眼 3旧的nfo中已经记录了它的中字特征
212 | if jav.subtitle:
213 | bool_subtitle = True # 判定成功
214 | dict_data['是否中字'] = settings.custom_subtitle_expression # '是否中字'这一命名元素被激活
215 | else:
216 | bool_subtitle = judge_exist_subtitle(root, jav.name_no_ext, list_subtitle_words_in_filename)
217 | dict_data['是否中字'] = settings.custom_subtitle_expression if bool_subtitle else ''
218 | # 判断是否是无码流出的作品,同理
219 | bool_divulge = judge_exist_divulge(root, jav.name_no_ext, list_divulge_words_in_filename)
220 | dict_data['是否流出'] = settings.custom_divulge_expression if bool_divulge else ''
221 |
222 | # 影片的相对于所选文件夹的路径,用于报错
223 | path_relative = sep + jav.path.replace(root_choose, '')
224 |
225 | # 获取nfo信息的javdb网页
226 | try:
227 | # 用户指定了网址,则直接得到jav所在网址
228 | if '图书馆' in jav.name:
229 | url_appointg = re.search(r'仓库(.+?)\.', jav.name)
230 | if str(url_appointg) != 'None':
231 | url_on_web = url_db + 'v/' + url_appointg.group(1)
232 | else:
233 | num_fail += 1
234 | record_fail(' >第' + str(num_fail) + '个失败!你指定的javdb网址有错误:' + path_relative + '\n')
235 | continue # 【退出对该jav的整理】
236 | # 用户没有指定网址,则去搜索
237 | else:
238 | url_search_web = url_db + 'search?q=' + jav.car + '&f=all'
239 | print(' >搜索车牌:', url_search_web)
240 | # 得到javdb搜索网页html
241 | html_web, cookies = get_search_db_html(url_search_web, cookies, proxy_db)
242 | # 尝试找movie-box 0链接 1车牌
243 | list_search_results = re.findall(r'href="/v/(.+?)" class="box" title=".+?"[\s\S]*?uid">(.+?)', html_web, re.DOTALL) # 匹配处理“标题”
244 | # print(list_search_results)
245 | if list_search_results: # 搜索结果页面只有一个box
246 | # print(list_search_results)
247 | # print(' >正在核查搜索结果...')
248 | jav_pref = jav.car.split('-')[0] # 匹配车牌的前缀字母
249 | jav_suf = jav.car.split('-')[-1].lstrip('0') # 当前车牌的后缀数字 去除多余的0
250 | list_fit_results = []
251 | for i in list_search_results:
252 | url_num = i[1].upper()
253 | url_suf = re.search(r'(\d\d+)', url_num).group(1).lstrip('0') # 匹配box上影片url,车牌的后缀数字,去除多余的0
254 | # print('url后缀:', url_suf)
255 | if jav_suf == url_suf: # 数字相同
256 | url_pref = re.search(r'([A-Z]+2?)', url_num).group(1).upper() # 匹配处理url所带车牌前面的字母“n”
257 | # print('url前缀:', url_suf)
258 | if jav_pref == url_pref: # 数字相同的基础下,字母也相同,即可能车牌相同
259 | list_fit_results.append(i)
260 | else:
261 | continue # 【退出对该jav的整理】
262 | # 搜索结果一个都匹配不上
263 | if not list_fit_results:
264 | num_fail += 1
265 | record_fail(' >第' + str(
266 | num_fail) + '个失败!javdb找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
267 | # print(html_web)
268 | continue # 【退出对该jav的整理】
269 | # 默认用第一个搜索结果
270 | url_on_web = url_db + 'v/' + list_fit_results[0][0]
271 | if len(list_fit_results) > 1:
272 | num_fail += 1
273 | record_fail(' >第' + str(
274 | num_fail) + '个警告!javdb搜索到同车牌的不同视频:' + jav.car + ',' + path_relative + '\n')
275 | # 找不到box
276 | else:
277 | num_fail += 1
278 | record_fail(' >第' + str(
279 | num_fail) + '个失败!javdb找不到该车牌的信息:' + jav.car + ',' + path_relative + '\n')
280 | continue # 【跳出对该jav的整理】
281 | # 经过上面的三种情况,可能找到了jav在web上的网页链接url_on_web
282 | print(' >获取信息:', url_on_web)
283 | # 得到最终的jav所在网页
284 | html_web, cookies = get_db_html(url_on_web, cookies, proxy_db)
285 | html = html_web
286 | # print(html_web)
287 |
288 | # 有大部分信息的html_web
289 | html_web = re.search(r'h2 class([\s\S]*?)想看', html_web, re.DOTALL).group(1)
290 | # print(html_web)
291 | # 标题
292 | title = re.search(r'strong>(.+?)', html_web).group(1).replace(' 中文字幕 ', '')
293 | # 去除xml文档和windows路径不允许的特殊字符 &<> \/:*?"<>|
294 | title = replace_xml_win(title)
295 | print(' >影片标题:', title)
296 | # title的开头是车牌号,想要后面的纯标题
297 | car_titleg = re.search(r'(.+?) (.+)', title)
298 | # 车牌号
299 | dict_data['车牌'] = car = car_titleg.group(1)
300 | # 给用户重命名用的标题是“短标题”,nfo中是“完整标题”,但用户在ini中只用写“标题”
301 | title_only = car_titleg.group(2)
302 | dict_data['完整标题'] = title_only
303 | # 处理影片的标题过长
304 | if len(title_only) > settings.int_title_len:
305 | dict_data['标题'] = title_only[:settings.int_title_len]
306 | else:
307 | dict_data['标题'] = title_only
308 | # DVD封面cover
309 | coverg = re.search(r'img src="(.+?)"', html_web) # 封面图片的正则对象
310 | if str(coverg) != 'None':
311 | url_cover = coverg.group(1)
312 | else:
313 | url_cover = ''
314 | # 发行日期
315 | premieredg = re.search(r'(\d\d\d\d-\d\d-\d\d)', html_web)
316 | if str(premieredg) != 'None':
317 | dict_data['发行年月日'] = time_premiered = premieredg.group(1)
318 | dict_data['发行年份'] = time_premiered[0:4]
319 | dict_data['月'] = time_premiered[5:7]
320 | dict_data['日'] = time_premiered[8:10]
321 | else:
322 | dict_data['发行年月日'] = time_premiered = '1970-01-01'
323 | dict_data['发行年份'] = '1970'
324 | dict_data['月'] = '01'
325 | dict_data['日'] = '01'
326 | # 片长 150 分钟 |
327 | runtimeg = re.search(r'value">(\d+) 分鍾<', html_web)
328 | if str(runtimeg) != 'None':
329 | dict_data['片长'] = runtimeg.group(1)
330 | else:
331 | dict_data['片长'] = '0'
332 | # 片商 制作商
333 | studiog = re.search(r'makers/.+?">(.+?)<', html_web)
334 | if str(studiog) != 'None':
335 | dict_data['片商'] = studio = replace_xml_win(studiog.group(1))
336 | else:
337 | dict_data['片商'] = 'FC2卖家'
338 | studio = ''
339 | # 特点
340 | genres = re.findall(r'tags.+?">(.+?)', html_web)
341 | if bool_subtitle: # 有“中字“,加上特征”中文字幕”
342 | genres.append('中文字幕')
343 | try:
344 | genres = [dict_genre[i] for i in genres if dict_genre[i] != '删除']
345 | except KeyError as error:
346 | num_fail += 1
347 | record_fail(' >第' + str(num_fail) + '个失败!发现新的特征需要添加至【特征对照表】:' + str(error) + '\n')
348 | continue
349 | # print(genres)
350 | #######################################################################
351 | dict_data['视频'] = dict_data['原文件名'] = jav.name_no_ext # dict_data['视频'],先定义为原文件名,即将发生变化。
352 | dict_data['原文件夹名'] = jav.folder
353 | # 是CD1还是CDn?
354 | num_all_episodes = dict_car_pref[jav.car] # 该车牌总共多少集
355 | if num_all_episodes > 1:
356 | str_cd = '-cd' + str(jav.episode)
357 | else:
358 | str_cd = ''
359 |
360 | # 1重命名视频【相同】
361 | try:
362 | dict_data, jav, num_temp = rename_mp4(jav, num_fail, settings, dict_data, list_name_video,
363 | path_relative, str_cd)
364 | num_fail = num_temp
365 | except FileExistsError:
366 | num_fail += 1
367 | continue
368 |
369 | # 2 归类影片【相同】只针对视频文件和字幕文件。注意:第2操作和下面(第3操作+第7操作)互斥,只能执行第2操作或(第3操作+第7操作),归类影片是针对“文件”还是“文件夹”。
370 | try:
371 | jav, num_temp = classify_files(jav, num_fail, settings, dict_data, list_classify_basis,
372 | root_classify)
373 | num_fail = num_temp
374 | except FileExistsError:
375 | num_fail += 1
376 | continue
377 |
378 | # 3重命名文件夹【相同】如果是针对“文件”归类,这一步会被跳过。 因为用户只需要归类视频文件,不需要管文件夹。
379 | try:
380 | jav, num_temp = rename_folder(jav, num_fail, settings, dict_data, list_name_folder,
381 | bool_separate_folder, num_all_episodes)
382 | num_fail = num_temp
383 | except FileExistsError:
384 | num_fail += 1
385 | continue
386 |
387 | # 更新一下path_relative
388 | path_relative = sep + jav.path.replace(root_choose, '') # 影片的相对于所选文件夹的路径,用于报错
389 |
390 | # 4写入nfo【独特】
391 | if settings.bool_nfo:
392 | # 如果是为空地准备的nfo,不需要多cd
393 | if settings.bool_cd_only:
394 | path_nfo = jav.root + sep + jav.name_no_ext.replace(str_cd, '') + '.nfo'
395 | else:
396 | path_nfo = jav.root + sep + jav.name_no_ext + '.nfo'
397 | # nfo中tilte的写法
398 | title_in_nfo = ''
399 | for i in list_name_nfo_title:
400 | title_in_nfo += dict_data[i]
401 | # 开始写入nfo,这nfo格式是参考的kodi的nfo
402 | f = open(path_nfo, 'w', encoding="utf-8")
403 | f.write("\n"
404 | "\n"
405 | " " + title_in_nfo + "\n"
406 | " " + title + "\n"
407 | " " + dict_data['发行年份'] + "\n"
408 | " NC-17\n"
409 | " NC-17\n"
410 | " JP\n"
411 | " " + time_premiered + "\n"
412 | " " + time_premiered + "\n"
413 | " " + dict_data['片长'] + "\n"
414 | " 日本\n"
415 | " " + studio + "\n"
416 | " " + car + "\n"
417 | " " + car + "\n")
418 | # 需要将特征写入genre
419 | if settings.bool_genre:
420 | for i in genres:
421 | f.write(" " + i + "\n")
422 | if settings.bool_write_studio and studio:
423 | f.write(" 卖家:" + studio + "\n")
424 | if list_extra_genres:
425 | for i in list_extra_genres:
426 | f.write(" " + dict_data[i] + "\n")
427 | # 需要将特征写入tag
428 | if settings.bool_tag:
429 | for i in genres:
430 | f.write(" " + i + "\n")
431 | if settings.bool_write_studio and studio:
432 | f.write(" 卖家:" + studio + "\n")
433 | if list_extra_genres:
434 | for i in list_extra_genres:
435 | f.write(" " + dict_data[i] + "\n")
436 | # 写入演员
437 | f.write(" \n FC2演员\n Actor\n \n")
438 | f.write("\n")
439 | f.close()
440 | print(' >nfo收集完成')
441 |
442 | # 5需要两张封面图片【独特】
443 | if settings.bool_jpg:
444 | path_fanart = jav.root + sep
445 | path_poster = jav.root + sep
446 | for i in list_name_fanart:
447 | path_fanart += dict_data[i]
448 | for i in list_name_poster:
449 | path_poster += dict_data[i]
450 | # kodi只需要一份图片,图片路径唯一
451 | if settings.bool_cd_only:
452 | path_fanart = path_fanart.replace(str_cd, '')
453 | path_poster = path_poster.replace(str_cd, '')
454 | # emby需要多份,现在不是第一集,直接复制第一集的图片
455 | elif jav.episode != 1:
456 | try:
457 | copyfile(path_fanart.replace(str_cd, '-cd1'), path_fanart)
458 | print(' >fanart.jpg复制成功')
459 | copyfile(path_poster.replace(str_cd, '-cd1'), path_poster)
460 | print(' >poster.jpg复制成功')
461 | except FileNotFoundError:
462 | pass
463 | # kodi或者emby需要的第一份图片
464 | if check_picture(path_fanart):
465 | # print(' >已有fanart.jpg')
466 | pass
467 | else:
468 | # 下载封面
469 | print(' >从javdb下载封面:', url_cover)
470 | try:
471 | download_pic(url_cover, path_fanart, proxy_db)
472 | print(' >fanart.jpg下载成功')
473 | except:
474 | num_fail += 1
475 | record_fail(' >第' + str(
476 | num_fail) + '个失败!下载fanart.jpg失败:' + url_cover + ',' + path_relative + '\n')
477 | continue # 退出对该jav的整理
478 | # 裁剪生成 poster
479 | if check_picture(path_poster):
480 | # print(' >已有poster.jpg')
481 | pass
482 | elif settings.bool_face:
483 | crop_poster_baidu(path_fanart, path_poster, client)
484 | # 需要加上条纹
485 | if settings.bool_watermark_subtitle and bool_subtitle:
486 | add_watermark_subtitle(path_poster)
487 | if settings.bool_watermark_divulge and bool_divulge:
488 | add_watermark_divulge(path_poster)
489 | else:
490 | crop_poster_default(path_fanart, path_poster, 2)
491 | # 需要加上条纹
492 | if settings.bool_watermark_subtitle and bool_subtitle:
493 | add_watermark_subtitle(path_poster)
494 | if settings.bool_watermark_divulge and bool_divulge:
495 | add_watermark_divulge(path_poster)
496 |
497 | # 6收集演员头像【相同】
498 |
499 | # 7归类影片,针对文件夹【相同】
500 | try:
501 | num_temp = classify_folder(jav, num_fail, settings, dict_data, list_classify_basis, root_classify,
502 | root, bool_separate_folder, num_all_episodes)
503 | num_fail = num_temp
504 | except FileExistsError:
505 | num_fail += 1
506 | continue
507 |
508 | except:
509 | num_fail += 1
510 | record_fail(' >第' + str(num_fail) + '个失败!发生错误,如一直在该影片报错请截图并联系作者:' + path_relative + '\n' + format_exc() + '\n')
511 | continue # 【退出对该jav的整理】
512 |
513 | # 完结撒花
514 | print('\n当前文件夹完成,', end='')
515 | if num_fail > 0:
516 | print('失败', num_fail, '个! ', root_choose, '\n')
517 | line = -1
518 | with open('【可删除】失败记录.txt', 'r', encoding="utf-8") as f:
519 | content = list(f)
520 | while 1:
521 | if content[line].startswith('已'):
522 | break
523 | line -= 1
524 | for i in range(line+1, 0):
525 | print(content[i], end='')
526 | print('\n“【可删除】失败记录.txt”已记录错误\n')
527 | else:
528 | print(' “0”失败! ', root_choose, '\n')
529 | # os.system('pause')
530 | input_start_key = input('回车继续选择文件夹整理:')
531 |
--------------------------------------------------------------------------------
/javsdt/StaticFiles/divulge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/divulge.png
--------------------------------------------------------------------------------
/javsdt/StaticFiles/emby.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/emby.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/ini.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/ini.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/javbus.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/javbus.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/javdb.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/javdb.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/javlibrary.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/javlibrary.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/javsdt.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/javsdt.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/subtitle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/subtitle.png
--------------------------------------------------------------------------------
/javsdt/StaticFiles/suren.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/suren.ico
--------------------------------------------------------------------------------
/javsdt/StaticFiles/update.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/StaticFiles/update.ico
--------------------------------------------------------------------------------
/javsdt/Update.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import requests, re, os
3 |
4 | now_version = '1.1.3'
5 | print('当前版本为:', now_version)
6 | print('正在检查更新...https://github.com/junerain123/javsdt/blob/master/%E6%A3%80%E6%9F%A5%E6%9B%B4%E6%96%B0.json')
7 | upd_url = 'https://github.com/junerain123/javsdt/blob/master/%E6%A3%80%E6%9F%A5%E6%9B%B4%E6%96%B0.json'
8 | try:
9 | rqs = requests.get(upd_url, timeout=20)
10 | except:
11 | print('连接github超时!请重新尝试!')
12 | os.system('pause')
13 | rqs.encoding = 'utf-8'
14 | html_github_update = rqs.text
15 | # print(html_github_update)
16 | version_g = re.search(r'version": "(.+?)<', html_github_update)
17 | new_version = version_g.group(1)
18 | download_g = re.search(r'lanzous.com/(.+?)<', html_github_update)
19 | new_download = 'https://www.lanzous.com/' + download_g.group(1)
20 | print('最新版本为:', new_version)
21 | if now_version != new_version:
22 | print('请下载最新的版本:', new_version, '!')
23 | print('下载链接为:', new_download, '!')
24 | else:
25 | print('你正在使用最新的版本,无需更新!')
26 | os.system('pause')
27 |
--------------------------------------------------------------------------------
/javsdt/divulge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/divulge.png
--------------------------------------------------------------------------------
/javsdt/emby_actors.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import requests, os
3 | from configparser import RawConfigParser
4 | from base64 import b64encode
5 | from traceback import format_exc
6 | from json import loads
7 | from os.path import exists
8 |
9 | # 检查“演员头像”文件夹是否就绪
10 | if not exists('演员头像'):
11 | print('\n“演员头像”文件夹丢失!请把它放进exe的文件夹中!\n')
12 | os.system('pause')
13 | # 读取配置文件,这个ini文件用来给用户设置emby网址和api id
14 | print('正在读取ini中的设置...')
15 | config_settings = RawConfigParser()
16 | try:
17 | config_settings.read('【点我设置整理规则】.ini', encoding='utf-8-sig')
18 | url_emby = config_settings.get("emby/jellyfin", "网址")
19 | api_key = config_settings.get("emby/jellyfin", "api id")
20 | bool_replace = True if config_settings.get("emby/jellyfin", "是否覆盖以前上传的头像?") == '是' else False
21 | except:
22 | print(format_exc())
23 | print('无法读取ini文件,请修改它为正确格式,或者打开“【ini】重新创建ini.exe”创建全新的ini!')
24 | os.system('pause')
25 | print('读取ini文件成功!\n')
26 | # 修正用户输入的emby网址,无论是不是带“/”
27 | if not url_emby.endswith('/'):
28 | url_emby += '/'
29 | # 成功的个数
30 | num_suc = 0
31 | num_fail = 0
32 | num_exist = 0
33 | sep = os.sep
34 | try:
35 | print('正在获取取emby中Persons清单...')
36 | # curl -X GET "http://localhost:8096/emby/Persons?api_key=3291434710e342089565ad05b6b2f499" -H "accept: application/json"
37 | # 得到所有“人员” emby api没有细分“演员”还是“导演”“编剧”等等 下面得到的是所有“有关人员”
38 | url_emby_persons = url_emby + 'emby/Persons?api_key=' + api_key # &PersonTypes=Actor
39 | try:
40 | rqs_emby = requests.get(url=url_emby_persons)
41 | except requests.exceptions.ConnectionError:
42 | print('无法访问emby服务端,请检查:', url_emby, '\n')
43 | os.system('pause')
44 | except:
45 | print(format_exc())
46 | print('发生未知错误,请截图并联系作者:', url_emby, '\n')
47 | os.system('pause')
48 | # 401,无权访问
49 | if rqs_emby.status_code == 401:
50 | print('请检查api id是否正确!\n')
51 | os.system('pause')
52 | # print(rqs_emby.text)
53 | try:
54 | list_persons = loads(rqs_emby.text)['Items']
55 | except:
56 | print(rqs_emby.text)
57 | print('发生错误!emby返回内容如上:')
58 | print('请截图并联系作者!')
59 | os.system('pause')
60 | num_persons = len(list_persons)
61 | print('当前有' + str(num_persons) + '个Person!\n')
62 | # os.system('pause')
63 | # 用户emby中的persons,在“演员头像”文件夹中,已有头像的,记录下来
64 | f_txt = open("已收录的人员清单.txt", 'w', encoding="utf-8")
65 | f_txt.close()
66 | f_txt = open("未收录的人员清单.txt", 'w', encoding="utf-8")
67 | f_txt.close()
68 | for dic_each_actor in list_persons:
69 | actor_name = dic_each_actor['Name']
70 | # 头像jpg/png在“演员头像”中的路径
71 | actor_pic_path = '演员头像' + sep + actor_name[0] + sep + actor_name
72 | if exists(actor_pic_path + '.jpg'):
73 | actor_pic_path = actor_pic_path + '.jpg'
74 | header = {"Content-Type": 'image/jpeg', }
75 | elif exists(actor_pic_path + '.png'):
76 | actor_pic_path = actor_pic_path + '.png'
77 | header = {"Content-Type": 'image/png', }
78 | else:
79 | print('>>暂无头像:', actor_name)
80 | f_txt = open("未收录的人员清单.txt", 'a', encoding="utf-8")
81 | f_txt.write(actor_name + '\n')
82 | f_txt.close()
83 | num_fail += 1
84 | continue
85 | # emby有某个演员,“演员头像”文件夹也有这个演员的头像,记录一下
86 | f_txt = open("已收录的人员清单.txt", 'a', encoding="utf-8")
87 | f_txt.write(actor_name + '\n')
88 | f_txt.close()
89 | # emby有某个演员,已经有他的头像,不再进行下面“上传头像”的操作
90 | if dic_each_actor['ImageTags']: # emby已经收录头像
91 | num_exist += 1
92 | if not bool_replace: # 不需要覆盖已有头像
93 | continue # 那么不进行下面的上传操作
94 | f_pic = open(actor_pic_path, 'rb') # 二进制方式打开图文件
95 | b6_pic = b64encode(f_pic.read()) # 读取文件内容,转换为base64编码
96 | f_pic.close()
97 | url_post_img = url_emby + 'emby/Items/' + dic_each_actor['Id'] + '/Images/Primary?api_key=' + api_key
98 | requests.post(url=url_post_img, data=b6_pic, headers=header)
99 | print('>>设置成功:', actor_name)
100 | num_suc += 1
101 |
102 | print('\nemby/jellyfin拥有人员', num_persons, '个!')
103 | print('已有头像', num_exist, '个!')
104 | if bool_replace:
105 | print('当前模式:覆盖以前上传的头像')
106 | else:
107 | print('当前模式:跳过以前上传的头像')
108 | print('成功上传', num_suc, '个!')
109 | print('暂无头像', num_fail, '个!')
110 | print('已保存至“未收录的人员清单.txt”\n')
111 | os.system('pause')
112 | except:
113 | print(format_exc())
114 | os.system('pause')
115 |
116 |
117 |
--------------------------------------------------------------------------------
/javsdt/subtitle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/subtitle.png
--------------------------------------------------------------------------------
/javsdt/【特征对照表】.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/javsdt/【特征对照表】.xlsx
--------------------------------------------------------------------------------
/javsdt/【素人车牌】.txt:
--------------------------------------------------------------------------------
1 | AID
2 | AKDL
3 | ARA
4 | BMH
5 | BNJC
6 | BZDC
7 | CUTE
8 | DCV
9 | EMOI
10 | ENDX
11 | ETQR
12 | ETVTM
13 | EVA
14 | EWDX
15 | EXMU
16 | EZD
17 | FAD
18 | FCTD
19 | GANA
20 | GAREA
21 | GAV
22 | GERBM
23 | GERK
24 | HAMENETS
25 | HEN
26 | HHH
27 | HMDN
28 | HOI
29 | HSAM
30 | HYPN
31 | IMDK
32 | INST
33 | ION
34 | JAC
35 | JKK
36 | JKZ
37 | JNT
38 | JOTK
39 | JTR
40 | KAGD
41 | KBVR
42 | KIRAY
43 | KITAIKE
44 | KJN
45 | KMTU
46 | KNB
47 | KSKO
48 | KURO
49 | LADY
50 | LAFBD
51 | LAS
52 | LOLI
53 | LUXU
54 | MAAN
55 | MAG
56 | MFC
57 | MGDN
58 | MISM
59 | MIUM
60 | MLA
61 | MMGH
62 | MMH
63 | MNTJ
64 | MTP
65 | MY
66 | NAMA
67 | NKR
68 | NNPJ
69 | NRPK
70 | NTK
71 | NTTR
72 | OBUT
73 | OKYH
74 | ONS
75 | ORE
76 | OREBMS
77 | OREC
78 | OREP
79 | ORERB
80 | ORETD
81 | ORETDP
82 | OREX
83 | OTIM
84 | PAPA
85 | PER
86 | PIZ
87 | PKJD
88 | RCTS
89 | REG
90 | REP
91 | SCP
92 | SCUTE
93 | SDGN
94 | SENN
95 | SGK
96 | SHOW
97 | SHYN
98 | SIMM
99 | SIRO
100 | SKIV
101 | SPCY
102 | SPOR
103 | SPRM
104 | SQB
105 | SRCN
106 | SRHO
107 | SRTD
108 | SSAN
109 | STKO
110 | SUKE
111 | SVMM
112 | SWEET
113 | SYBI
114 | TRUMG
115 | URF
116 | UTSU
117 | VOV
118 | YKMC
119 | YRTB
120 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | baidu-aip==2.2.18.0
2 | certifi==2020.12.5
3 | chardet==3.0.4
4 | idna==2.7
5 | Pillow==8.1.0
6 | PySocks==1.7.1
7 | requests==2.20.0
8 | urllib3==1.24.3
9 | xlrd==1.2.0
10 |
--------------------------------------------------------------------------------
/检查更新.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.1.5",
3 | "download": "https://junerain.lanzous.com/ivp8Plg6wza"
4 | }
5 |
--------------------------------------------------------------------------------
/测试影片.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanza1/AVScraper/615821cc93cf039fda4d0ed930a19dae6aa3451b/测试影片.zip
--------------------------------------------------------------------------------