批量修改喜马拉雅下载节目的文件名
2017-09-28 13:46阅读:
要过节啦,下载了一批喜马拉雅的有声读物,准备放到SD卡里到车上听。到目录一瞧,嘿,都是些啥玩意。
│
├─323366
│ 51937074.m4a
│ 52070404.m4a
│
├─4756811
│ 18556415.m4a
│
├─6729285
│ 38100357.m4a
│
└─7651313
50867022.m4a
我想要的是类似这样的目录和歌曲名
│
├─CCTV朗读者
│ 朗读者特别节目丨王姬:致母亲“妈妈,下辈子请您做我的女儿。”.m4a
│
├─冷历史
│ 一线业务代表怎样像白起一样做起来.m4a
│ 职场上千万不要犯和白起一样的错.m4a
│
├─摸金天师(盗墓小说):紫襟故事
│ 《摸金天师》第001章 百辟刀(求订阅,打赏!).m4a
│
└─晓说2017
晓说第23期:口述历史对谈马未都(上)老北京寻宝记.m4a
研究一下喜马拉雅的下载目录,发现下载的每个节目由两个描述性的jSON文件和存放具体文件的目录组成。举个例子更容易明白,对上面的323366,在下载的根目录下,有两个323366开头的JSON文件:
1) 322266info.json,节目总体描述
323366info.json描述了节目信息,我们感兴趣的关键信息是'Title',表示节目名,“冷历史”;我们要用这个名字修改存放文件的目录名
2) 323366list.json,具体节目描述
323366list.json表示节目里包含的曲目名,是一个JSON数组,每个表示一个曲目。list文件的第
一个“Title”=“职场上千万不要犯和白起一样的错”
初步想法就是利用这两个文件里的信息,修改文件目录名,和文件目录里的各个音频文件名。
这玩意下载的多了,没法手动去逐个改,还不得累死我这老胳膊老腿的。所以决定写个Python程序,来完成这个任务。
这是我写的第二个python程序,所以坑还真不少,有得坑跟喜马拉雅有关。简单列一些,供以后参考。
1. 编码坑
之前就掉进python的坑里,好不容易爬出来,以为都应该明白了呢。现实总是残酷的多,要解析JSON文件,总得先读进来吧,如下:
with open('323366info.json','r') as load_f:
load_dict = json.load(load_f)
print(load_dict['title'])
总是在load这句,报错:UnicodeDecodeError:
'gbk' codec can't decode byte 0xb2 in position 93: illegal
multibyte sequence
即使在load里加入了“encoding=”utf-8””。以为又是cmd窗口的问题,
用chcp修改了代码页,无济于事。
仔细研究,发现open默认按字符方式打开,这时其实有一个编码隐含在这里,我的Windows系统是中文版,默认编码是GBK,Python3应该是取了这个默认值,所以修改CMD窗口无济于事。
了解了来龙去脉,修改就简单了,只需将第一句话修改成:
with open('323366info.json','r',encoding = 'utf-8') as
load_f:
2. 正则表达式坑
喜马拉雅的Title是用户上传的,所以Title里包含什么都不奇怪。但Windows目录名是有禁忌的,下面这些字符都不可以出现在文件和目录名中:
/\:*?'<>|]
可以管这些叫咒符,自然的想法就是遇到这些咒符,就查一下替换掉。
等一下,这不就是正则表达式擅长的吗,虽然没怎么用过,我还是决定试一试这高级玩意。
“\”,“:”,“?”,“|”,这些都是正则表达式的元字符,应该需要转义,但也有文档说,如果包含在“[...]'内,应该不需要,但实际上报错,还好可以在交互窗口中逐个试,最后发现应该写成这样才可以:
illegal_Char = re.compile(r'[/\\:*?\'<>|]')
也就是只有“\”和“'”需要转义,从道理上倒也讲得通,解释器找到“'”就认为这一个语句结束了,为什么不能说的更清楚些呢。
3. 喜马拉雅的同名节目坑
同一个节目目录下,居然有曲目完全同名。虽然知道喜马拉雅号称UGC(用户生成内容),但不能这么坑吧。
没办法,解决方法是,从xxxlist.json里找到了“ID”字段,不同曲目可能完全同名,但ID一定是不同的,如果遇到重名的,则给后出现的曲目加一个xxxxx的部分,比如如下罗辑思维的例子:
|
├─你是巨婴吗x[罗辑思维]No·198
├─你因挣钱而伟大 [罗辑思维]No.117
├─你因挣钱而伟大 [罗辑思维]No.1176585108
4. UTF-8与GBK的坑
对单字节高于0x80的字符,Unicode是支持的。比如,一些节目的Title里包含“-”字符,注意这里的“-”不是键盘上那个,而是在扩展ASCII里,这个被编码为0xA0,UTF-8编码为0xC2
A0,奇怪的是,GBK不支持这个字符,或者说python的decode函数不支持,所以总是报encoding
error。后来发现可以先主动转一遍,对无法转换的字符,指定Ignore,则可以跳过.
print(old,'==>', new.encode('gbk','ignore').decode('gbk'))
差不多了,这些坑踩了个遍,我得第二个python程序可以正常工作了,我的国庆有声读物下载的也差不多了,有1700多个,运行一遍,10秒钟全部改完了。嗯,还不错。
贴上其中的一个关键函数,完整程序有需要者可以找我要
def ren_files(dir):
updir = os.getcwd()
subdir = '.\\'+dir
os.chdir(subdir)
print(os.getcwd())
#####修改文件#####
#获取上级目录下的list文件,是个多维JSON,包括了目录下所有节目信息
infofilepath = updir + '\\' + dir + 'list.json'
#print(infofilepath)
infofile = open(infofilepath,'r',encoding = 'utf-8')
playlist = json.load(infofile)
#print(playlist)
#print(len(playlist))
for i in range(len(playlist)):
old = str(playlist[i]['id']) + '.m4a'
new = playlist[i]['title'] + '.m4a'
new = re.sub(illegal_Char,'x',new)
#同一目录下会有同名文件,奇葩的喜马拉雅
if (os.path.exists(new)):
new = new = playlist[i]['title'] +
str(playlist[i]['trackId']) + '.m4a'
new = re.sub(illegal_Char,'x',new)
#print总是要按控制台的默认编码打印,有些节目名包含“0xc2a0”这个字符,是特殊的“-”符号,
#GBK无法编码这个字符,所以我们这里先主动编码一下,对无法解释的字符选择ignore,然后解码,
print(old,'==>',
new.encode('gbk','ignore').decode('gbk'))
os.rename(old, new);
infofile.close()
#####修改文件结束#####
os.chdir(updir)
#####修改目录名#####
infofilepath = updir + '\\' + dir + 'info.json'
print(infofilepath)
infofile = open(infofilepath,'r',encoding = 'utf-8')
playlist = json.load(infofile)
old = dir
new = playlist['title']
new = re.sub(illegal_Char,'x',new)
print('dir: ',old,'==>', new)
os.rename(old, new);
infofile.close()
#####修改目录名结束#####
return