mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-15 16:19:28 +01:00
Backend stuff done to get separate lossless & lossy directories working
This commit is contained in:
@@ -13,10 +13,10 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
import os, time
|
||||
from operator import itemgetter
|
||||
import datetime
|
||||
import re
|
||||
import re, shutil
|
||||
|
||||
import headphones
|
||||
|
||||
@@ -218,3 +218,35 @@ def extract_song_data(s):
|
||||
else:
|
||||
logger.info("Couldn't parse " + s + " into a valid Newbin format")
|
||||
return (name, album, year)
|
||||
|
||||
def smartMove(src, dest, delete=True):
|
||||
|
||||
source_dir = os.path.dirname(src)
|
||||
filename = os.path.basename(src)
|
||||
|
||||
if os.path.isfile(os.path.join(dest, filename)):
|
||||
logger.info('Destination file exists: %s' % os.path.join(dest, filename).decode(headphones.SYS_ENCODING))
|
||||
title = os.path.splitext(filename)[0]
|
||||
ext = os.path.splitext(filename)[1]
|
||||
i = 1
|
||||
while True:
|
||||
newfile = title + '(' + str(i) + ')' + ext
|
||||
if os.path.isfile(os.path.join(dest, newfile)):
|
||||
i += 1
|
||||
else:
|
||||
logger.info('Renaming to %s' % newfile)
|
||||
try:
|
||||
os.rename(src, os.path.join(source_dir, newfile))
|
||||
filename = newfile
|
||||
except Exception, e:
|
||||
logger.warn('Error renaming %s: %s' % (src.decode(headphones.SYS_ENCODING), e))
|
||||
break
|
||||
|
||||
try:
|
||||
if delete:
|
||||
shutil.move(os.path.join(source_dir, filename), os.path.join(dest, filename))
|
||||
else:
|
||||
shutil.copy(os.path.join(source_dir, filename), os.path.join(dest, filename))
|
||||
return True
|
||||
except Exception, e:
|
||||
logger.warn('Error moving file %s: %s' % (filename.decode(headphones.SYS_ENCODING), e))
|
||||
|
||||
@@ -138,7 +138,8 @@ def command(encoder,musicSource,musicDest,albumPath):
|
||||
time.sleep(10)
|
||||
return_code = call(cmd, shell=True)
|
||||
if (return_code==0) and (os.path.exists(musicDest)):
|
||||
os.remove(musicSource)
|
||||
if headphones.DELETE_LOSSLESS_FILES:
|
||||
os.remove(musicSource)
|
||||
shutil.move(musicDest,albumPath)
|
||||
logger.info('Music "%s" encoded in %s' % (musicSource,getTimeEncode(startMusicTime)))
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
|
||||
renameFiles(albumpath, downloaded_track_list, release)
|
||||
|
||||
if headphones.MOVE_FILES and headphones.DESTINATION_DIR:
|
||||
albumpath = moveFiles(albumpath, release, tracks)
|
||||
albumpaths = moveFiles(albumpath, release, tracks)
|
||||
|
||||
if headphones.MOVE_FILES and not headphones.DESTINATION_DIR:
|
||||
logger.error('No DESTINATION_DIR has been set. Set "Destination Directory" to the parent directory you want to move the files to')
|
||||
@@ -273,8 +273,9 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
|
||||
myDB.action('UPDATE albums SET status = "Downloaded" WHERE AlbumID=?', [albumid])
|
||||
myDB.action('UPDATE snatched SET status = "Processed" WHERE AlbumID=?', [albumid])
|
||||
|
||||
# Update the have tracks
|
||||
librarysync.libraryScan(dir=albumpath, append=True, ArtistID=release['ArtistID'], ArtistName=release['ArtistName'])
|
||||
# Update the have tracks for all created dirs:
|
||||
for albumpath in albumpaths:
|
||||
librarysync.libraryScan(dir=albumpath, append=True, ArtistID=release['ArtistID'], ArtistName=release['ArtistName'])
|
||||
|
||||
logger.info('Post-processing for %s - %s complete' % (release['ArtistName'], release['AlbumTitle']))
|
||||
|
||||
@@ -297,7 +298,8 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list)
|
||||
|
||||
if headphones.SYNOINDEX_ENABLED:
|
||||
syno = notifiers.Synoindex()
|
||||
syno.notify(albumpath)
|
||||
for albumpath in albumpaths:
|
||||
syno.notify(albumpath)
|
||||
|
||||
def embedAlbumArt(artwork, downloaded_track_list):
|
||||
logger.info('Embedding album art')
|
||||
@@ -375,71 +377,138 @@ def moveFiles(albumpath, release, tracks):
|
||||
|
||||
if folder.startswith('.'):
|
||||
folder = folder.replace(0, '_')
|
||||
|
||||
# Grab our list of files early on so we can determine if we need to create
|
||||
# the lossy_dest_dir, lossless_dest_dir, or both
|
||||
files_to_move = []
|
||||
lossy_media = False
|
||||
lossless_media = False
|
||||
|
||||
destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING)
|
||||
|
||||
last_folder = headphones.FOLDER_FORMAT.split('/')[-1]
|
||||
|
||||
# Only rename the folder if they use the album name, otherwise merge into existing folder
|
||||
if os.path.exists(destination_path) and 'album' in last_folder.lower():
|
||||
i = 1
|
||||
while True:
|
||||
newfolder = folder + '[%i]' % i
|
||||
destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING)
|
||||
if os.path.exists(destination_path):
|
||||
i += 1
|
||||
else:
|
||||
folder = newfolder
|
||||
break
|
||||
|
||||
logger.info('Moving files from %s to %s' % (unicode(albumpath, headphones.SYS_ENCODING, errors="replace"), unicode(destination_path, headphones.SYS_ENCODING, errors="replace")))
|
||||
|
||||
# Basically check if generic/non-album folders already exist, since we're going to merge
|
||||
if not os.path.exists(destination_path):
|
||||
try:
|
||||
os.makedirs(destination_path)
|
||||
except Exception, e:
|
||||
logger.error('Could not create folder for %s. Not moving: %s' % (release['AlbumTitle'], e))
|
||||
return albumpath
|
||||
|
||||
# Move files to the destination folder, renaming them if they already exist
|
||||
for r,d,f in os.walk(albumpath):
|
||||
for files in f:
|
||||
if os.path.isfile(os.path.join(destination_path, files)):
|
||||
logger.info('Destination file exists: %s' % os.path.join(destination_path, files))
|
||||
title = os.path.splitext(files)[0]
|
||||
ext = os.path.splitext(files)[1]
|
||||
i = 1
|
||||
while True:
|
||||
newfile = title + '(' + str(i) + ')' + ext
|
||||
if os.path.isfile(os.path.join(destination_path, newfile)):
|
||||
i += 1
|
||||
else:
|
||||
logger.info('Renaming to %s' % newfile)
|
||||
try:
|
||||
os.rename(os.path.join(r, files), os.path.join(r, newfile))
|
||||
files = newfile
|
||||
except Exception, e:
|
||||
logger.warn('Error renaming %s: %s' % (files, e))
|
||||
break
|
||||
files_to_move.append(os.path.join(r, files))
|
||||
if any(files.lower.endswith(x) for x in headphones.LOSSY_MEDIA_FORMATS):
|
||||
lossy_media = True
|
||||
if any(files.lower.endswith(x) for x in headphones.LOSSLESS_MEDIA_FORMATS):
|
||||
lossless_media = True
|
||||
|
||||
# Do some sanity checking to see what directories we need to create:
|
||||
make_lossy_folder = False
|
||||
make_lossless_folder = False
|
||||
|
||||
lossy_destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING)
|
||||
lossless_destination_path = os.path.normpath(os.path.join(headphones.LOSSLESS_DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING)
|
||||
|
||||
# If they set a destination dir for lossless media, only create the lossy folder if there is lossy media
|
||||
if headphones.LOSSLESS_DESTINATION_DIR:
|
||||
if lossy_media:
|
||||
make_lossy_folder = True
|
||||
if lossless_media:
|
||||
make_lossless_folder = True
|
||||
# If they haven't set a lossless dest_dir, just create the "lossy" folder
|
||||
else:
|
||||
make_lossy_folder = True
|
||||
|
||||
last_folder = headphones.FOLDER_FORMAT.split('/')[-1]
|
||||
|
||||
if make_lossless_folder:
|
||||
# Only rename the folder if they use the album name, otherwise merge into existing folder
|
||||
if os.path.exists(lossless_destination_path) and 'album' in last_folder.lower():
|
||||
i = 1
|
||||
while True:
|
||||
newfolder = folder + '[%i]' % i
|
||||
lossless_destination_path = os.path.normpath(os.path.join(headphones.LOSSLESS_DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING)
|
||||
if os.path.exists(destination_path):
|
||||
i += 1
|
||||
else:
|
||||
folder = newfolder
|
||||
break
|
||||
|
||||
if not os.path.exists(lossless_destination_path):
|
||||
try:
|
||||
shutil.move(os.path.join(r, files), os.path.join(destination_path, files))
|
||||
os.makedirs(lossless_destination_path)
|
||||
except Exception, e:
|
||||
logger.warn('Error moving file %s: %s' % (files, e))
|
||||
logger.error('Could not create lossless folder for %s. (Error: %s)' % (release['AlbumTitle'], e))
|
||||
if not make_lossy_folder:
|
||||
return albumpath
|
||||
|
||||
if make_lossy_folder:
|
||||
if os.path.exists(lossy_destination_path) and 'album' in last_folder.lower():
|
||||
i = 1
|
||||
while True:
|
||||
newfolder = folder + '[%i]' % i
|
||||
lossy_destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING)
|
||||
if os.path.exists(lossy_destination_path):
|
||||
i += 1
|
||||
else:
|
||||
folder = newfolder
|
||||
break
|
||||
|
||||
if not os.path.exists(lossy_destination_path):
|
||||
try:
|
||||
os.makedirs(lossy_destination_path)
|
||||
except Exception, e:
|
||||
logger.error('Could not create folder for %s. Not moving: %s' % (release['AlbumTitle'], e))
|
||||
return albumpath
|
||||
|
||||
logger.info('Checking which files we need to move.....')
|
||||
|
||||
# Move files to the destination folder, renaming them if they already exist
|
||||
# If we have two desination_dirs, move non-music files to both
|
||||
if make_lossy_folder and make_lossless_folder:
|
||||
|
||||
for file_to_move in files_to_move:
|
||||
|
||||
if any(file_to_move.lower.endswith(x) for x in headphones.LOSSY_MEDIA_FORMATS):
|
||||
helpers.smartMove(file_to_move, lossy_destination_path)
|
||||
|
||||
elif any(files.lower.endswith(x) for x in headphones.LOSSLESS_MEDIA_FORMATS):
|
||||
helpers.smartMove(file_to_move, lossless_destination_path)
|
||||
|
||||
# If it's a non-music file, move it to both dirs
|
||||
else:
|
||||
|
||||
moved_to_lossy_folder = helpers.smartMove(file_to_move, lossy_destination_path, delete=False)
|
||||
moved_to_lossless_folder = helpers.smartMove(file_to_move, lossless_destination_path, delete=False)
|
||||
|
||||
if moved_to_lossy_folder or moved_to_lossless_folder:
|
||||
try:
|
||||
os.remove(file_to_move)
|
||||
except Exception, e:
|
||||
logger.error("Error deleting file '" + file_to_move.decode(headphones.SYS_ENCODING) + "' from source directory")
|
||||
else:
|
||||
logger.error("Error copying '" + file_to_move.decode(headphones.SYS_ENCODING) + "'. Not deleting from download directory")
|
||||
|
||||
elif make_lossless_folder and not make_lossy_folder:
|
||||
|
||||
for file_to_move in files_to_move:
|
||||
helpers.smartMove(file_to_move, lossless_destination_path)
|
||||
|
||||
else:
|
||||
|
||||
for file_to_move in files_to_move:
|
||||
helpers.smartMove(file_to_move, lossy_destination_path)
|
||||
|
||||
# Chmod the directories using the folder_format (script courtesy of premiso!)
|
||||
folder_list = folder.split('/')
|
||||
temp_f = headphones.DESTINATION_DIR
|
||||
|
||||
for f in folder_list:
|
||||
|
||||
temp_f = os.path.join(temp_f, f)
|
||||
|
||||
try:
|
||||
os.chmod(os.path.normpath(temp_f).encode(headphones.SYS_ENCODING), int(headphones.FOLDER_PERMISSIONS, 8))
|
||||
except Exception, e:
|
||||
logger.error("Error trying to change permissions on folder: %s" % temp_f)
|
||||
temp_fs = []
|
||||
|
||||
if make_lossless_folder:
|
||||
temp_fs.append(headphones.LOSSLESS_DESTINATION_DIR)
|
||||
|
||||
if make_lossy_folder:
|
||||
temp_fs.append(headphones.DESTINATION_DIR)
|
||||
|
||||
for temp_f in temp_fs:
|
||||
|
||||
for f in folder_list:
|
||||
|
||||
temp_f = os.path.join(temp_f, f)
|
||||
|
||||
try:
|
||||
os.chmod(os.path.normpath(temp_f).encode(headphones.SYS_ENCODING), int(headphones.FOLDER_PERMISSIONS, 8))
|
||||
except Exception, e:
|
||||
logger.error("Error trying to change permissions on folder: %s" % temp_f)
|
||||
|
||||
# If we failed to move all the files out of the directory, this will fail too
|
||||
try:
|
||||
@@ -447,42 +516,68 @@ def moveFiles(albumpath, release, tracks):
|
||||
except Exception, e:
|
||||
logger.error('Could not remove directory: %s. %s' % (albumpath, e))
|
||||
|
||||
return destination_path
|
||||
destination_paths = []
|
||||
|
||||
if make_lossy_folder:
|
||||
destination_paths.append(lossy_destination_path)
|
||||
if make_lossless_folder:
|
||||
destination_paths.append(lossless_destination_path)
|
||||
|
||||
return destination_paths
|
||||
|
||||
def correctMetadata(albumid, release, downloaded_track_list):
|
||||
|
||||
logger.info('Writing metadata')
|
||||
items = []
|
||||
logger.info('Preparing to write metadata to tracks....')
|
||||
lossy_items = []
|
||||
lossless_items = []
|
||||
|
||||
# Process lossless & lossy media formats separately
|
||||
for downloaded_track in downloaded_track_list:
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
items.append(beets.library.Item.from_path(downloaded_track))
|
||||
if any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS):
|
||||
lossless_items.append(beets.library.Item.from_path(downloaded_track))
|
||||
elif any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS):
|
||||
lossy_items.append(beets.library.Item.from_path(downloaded_track))
|
||||
else:
|
||||
logger.warn("Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING) + " because it is not a mutagen friendly file format")
|
||||
except Exception, e:
|
||||
logger.error("Beets couldn't create an Item from: " + downloaded_track + " - not a media file?" + str(e))
|
||||
|
||||
try:
|
||||
cur_artist, cur_album, candidates, rec = autotag.tag_album(items, search_artist=helpers.latinToAscii(release['ArtistName']), search_album=helpers.latinToAscii(release['AlbumTitle']))
|
||||
except Exception, e:
|
||||
logger.error('Error getting recommendation: %s. Not writing metadata' % e)
|
||||
return
|
||||
if rec == 'RECOMMEND_NONE':
|
||||
logger.warn('No accurate album match found for %s, %s - not writing metadata' % (release['ArtistName'], release['AlbumTitle']))
|
||||
return
|
||||
|
||||
dist, info, mapping, extra_items, extra_tracks = candidates[0]
|
||||
logger.debug('Beets recommendation: %s' % rec)
|
||||
autotag.apply_metadata(info, mapping)
|
||||
|
||||
if len(items) != len(downloaded_track_list):
|
||||
logger.warn("Mismatch between number of tracks downloaded and the metadata items, but I'll try to write it anyway")
|
||||
|
||||
i = 1
|
||||
for item in items:
|
||||
|
||||
logger.error("Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING) + " - not a media file?" + str(e))
|
||||
|
||||
for items in [lossy_items, lossless_items]:
|
||||
|
||||
if not items:
|
||||
continue
|
||||
|
||||
try:
|
||||
item.write()
|
||||
cur_artist, cur_album, candidates, rec = autotag.tag_album(items, search_artist=helpers.latinToAscii(release['ArtistName']), search_album=helpers.latinToAscii(release['AlbumTitle']))
|
||||
except Exception, e:
|
||||
logger.warn('Error writing metadata to track %i: %s' % (i,e))
|
||||
i += 1
|
||||
logger.error('Error getting recommendation: %s. Not writing metadata' % e)
|
||||
return
|
||||
if rec == 'RECOMMEND_NONE':
|
||||
logger.warn('No accurate album match found for %s, %s - not writing metadata' % (release['ArtistName'], release['AlbumTitle']))
|
||||
return
|
||||
|
||||
if candidates:
|
||||
dist, info, mapping, extra_items, extra_tracks = candidates[0]
|
||||
else:
|
||||
logger.warn('No accurate album match found for %s, %s - not writing metadata' % (release['ArtistName'], release['AlbumTitle']))
|
||||
return
|
||||
|
||||
logger.info('Beets recommendation for tagging items: %s' % rec)
|
||||
|
||||
# TODO: Handle extra_items & extra_tracks
|
||||
|
||||
autotag.apply_metadata(info, mapping)
|
||||
|
||||
for item in items:
|
||||
try:
|
||||
item.write()
|
||||
logger.info("Successfully applied metadata to: " + item.path.decode(headphones.SYS_ENCODING))
|
||||
except Exception, e:
|
||||
logger.warn("Error writing metadata to " + item.path.decode(headphones.SYS_ENCODING) + ": " + str(e))
|
||||
|
||||
def embedLyrics(downloaded_track_list):
|
||||
logger.info('Adding lyrics')
|
||||
|
||||
Reference in New Issue
Block a user