Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- import os, sys, argparse, re, subprocess, fnmatch
- parser = argparse.ArgumentParser(description='Sync music library and playlists to sd card')
- parser.add_argument('-l', '--library', default=os.path.expanduser('~/Music/Library'), help='Path to music library')
- parser.add_argument('-s', '--sd-path', default='/mnt/sd', help='Directory to sync to. Parent directory of library and playlists directories')
- parser.add_argument('-p', '--playlist-dir', default=os.path.expanduser('~/.quodlibet/playlists'), help='Path to playlist directory')
- parser.add_argument('--library-only', action='store_true', help='Only sync the library and not the playlists')
- parser.add_argument('--playlists-only', action='store_true', help='Only sync the playlists and not the library')
- parser.add_argument('--dry-run', action='store_true', help='Test run without making any changes')
- parser.add_argument('--confirm', action='store_true', help='Don\'t ask for confirmation interactively')
- parser.add_argument('--no-progress', action='store_true', help='Don\'t show progress while syncing library')
- parser.add_argument('--ignore-nosync', action='store_true', help='Don\'t use .nosync file if it exists')
- args = parser.parse_args()
- library = os.path.join(os.path.abspath(args.library), '')
- sd_path = os.path.abspath(args.sd_path)
- src_playlist_dir = os.path.abspath(args.playlist_dir)
- def get_confirm(message):
- response = input(message)
- return re.match('y|yes', response, re.IGNORECASE)
- excludes = []
- nosync = os.path.join(library, '.nosync')
- if os.path.exists(nosync) and not args.ignore_nosync:
- with open(nosync) as nosync_lines:
- for line in nosync_lines:
- line = line[:-1]
- if line.startswith(library):
- line = '/' + line[len(library):]
- excludes.append(line)
- exclude_re = []
- for ex in excludes:
- exclude_re.append(re.compile(fnmatch.translate(os.path.join(library, ex))[:-7]))
- def is_excluded(song):
- return any(exre.match(song) for exre in exclude_re)
- def sync_library():
- print('Beginning library sync')
- rsync_args = ['rsync', '--recursive', '--times', '--verbose', '--delete', '--compress', '--modify-window=2']
- if args.dry_run:
- rsync_args.append('--dry-run')
- if not args.no_progress:
- rsync_args.extend(['--info=progress2'])
- for ex in excludes:
- rsync_args.extend(['--exclude', ex])
- rsync_args.extend(['--', library, os.path.join(sd_path, 'library')])
- if not (args.confirm or get_confirm("Command: {2}\nSync library from {0} to {1}? [y/n] ".format(library, sd_path, ' '.join(rsync_args)))):
- print('Library sync cancelled')
- return
- try:
- returncode = subprocess.run(rsync_args).returncode
- except OSError as e:
- print('Unable to start rsync process: {0}'.format(e))
- if returncode != 0:
- print('Error: rsync exited with code {0}'.format(returncode))
- return
- print('Successfully synced library')
- def sync_playlists():
- print('Beginning playlist sync')
- dst_playlist_dir = os.path.join(sd_path, 'playlists')
- if not (args.confirm or get_confirm("Sync playlists from {0} to {1}? [y/n] ".format(src_playlist_dir, dst_playlist_dir))):
- print('Playlist sync cancelled')
- return
- if not os.path.isdir(dst_playlist_dir) and not args.dry_run:
- try:
- os.mkdir(dst_playlist_dir)
- except OSError as e:
- print('Unable to create directory {0}: {1}. Skipping playlist sync'.format(dst_playlist_dir, e))
- return
- try:
- with open(os.path.join(sd_path, 'playlists.txt'), 'r') as playlists:
- for playlist_name in playlists:
- playlist_name = playlist_name.strip()
- print('Attempting to sync playlist: {0}'.format(playlist_name))
- src_playlist_path = os.path.join(src_playlist_dir, playlist_name)
- if not os.path.isfile(src_playlist_path):
- print('Playlist not found, skipping')
- continue
- dst_playlist_path = os.path.join(dst_playlist_dir, playlist_name) + '.m3u'
- added_songs = set()
- ignored_songs = 0
- if not args.dry_run:
- with open(src_playlist_path, 'r') as src_playlist:
- with open(dst_playlist_path, 'w') as dst_playlist:
- for line in src_playlist:
- if line.startswith(library) and line not in added_songs and not is_excluded(line):
- dst_playlist.write(line.replace(library, '../library/'))
- added_songs.add(line)
- else:
- ignored_songs += 1
- print('Successfuly synced playlist. {0} songs ignored as duplicates or not in library'.format(ignored_songs))
- except OSError:
- print('Playlists file not found, skipping playlist sync')
- return
- print('Finished syncing playlists')
- if args.library_only and args.playlists_only:
- sys.exit('--only-library and --only-playlist must not both be provided')
- if not args.playlists_only:
- sync_library()
- if not args.library_only:
- sync_playlists()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement