Python實現mp3 ID3v2.3資訊提取

專注的阿熊發表於2021-01-27

實現程式碼

# 引用所需模組 import re  # 正規表示式

# mp3 資訊和路徑提取 def mp3Info(input_file_url):

    # 讀取 mp3 檔案

    input_file_url = input_file_url

    with open(input_file_url, "rb") as input_file:

        mp3_data = input_file.read().hex()

    # 判斷 mp3 檔案型別是否是 ID3v2.3 格式

    if mp3_data[:6] == "494433" and mp3_data[6:8] == "03":

        print(" 歌曲是 ID3v2.3 版本 , 正在提取資訊 ...")

        # 獲取歌曲名稱

        if re.search(r"\\", input_file_url):

            input_file_name = re.search("(.*).mp3", input_file_url.split("\\")[-1]).group(1)

        else:

            input_file_name = re.search("(.*).mp3", input_file_url).group(1)

        # 獲取歌曲路徑

        if re.search("(.*)" + input_file_name + ".mp3", input_file_url):

            input_file_path = re.search("(.*)" + input_file_name + ".mp3", input_file_url).group(1)

        else:

            input_file_path = ""

        return mp3_data, input_file_path, input_file_name  # 返回 mp3 16 進位制資料 , 輸入檔案路徑 , 輸入檔案檔名

    else:

        return ""

# 提取標籤內容函式 def tagInfo(tag_name, mp3_data):

    # 標籤名稱, mp3 完整資料

    tag_name, mp3_data = tag_name, mp3_data

    # 標籤列表

    tag_name_list = {"TIT2": "54495432", "TPE1": "54504531", "TALB": "54414c42"}

    if tag_name in tag_name_list:

        tag_hex = tag_name_list[tag_name]  # 標籤的 16 進位制資料

        # 標籤長度

        tag_len = int(re.search(tag_hex + "(.{8})", mp3_data).group(1), 16)

        # print("%s 標籤的長度是 %s 個位元組 " % (tag_name,tag_len))

        # 判斷標籤型別

        tag_index = mp3_data.find(tag_hex)

        tag_data_type = mp3_data[(tag_index + 2 * (4 + 4 + 2)):(tag_index + 2 * (4 + 4 + 2 + 1))]

        # 判斷內容編碼方式

        if tag_data_type == "00":

            encoding_type = 'iso8859-1'

            # print(" 採用 ISO-8859-1 編碼 ")

        if tag_data_type == "01":

            encoding_type = 'utf-16-le'

            # print(" 採用 UTF-16LE 編碼 ")

        elif tag_data_type == "02":

            encoding_type = 'utf-16-be'

            # print(" 採用 UTF-16BE 編碼 ")

        # elif tag_data_type == "03":    # (僅 ID3V2.4 才支援)

        #     encoding_type = 'utf-8'

        #     print(" 採用 UTF-8 編碼 ")

        # 提取標籤內容

        tag_data_hex = mp3_data[(tag_index + 2 * (4 + 4 + 2 + 1)):(

                tag_index + 2 * (4 + 4 + 2 + 1) + tag_len * 2 - 2)]  # 取標籤內容 (16 進位制 )

        tag_data_bytes = bytes.fromhex(tag_data_hex)  # 將字串轉換為位元組流資料

        tag_info = tag_data_bytes.decode(encoding_type, 'ignore')  # 根據編碼型別解碼

        return tag_info  # 返回標籤的內容

    else:

        return ""

# 提取所需標籤資訊 def tagsInfo():

    # 標籤型別 TIT2: 標題 ,TPE1: 藝術家 ,TALB: 專輯

    tags = {"TIT2": " 歌名 ", "TPE1": " 歌手 ", "TALB": " 專輯 "}

    # 標籤內容提取

    tags_info = {}

    for i in tags:

        tag_name = i

        tag_info = tagInfo(tag_name, mp3_data)  # 標籤資料

        tags_info[tags[i]] = tag_info.encode('utf-8').decode('utf-8-sig')  # 使用 utf-8-sig 編碼,否則出現 '\ufeff' BOM 資料

    return tags_info  # 返回所有標籤的內容

# 獲取歌曲時長函式跟單網 def mp3Duration(mp3_data):

    music_index = mp3_data.find("496e666f0000000f")  # 定位歌曲實際的起始位置

    music_size = len(mp3_data[music_index:]) / 2  # 歌曲位元組長度

    duration = music_size * 8 / (128 * 1000)  # 獲取歌曲時長,單位 s

    duration_show = str(int(duration / 60)) + ":" + str(int(duration % 60))  # 格式化歌曲時長

    return duration_show  # 返回格式化的歌曲時長

# 提取圖片函式 def imgTag(mp3_data, input_file_path, input_file_name):

    # 歌曲資料 , 輸入檔案的路徑 , 輸入檔案的檔名

    mp3_data, input_file_path, input_file_name = mp3_data, input_file_path, input_file_name

    # 圖片資料的提取

    img_data_hex = re.search(r"ffd8.+?496e666f0000000f", mp3_data)[0]  # 圖片的 16 進位制資料

    if img_data_hex:

        img_data_bytes = bytes.fromhex(img_data_hex)  # 將字串轉換為位元組流資料

        out_file_name = input_file_path + input_file_name + '.jpg'

        with open(out_file_name, "wb") as out_file:

            out_file.write(img_data_bytes)

        return "%s%s.jpg" % (input_file_path, input_file_name)

    else:

        return ""

if __name__ == '__main__':

    try:

        # 提示資訊

        print("##### 本程式為提取 mp3 ID3v2.3 格式的歌曲資訊 #####")

        # mp3 路徑

        input_file_url = input(" 請輸入需要提取的檔案路徑: ")

        # 獲取歌曲資訊

        mp3_info = mp3Info(input_file_url)

        if mp3_info:

            # 獲取檔案路徑 , 檔名

            mp3_data, input_file_path, input_file_name = mp3_info  # 返回 mp3 16 進位制資料 , 輸入檔案路徑 , 輸入檔案檔名

            # 獲取標籤資料

            tags_info = tagsInfo()

            # 獲取歌曲時長資訊

            mp3_duration = mp3Duration(mp3_data)

            tags_info[" 時長 "] = mp3_duration  # 新增時長欄位

            # 獲取圖片資料

            imgInfo = imgTag(mp3_data, input_file_path, input_file_name)

            tags_info[" 圖片路徑 "] = imgInfo  # 新增圖片欄位

            print(tags_info)

            # 日誌資訊

            log = " 歌曲路徑 : " + input_file_path + input_file_name + ".mp3 \n" + " 歌曲資訊: " + str(

                tags_info) + "\n\n"

        else:

            # 日誌資訊

            log = " 暫不支援此檔案的提取 , 本程式僅支援 ID3v2.3 格式的 mp3 檔案 \n\n"

            print(" 暫不支援此檔案的提取 , 本程式僅支援 ID3v2.3 格式的 mp3 檔案 ")

    except:

        # 日誌資訊

        log = " 意外錯誤 \n\n"

        print(" 意外錯誤 ")

    finally:

        # 儲存日誌

        with open(r"log.txt", "a") as out_file:

            out_file.write(log)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2753833/,如需轉載,請註明出處,否則將追究法律責任。

相關文章