Skip to content

Instantly share code, notes, and snippets.

@nicholastay
Created January 10, 2019 13:00
Show Gist options
  • Save nicholastay/1273da34ff3cdfcbf7d4cce3aeb1e3d1 to your computer and use it in GitHub Desktop.
Save nicholastay/1273da34ff3cdfcbf7d4cce3aeb1e3d1 to your computer and use it in GitHub Desktop.
ALSong lyrics plugin for MusicBrainz Picard (warn: getting lyrics is synchronous, so UI will be locked)
PLUGIN_NAME = 'ALSong Lyrics'
PLUGIN_AUTHOR = 'Nicholas Tay (nexerq)'
PLUGIN_DESCRIPTION = 'Gets lyric data from ALSong API.'
PLUGIN_VERSION = '0.1.0'
PLUGIN_API_VERSIONS = ['2.0']
PLUGIN_LICENSE = 'Zlib'
# Based on musixmatch plugin as a starting point
from picard.metadata import register_track_metadata_processor
from picard.file import File
from picard.ui.itemviews import BaseAction, register_track_action, register_file_action
from picard.log import info, warning, error
import re
import urllib.request
from xml.sax.saxutils import escape
# https://github.com/sunghwan2789/osu-lyrics/blob/master/osu!Lyrics/Lyrics/Sources/AlsongSource.cs
ALSONG_API = 'http://lyrics.alsong.co.kr/alsongwebservice/service1.asmx'
TEMPLATE = u'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"><Body><GetResembleLyric2 xmlns="ALSongWebServer"><stQuery><strTitle>%s</strTitle><strArtistName>%s</strArtistName></stQuery></GetResembleLyric2></Body></Envelope>'
HEADER_DATA = { 'User-Agent': 'gSOAP', 'Content-Type': 'application/soap+xml; charset=UTF-8', 'SOAPAction': '"ALSongWebServer/GetResembleLyric2"' }
lyricReg = re.compile('<strLyric>(.*?)</strLyric>')
timingsReg = re.compile('^\\[\\d\\d:\\d\\d.\\d\\d\\]', re.MULTILINE)
def process_track(album, metadata, release, track):
get_lyrics(metadata)
def get_lyrics(metadata):
try:
info('Trying to get ALSong lyrics for "%s"...', metadata['title'])
data = TEMPLATE % (escape(metadata['title']), escape(metadata['artist']))
data = data.encode('utf8') # to bytes so we can post (utf8 bytes as def in headers)
req = urllib.request.Request(ALSONG_API, data, HEADER_DATA)
with urllib.request.urlopen(req) as response:
info('Pulled lyric page data.')
page = response.read().decode('utf-8')
#info(page)
match = lyricReg.search(page)
if match != None:
lyr = match.group(1) # still need to clean up
lyr = lyr.replace('&lt;br&gt;', '\n') # html newlines
lyr = re.sub(timingsReg, '', lyr) # unfortunately cant do synced lyrics for now, so we remove timings :(
metadata['lyrics:description'] = lyr
info('Lyrics found and written to tag.')
else:
info('No lyrics found.')
except Exception as e:
info('EXCEPTION: %s', e)
pass
# Uncomment for automatic on lookup
#register_track_metadata_processor(process_track)
class AlsongLyricsMenu(BaseAction):
NAME = 'Try get lyrics from ALSong'
def callback(self, objs):
for obj in objs:
if isinstance(obj, File):
get_lyrics(obj.metadata)
else:
for file in obj.iterfiles():
get_lyrics(file.metadata)
alm = AlsongLyricsMenu()
register_file_action(alm)
register_track_action(alm)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment