用python对MP3歌曲按歌手或者专辑名称进行分类管理

最近MP3歌曲需要分类,就借助网上其他高手制作的库,写了个自动分类程序,可以迅速将mp3歌曲按歌手或者专辑名称进行分类安置。前提条件:假设mp3文件都有 ID3v2 帧标识,或者是按 歌手-歌曲名的方式命名的文件。
关于ID3v2标识的含义,参考https://www.cnblogs.com/nightnine/p/5062624.html
感谢高人制作的MP3标签解析库,适合python3.X版本。库文件详见:【原】Python3 下 MP3格式文件的ID3v2标签与压缩信息读取_Allen恒思凝_新浪博客
以下为程序:
 
# -*- coding: utf-8 -*-
"""
-----------------------------------主程序-------------------------------
按歌手或者专辑名移动MP3.py 
将这个主程序和ID3v2.py , MP3.py  ,MP3Info.py 三个文件(此三个文件详见前面链接2)放在一起,就可以用了。
Created on Sun Jun 14 22:35:36 2020
用于快速给mp3歌曲按歌手或者专辑进行分类
@author: user
"""
import MP3
import re
import os
import shutil

#原音乐所在文件夹=os.path.split(os.path.realpath(__file__))[0]  #若启动此语句,就是默认处理当前py文件所在路径
原音乐所在文件夹=r'C:\音乐归集'
归集方式='专辑'#可选择参数:歌手 或 专辑

转移目标文件夹路径=os.path.join('C:\音乐归集-专辑')
def thwb(dthwb,nr):
    for i in range(len(dthwb)):
        if isinstance(dthwb[i],str):#是文本类型直接替换成没有
            nr=nr.replace(dthwb[i],'')
        elif isinstance(dthwb[i],list):#事列表类型,替换为指定的值
            nr=nr.replace(dthwb[i][0],dthwb[i][1])
    return nr
xttszf=[['?','?'],[':',':'],['*','*'],['<','<'],['>','>'],[r'/','/'],['\\','\'],['|','|'],['"','"']]#windows文件系统不允许以下字符   < > / \ | : " * ?
def find_file(path, ext, file_list=[]):
    dir = os.listdir(path)
    for i in dir:
       i = os.path.join(path, i)
       if os.path.isdir(i):
          find_file(i, ext, file_list)
       else:
           if ext == os.path.splitext(i)[1]:
              file_list.append(i)
    return file_list
ext = ".mp3"
file_list = find_file(原音乐所在文件夹, ext)
for file in file_list:
    a = MP3.MP3(file)
    filename = os.path.basename(file)
    try:
#        乐曲名称=a.d['TIT2']
        if 归集方式=='歌手':
            歌手=a.d['TPE1']
            歌手=thwb(xttszf,歌手)#此处必须对获取的题目做个处理,避免无法作为正常文件路径
            待转移文件夹路径_file=os.path.join(转移目标文件夹路径,歌手)
        elif 归集方式=='专辑':
            专辑名=a.d['TALB']
            专辑名=thwb(xttszf,专辑名)
            待转移文件夹路径_file=os.path.join(转移目标文件夹路径,专辑名)
        if not os.path.exists(待转移文件夹路径_file):
            os.makedirs(待转移文件夹路径_file)
#        print(待转移文件夹路径_file)
        shutil.move(file,待转移文件夹路径_file)
    except Exception as exc:
        try:#按第二方案,假设是歌手-歌曲名的命名方式
            文件名后缀=os.path.splitext(file)[1]
            文件名=filename.replace(文件名后缀,'')

#            print(歌手)
#            print(乐曲名称)
            if 归集方式=='歌手':
                word = u'-'
                a = [m.start() for m in re.finditer(word, 文件名)]#找到所有-符号所在位置
                歌手=文件名[:a[-1]].strip()
                歌手=thwb(xttszf,歌手)
#                乐曲名称=文件名[a[-1]+1:].strip()
                待转移文件夹路径_file=os.path.join(转移目标文件夹路径,歌手)
            if 归集方式=='专辑':
                专辑名='未分类专辑'
                待转移文件夹路径_file=os.path.join(转移目标文件夹路径,专辑名)
            if not os.path.exists(待转移文件夹路径_file):
               os.makedirs(待转移文件夹路径_file)
            shutil.move(file,待转移文件夹路径_file)
        except Exception as exc:
            print(exc)

下面是对应库文件代码,留存,怕网页内容丢了

---1/3------------

# ID3v2.py  version 1.2

# Module for manipulating ID3 informational tags in MP3 audio files

# 鉴于现在适用与python3的ID3软件包很少,遂自己写了一个。现在网上的mp3一般都有ID3v2标签,

# 本模块功能就是读取mp3文件的ID3v2标签,把标签记录在一个集合里面。

# 特别的,对于最常见的歌手,曲名和专辑名,可以通过一些内部属性直接调用访问。

# Written 2013/4/19 By Kayneo <kayneo@yeah.net>

# This is the first thing I've written in Python.

# constructor:

#       ID3(filename)

# then you can use the ID3v2 tag as in the follwing

#

# ID3.d

#   It's a set containing all the tag found in ID3v2

#

# ID3.title or ID3.d['TIT2']

#   The title of the song

#

# ID3.artist of ID3.d['TPE1']

#    The artist

#

# ID3.album or ID3.d['TALB']

#    The album

#

# ID3.haspic

#    Whether or not has a pic

#

# ID3.tagverison

#    The ID3v2 version :v2.3 or v2.4

#

# ID3.tagsize

#    The size of the ID3 tag

#

# ID3.d['TYER']

#    The year

#

# ID3.d[etc.]

#    Other tags.

# Usage :

# import ID3v2

# a=ID3v2.ID3('filename')

# print(a.d)

# print(a.artist, a.title, a.album)

def trip_space(s):

    while len(s) > 0 and s[-1] == '\x00':

        s = s[:-1]

##    while len(s) > 0 and s[:2]  == b'\x00\x00':

##        s = s[2:]

    return s

class NoID3v2Error(Exception):

    def __init__(self, msg):

        self.msg = msg

    def __str__(self):

        return self.msg

class ID3:

    def __init__(self, file):

        self.fname = file

        try:

            self.file = open(file, 'rb')

        except IOError as msg:

            print('{0:s} open Error! {1:s}'.format(self.fname,msg))

            return

        

        if self.file.read(3) != b'ID3' :

            #print('No ID3v2 Tag')

            raise NoID3v2Error('No ID3v2 Tag')

            self.file.close()

            return

        self.d = {}

        self.tagversion = 0

        self.tagsize = 0

        self.haspic = False

        self.artist = ''

        self.title = ''

        self.album = ''

        

        HDR = self.file.read(7)

        self.tagv = 'v%d.%d'%(2,HDR[0])

        self.tagsize = HDR[-1]+HDR[-2]*0x80+HDR[-3]*0x4000+HDR[-4]*0x200000 +10

        #print (self.tagsize)

        

        while True:

            a = self.file.read(1)

            if a ==  b'\x00' or a == b'\xff': break

            

            self.file.seek(-1,1)

            fhdr = self.file.read(10) # ;print (fhdr)

            sz = fhdr[-3]+fhdr[-4]*0x100 +fhdr[-5]*0x10000+fhdr[-6]*0x1000000

            kind = fhdr[0:4].decode()

            if kind != 'APIC':

                info = self.file.read(sz) #;print (info)

                try:

                    st = info.rfind(b'\xff\xfe')

                    if st != -1: # \x01\xff\xfe.....\xff\xfe

                       self.d[kind] = trip_space(info[st+2:].decode('utf16'))

                       

                    elif info.startswith(b'\x03'):

                        self.d[kind] = trip_space(info[1:].decode())

                        

                    else: #\x00

                        self.d[kind] = info[1:-1].replace(b'\x00',b'\x20').decode('gbk')

                        

                except UnicodeDecodeError as msg:

                    #print('Decode Error @%s, Content is %s\nMsg:%s'%(kind,info, msg))

                    pass

                    

            else:

                self.haspic = True

                break

                #self.file.seek(sz,1)

            #print(self.file.tell()) 

        

        if 'TPE1' in self.d.keys(): self.artist = self.d['TPE1']

        if 'TIT2' in self.d.keys(): self.title  = self.d['TIT2']

        if 'TALB' in self.d.keys(): self.album  = self.d['TALB']

        self.file.close()

---2/3-------------

# MP3.py  Version 1.0

# This module is to get the ID3v2 and infomation of MP3 file.

#获取MP3的信息包含id3v2信息

# Written 2013/4/19 By Kayneo <kayneo@yeah.net>

# This is the first thing I've written in Python.

# Constrctor:

#       MP3(filename)

#then you can use the ID3v2 tag as in the follwing

#

# MP3.title or MP3.d['TIT2']

#   The title of the song

#

# MP3.artist of MP3.d['TPE1']

#    The artist

#

# MP3.album or MP3.d['TALB']

#    The album

#

# MP3.bitrate or ID3.d['Bitrate']

#   The bitrate of the song

#

# MP3.trackmod or MP3.d['Trackmod']

#    The mode of track. 声道模式

#

# MP3.sample_freq or MP3.d['Sample Frequency']

#    The frequency of sample 采样率

#

# MP3.d[...]

#    Various properties of MP3

#

# Usage :

# import MP3

# a=MP3.MP3('filename')

# print(a.d)

# print(a.artist, a.title, a.bitrate)

from MP3Info import MP3Info

from ID3v2 import *

class MP3:

    def __init__(self, file, name='unknown'):

        self.name = file

        self.artist  = ''

        self.title   = ''

        self.album   = ''

        

        self.bitrate     = ''

        self.trackmod    = ''

        self.sample_freq = ''

        self.d={}

        

        try:

            mp3info = MP3Info(file)

            

            self.bitrate = mp3info.bitrate

            self.trackmod= mp3info.trackmod

            self.sample_freq = mp3info.sample_freq

        

            id3     = ID3(file)

            

            self.artist = id3.artist

            self.title = id3.title

            self.album = id3.album

            self.d = dict(mp3info.d, **id3.d)

            

        except NoID3v2Error as msg:

            self.d = mp3info.d

            print(msg)

##        except :

##            print('Some Error!')

##            

            

---3/3------------------------------------------------------            

# MP3Info.py Version 1.0

# This module focus on geting the infomation of the MP3 file, such as bitrate, sample frequency.

# 获取MP3的信息,包括比特率,取样率,等等。

# Written 2013/4/19 By Kayneo <kayneo@yeah.net>

# This is the first thing I've written in Python.

# constructor:

#       MP3Info(filename)

# then you can use the ID3v2 tag as in the follwing

#

# MP3.d

#   It's a set containing all the tag found in MP3

#

# MP3Info.version of MP3Info.d['Version']

#    The version of the file

#

# MP3Info.bitrate or MP3Info.d['Bitrate']

#   The bitrate of the song

#

# MP3Info.trackmod or MP3Info.d['Trackmod']

#    The mode of track. 声道模式

#

# MP3Info.sample_freq or MP3Info.d['Sample Frequency']

#    The frequency of sample 采样率

#

# MP3Info.copyright or MP3Info.d['Copyright']

#    The copyright of MP3

#

# MP3Info.original or MP3Info.d['Original']

#    Whether or not Original 是否原版

#

# MP3Info.frame_mod or MP3Info.d['Frame Mode']

#    The mode of frame

# Usage :

# import MP3Info 

# a=MP3Info.MP3Info('filename')

# print (a.d)

# print(a.bitrate)

class MP3Info:

    MP3Version = {0b00:'MPEG 2.5', 0b01:'UNDEFINED', 0b10:'MPEG 2', 0b11:'MPEG 1'}

    MP3Layer = {0b00:'UNDEFINED', 0b01:'Layer 3', 0b10:'Layer 2', 0b11:'Layer 1'}

    MP3CRC = {0b0:'校检', 0b1:'非校检'}

    MP3Bitrate = {0b0000:'free',

                  0b0001:32,

                  0b0010:40,

                  0b0011:48,

                  0b0100:56,

                  0b0101:64,

                  0b0110:80,

                  0b0111:96,

                  0b1000:112,

                  0b1001:128,

                  0b1010:160,

                  0b1011:192,

                  0b1100:224,

                  0b1101:256,

                  0b1110:320,

                  0b1111:'bad'}

    MP3Samp_freq = {0b00:441000, 0b01:48000, 0b10:32000, 0b11:'UNdefined'}

    MP3Frame_mod = {0:'无需调整',1:'调整'}

    MP3Trackmod ={0b00:'立体声',0b01:'联合立体声',0b10:'双声道',0b11:'单声道'}

    MP3Copyright ={0b0:'不合法', 0b1:'合法'}

    MP3Original = {0b0:'非原版', 0b1:'原版'}

    def __init__(self, file):

        self.name = file

        try:

            self.file = open(file, 'rb')

        except IOError as msg:

            print('{0:s} open Error! {1:s}'.format(self.fname,msg))

            return

        if self.file.read(3) == b'ID3':

            HDR=self.file.read(7)

            tagsz = HDR[-1]+HDR[-2]*0x80+HDR[-3]*0x4000+HDR[-4]*0x200000 +10

            self.file.seek(tagsz,0)

        else:

            self.file.seek(0)

        framehdr = self.file.read(4)

        vbrinfo  = self.file.read(32)

        

        self.file.close()

        self.d={}

        

        self.version = self.MP3Version[(framehdr[1]&0b00011000)>>3] +' - ' +self.MP3Layer[(framehdr[1] & 0b00000110)>>1]

        self.bitrate = self.MP3Bitrate[framehdr[2]>>4]

        self.sample_freq = self.MP3Samp_freq[(framehdr[2]&0b00001100)>>2]

        self.padding = (framehdr[2]&0b00000010)>>1

        self.frame_mod = self.MP3Frame_mod[self.padding]

        self.trackmod = self.MP3Trackmod[framehdr[3]>>6]

        self.copyright = self.MP3Copyright[(framehdr[3]&0b00001000)>>3]

        self.original = self.MP3Original[(framehdr[3] &0b00000100)>>2]

        if self.version : self.d['Version'] = self.version

        if self.bitrate : self.d['Bitrate'] = self.bitrate

        if self.sample_freq : self.d['Sample Frequency'] = self.sample_freq

        if self.frame_mod : self.d['Frame Mode'] = self.frame_mod

        if self.trackmod :self.d['Track Mode'] = self.trackmod

        if self.copyright: self.d['Copyright'] = self.copyright

        if self.original : self.d['Original'] = self.original

        

        

 ------------ single.py -----------------

import MP3,re

file = r'a.mp3'

a = MP3.MP3(file)

print (a.d)

---------------------------------

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值