mirror of
https://github.com/rembo10/headphones.git
synced 2026-03-23 05:09:28 +00:00
Merge remote-tracking branch 'AdeHub/master' into develop
This commit is contained in:
181
headphones/getXldProfile.py
Executable file
181
headphones/getXldProfile.py
Executable file
@@ -0,0 +1,181 @@
|
||||
import os.path
|
||||
import plistlib
|
||||
import sys
|
||||
import xml.parsers.expat as expat
|
||||
import commands
|
||||
from headphones import logger
|
||||
|
||||
def getXldProfile(xldProfile):
|
||||
xldProfileNotFound = xldProfile
|
||||
expandedPath = os.path.expanduser('~/Library/Preferences/jp.tmkk.XLD.plist')
|
||||
try:
|
||||
preferences = plistlib.Plist.fromFile(expandedPath)
|
||||
except (expat.ExpatError):
|
||||
os.system("/usr/bin/plutil -convert xml1 %s" % expandedPath )
|
||||
try:
|
||||
preferences = plistlib.Plist.fromFile(expandedPath)
|
||||
except (ImportError):
|
||||
os.system("/usr/bin/plutil -convert binary1 %s" % expandedPath )
|
||||
logger.info('The plist at "%s" has a date in it, and therefore is not useable.' % expandedPath)
|
||||
return(xldProfileNotFound, None, None)
|
||||
except (ImportError):
|
||||
logger.info('The plist at "%s" has a date in it, and therefore is not useable.' % expandedPath)
|
||||
except:
|
||||
logger.info('Unexpected error:', sys.exc_info()[0])
|
||||
return(xldProfileNotFound, None, None)
|
||||
|
||||
xldProfile = xldProfile.lower()
|
||||
profiles = preferences.get('Profiles')
|
||||
|
||||
for profile in profiles:
|
||||
|
||||
profilename = profile.get('XLDProfileManager_ProfileName')
|
||||
xldProfileForCmd = profilename
|
||||
profilename = profilename.lower()
|
||||
xldFormat = None
|
||||
xldBitrate = None
|
||||
|
||||
if profilename == xldProfile:
|
||||
|
||||
OutputFormatName = profile.get('OutputFormatName')
|
||||
ShortDesc = profile.get('ShortDesc')
|
||||
|
||||
# Determine format and bitrate
|
||||
|
||||
if OutputFormatName == 'WAV':
|
||||
xldFormat = 'wav'
|
||||
|
||||
elif OutputFormatName == 'AIFF':
|
||||
xldFormat = 'aiff'
|
||||
|
||||
elif 'PCM' in OutputFormatName:
|
||||
xldFormat = 'pcm'
|
||||
|
||||
elif OutputFormatName == 'Wave64':
|
||||
xldFormat = 'w64'
|
||||
|
||||
elif OutputFormatName == 'MPEG-4 AAC':
|
||||
xldFormat = 'm4a'
|
||||
if 'CBR' in ShortDesc or 'ABR' in ShortDesc or 'CVBR' in ShortDesc:
|
||||
xldBitrate = int(profile.get('XLDAacOutput2_Bitrate'))
|
||||
elif 'TVBR' in ShortDesc:
|
||||
XLDAacOutput2_VBRQuality = int(profile.get('XLDAacOutput2_VBRQuality'))
|
||||
if XLDAacOutput2_VBRQuality > 122:
|
||||
xldBitrate = 320
|
||||
elif XLDAacOutput2_VBRQuality > 113 and XLDAacOutput2_VBRQuality <= 122:
|
||||
xldBitrate = 285
|
||||
elif XLDAacOutput2_VBRQuality > 104 and XLDAacOutput2_VBRQuality <= 113:
|
||||
xldBitrate = 255
|
||||
elif XLDAacOutput2_VBRQuality > 95 and XLDAacOutput2_VBRQuality <= 104:
|
||||
xldBitrate = 225
|
||||
elif XLDAacOutput2_VBRQuality > 86 and XLDAacOutput2_VBRQuality <= 95:
|
||||
xldBitrate = 195
|
||||
elif XLDAacOutput2_VBRQuality > 77 and XLDAacOutput2_VBRQuality <= 86:
|
||||
xldBitrate = 165
|
||||
elif XLDAacOutput2_VBRQuality > 68 and XLDAacOutput2_VBRQuality <= 77:
|
||||
xldBitrate = 150
|
||||
elif XLDAacOutput2_VBRQuality > 58 and XLDAacOutput2_VBRQuality <= 68:
|
||||
xldBitrate = 135
|
||||
elif XLDAacOutput2_VBRQuality > 49 and XLDAacOutput2_VBRQuality <= 58:
|
||||
xldBitrate = 115
|
||||
elif XLDAacOutput2_VBRQuality > 40 and XLDAacOutput2_VBRQuality <= 49:
|
||||
xldBitrate = 105
|
||||
elif XLDAacOutput2_VBRQuality > 31 and XLDAacOutput2_VBRQuality <= 40:
|
||||
xldBitrate = 95
|
||||
elif XLDAacOutput2_VBRQuality > 22 and XLDAacOutput2_VBRQuality <= 31:
|
||||
xldBitrate = 80
|
||||
elif XLDAacOutput2_VBRQuality > 13 and XLDAacOutput2_VBRQuality <= 22:
|
||||
xldBitrate = 75
|
||||
elif XLDAacOutput2_VBRQuality > 4 and XLDAacOutput2_VBRQuality <= 13:
|
||||
xldBitrate = 45
|
||||
elif XLDAacOutput2_VBRQuality >= 0 and XLDAacOutput2_VBRQuality <= 4:
|
||||
xldBitrate = 40
|
||||
|
||||
elif OutputFormatName == 'Apple Lossless':
|
||||
xldFormat = 'm4a'
|
||||
|
||||
elif OutputFormatName == 'FLAC':
|
||||
if 'ogg' in ShortDesc:
|
||||
xldFormat = 'oga'
|
||||
else:
|
||||
xldFormat = 'flac'
|
||||
|
||||
elif OutputFormatName == 'MPEG-4 HE-AAC':
|
||||
xldFormat = 'm4a'
|
||||
xldBitrate = int(profile.get('Bitrate'))
|
||||
|
||||
elif OutputFormatName == 'LAME MP3':
|
||||
xldFormat = 'mp3'
|
||||
if 'VBR' in ShortDesc:
|
||||
VbrQuality = float(profile.get('VbrQuality'))
|
||||
if VbrQuality < 1:
|
||||
xldBitrate = 260
|
||||
elif VbrQuality >= 1 and VbrQuality < 2:
|
||||
xldBitrate = 250
|
||||
elif VbrQuality >= 2 and VbrQuality < 3:
|
||||
xldBitrate = 210
|
||||
elif VbrQuality >= 3 and VbrQuality < 4:
|
||||
xldBitrate = 195
|
||||
elif VbrQuality >= 4 and VbrQuality < 5:
|
||||
xldBitrate = 185
|
||||
elif VbrQuality >= 5 and VbrQuality < 6:
|
||||
xldBitrate = 150
|
||||
elif VbrQuality >= 6 and VbrQuality < 7:
|
||||
xldBitrate = 130
|
||||
elif VbrQuality >= 7 and VbrQuality < 8:
|
||||
xldBitrate = 120
|
||||
elif VbrQuality >= 8 and VbrQuality < 9:
|
||||
xldBitrate = 105
|
||||
elif VbrQuality >= 9:
|
||||
xldBitrate = 85
|
||||
elif 'CBR' in ShortDesc:
|
||||
xldBitrate = int(profile.get('Bitrate'))
|
||||
elif 'ABR' in ShortDesc:
|
||||
xldBitrate = int(profile.get('AbrBitrate'))
|
||||
|
||||
elif OutputFormatName == 'Opus':
|
||||
xldFormat = 'opus'
|
||||
xldBitrate = int(profile.get('XLDOpusOutput_Bitrate'))
|
||||
|
||||
elif OutputFormatName == 'Ogg Vorbis':
|
||||
xldFormat = 'ogg'
|
||||
XLDVorbisOutput_Quality = float(profile.get('XLDVorbisOutput_Quality'))
|
||||
if XLDVorbisOutput_Quality <= -2:
|
||||
xldBitrate = 32
|
||||
elif XLDVorbisOutput_Quality > -2 and XLDVorbisOutput_Quality <= -1:
|
||||
xldBitrate = 48
|
||||
elif XLDVorbisOutput_Quality > -1 and XLDVorbisOutput_Quality <= 0:
|
||||
xldBitrate = 64
|
||||
elif XLDVorbisOutput_Quality > 0 and XLDVorbisOutput_Quality <= 1:
|
||||
xldBitrate = 80
|
||||
elif XLDVorbisOutput_Quality > 1 and XLDVorbisOutput_Quality <= 2:
|
||||
xldBitrate = 96
|
||||
elif XLDVorbisOutput_Quality > 2 and XLDVorbisOutput_Quality <= 3:
|
||||
xldBitrate = 112
|
||||
elif XLDVorbisOutput_Quality > 3 and XLDVorbisOutput_Quality <= 4:
|
||||
xldBitrate = 128
|
||||
elif XLDVorbisOutput_Quality > 4 and XLDVorbisOutput_Quality <= 5:
|
||||
xldBitrate = 160
|
||||
elif XLDVorbisOutput_Quality > 5 and XLDVorbisOutput_Quality <= 6:
|
||||
xldBitrate = 192
|
||||
elif XLDVorbisOutput_Quality > 6 and XLDVorbisOutput_Quality <= 7:
|
||||
xldBitrate = 224
|
||||
elif XLDVorbisOutput_Quality > 7 and XLDVorbisOutput_Quality <= 8:
|
||||
xldBitrate = 256
|
||||
elif XLDVorbisOutput_Quality > 8 and XLDVorbisOutput_Quality <= 9:
|
||||
xldBitrate = 320
|
||||
elif XLDVorbisOutput_Quality > 9:
|
||||
xldBitrate = 500
|
||||
|
||||
elif OutputFormatName == 'WavPack':
|
||||
xldFormat = 'wv'
|
||||
if ShortDesc != 'normal':
|
||||
xldBitrate = int(profile.get('XLDWavpackOutput_BitRate'))
|
||||
|
||||
# Lossless
|
||||
if xldFormat and not xldBitrate:
|
||||
xldBitrate = 500
|
||||
|
||||
return(xldProfileForCmd, xldFormat, xldBitrate)
|
||||
|
||||
return(xldProfileNotFound, None, None)
|
||||
@@ -27,7 +27,26 @@ try:
|
||||
except ImportError:
|
||||
import lib.argparse as argparse
|
||||
|
||||
# xld
|
||||
|
||||
if headphones.ADVANCEDENCODER.lower().startswith('xld'):
|
||||
XLDPROFILE = headphones.ADVANCEDENCODER[4:]
|
||||
import getXldProfile
|
||||
XLD = True
|
||||
else:
|
||||
XLD = False
|
||||
|
||||
def encode(albumPath):
|
||||
|
||||
# Return if xld details not found
|
||||
|
||||
if XLD:
|
||||
global xldProfile
|
||||
(xldProfile, xldFormat, xldBitrate) = getXldProfile.getXldProfile(XLDPROFILE)
|
||||
if not xldFormat:
|
||||
logger.error(u'Details for xld profile "%s" not found, will not be reencoded' % (xldProfile))
|
||||
return None
|
||||
|
||||
tempDirEncode=os.path.join(albumPath,"temp")
|
||||
musicFiles=[]
|
||||
musicFinalFiles=[]
|
||||
@@ -46,26 +65,48 @@ def encode(albumPath):
|
||||
for r,d,f in os.walk(albumPath):
|
||||
for music in f:
|
||||
if any(music.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
|
||||
|
||||
if not XLD:
|
||||
encoderFormat = headphones.ENCODEROUTPUTFORMAT.encode(headphones.SYS_ENCODING)
|
||||
else:
|
||||
xldMusicFile = os.path.join(r, music)
|
||||
xldInfoMusic = MediaFile(xldMusicFile)
|
||||
encoderFormat = xldFormat
|
||||
|
||||
if (headphones.ENCODERLOSSLESS):
|
||||
if (music.lower().endswith('.flac')):
|
||||
ext = os.path.normpath(os.path.splitext(music)[1].lstrip(".")).lower()
|
||||
if not XLD and ext == 'flac' or XLD and (ext != xldFormat and (xldInfoMusic.bitrate / 1000 > 500)):
|
||||
musicFiles.append(os.path.join(r, music))
|
||||
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT.encode(headphones.SYS_ENCODING))
|
||||
musicTemp = os.path.normpath(os.path.splitext(music)[0] + '.' + encoderFormat)
|
||||
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
|
||||
else:
|
||||
logger.debug('Music "%s" is already encoded' % (music))
|
||||
else:
|
||||
musicFiles.append(os.path.join(r, music))
|
||||
musicTemp = os.path.normpath(os.path.splitext(music)[0]+'.'+headphones.ENCODEROUTPUTFORMAT.encode(headphones.SYS_ENCODING))
|
||||
musicTemp = os.path.normpath(os.path.splitext(music)[0] + '.' + encoderFormat)
|
||||
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
|
||||
|
||||
if headphones.ENCODER=='lame':
|
||||
|
||||
if XLD:
|
||||
if headphones.ENCODERFOLDER:
|
||||
encoder = os.path.join(headphones.ENCODERFOLDER.encode(headphones.SYS_ENCODING), 'xld')
|
||||
else:
|
||||
encoder = os.path.join('/Applications', 'xld')
|
||||
elif headphones.ENCODER=='lame':
|
||||
encoder=os.path.join(headphones.ENCODERFOLDER.encode(headphones.SYS_ENCODING),'lame')
|
||||
elif headphones.ENCODER=='ffmpeg':
|
||||
encoder=os.path.join(headphones.ENCODERFOLDER.encode(headphones.SYS_ENCODING),'ffmpeg')
|
||||
|
||||
i=0
|
||||
for music in musicFiles:
|
||||
infoMusic=MediaFile(music)
|
||||
if headphones.ENCODER == 'lame':
|
||||
|
||||
if XLD:
|
||||
if xldBitrate and (infoMusic.bitrate / 1000 <= xldBitrate):
|
||||
logger.info('Music "%s" has bitrate <= "%skbit", will not be reencoded' % (music.decode(headphones.SYS_ENCODING, 'replace'), xldBitrate))
|
||||
else:
|
||||
command(encoder,music,musicTempFiles[i],albumPath)
|
||||
ifencoded=1
|
||||
elif headphones.ENCODER == 'lame':
|
||||
if not any(music.decode(headphones.SYS_ENCODING, 'replace').lower().endswith('.' + x) for x in ["mp3", "wav"]):
|
||||
logger.warn(u'Lame cant encode "%s" format for "%s", use ffmpeg' % (os.path.splitext(music)[1].decode(headphones.SYS_ENCODING, 'replace'),music.decode(headphones.SYS_ENCODING, 'replace')))
|
||||
else:
|
||||
@@ -106,7 +147,17 @@ def command(encoder,musicSource,musicDest,albumPath):
|
||||
return_code=1
|
||||
cmd=''
|
||||
startMusicTime=time.time()
|
||||
if headphones.ENCODER == 'lame':
|
||||
|
||||
if XLD:
|
||||
xldDestDir = os.path.split(musicDest)[0]
|
||||
cmd = encoder
|
||||
cmd = cmd + ' "' + musicSource + '"'
|
||||
cmd = cmd + ' --profile'
|
||||
cmd = cmd + ' "' + xldProfile + '"'
|
||||
cmd = cmd + ' -o'
|
||||
cmd = cmd + ' "' + xldDestDir + '"'
|
||||
|
||||
elif headphones.ENCODER == 'lame':
|
||||
if headphones.ADVANCEDENCODER =='':
|
||||
cmd=encoder + ' -h'
|
||||
if headphones.ENCODERVBRCBR=='cbr':
|
||||
|
||||
@@ -28,6 +28,15 @@ from lib.beets.mediafile import MediaFile
|
||||
import headphones
|
||||
from headphones import db, albumart, librarysync, lyrics, logger, helpers
|
||||
|
||||
# xld
|
||||
|
||||
if headphones.ADVANCEDENCODER.lower().startswith('xld'):
|
||||
XLDPROFILE = headphones.ADVANCEDENCODER[4:]
|
||||
import getXldProfile
|
||||
XLD = True
|
||||
else:
|
||||
XLD = False
|
||||
|
||||
postprocessor_lock = threading.Lock()
|
||||
|
||||
def checkFolder():
|
||||
@@ -147,12 +156,73 @@ def verify(albumid, albumpath):
|
||||
tracks = myDB.select('SELECT * from tracks WHERE AlbumID=?', [albumid])
|
||||
|
||||
downloaded_track_list = []
|
||||
|
||||
downloaded_cuecount = 0
|
||||
|
||||
for r,d,f in os.walk(albumpath):
|
||||
for files in f:
|
||||
if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
|
||||
downloaded_track_list.append(os.path.join(r, files))
|
||||
elif files.lower().endswith('.cue'):
|
||||
downloaded_cuecount += 1
|
||||
|
||||
# use xld to split cue
|
||||
|
||||
if XLD and headphones.MUSIC_ENCODER and downloaded_cuecount and downloaded_cuecount >= len(downloaded_track_list):
|
||||
|
||||
(xldProfile, xldFormat, xldBitrate) = getXldProfile.getXldProfile(XLDPROFILE)
|
||||
if not xldFormat:
|
||||
logger.info(u'Details for xld profile "%s" not found, cannot split cue' % (xldProfile))
|
||||
else:
|
||||
if headphones.ENCODERFOLDER:
|
||||
xldencoder = os.path.join(headphones.ENCODERFOLDER, 'xld')
|
||||
else:
|
||||
xldencoder = os.path.join('/Applications','xld')
|
||||
|
||||
for r,d,f in os.walk(albumpath):
|
||||
xldfolder = r
|
||||
xldfile = ''
|
||||
xldcue = ''
|
||||
for file in f:
|
||||
if any(file.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS) and not xldfile:
|
||||
xldfile = os.path.join(r, file)
|
||||
elif file.lower().endswith('.cue') and not xldcue:
|
||||
xldcue = os.path.join(r, file)
|
||||
|
||||
if xldfile and xldcue and xldfolder:
|
||||
xldcmd = xldencoder
|
||||
xldcmd = xldcmd + ' "' + xldfile + '"'
|
||||
xldcmd = xldcmd + ' -c'
|
||||
xldcmd = xldcmd + ' "' + xldcue + '"'
|
||||
xldcmd = xldcmd + ' --profile'
|
||||
xldcmd = xldcmd + ' "' + xldProfile + '"'
|
||||
xldcmd = xldcmd + ' -o'
|
||||
xldcmd = xldcmd + ' "' + xldfolder + '"'
|
||||
logger.info(u"Cue found, splitting file " + xldfile.decode(headphones.SYS_ENCODING, 'replace'))
|
||||
logger.debug(xldcmd)
|
||||
os.system(xldcmd)
|
||||
|
||||
# count files, should now be more than original if xld successfully split
|
||||
|
||||
new_downloaded_track_list_count = 0
|
||||
for r,d,f in os.walk(albumpath):
|
||||
for file in f:
|
||||
if any(file.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
|
||||
new_downloaded_track_list_count += 1
|
||||
|
||||
if new_downloaded_track_list_count > len(downloaded_track_list):
|
||||
|
||||
# rename original unsplit files
|
||||
for downloaded_track in downloaded_track_list:
|
||||
os.rename(downloaded_track, downloaded_track + '.original')
|
||||
|
||||
#reload
|
||||
|
||||
downloaded_track_list = []
|
||||
for r,d,f in os.walk(albumpath):
|
||||
for file in f:
|
||||
if any(file.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS):
|
||||
downloaded_track_list.append(os.path.join(r, file))
|
||||
|
||||
# test #1: metadata - usually works
|
||||
logger.debug('Verifying metadata...')
|
||||
|
||||
@@ -233,9 +303,12 @@ def verify(albumid, albumpath):
|
||||
def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list):
|
||||
|
||||
logger.info('Starting post-processing for: %s - %s' % (release['ArtistName'], release['AlbumTitle']))
|
||||
#start enconding
|
||||
#start encoding
|
||||
if headphones.MUSIC_ENCODER:
|
||||
downloaded_track_list=music_encoder.encode(albumpath)
|
||||
|
||||
if not downloaded_track_list:
|
||||
return
|
||||
|
||||
album_art_path = albumart.getAlbumArt(albumid)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user