Files
headphones/headphones/music_encoder.py

216 lines
8.9 KiB
Python

# This file is part of Headphones.
#
# Headphones is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Headphones is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
import os
import headphones
import shutil
import time
from subprocess import call
from headphones import logger
from lib.beets.mediafile import MediaFile
try:
import argparse
except ImportError:
import lib.argparse as argparse
# xld
if headphones.ENCODER == 'xld':
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(headphones.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=[]
musicTempFiles=[]
encoder =""
startAlbumTime=time.time()
ifencoded=0
if not os.path.exists(tempDirEncode):
os.mkdir(tempDirEncode)
else:
shutil.rmtree(tempDirEncode)
time.sleep(1)
os.mkdir(tempDirEncode)
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):
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] + '.' + 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] + '.' + encoderFormat)
musicTempFiles.append(os.path.join(tempDirEncode, musicTemp))
if headphones.ENCODER_PATH:
encoder = headphones.ENCODER_PATH.encode(headphones.SYS_ENCODING)
else:
if XLD:
encoder = os.path.join('/Applications', 'xld')
elif headphones.ENCODER =='lame':
if headphones.SYS_PLATFORM == "win32":
## NEED THE DEFAULT LAME INSTALL ON WIN!
encoder = "C:/Program Files/lame/lame.exe"
else:
encoder="lame"
elif headphones.ENCODER =='ffmpeg':
if headphones.SYS_PLATFORM == "win32":
encoder = "C:/Program Files/ffmpeg/bin/ffmpeg.exe"
else:
encoder="ffmpeg"
i=0
for music in musicFiles:
infoMusic=MediaFile(music)
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:
if (music.decode(headphones.SYS_ENCODING, 'replace').lower().endswith('.mp3') and (int(infoMusic.bitrate/1000)<=headphones.BITRATE)):
logger.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music.decode(headphones.SYS_ENCODING, 'replace'),headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
else:
if headphones.ENCODEROUTPUTFORMAT=='ogg':
if music.decode(headphones.SYS_ENCODING, 'replace').lower().endswith('.ogg'):
logger.warn('Can not reencode .ogg music "%s"' % (music.decode(headphones.SYS_ENCODING, 'replace')))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
elif (headphones.ENCODEROUTPUTFORMAT=='mp3' or headphones.ENCODEROUTPUTFORMAT=='m4a'):
if (music.decode(headphones.SYS_ENCODING, 'replace').lower().endswith('.'+headphones.ENCODEROUTPUTFORMAT) and (int(infoMusic.bitrate/1000)<=headphones.BITRATE)):
logger.info('Music "%s" has bitrate<="%skbit" will not be reencoded' % (music.decode(headphones.SYS_ENCODING, 'replace'),headphones.BITRATE))
else:
command(encoder,music,musicTempFiles[i],albumPath)
ifencoded=1
i=i+1
shutil.rmtree(tempDirEncode)
time.sleep(1)
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):
musicFinalFiles.append(os.path.join(r, music))
if ifencoded==0:
logger.info('Encoding for folder "%s" is not needed' % (albumPath.decode(headphones.SYS_ENCODING, 'replace')))
return musicFinalFiles
def command(encoder,musicSource,musicDest,albumPath):
return_code=1
cmd=''
startMusicTime=time.time()
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':
cmd=cmd+ ' --resample ' + str(headphones.SAMPLINGFREQUENCY) + ' -b ' + str(headphones.BITRATE)
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -V'+str(headphones.ENCODERQUALITY)
cmd=cmd+ ' ' + headphones.ADVANCEDENCODER
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicSource + '"'
cmd=cmd+ ' "' + musicDest +'"'
elif headphones.ENCODER == 'ffmpeg':
cmd='"' + encoder + '"' + ' -i'
cmd=cmd+ ' "' + musicSource + '"'
if headphones.ADVANCEDENCODER =='':
if headphones.ENCODEROUTPUTFORMAT=='ogg':
cmd=cmd+ ' -acodec libvorbis'
if headphones.ENCODEROUTPUTFORMAT=='m4a':
cmd=cmd+ ' -strict experimental'
if headphones.ENCODERVBRCBR=='cbr':
cmd=cmd+ ' -ar ' + str(headphones.SAMPLINGFREQUENCY) + ' -ab ' + str(headphones.BITRATE) + 'k'
elif headphones.ENCODERVBRCBR=='vbr':
cmd=cmd+' -aq ' + str(headphones.ENCODERQUALITY)
cmd=cmd+ ' -y -ac 2 -vn'
else:
cmd=cmd+' '+ headphones.ADVANCEDENCODER
cmd=cmd+ ' "' + musicDest + '"'
logger.debug(cmd)
try:
return_code = call(cmd, shell=True)
if (return_code==0) and (os.path.exists(musicDest)):
if headphones.DELETE_LOSSLESS_FILES:
os.remove(musicSource)
shutil.move(musicDest,albumPath)
logger.info('Music "%s" encoded in %s' % (musicSource,getTimeEncode(startMusicTime)))
except subprocess.CalledProcessError, e:
logger.warn('Music "%s" encoding error : %s' % (musicSource, e.output))
def getTimeEncode(start):
seconds =int(time.time()-start)
hours = seconds / 3600
seconds -= 3600*hours
minutes = seconds / 60
seconds -= 60*minutes
return "%02d:%02d:%02d" % (hours, minutes, seconds)