MP3 檔案的 ID3v1 標籤位於檔案末尾 128 位元組,包含標題、藝術家、專輯、年份、註釋、流派等資訊。本文實作一個純 Python 2.x 腳本,遞迴掃描目錄解析所有 MP3 標籤並輸出。
| 欄位 | 位移 | 長度 |
|---|---|---|
| TAG 標識 | 0-2 | 3 bytes |
| 標題 | 3-32 | 30 bytes |
| 藝術家 | 33-62 | 30 bytes |
| 專輯 | 63-92 | 30 bytes |
| 年份 | 93-96 | 4 bytes |
| 註釋 | 97-126 | 30 bytes |
| 流派 | 127 | 1 byte |
import os, sys
from UserDict import UserDict
def stripnulls(data):
return data.replace("\x00", "").strip()
class FileInfo(UserDict):
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
class MP3FileInfo(FileInfo):
tagDataMap = {
"title": (3, 33, stripnulls),
"artist": (33, 63, stripnulls),
"album": (63, 93, stripnulls),
"year": (93, 97, stripnulls),
"comment": (97, 126, stripnulls),
"genre": (127, 128, ord)
}
def __parse(self, filename):
self.clear()
try:
fsock = open(filename, "rb", 0)
try:
fsock.seek(-128, 2) # 從檔案末尾倒數 128 位元組
tagdata = fsock.read(128)
finally:
fsock.close()
if tagdata[:3] == "TAG":
for tag, (start, end, parseFunc) in self.tagDataMap.items():
self[tag] = parseFunc(tagdata[start:end])
except IOError:
pass
def __setitem__(self, key, item):
if key == "name" and item:
self.__parse(item)
FileInfo.__setitem__(self, key, item)
def listDirectory(directory, fileExtList):
fileList = [os.path.normcase(f) for f in os.listdir(directory)]
fileList = [os.path.join(directory, f) for f in fileList
if os.path.splitext(f)[1] in fileExtList]
return [getFileInfoClass(f)(f) for f in fileList]
def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):
subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]
return hasattr(module, subclass) and getattr(module, subclass) or FileInfo
if __name__ == "__main__":
for info in listDirectory("E:\\Music", [".mp3"]):
print "\n".join(["%s=%s" % (k, v) for k, v in info.items()])
print
album=What Are Words - Single
comment=pythontab
name=E:\Music\chris medina - what_are_words.mp3
title=What Are Words
artist=Chris Medina
year=2011
genre=13
album=After the Wedding
comment=pythontab
name=E:\Music\two fathers.mp3
title=Two Fathers
artist=pythontab
year=2010
genre=255
seek(-128, 2):從檔案末尾(whence=2)定位UserDict:字典繼承基類,支援 __setitem__ 覆寫getFileInfoClass:根據副檔名動態選擇解析類別stripnulls 清除空字元與首尾空白mutagen、eyed3 等成熟庫處理複雜格式