批量修改喜马拉雅下载节目的文件名

要过节啦,下载了一批喜马拉雅的有声读物,准备放到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:
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系统是中文版,默认编码是GBKPython3应该是取了这个默认值,所以修改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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页