使用Python讀取和寫入mp3文件的id3v1信息

ybw8 9年前發布 | 11K 次閱讀 Python Python開發

1.起因

一直以來瘋迷“冬吳相對論”,為了整理下載他的MP3花了不少功夫,今天突然發現將電腦中的mp3導入到itunes后,文件名竟然不識別了。#_* itunes自動識別了mp3的信息內容。多次一舉么,文件名挺好。事實如此,讓我深感不完美。一定要將文件名也寫如MP3信息中區。

網上一搜,一大把的python代碼,都是用了eyeD3這個組件包。照著例子簡單搞了兩下就出來一個版本,運行發現latin_1啥的編碼問題。OK把它的tag和id3還有frames包中的編碼統統改成GBK就能解決了。但是又發現,如果文件原本沒有id3v1時,獲取title就直接報錯了。找了兩下沒有發現有人提這個問題。看來只能自己動手了。那就完全不用eyeD3包了。因為id3v1確實很簡單。

2.分析

百度就有說,我想寫的這些信息可保存于mp3文件的尾部。

ID3V1比較簡單,它是存放在MP3文件的末尾,用16進制的編輯器打開一個MP3文件,查看其末尾的128個順序存放字節,數據結構定義如下:

char Header[3]; /標簽頭必須是"TAG"否則認為沒有標簽/

char Title[30]; /標題/

char Artist[30]; /作者/

char Album[30]; /專集/

char Year[4]; /出品年代/

char Comment[30]; /備注/

char Genre; /類型/

ID3V1的各項信息都是順序存放,沒有任何標識將其分開,比如標題信息不足30個字節,則使用'\0'補足,否則將造成信息錯誤。

3.解決

還好,文件結構不復雜,處理起來就相對簡單。思路很簡單,讀取mp3文件的尾部128字節,判斷一下有米有TAG,有了就把最后的128節用我們自己的信息替換掉,沒有就補充128字節上去。

4.代碼

最好的文檔就是源碼,當然我回寫注釋的。沒有依賴eyeD3這樣的包,純手工寫法。

#encoding=utf8
__author__ ='[email protected]'import os
importstructdefGetFiles(path):"""
    讀取指定目錄的文件
    """FileDic=[]
    files=os.listdir(path)for f in files:
        f=f[:-4]FileDic.append(f)returnFileDic,files
def_GetLast128K(path,file):
    ff1=open(os.path.join(path,file),"rb")
    ff1.seek(-128,2)
    id3v1data=ff1.read()
    ff1.close()return id3v1data
def_GetAllBinData(path,file):
    ff1=open(os.path.join(path,file),"rb")
    data=ff1.read()
    ff1.close()return data
defSetTag(path,file,title,artist,album,year,comment,genre):"""
    設置mp3的ID3 v1中的部分參數
    char Header[3]; /*標簽頭必須是"TAG"否則認為沒有標簽*/
    char Title[30]; /*標題*/
    char Artist[30]; /*作者*/
    char Album[30]; /*專集*/
    char Year[4]; /*出品年代*/
    char Comment[30]; /*備注*/
    char Genre; /*類型*/
    mp3文件尾部128字節為id3v1的數據,如果有數據則讀取修改,無數據則補充
    """
    header='TAG'#組合出最后128K的id3V1的數據內容
    str =struct.pack('3s30s30s30s4s30ss',header,title,artist,album,year,comment,genre)#獲取原始全部數據
    data=_GetAllBinData(path,file)#獲取末尾的128字節數據
    id3v1data=_GetLast128K(path,file)#打開原文件準備寫入
    ff=open(os.path.join(path,file),"wb")try:#判斷是否有id3v1數據if id3v1data[0:3]!=header:#倒數128字節不是以TAG開頭的說明沒有#按照id3v1的結構補充上去
            ff.write(data+str)else:#有的情況下要換一下
            ff.write(data[0:-128]+str)
        ff.close()print"OK"+title
    except:
        ff.write(data)print"Error "+title
    finally:if ff :ff.close()if __name__=="__main__":#我存放mp3文件的目錄
    path=u"K:\\reading\\閱讀\\相對論"#獲取到文件名和文件全名
    names,files=GetFiles(path)#苦力代碼for i in range(len(files)):#注意編碼解碼
        title=names[i].encode('gbk')
        artist=u'作者'.encode('gbk')
        album=u'相對論'.encode('gbk')
        year=''
        comment=''
        genre=''#調用函數處理SetTag(path,files[i],title,artist,album,year,comment,genre)

5.后續

使用了以后id3v1的信息全部按文件名改好了,其中的SetTag函數也可以遷移到別的程序里用來改id3v1的信息。但是寫文件那里,無論是否有TAG都得重寫全部文件內容。效率一般般。速度沒有eyeD3這種組件快。但那時eyeD3不能支持中文,而且文件本來沒id3v1信息時會出錯,自己的就放心多了。 bingo 收工。


 本文由用戶 ybw8 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!