Skip to content
This repository was archived by the owner on Feb 9, 2022. It is now read-only.

Commit c975898

Browse files
author
yodhcn
committed
v1.3.0
将配置文件格式改为 json
1 parent edbf771 commit c975898

File tree

5 files changed

+111
-98
lines changed

5 files changed

+111
-98
lines changed

README.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
# Doujin_Voice_Renamer
22

3-
使用说明:
4-
5-
"配置文件.txt"路径要求:
6-
与主程序"DLsite重命名工具_v1.2.1"在同一路径下
7-
8-
"配置文件.txt" 文件格式要求:.txt文本格式 UTF-8编码
9-
10-
关键字:“社团”、“RJ号”、“标题”和“声优”
11-
这四个关键字将会被程序替换
12-
13-
程序只会读取配置文件第一行的内容
14-
请在 "配置文件.txt" 的第一行输入你自定义的规则
15-
例如:[社团] 标题 (RJ号)
16-
17-
重命名前:RJ149268 哀しみのイき人形
18-
自定义规则:[社团] 标题 (RJ号)
19-
重命名后:[Hypnotic_Yanh] 哀しみのイき人形《催眠音声・男女版同梱》 (RJ149268)
20-
21-
注意:
22-
由于某些社团不会在DLSite页面靠右侧的列表里输入声优名称
23-
有些作品的"声优"关键字没法被程序爬取到,也就无法自动替换,请手动修改
24-
25-
![示例图片](https://i.loli.net/2019/08/29/KJxOBVktrlfZ6sa.png)
3+
### 使用说明:
4+
5+
**关键字**:"circle", "workno", "title" 和 "cv", 模板中的这四个关键字将会被程序替换
6+
7+
**默认模板**: "template": "workno [circle] title (cv)"
8+
9+
**自定义模板**: 请修改 "config.json" 中的 "template"
10+
11+
例如:"template": "[circle] title (workno)"
12+
13+
重命名前:RJ149268 哀しみのイき人形
14+
15+
重命名后:[Hypnotic_Yanh] 哀しみのイき人形《催眠音声・男女版同梱》 (RJ149268)
16+
17+
### 注意:
18+
19+
如需在自定义模板包含 "(cv)", 请将其放在模板字符串的末尾
20+
21+
- 正确的例子: "template": "workno [circle] title (cv)"
22+
- 错误的例子: "template": "workno [circle] (cv) title" 这可能会导致在重命名后,文件夹名称中出现多余的空格
23+
24+
![示例图片](https://i.loli.net/2019/08/29/KJxOBVktrlfZ6sa.png)

dist/配置文件.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

test.py

Lines changed: 88 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
import time
88
import re
99
import os
10+
import json
1011

1112
# 默认配置
12-
template = 'RJ号 [社团] 标题 (声优)' # 默认命名格式
13+
template = 'workno [circle] title (cv)' # 默认命名模板
1314

1415
RJ_WEBPATH = 'https://www.dlsite.com/maniax/work/=/product_id/'
1516
RT_WEBPATH = 'https://www.dlsite.com.tw/work/product_id/'
@@ -23,14 +24,16 @@
2324

2425

2526
# 避免ERROR: Max retries exceeded with url
26-
requests.adapters.DEFAULT_RETRIES = 5 # 增加重连次数
27+
requests.adapters.DEFAULT_RETRIES = 5 # 增加重连次数
2728
s = requests.session()
28-
s.keep_alive = False # 关闭多余连接
29-
#s.get(url) # 你需要的网址
29+
s.keep_alive = False # 关闭多余连接
30+
# s.get(url) # 你需要的网址
3031

3132
# 查找母串内所有子串的位置, 查找失败返回-1
32-
def find_all(source,dest):
33-
length1,length2 = len(source),len(dest)
33+
34+
35+
def find_all(source, dest):
36+
length1, length2 = len(source), len(dest)
3437
dest_list = []
3538
temp_list = []
3639
if length1 < length2:
@@ -47,13 +50,15 @@ def find_all(source,dest):
4750
if source[x:x+length2] != dest:
4851
#print(" dest != slice")
4952
temp_list.append(x)
50-
#else:
51-
#print(" dest == slice")
53+
# else:
54+
#print(" dest == slice")
5255
for x in temp_list:
5356
dest_list.remove(x)
5457
return dest_list
5558

5659
# 从文件夹名称中提取r_code
60+
61+
5762
def get_r_code(originalName, matchCode):
5863
index_list = find_all(originalName, matchCode)
5964
if index_list == -1:
@@ -64,49 +69,55 @@ def get_r_code(originalName, matchCode):
6469
pattern = re.compile("^"+matchCode+"\d{6}$")
6570
if pattern.match(r_code):
6671
return r_code.upper()
67-
return ""
72+
return ""
73+
6874

6975
def match_rj(rj_code):
70-
# requests库是一个常用于http请求的模块
76+
# requests库是一个常用于http请求的模块
7177
url = RJ_WEBPATH + rj_code
7278
try:
73-
r = s.get(url, allow_redirects=False, cookies=R_COOKIE) # allow_redirects=False 禁止重定向
79+
# allow_redirects=False 禁止重定向
80+
r = s.get(url, allow_redirects=False, cookies=R_COOKIE)
7481
# HTTP状态码==200表示请求成功
7582
if r.status_code != 200:
7683
#print(" Status code:", r.status_code, "\nurl:", url)
7784
return r.status_code, "", "", []
78-
85+
7986
# fromstring()在解析xml格式时, 将字符串转换为Element对象, 解析树的根节点
8087
# 在python中, 对get请求返回的r.content做fromstring()处理, 可以方便进行后续的xpath()定位等
8188
tree = html.fromstring(r.content)
8289
title = tree.xpath('//a[@itemprop="url"]/text()')[0]
83-
circle = tree.xpath('//span[@itemprop="brand" and @class="maker_name"]/*/text()')[0]
84-
cvList = tree.xpath('//*[@id="work_outline"]/tr/th[contains(text(), "声優")]/../td/a/text()')
90+
circle = tree.xpath(
91+
'//span[@itemprop="brand" and @class="maker_name"]/*/text()')[0]
92+
cvList = tree.xpath(
93+
'//*[@id="work_outline"]/tr/th[contains(text(), "声優")]/../td/a/text()')
8594
return 200, title, circle, cvList
8695

8796
except os.error as err:
8897
text.insert(tk.END, "**请求超时!\n")
8998
text.insert(tk.END, " 请检查网络连接\n")
9099
return "", "", "", []
91-
100+
101+
92102
def match_rt(rt_code):
93103
url = RT_WEBPATH + rt_code
94104
try:
95105
r = s.get(url + '.html', allow_redirects=False, cookies=R_COOKIE)
96106
if r.status_code != 200:
97107
#print(" Status code:", r.status_code, "\nurl:", url)
98108
return r.status_code, "", "", []
99-
109+
100110
tree = html.fromstring(r.content)
101111
title = tree.xpath('//div[@class="works_summary"]/h3/text()')[0]
102112
circle = tree.xpath('//a[@class="summary_author"]/text()')[0]
103113
return 200, title, circle, []
104-
114+
105115
except os.error as err:
106116
text.insert(tk.END, "**请求超时!\n")
107117
text.insert(tk.END, " 请检查网络连接\n")
108118
return "", "", "", []
109119

120+
110121
def nameChange():
111122
# askdirectory()文件对话框, 选择目录, 返回目录名
112123
path = filedialog.askdirectory()
@@ -121,84 +132,89 @@ def nameChange():
121132
files = os.listdir(path)
122133
for file in files:
123134
# os.path.isdir()用于判断对象是否为一个目录。
124-
if os.path.isdir(os.path.join(path,file)):
135+
if os.path.isdir(os.path.join(path, file)):
125136
# 获取文件夹原始名称
126137
originalName = file
127138
# 尝试获取r_code
128139
r_code = ""
129-
for matchCode in ['RJ','rj','RT','rt']:
140+
for matchCode in ['RJ', 'rj', 'RT', 'rt']:
130141
r_code = get_r_code(originalName, matchCode)
131142
if r_code:
132143
break
133144
# 如果没能提取到r_code
134145
if r_code == "":
135-
continue # 跳过该文件夹
146+
continue # 跳过该文件夹
136147
else:
137148
#print('Processing: ' + r_code)
138149
text.insert(tk.END, 'Processing: ' + r_code + '\n')
139-
if r_code[1] == "J" :
150+
if r_code[1] == "J":
140151
r_status, title, circle, cvList = match_rj(r_code)
141-
elif r_code[1] == "T" :
152+
elif r_code[1] == "T":
142153
r_status, title, circle, cvList = match_rt(r_code)
143154
# 如果顺利爬取网页信息
144155
if r_status == 200 and title and circle:
145-
if var1.get():
156+
if var1.get():
146157
# 删除title中的【.*?】
147158
title = re.sub(u"\\【.*?】", "", title)
148159

149-
new_name = template.replace("RJ号", r_code)
150-
new_name = new_name.replace("标题", title)
151-
new_name = new_name.replace("社团", circle)
152-
160+
new_name = template.replace("workno", r_code)
161+
new_name = new_name.replace("title", title)
162+
new_name = new_name.replace("circle", circle)
163+
153164
cv = ""
154-
if cvList: #如果cvList非空
155-
for name in cvList:
165+
if cvList: # 如果cvList非空
166+
for name in cvList:
156167
cv += " " + name
157-
new_name = new_name.replace("声优", cv[1:])
158-
#else:
159-
#new_name = new_name.replace("(声优)", "")
160-
161-
162-
# 将Windows文件名中的非法字符替换
163-
new_name = re.sub(filter, " ", new_name) # re.sub(pattern, repl, string)
168+
new_name = new_name.replace("cv", cv[1:])
169+
else:
170+
new_name = new_name.replace("(cv)", "")
171+
172+
# 将Windows文件名中的非法字符替换
173+
# re.sub(pattern, repl, string)
174+
new_name = re.sub(filter, " ", new_name)
164175
# 尝试重命名
165176
try:
166177
# strip() 去掉字符串两边的空格
167-
os.rename(os.path.join(path, originalName), os.path.join(path, new_name.strip()))
178+
os.rename(os.path.join(path, originalName),
179+
os.path.join(path, new_name.strip()))
168180
except os.error as err:
169-
text.insert(tk.END, "**重命名失败!\n" )
170-
text.insert(tk.END, " " + os.path.join(path, originalName) + "\n")
181+
text.insert(tk.END, "**重命名失败!\n")
182+
text.insert(
183+
tk.END, " " + os.path.join(path, originalName) + "\n")
171184
text.insert(tk.END, " 请检查是否存在重复的名称\n")
172185
elif r_status == 404:
173186
text.insert(tk.END, "**爬取DLsite过程中出现错误!\n")
174187
text.insert(tk.END, " 请检查本作是否已经下架或被收入合集\n")
175188
elif r_status != "":
176189
text.insert(tk.END, "**爬取DLsite过程中出现错误!\n")
177-
text.insert(tk.END, " 网页 URL: " + RJ_WEBPATH + r_code + "\n")
178-
text.insert(tk.END, " HTTP 响应代码: " + str(r_status) + "\n")
179-
180-
time.sleep(0.1) #set delay to avoid being blocked from server
181-
#print("~Finished.")
190+
text.insert(tk.END, " 网页 URL: " +
191+
RJ_WEBPATH + r_code + "\n")
192+
text.insert(tk.END, " HTTP 响应代码: " +
193+
str(r_status) + "\n")
194+
195+
# set delay to avoid being blocked from server
196+
time.sleep(0.1)
197+
# print("~Finished.")
182198
text.insert(tk.END, "*******完成!*******\n\n\n\n")
183199
tk.messagebox.showinfo(title="提示", message="完成!")
184-
200+
185201
cbtn.config(state=tk.NORMAL)
186202
btn.config(state=tk.NORMAL)
187203
btn['text'] = "选择路径"
188-
204+
205+
189206
def thread_it(func, *args):
190207
'''将函数打包进线程'''
191208
# 创建
192-
t = threading.Thread(target=func, args=args)
209+
t = threading.Thread(target=func, args=args)
193210
# 守护 !!!
194-
t.setDaemon(True)
211+
t.setDaemon(True)
195212
# 启动
196213
t.start()
197214
# 阻塞--卡死界面!
198215
# t.join()
199216

200217

201-
202218
root = tk.Tk() # 实例化object,建立窗口root
203219
root.title('DLsite重命名工具 v1.0') # 给窗口的可视化起名字
204220
root.geometry('300x375') # 设定窗口的大小(横向 * 纵向)
@@ -210,38 +226,37 @@ def thread_it(func, *args):
210226
# os.path.dirname(__file__) 当前脚本所在路径
211227
basedir = os.path.abspath(os.path.dirname(__file__))
212228
try:
213-
fname = os.path.join(basedir, '配置文件.txt')
214-
215-
with open(fname, 'r', encoding='utf-8') as f: # 打开配置文件
216-
lines = f.readlines() # 读取所有行
217-
first_line = lines[0] # 取第一行
218-
if first_line != '\n': # 第一行非空
219-
if ("RJ号" in first_line):
220-
template = first_line
221-
text.insert(tk.END, "**使用自定义命名格式:\n")
229+
fname = os.path.join(basedir, 'config.json')
230+
with open(fname, 'r') as f:
231+
config = json.load(f)
232+
if config["template"]: # 模板非空
233+
if ("workno" in config["template"]):
234+
template = config["template"]
235+
text.insert(tk.END, "**使用自定义命名模板:\n")
222236
text.insert(tk.END, " " + template.strip() + "\n\n")
223237
else:
224-
text.insert(tk.END, "**配置文件第一行格式错误\n")
225-
text.insert(tk.END, " 请修改配置文件\n")
226-
text.insert(tk.END, " 否则将使用默认命名格式:\n")
227-
text.insert(tk.END, " RJ号 [社团] 标题 (声优)\n\n")
238+
text.insert(tk.END, "**模板格式错误: 模板中必须包含\"workno\"!\n")
239+
text.insert(tk.END, " 使用默认命名模板:\n")
240+
text.insert(tk.END, " workno [circle] title (cv)\n\n")
228241
else:
229-
text.insert(tk.END, "**配置文件第一行为空!\n")
230-
text.insert(tk.END, " 请修改配置文件\n")
231-
text.insert(tk.END, " 否则将使用默认命名格式:\n")
232-
text.insert(tk.END, " RJ号 [社团] 标题 (声优)\n\n")
233-
242+
text.insert(tk.END, "**使用默认命名模板:\n")
243+
text.insert(tk.END, " workno [circle] title (cv)\n\n")
244+
234245
except os.error as err:
235-
text.insert(tk.END, "**配置文件缺失!\n")
236-
text.insert(tk.END, "**将使用默认命名格式:\n")
237-
text.insert(tk.END, " RJ号 [社团] 标题 (声优)\n")
246+
# 生成配置文件
247+
with open(fname, "w") as f:
248+
json.dump({'template': ''}, f, sort_keys=True,
249+
indent=4, separators=(',', ': '))
250+
text.insert(tk.END, "**使用默认命名模板:\n")
251+
text.insert(tk.END, " workno [circle] title (cv)\n")
238252

239253
var1 = tk.IntVar() # 定义var1整型变量用来存放选择行为返回值
240-
cbtn = tk.Checkbutton(root, text='去除标题中【】之间的内容', variable=var1, onvalue=1, offvalue=0) # 传值原理类似于radiobutton部件
254+
cbtn = tk.Checkbutton(root, text='去除title中【】之间的内容', variable=var1,
255+
onvalue=1, offvalue=0) # 传值原理类似于radiobutton部件
241256

242-
btn = tk.Button(root, text='选择路径', command=lambda :thread_it(nameChange))
257+
btn = tk.Button(root, text='选择路径', command=lambda: thread_it(nameChange))
243258

244259
btn.pack()
245260
cbtn.pack()
246261

247-
root.mainloop()
262+
root.mainloop()

打包.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
CALL D:\ProgramData\Anaconda3\Scripts\activate.bat D:\ProgramData\Anaconda3
1+
CALL C:\ProgramData\Anaconda3\Scripts\activate.bat C:\ProgramData\Anaconda3
22
pyinstaller -F -w -i favicon_128x128.ico test.py
33
pause

0 commit comments

Comments
 (0)