mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-20 18:45:32 +01:00
216 lines
8.9 KiB
Python
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)
|