1. python如何读取mp3、flac等音乐类型的歌曲时长
个人觉得python中的tinytag库最好用
一开始还找了另一种实现方式,不过发现不能读取flac类型的,就去找其他实现,然后就找到tinytag库。【方法2(第二个代码模块)最好用!不管什么类型都可以,而且不止可以看持续时长,可以把后面的.duration删掉可以发现名称、专辑、歌手等信息都有】
import librosa
"""method 1"""
for list1 in path_list1:
for index, elements in enumerate(os.listdir(list1)):
duration = int(librosa.get_duration(path=list1 + '\\' + elements))
len_list.append(duration)
name_list.append(elements)
from tinytag import TinyTag
"""method 2"""
for list1 in path_list1:
for index, elements in enumerate(os.listdir(list1)):
duration = TinyTag.get(list1 + '\\' + elements).duration
len_list.append(int(duration))
name_list.append(elements)
“获取时长都在倒数第3行duration”
2. 指定一个数字,计算出一首或两首歌的时长与该数最接近
【目前用不到3首的,但是感觉以后可以两首跟1首结合就是3首了,但是1、2首写得有点乱,抽象起来可能会有点麻烦】
下面是自己设计的歌曲时长相加或者单首歌曲时长等于目标值,返回歌曲名称和歌曲时长,其实还设计了精度,就是歌曲各种组合,使得与用户给出的目标值相差在一定的秒数误差内。
下面是源码,【缺点是排序算法设计的不好(运行的慢,好在当时歌曲量就500多首),但是当时着急用,想着先写出来,有时间再改】
其中,需要根据情况修改的地方:
- 开头第8行的精度jing_du, 歌曲组合后的时长与目标时长 的差值 的绝对值最大不超过该精度
- 紧接着的下面的path_list是我电脑中歌曲存放的路径
- 最后main函数开头那里指定了目标数字是输入的,可能会视情况而定,也可以不改。
import os
from tinytag import TinyTag
len_list = [] # 用于存储歌曲总秒数的列表
name_list = [] # 用于存储歌曲名称
"""所有需要修改的参数"""
jing_du = 2 # 歌曲相差的间隔
path_list = [r'E:\20231006资料统一\音乐\已经去iTunes', r'E:\20231006资料统一\音乐\MP3COpy\Music',
r'E:\20231006资料统一\音乐\MP3COpy\新建文件夹1', r'E:\20231006资料统一\音乐\MP3COpy\新建文件夹 (3)',
r'E:\20231006资料统一\音乐\准备去ituns(封面)', r'E:\20231006资料统一\音乐\林俊杰', r'E:\20231006资料统一\音乐\周杰伦']
def self_alg(numbers, target_sum):
"""思路:
目标值与最小值或者最大值的差如果小于10秒,可认为算法结束
首先判断目标数字是否在最大和最小之间
如果小于最小,就用最小; 如果大于最大(这是最常见的状态)试着判断最小和次小的和,看看结果
----【【【【【receive统一返回下标索引】】】】】----
"""
gap_num = 10 # 两首歌曲间的差值
return_list = [] # 最终返回的索引列表
if min(numbers) < target_sum < max(numbers): # 在最大和最小之间
print('min(numbers) < target_sum < max(numbers)')
one_song_alg()
exit()
if min(numbers) > target_sum: # 比最小还小
print('min(numbers) > target_sum\n') # 提示视频过短
return_list.append(numbers.index(min(numbers)))
return return_list # 返回目标值的索引
if max(numbers) < target_sum: # 比最大还大【主要情况】
if 2 * min(numbers) > target_sum: # 小于两倍最小值
print('2 * min(numbers) > target_sum\n') # 提示视频过短
return_list.append(numbers.index(min(numbers))) # 虽然比最大的大,但是比两个最小的还小,那么可以
return_list.append(numbers.index(min(numbers)))
return return_list
if 2 * min(numbers) < target_sum < 2 * max(numbers): # 大于两倍最小值并且小于两倍最大值
print('2 * min(numbers) < target_sum < 2 * max(numbers)')
temp_list = [] # 存放两首歌各自长度的列表
sum_list = [] # 计算上面两首歌长度之和
for i in range(len(numbers)):
for j in range(i, len(numbers)):
if abs(target_sum - numbers[i] - numbers[j]) <= gap_num:
temp_list.append([i, j]) # 两首歌的长度的下标索引的存储列表
sum_list.append(abs(target_sum - numbers[i] - numbers[j])) # 列表里面存在与目标值的距离
# 接下来在歌曲长度列表中查找合适的最小值:
for ll in sum_list: # 选取差值最小
if ll < min(sum_list) + gap_num and temp_list[sum_list.index(ll)] not in return_list: # 误差内,且没加过
return_list.append(temp_list[sum_list.index(ll)])
return return_list # 取最后一次满足条件的
if 2 * max(numbers) < target_sum:
print('2 * max(numbers) < target_sum')
return_list.append(numbers.index(max(numbers))) # 虽然比最大的大,但是比两个最小的还小,那么可以
return_list.append(numbers.index(max(numbers)))
return return_list
def list_alg_paixu(path_list1):
"""
本函数算法主要内容:每10秒1列表,最大、小作差,//10得出长度37左右,按照长度的索引来添加歌曲长度,对所有的歌曲这样遍历一遍。
第一个for循环,把所有歌曲的时长,名称添加到全局列表中
"""
"""下面先是旧的获取歌曲时长,然后到所有的flac和mp3都能获取时长"""
for list1 in path_list1: # 主要在这里获取歌曲长度
for index, elements in enumerate(os.listdir(list1)):
duration = TinyTag.get(list1 + '\\' + elements).duration
len_list.append(int(duration))
name_list.append(elements)
qufeng_len_list = [] # 存的是同10秒内歌曲的下标,到用的时候就显示除前后一个列表
range_len_list = (max(len_list) - min(len_list))//10 + 1 # 这里必须得加一,别忽略了
for i in range(range_len_list):
qufeng_len_list.append([]) # 划分这么多个空列表,每10秒1列表
for index_i, elements_i in enumerate(len_list):
temp_range = (elements_i-min(len_list))//10
qufeng_len_list[temp_range].append(index_i)
return qufeng_len_list
def alg3_selece_appropriate(my_receive):
"""
my_receive长这样 [[0, 2], [0, 3], [0, 4], [0, 6], [0, 11], [0, 12], [0, 15], [0, 20], [0, 36], [0, 171]],算法找到的相似长度的歌曲
第一个for循环是把上面这样的二维列表拉成一维的列表
接着把receive列表里面的元素循环一遍,把该元素所在同10s的列表的前中后都加入合适的列表,接着拉成一维
判断两首歌与目标时间之差的绝对值是否等于目标精度(目前是把精度也升序循环了一遍)
最后输出结果,打算倒着来,因为最先看到的一般在最后,那么精度最好的在最后
"""
temp_receive = []
try:
for j in my_receive:
for i in j:
if i not in temp_receive:
temp_receive.append(i)
print(temp_receive)
except TypeError:
for j in my_receive:
if j not in temp_receive:
temp_receive.append(j)
last_len_list = [] # 存相似长度的歌曲,二维列表,里面的其中一个是相似度十分接近的
for i in temp_receive:
for total_j in range(len(same_qufeng_len_list)):
if i in same_qufeng_len_list[total_j]:
try:
last_len_list.append(same_qufeng_len_list[total_j]) # 相似长度的索引列表存进去了,这里其实可以添加前后的,但是担心太多算不过来,以后【改进】(只要前后加进去,必找到最合适的)
last_len_list.append(same_qufeng_len_list[total_j - 1])
last_len_list.append(same_qufeng_len_list[total_j + 1])
except IndexError:
pass
# print(last_len_list)
take_list = [] # 把上面元素相近的所有元素都取出来
result_list = [] # 最优解
for i in last_len_list:
for j in i:
if j not in take_list:
take_list.append(j)
for i in range(len(take_list)):
for j in range(i, len(take_list)):
if abs(len_list[i] + len_list[j] - target_num) < jing_du:
result_list.append([len_list[i] + len_list[j], name_list[i], name_list[j]])
# 最后输出结果
result_count = 0
for p in range(jing_du - 1, -1, -1):
print('\n\n\n精度: ', p)
for i in result_list:
if abs(i[0] - target_num) == p:
print('%d\t %-25s \t %-20s' % (i[0], i[1], i[2]))
# print(i[0], i[1], '\t', i[2])
result_count += 1
print('\n共找到{}个结果!'.format(result_count))
input('Press any key to exit.')
def one_song_alg():
"""
如果只有一首歌,那么就调用这个函数,返回在精度误差内的歌曲。
"""
index_list = []
for i in range(len(len_list)):
if abs(len_list[i] - target_num) < jing_du and i not in index_list:
# print(len_list[i], name_list[i])
index_list.append(i)
for j in range(jing_du): # 重复是难免的,因为旧mp3中有许多现在也有的,下标算法没问题,是歌曲重复了。
for i in index_list:
if abs(len_list[i] - target_num) == j:
print(len_list[i], name_list[i])
print('')
if __name__ == '__main__':
target_num = int(input("请输入总音乐的秒数:")) # 视频长度的秒数
same_qufeng_len_list = list_alg_paixu(path_list)
receive = self_alg(len_list, target_num) # 默认receive里面都是返回的视频的时长的 索引下标!!! 求时长还是len_list[i]
if len(receive) == 2:
print(len_list[receive[0]], name_list[receive[0]])
print(len_list[receive[1]], name_list[receive[1]])
alg3_selece_appropriate(receive) # 最主要算法3,整合receive和时长相近的歌曲,最后输出结果