mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-15 16:19:28 +01:00
Added option to embed lyrics - modified config page, added lyrics variables where needed
This commit is contained in:
@@ -205,6 +205,7 @@
|
||||
<h4><input type="checkbox" name="cleanup_files" value="1" ${config['cleanup_files']} /> Delete leftover files (.m3u, .nfo, .sfv, .nzb, etc.)</h4>
|
||||
<h4><input type="checkbox" name="add_album_art" value="1" ${config['add_album_art']}> Add album art as 'folder.jpg' to album folder</h4>
|
||||
<h4><input type="checkbox" name="embed_album_art" value="1" ${config['embed_album_art']}> Embed album art in each file</h4>
|
||||
<h4><input type="checkbox" name="embed_lyrics" value="1" ${config['embed_lyrics']}> Embed lyrics</h4>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
<h4><input type="checkbox" name="cleanup_files" value="1" ${config['cleanup_files']} /> Delete leftover files (.m3u, .nfo, .sfv, .nzb, etc.)</h4>
|
||||
<h4><input type="checkbox" name="add_album_art" value="1" ${config['add_album_art']}> Add album art as 'folder.jpg' to album folder</h4>
|
||||
<h4><input type="checkbox" name="embed_album_art" value="1" ${config['embed_album_art']}> Embed album art in each file</h4>
|
||||
<h4><input type="checkbox" name="embed_lyrics" value="1" ${config['embed_lyrics']}> Embed lyrics</h4>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -260,7 +261,7 @@
|
||||
<td>
|
||||
<h2>Re-Encoding Options:</h2>
|
||||
<br>
|
||||
<h3><input type="checkbox" name="encode" value="1" ${config['encode']}/>Re-encode Postprocessed Albuns</h3>
|
||||
<h3><input type="checkbox" name="encode" value="1" ${config['encode']}/> Re-encode downloads during postprocessing</h3>
|
||||
<i class="smalltext">Note: this option requires the lame or ffmpeg encoder</i>
|
||||
<br><br>
|
||||
<%
|
||||
@@ -275,66 +276,30 @@
|
||||
<option value="lame" ${lameselect}>lame</option>
|
||||
<option value="ffmpeg" ${ffmpegselect}>ffmpeg</option>
|
||||
</select>
|
||||
|
||||
<%
|
||||
if config['encoderoutputformat'] == 'ogg':
|
||||
oggselect = 'selected="selected"'
|
||||
mp3select = ''
|
||||
m4aselect = ''
|
||||
elif config['encoderoutputformat'] == 'm4a':
|
||||
oggselect = ''
|
||||
m4aselect = 'selected="selected"'
|
||||
mp3select = ''
|
||||
else:
|
||||
oggselect = ''
|
||||
m4aselect = ''
|
||||
mp3select = 'selected="selected"'
|
||||
%>
|
||||
|
||||
Format: <select name="encoderoutputformat">
|
||||
<option value="mp3" ${mp3select}>mp3</option>
|
||||
<option value="ogg" ${oggselect}>ogg</option>
|
||||
<option value="m4a" ${m4aselect}>m4a</option>
|
||||
%for x in ['mp3', 'ogg', 'm4a']:
|
||||
<%
|
||||
if config['encoderoutputformat'] == x:
|
||||
outputselect = 'selected'
|
||||
else:
|
||||
outputselect = ''
|
||||
%>
|
||||
<option value=${x} ${outputselect}>${x}</option>
|
||||
%endfor
|
||||
</select></h4>
|
||||
|
||||
<br>
|
||||
<%
|
||||
if config["bitrate"] == 64:
|
||||
bitrate64select = 'selected="selected"'
|
||||
bitrate128select = ''
|
||||
bitrate192select = ''
|
||||
bitrate256select = ''
|
||||
bitrate320select = ''
|
||||
elif config["bitrate"] == 128:
|
||||
bitrate64select = ''
|
||||
bitrate128select = 'selected="selected"'
|
||||
bitrate192select = ''
|
||||
bitrate256select = ''
|
||||
bitrate320select = ''
|
||||
elif config["bitrate"] == 192:
|
||||
bitrate64select = ''
|
||||
bitrate128select = ''
|
||||
bitrate192select = 'selected="selected"'
|
||||
bitrate256select = ''
|
||||
bitrate320select = ''
|
||||
elif config["bitrate"] == 256:
|
||||
bitrate64select = ''
|
||||
bitrate128select = ''
|
||||
bitrate192select = ''
|
||||
bitrate256select = 'selected="selected"'
|
||||
bitrate320select = ''
|
||||
else:
|
||||
bitrate64select = ''
|
||||
bitrate128select = ''
|
||||
bitrate192select = ''
|
||||
bitrate256select = ''
|
||||
bitrate320select = 'selected="selected"'
|
||||
%>
|
||||
<h4>Bitrate: <select name="bitrate">
|
||||
<option value=64 ${bitrate64select}> 64 kbps</option>
|
||||
<option value=128 ${bitrate128select}>128 kbps</option>
|
||||
<option value=192 ${bitrate192select}>192 kbps</option>
|
||||
<option value=256 ${bitrate256select}>256 kbps</option>
|
||||
<option value=320 ${bitrate320select}>320 kbps</option>
|
||||
%for x in [64, 128, 192, 256, 320]:
|
||||
<%
|
||||
if config["bitrate"] == x:
|
||||
bitrateselected = "selected"
|
||||
else:
|
||||
bitrateselected = ''
|
||||
%>
|
||||
<option value=${x} ${bitrateselected}> ${x} kbps</option>
|
||||
%endfor
|
||||
</select>
|
||||
|
||||
<%
|
||||
@@ -361,5 +326,5 @@
|
||||
|
||||
<p class="center"><input type="submit" value="Save Changes"><br>
|
||||
(Web Interface changes require a restart to take effect)</h3>
|
||||
</form>
|
||||
</%def>
|
||||
</form>
|
||||
</%def>
|
||||
|
||||
@@ -73,6 +73,7 @@ RENAME_FILES = False
|
||||
CLEANUP_FILES = False
|
||||
ADD_ALBUM_ART = False
|
||||
EMBED_ALBUM_ART = False
|
||||
EMBED_LYRICS = False
|
||||
DOWNLOAD_DIR = None
|
||||
BLACKHOLE = None
|
||||
BLACKHOLE_DIR = None
|
||||
@@ -175,7 +176,7 @@ def initialize():
|
||||
HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, LAUNCH_BROWSER, GIT_PATH, \
|
||||
CURRENT_VERSION, LATEST_VERSION, MUSIC_DIR, DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, \
|
||||
ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, \
|
||||
ADD_ALBUM_ART, EMBED_ALBUM_ART, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, NZB_SEARCH_INTERVAL, \
|
||||
ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, NZB_SEARCH_INTERVAL, \
|
||||
LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
|
||||
NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \
|
||||
NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \
|
||||
@@ -223,6 +224,7 @@ def initialize():
|
||||
CLEANUP_FILES = bool(check_setting_int(CFG, 'General', 'cleanup_files', 0))
|
||||
ADD_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'add_album_art', 0))
|
||||
EMBED_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'embed_album_art', 0))
|
||||
EMBED_LYRICS = bool(check_setting_int(CFG, 'General', 'embed_lyrics', 0))
|
||||
DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '')
|
||||
BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0))
|
||||
BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '')
|
||||
@@ -404,6 +406,7 @@ def config_write():
|
||||
new_config['General']['cleanup_files'] = int(CLEANUP_FILES)
|
||||
new_config['General']['add_album_art'] = int(ADD_ALBUM_ART)
|
||||
new_config['General']['embed_album_art'] = int(EMBED_ALBUM_ART)
|
||||
new_config['General']['embed_lyrics'] = int(EMBED_LYRICS)
|
||||
new_config['General']['download_dir'] = DOWNLOAD_DIR
|
||||
new_config['General']['blackhole'] = int(BLACKHOLE)
|
||||
new_config['General']['blackhole_dir'] = BLACKHOLE_DIR
|
||||
|
||||
67
headphones/lyrics.py
Normal file
67
headphones/lyrics.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import re
|
||||
import urllib
|
||||
from xml.dom import minidom
|
||||
import htmlentitydefs
|
||||
|
||||
from headphones import logger
|
||||
|
||||
def getLyrics(artist, song):
|
||||
|
||||
params = { "artist": artist,
|
||||
"song": song,
|
||||
"fmt": 'xml'
|
||||
}
|
||||
|
||||
searchURL = 'http://lyrics.wikia.com/api.php?' + urllib.urlencode(params)
|
||||
|
||||
try:
|
||||
data = urllib.urlopen(searchURL).read()
|
||||
except Exception, e:
|
||||
logger.warn('Error opening: %s. Error: %s' % (searchURL, e))
|
||||
return
|
||||
|
||||
parseddata = minidom.parseString(data)
|
||||
|
||||
url = parseddata.getElementsByTagName("url")
|
||||
|
||||
if url:
|
||||
lyricsurl = url[0].firstChild.nodeValue
|
||||
else:
|
||||
logger.info('No lyrics found for %s - %s' % (artist, song))
|
||||
return
|
||||
|
||||
try:
|
||||
lyricspage = urllib.urlopen(lyricsurl).read()
|
||||
except Exception, e:
|
||||
logger.warn('Error fetching lyrics from: %s. Error: %s' % (lyricsurl, e))
|
||||
return
|
||||
|
||||
m = re.compile('''<div class='lyricbox'><div class='rtMatcher'>.*?</div>(.*?)<!--''').search(lyricspage)
|
||||
|
||||
lyrics = convert_html_entities(m.group(1)).replace('<br />', '\n')
|
||||
|
||||
return lyrics
|
||||
|
||||
def convert_html_entities(s):
|
||||
matches = re.findall("&#\d+;", s)
|
||||
if len(matches) > 0:
|
||||
hits = set(matches)
|
||||
for hit in hits:
|
||||
name = hit[2:-1]
|
||||
try:
|
||||
entnum = int(name)
|
||||
s = s.replace(hit, unichr(entnum))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
matches = re.findall("&\w+;", s)
|
||||
hits = set(matches)
|
||||
amp = "&"
|
||||
if amp in hits:
|
||||
hits.remove(amp)
|
||||
for hit in hits:
|
||||
name = hit[1:-1]
|
||||
if htmlentitydefs.name2codepoint.has_key(name):
|
||||
s = s.replace(hit, unichr(htmlentitydefs.name2codepoint[name]))
|
||||
s = s.replace(amp, "&")
|
||||
return s
|
||||
@@ -7,7 +7,7 @@ from lib.beets import autotag
|
||||
from lib.beets.mediafile import MediaFile
|
||||
|
||||
import headphones
|
||||
from headphones import db, albumart, logger, helpers
|
||||
from headphones import db, albumart, lyrics, logger, helpers
|
||||
|
||||
def checkFolder():
|
||||
|
||||
@@ -219,6 +219,9 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
|
||||
if headphones.CORRECT_METADATA:
|
||||
correctMetadata(albumid, release, downloaded_track_list)
|
||||
|
||||
if headphones.EMBED_LYRICS:
|
||||
embedLyrics(downloaded_track_list)
|
||||
|
||||
if headphones.RENAME_FILES:
|
||||
renameFiles(albumpath, downloaded_track_list, release)
|
||||
|
||||
@@ -255,7 +258,8 @@ def embedAlbumArt(artwork, downloaded_track_list):
|
||||
f = MediaFile(downloaded_track)
|
||||
except:
|
||||
logger.error('Could not read %s. Not adding album art' % downloaded_track)
|
||||
|
||||
continue
|
||||
|
||||
logger.debug('Adding album art to: %s' % downloaded_track)
|
||||
f.art = artwork
|
||||
f.save()
|
||||
@@ -380,6 +384,29 @@ def correctMetadata(albumid, release, downloaded_track_list):
|
||||
|
||||
for item in items:
|
||||
item.write()
|
||||
|
||||
def embedLyrics(downloaded_track_list):
|
||||
logger.info('Adding lyrics')
|
||||
|
||||
for downloaded_track in downloaded_track_list:
|
||||
|
||||
try:
|
||||
f = MediaFile(downloaded_track)
|
||||
except:
|
||||
logger.error('Could not read %s. Not checking lyrics' % downloaded_track)
|
||||
|
||||
if f.albumartist and f.title:
|
||||
metalyrics = lyrics.getLyrics(f.albumartist, f.title)
|
||||
elif f.artist and f.title:
|
||||
metalyrics = lyrics.getLyrics(f.artist, f.title)
|
||||
else:
|
||||
logger.info('No artist/track metadata found for track: %s. Not fetching lyrics' % downloaded_track)
|
||||
metalyrics = None
|
||||
|
||||
if lyrics:
|
||||
logger.debug('Adding lyrics to: %s' % downloaded_track)
|
||||
f.lyrics = metalyrics
|
||||
f.save()
|
||||
|
||||
def renameFiles(albumpath, downloaded_track_list, release):
|
||||
logger.info('Renaming files')
|
||||
|
||||
@@ -344,6 +344,7 @@ class WebInterface(object):
|
||||
"cleanup_files" : checked(headphones.CLEANUP_FILES),
|
||||
"add_album_art" : checked(headphones.ADD_ALBUM_ART),
|
||||
"embed_album_art" : checked(headphones.EMBED_ALBUM_ART),
|
||||
"embed_lyrics" : checked(headphones.EMBED_LYRICS),
|
||||
"dest_dir" : headphones.DESTINATION_DIR,
|
||||
"folder_format" : headphones.FOLDER_FORMAT,
|
||||
"file_format" : headphones.FILE_FORMAT,
|
||||
@@ -366,7 +367,7 @@ class WebInterface(object):
|
||||
sab_host=None, sab_username=None, sab_apikey=None, sab_password=None, sab_category=None, download_dir=None, blackhole=0, blackhole_dir=None,
|
||||
usenet_retention=None, nzbmatrix=0, nzbmatrix_username=None, nzbmatrix_apikey=None, newznab=0, newznab_host=None, newznab_apikey=None,
|
||||
nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, newzbin=0, newzbin_uid=None, newzbin_password=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0,
|
||||
rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, interface=None, log_dir=None,
|
||||
rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, interface=None, log_dir=None,
|
||||
encode=0, encoder=None, bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None):
|
||||
|
||||
headphones.HTTP_HOST = http_host
|
||||
@@ -404,6 +405,7 @@ class WebInterface(object):
|
||||
headphones.CLEANUP_FILES = cleanup_files
|
||||
headphones.ADD_ALBUM_ART = add_album_art
|
||||
headphones.EMBED_ALBUM_ART = embed_album_art
|
||||
headphones.EMBED_LYRICS = embed_lyrics
|
||||
headphones.DESTINATION_DIR = destination_dir
|
||||
headphones.FOLDER_FORMAT = folder_format
|
||||
headphones.FILE_FORMAT = file_format
|
||||
|
||||
Reference in New Issue
Block a user