add feature: read album picture from file/url

This commit is contained in:
Terry Geng 2020-02-04 18:00:11 +08:00
parent 30879db7b8
commit 98f096f08f
2 changed files with 90 additions and 35 deletions

View File

@ -56,6 +56,10 @@ class PlayList:
return self.playlist[self.next_index()] return self.playlist[self.next_index()]
def jump(self, index):
self.current_index = index
return self.playlist[index]
def clear(self): def clear(self):
self.playlist = [] self.playlist = []
self.current_index = 0 self.current_index = 0

View File

@ -20,6 +20,7 @@ import util
import base64 import base64
from PIL import Image from PIL import Image
from io import BytesIO from io import BytesIO
import mutagen
from mutagen.easyid3 import EasyID3 from mutagen.easyid3 import EasyID3
import re import re
import media.url import media.url
@ -37,7 +38,8 @@ type : url
title title
path path
duration duration
thundnail artist
thumbnail
user user
ready (validation, no, downloading, yes) ready (validation, no, downloading, yes)
from_playlist (yes,no) from_playlist (yes,no)
@ -53,7 +55,9 @@ type : radio
type : file type : file
path path
title title
artist
duration duration
thumbnail
user user
""" """
@ -101,6 +105,7 @@ class MumbleBot:
self.nb_exit = 0 self.nb_exit = 0
self.thread = None self.thread = None
self.is_playing = False self.is_playing = False
self.is_pause = False
if var.config.getboolean("webinterface", "enabled"): if var.config.getboolean("webinterface", "enabled"):
wi_addr = var.config.get("webinterface", "listening_addr") wi_addr = var.config.get("webinterface", "listening_addr")
@ -155,8 +160,6 @@ class MumbleBot:
self.mumble.channels.find_by_name(self.channel).move_in() self.mumble.channels.find_by_name(self.channel).move_in()
self.mumble.set_bandwidth(200000) self.mumble.set_bandwidth(200000)
self.loop()
# Set the CTRL+C shortcut # Set the CTRL+C shortcut
def ctrl_caught(self, signal, frame): def ctrl_caught(self, signal, frame):
logging.info( logging.info(
@ -602,10 +605,15 @@ class MumbleBot:
logging.debug("Next into the queue") logging.debug("Next into the queue")
return var.playlist.next() return var.playlist.next()
def launch_music(self): def launch_music(self, index=-1):
uri = "" uri = ""
music = var.playlist.next() music = None
logging.debug("launch_music asked" + str(music)) if index == -1:
music = var.playlist.next()
else:
music = var.playlist.jump(index)
logging.debug("launch_music asked" + str(music['path']))
if music["type"] == "url": if music["type"] == "url":
# Delete older music is the tmp folder is too big # Delete older music is the tmp folder is too big
media.system.clear_tmp_folder(var.config.get( media.system.clear_tmp_folder(var.config.get(
@ -619,42 +627,31 @@ class MumbleBot:
self.download_music(music) self.download_music(music)
if music == False: if music == False:
var.playlist.remove() var.playlist.remove()
return
# get the Path if self.update_music_tag_info():
uri = music['path'] music = var.playlist.current_item()
if os.path.isfile(uri):
audio = EasyID3(uri)
print(audio["title"])
title = ""
if audio["title"]:
# take the title from the file tag
title = audio["title"][0]
# Remove .mp3 and add .jpg thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
path_thumbnail = music['path'][:-4] + '.jpg' music['thumbnail'] + '"/>'
thumbnail_html = ""
if os.path.isfile(path_thumbnail):
# Create the image message
im = Image.open(path_thumbnail)
im.thumbnail((100, 100), Image.ANTIALIAS)
buffer = BytesIO()
im.save(buffer, format="JPEG")
thumbnail_base64 = base64.b64encode(buffer.getvalue())
thumbnail_html = '<img src="data:image/PNG;base64,' + \
thumbnail_base64.decode() + '"/>'
logging.debug("Thumbail data " + thumbnail_html)
if var.config.getboolean('bot', 'announce_current_music'): if var.config.getboolean('bot', 'announce_current_music'):
self.send_msg(var.config.get( self.send_msg(var.config.get(
'strings', 'now_playing') % (title, thumbnail_html)) 'strings', 'now_playing') % (music['title'], thumbnail_html))
else:
logging.error("Error with the path during launch_music")
pass
elif music["type"] == "file": elif music["type"] == "file":
uri = var.config.get('bot', 'music_folder') + \ uri = var.config.get('bot', 'music_folder') + \
var.playlist.current_item()["path"] var.playlist.current_item()["path"]
if self.update_music_tag_info(uri):
music = var.playlist.current_item()
thumbnail_html = '<img width="80" src="data:image/jpge;base64,' + \
music['thumbnail'] + '"/>'
#logging.debug("Thumbnail data " + thumbnail_html)
if var.config.getboolean('bot', 'announce_current_music'):
self.send_msg(var.config.get(
'strings', 'now_playing') % (music['title'], thumbnail_html))
elif music["type"] == "radio": elif music["type"] == "radio":
uri = music["url"] uri = music["url"]
title = media.radio.get_radio_server_description(uri) title = media.radio.get_radio_server_description(uri)
@ -744,6 +741,51 @@ class MumbleBot:
break break
var.playlist.playlist[index] = music var.playlist.playlist[index] = music
def update_music_tag_info(self, uri=""):
music = var.playlist.current_item()
if not music['type'] == 'file' and not music['type'] == 'url':
return False
# get the Path
if uri == "":
uri = music['path']
if os.path.isfile(uri):
music = self.get_music_tag_info(music, uri)
var.playlist.update(music)
return True
else:
logging.error("Error with the path during launch_music")
return False
def get_music_tag_info(self, music, uri=""):
if not uri:
uri = music['path']
if os.path.isfile(uri):
audio = EasyID3(uri)
if audio["title"]:
# take the title from the file tag
music['title'] = audio["title"][0]
music['artist'] = ', '.join(audio["artist"])
path_thumbnail = uri[:-3] + "jpg"
if os.path.isfile(path_thumbnail):
im = Image.open(path_thumbnail)
im.thumbnail((100, 100), Image.ANTIALIAS)
buffer = BytesIO()
im.save(buffer, format="JPEG")
music['thumbnail'] = base64.b64encode(buffer.getvalue()).decode('utf-8')
# try to extract artwork from mp3 ID3 tag
elif uri[-3:] == "mp3":
tags = mutagen.File(uri)
if "APIC:" in tags:
music['thumbnail'] = base64.b64encode(tags["APIC:"].data).decode('utf-8')
return music
def async_download_next(self): def async_download_next(self):
# Function start if the next music isn't ready # Function start if the next music isn't ready
# Do nothing in case the next music is already downloaded # Do nothing in case the next music is already downloaded
@ -795,7 +837,7 @@ class MumbleBot:
# get next music # get next music
self.is_playing = False self.is_playing = False
self.next() self.next()
if len(var.playlist.playlist) > 0: if not self.is_pause and len(var.playlist.playlist) > 0:
if var.playlist.current_item()['type'] in ['radio', 'file'] \ if var.playlist.current_item()['type'] in ['radio', 'file'] \
or (var.playlist.current_item()['type'] == 'url' and var.playlist.current_item()['ready'] not in ['validation', 'downloading']): or (var.playlist.current_item()['type'] == 'url' and var.playlist.current_item()['ready'] not in ['validation', 'downloading']):
# Check if the music can be start before launch the music # Check if the music can be start before launch the music
@ -819,6 +861,14 @@ class MumbleBot:
var.playlist.clear() var.playlist.clear()
self.is_playing = False self.is_playing = False
def pause(self):
# Kill the ffmpeg thread
if self.thread:
self.thread.kill()
self.thread = None
self.is_playing = False
self.is_pause = True
def set_comment(self): def set_comment(self):
self.mumble.users.myself.comment(var.config.get('bot', 'comment')) self.mumble.users.myself.comment(var.config.get('bot', 'comment'))
@ -892,4 +942,5 @@ if __name__ == '__main__':
var.config = config var.config = config
var.db = db var.db = db
botamusique = MumbleBot(args) var.botamusique = MumbleBot(args)
var.botamusique.loop()