Esempio n. 1
0
def main():
	if os.name == 'nt':
		sys.argv = win32_unicode_argv()
	else:
		sys.argv = [arg.decode(sys.stdin.encoding) for arg in sys.argv]

	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['input']:
		cli['input'] = [os.getcwd()]

	mmw = MusicManagerWrapper(log=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	filepath_exclude_patterns = "|".join(pattern for pattern in cli['exclude']) if cli['exclude'] else None

	songs_to_upload, _, songs_to_exclude = mmw.get_local_songs(
		cli['input'], include_filters, exclude_filters, cli['include-all'], cli['exclude-all'],
		filepath_exclude_patterns, not cli['no-recursion'], int(cli['max-depth'])
	)

	songs_to_upload.sort()
	songs_to_exclude.sort()

	if cli['dry-run']:
		logger.info("\nFound {0} song(s) to upload".format(len(songs_to_upload)))

		if songs_to_upload:
			logger.info("\nSongs to upload:\n")

			for song in songs_to_upload:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to upload")

		if songs_to_exclude:
			logger.info("\nSongs to exclude:\n")

			for song in songs_to_exclude:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to exclude")
	else:
		if songs_to_upload:
			logger.info("\nUploading {0} song(s) to Google Music\n".format(len(songs_to_upload)))

			mmw.upload(songs_to_upload, enable_matching=cli['match'], delete_on_success=cli['delete-on-success'])
		else:
			logger.info("\nNo songs to upload")

	mmw.logout()
	logger.info("\nAll done!")
Esempio n. 2
0
def main():
	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['output']:
		cli['output'] = os.getcwd()

	mmw = MusicManagerWrapper(enable_logging=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	if not mmw.is_authenticated:
		sys.exit()

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	songs_to_download, songs_to_filter = mmw.get_google_songs(
		include_filters=include_filters, exclude_filters=exclude_filters,
		all_includes=cli['all-includes'], all_excludes=cli['all-excludes']
	)

	songs_to_download.sort(key=lambda song: (song.get('artist'), song.get('album'), song.get('track_number')))

	if cli['dry-run']:
		logger.info("\nFound {0} song(s) to download".format(len(songs_to_download)))

		if songs_to_download:
			logger.info("\nSongs to download:\n")

			for song in songs_to_download:
				title = song.get('title', "<title>")
				artist = song.get('artist', "<artist>")
				album = song.get('album', "<album>")
				song_id = song['id']

				logger.log(QUIET, "{0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
		else:
			logger.info("\nNo songs to download")

		if songs_to_filter:
			logger.info("\nSongs to filter:\n")

			for song in songs_to_filter:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to filter")
	else:
		if songs_to_download:
			logger.info("\nDownloading {0} song(s) from Google Music\n".format(len(songs_to_download)))
			mmw.download(songs_to_download, template=cli['output'])
		else:
			logger.info("\nNo songs to download")

	mmw.logout()
	logger.info("\nAll done!")
Esempio n. 3
0
def main():
	if os.name == 'nt':
		sys.argv = win32_unicode_argv()
	else:
		sys.argv = [arg.decode(sys.stdin.encoding) for arg in sys.argv]

	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['output']:
		cli['output'] = os.getcwd()

	mmw = MusicManagerWrapper(log=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	songs_to_download, _ = mmw.get_google_songs(include_filters, exclude_filters, cli['include-all'], cli['exclude-all'])

	songs_to_download.sort(key=lambda song: (song.get('artist'), song.get('album'), song.get('trackNumber')))

	if cli['dry-run']:
		logger.info("\nFound {0} song(s) to download".format(len(songs_to_download)))

		if songs_to_download:
			logger.info("\nSongs to download:\n")

			for song in songs_to_download:
				title = song.get('title', "<empty>")
				artist = song.get('artist', "<empty>")
				album = song.get('album', "<empty>")
				song_id = song['id']

				logger.log(QUIET, "{0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
		else:
			logger.info("\nNo songs to download")
	else:
		if songs_to_download:
			logger.info("\nDownloading {0} song(s) from Google Music\n".format(len(songs_to_download)))
			mmw.download(songs_to_download, cli['output'])
		else:
			logger.info("\nNo songs to download")

	mmw.logout()
	logger.info("\nAll done!")
Esempio n. 4
0
def main():
	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['no-recursion']:
		cli['max-depth'] = 0
	else:
		cli['max-depth'] = int(cli['max-depth']) if cli['max-depth'] else float('inf')

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['input']:
		cli['input'] = [os.getcwd()]

	if not cli['output']:
		cli['output'] = os.getcwd()

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	mmw = MusicManagerWrapper(enable_logging=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	if cli['down']:
		matched_google_songs, _ = mmw.get_google_songs(include_filters, exclude_filters, cli['all-includes'], cli['all-excludes'])

		logger.info("")

		cli['input'] = template_to_base_path(cli['output'], matched_google_songs)

		matched_local_songs, _, _ = mmw.get_local_songs(cli['input'], exclude_patterns=cli['exclude'])

		logger.info("\nScanning for missing songs...")
		songs_to_download = compare_song_collections(matched_google_songs, matched_local_songs)

		songs_to_download.sort(key=lambda song: (song.get('artist'), song.get('album'), song.get('track_number')))

		if cli['dry-run']:
			logger.info("\nFound {0} song(s) to download".format(len(songs_to_download)))

			if songs_to_download:
				logger.info("\nSongs to download:\n")

				for song in songs_to_download:
					title = song.get('title', "<empty>")
					artist = song.get('artist', "<empty>")
					album = song.get('album', "<empty>")
					song_id = song['id']

					logger.log(QUIET, "{0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
			else:
				logger.info("\nNo songs to download")
		else:
			if songs_to_download:
				logger.info("\nDownloading {0} song(s) from Google Music\n".format(len(songs_to_download)))
				mmw.download(songs_to_download, cli['output'])
			else:
				logger.info("\nNo songs to download")
	else:
		matched_google_songs, _ = mmw.get_google_songs()

		logger.info("")

		matched_local_songs, songs_to_filter, songs_to_exclude = mmw.get_local_songs(
			cli['input'], include_filters, exclude_filters, cli['all-includes'], cli['all-excludes'],
			cli['exclude'], cli['max-depth']
		)

		logger.info("\nScanning for missing songs...")

		songs_to_upload = compare_song_collections(matched_local_songs, matched_google_songs)

		# Sort lists for sensible output.
		songs_to_upload.sort()
		songs_to_exclude.sort()

		if cli['dry-run']:
			logger.info("\nFound {0} song(s) to upload".format(len(songs_to_upload)))

			if songs_to_upload:
				logger.info("\nSongs to upload:\n")

				for song in songs_to_upload:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to upload")

			if songs_to_filter:
				logger.info("\nSongs to filter:\n")

				for song in songs_to_filter:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to filter")

			if songs_to_exclude:
				logger.info("\nSongs to exclude:\n")

				for song in songs_to_exclude:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to exclude")
		else:
			if songs_to_upload:
				logger.info("\nUploading {0} song(s) to Google Music\n".format(len(songs_to_upload)))

				mmw.upload(songs_to_upload, enable_matching=cli['match'], delete_on_success=cli['delete-on-success'])
			else:
				logger.info("\nNo songs to upload")

				# Delete local files if they already exist on Google Music.
				if cli['delete-on-success']:
					for song in matched_local_songs:
						try:
							os.remove(song)
						except:
							logger.warning("Failed to remove {} after successful upload".format(song))

	mmw.logout()
	logger.info("\nAll done!")
Esempio n. 5
0
def main():
    cli = dict((key.lstrip("-<").rstrip(">"), value)
               for key, value in docopt(__doc__).items())

    if cli['quiet']:
        logger.setLevel(QUIET)
    else:
        logger.setLevel(logging.INFO)

    if not cli['output']:
        cli['output'] = os.getcwd()

    mmw = MusicManagerWrapper(enable_logging=cli['log'])
    mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

    if not mmw.is_authenticated:
        sys.exit()

    include_filters = [
        tuple(filt.split(':', 1)) for filt in cli['include-filter']
    ]
    exclude_filters = [
        tuple(filt.split(':', 1)) for filt in cli['exclude-filter']
    ]

    songs_to_download, songs_to_filter = mmw.get_google_songs(
        include_filters=include_filters,
        exclude_filters=exclude_filters,
        all_includes=cli['all-includes'],
        all_excludes=cli['all-excludes'])

    songs_to_download.sort(key=lambda song: (song.get(
        'artist'), song.get('album'), song.get('track_number')))

    if cli['dry-run']:
        logger.info("\nFound {0} song(s) to download".format(
            len(songs_to_download)))

        if songs_to_download:
            logger.info("\nSongs to download:\n")

            for song in songs_to_download:
                title = song.get('title', "<title>")
                artist = song.get('artist', "<artist>")
                album = song.get('album', "<album>")
                song_id = song['id']

                logger.log(
                    QUIET,
                    "{0} -- {1} -- {2} ({3})".format(title, artist, album,
                                                     song_id))
        else:
            logger.info("\nNo songs to download")

        if songs_to_filter:
            logger.info("\nSongs to filter:\n")

            for song in songs_to_filter:
                logger.log(QUIET, song)
        else:
            logger.info("\nNo songs to filter")
    else:
        if songs_to_download:
            logger.info("\nDownloading {0} song(s) from Google Music\n".format(
                len(songs_to_download)))
            mmw.download(songs_to_download, template=cli['output'])
        else:
            logger.info("\nNo songs to download")

    mmw.logout()
    logger.info("\nAll done!")
def main():
    cli = dict((key.lstrip("-<").rstrip(">"), value)
               for key, value in docopt(__doc__).items())

    if cli['no-recursion']:
        cli['max-depth'] = 0
    else:
        cli['max-depth'] = int(
            cli['max-depth']) if cli['max-depth'] else float('inf')

    if cli['quiet']:
        logger.setLevel(QUIET)
    else:
        logger.setLevel(logging.INFO)

    if not cli['input']:
        cli['input'] = [os.getcwd()]

    mmw = MusicManagerWrapper(enable_logging=cli['log'])
    mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

    if not mmw.is_authenticated:
        sys.exit()

    include_filters = [
        tuple(filt.split(':', 1)) for filt in cli['include-filter']
    ]
    exclude_filters = [
        tuple(filt.split(':', 1)) for filt in cli['exclude-filter']
    ]

    songs_to_upload, songs_to_filter, songs_to_exclude = mmw.get_local_songs(
        cli['input'],
        include_filters=include_filters,
        exclude_filters=exclude_filters,
        all_includes=cli['all-includes'],
        all_excludes=cli['all-excludes'],
        exclude_patterns=cli['exclude'],
        max_depth=cli['max-depth'])

    songs_to_upload.sort()
    songs_to_exclude.sort()

    if cli['dry-run']:
        logger.info("\nFound {0} song(s) to upload".format(
            len(songs_to_upload)))

        if songs_to_upload:
            logger.info("\nSongs to upload:\n")

            for song in songs_to_upload:
                logger.log(QUIET, song)
        else:
            logger.info("\nNo songs to upload")

        if songs_to_filter:
            logger.info("\nSongs to filter:\n")

            for song in songs_to_filter:
                logger.log(QUIET, song)
        else:
            logger.info("\nNo songs to filter")

        if songs_to_exclude:
            logger.info("\nSongs to exclude:\n")

            for song in songs_to_exclude:
                logger.log(QUIET, song)
        else:
            logger.info("\nNo songs to exclude")
    else:
        if songs_to_upload:
            logger.info("\nUploading {0} song(s) to Google Music\n".format(
                len(songs_to_upload)))

            mmw.upload(songs_to_upload,
                       enable_matching=cli['match'],
                       delete_on_success=cli['delete-on-success'])
        else:
            logger.info("\nNo songs to upload")

    mmw.logout()
    logger.info("\nAll done!")
Esempio n. 7
0
def main():
	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['no-recursion']:
		cli['max-depth'] = 0
	else:
		cli['max-depth'] = int(cli['max-depth']) if cli['max-depth'] else float('inf')

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['input']:
		cli['input'] = [os.getcwd()]

	mmw = MusicManagerWrapper(enable_logging=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	songs_to_upload, songs_to_filter, songs_to_exclude = mmw.get_local_songs(
		cli['input'], include_filters, exclude_filters, cli['all-includes'], cli['all-excludes'],
		cli['exclude'], cli['max-depth']
	)

	songs_to_upload.sort()
	songs_to_exclude.sort()

	if cli['dry-run']:
		logger.info("\nFound {0} song(s) to upload".format(len(songs_to_upload)))

		if songs_to_upload:
			logger.info("\nSongs to upload:\n")

			for song in songs_to_upload:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to upload")

		if songs_to_filter:
			logger.info("\nSongs to filter:\n")

			for song in songs_to_filter:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to filter")

		if songs_to_exclude:
			logger.info("\nSongs to exclude:\n")

			for song in songs_to_exclude:
				logger.log(QUIET, song)
		else:
			logger.info("\nNo songs to exclude")
	else:
		if songs_to_upload:
			logger.info("\nUploading {0} song(s) to Google Music\n".format(len(songs_to_upload)))

			mmw.upload(songs_to_upload, enable_matching=cli['match'], delete_on_success=cli['delete-on-success'])
		else:
			logger.info("\nNo songs to upload")

	mmw.logout()
	logger.info("\nAll done!")
Esempio n. 8
0
def main():
    cli = dict((key.lstrip("-<").rstrip(">"), value)
               for key, value in docopt(__doc__).items())

    if cli['no-recursion']:
        cli['max-depth'] = 0
    else:
        cli['max-depth'] = int(
            cli['max-depth']) if cli['max-depth'] else float('inf')

    if cli['quiet']:
        logger.setLevel(QUIET)
    else:
        logger.setLevel(logging.INFO)

    if not cli['input']:
        cli['input'] = [os.getcwd()]

    if not cli['output']:
        cli['output'] = os.getcwd()

    include_filters = [
        tuple(filt.split(':', 1)) for filt in cli['include-filter']
    ]
    exclude_filters = [
        tuple(filt.split(':', 1)) for filt in cli['exclude-filter']
    ]

    mmw = MusicManagerWrapper(enable_logging=cli['log'])
    mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

    if not mmw.is_authenticated:
        sys.exit()

    if cli['down']:
        matched_google_songs, _ = mmw.get_google_songs(
            include_filters=include_filters,
            exclude_filters=exclude_filters,
            all_includes=cli['all-includes'],
            all_excludes=cli['all-excludes'])

        logger.info("")

        cli['input'] = [
            template_to_base_path(cli['output'], matched_google_songs)
        ]

        matched_local_songs, __, __ = mmw.get_local_songs(
            cli['input'], exclude_patterns=cli['exclude'])

        logger.info("\nFinding missing songs...")
        songs_to_download = compare_song_collections(matched_google_songs,
                                                     matched_local_songs)

        songs_to_download.sort(key=lambda song: (song.get(
            'artist'), song.get('album'), song.get('track_number')))

        if cli['dry-run']:
            logger.info("\nFound {0} song(s) to download".format(
                len(songs_to_download)))

            if songs_to_download:
                logger.info("\nSongs to download:\n")

                for song in songs_to_download:
                    title = song.get('title', "<title>")
                    artist = song.get('artist', "<artist>")
                    album = song.get('album', "<album>")
                    song_id = song['id']

                    logger.log(
                        QUIET, "{0} -- {1} -- {2} ({3})".format(
                            title, artist, album, song_id))
            else:
                logger.info("\nNo songs to download")
        else:
            if songs_to_download:
                logger.info(
                    "\nDownloading {0} song(s) from Google Music\n".format(
                        len(songs_to_download)))
                mmw.download(songs_to_download, template=cli['output'])
            else:
                logger.info("\nNo songs to download")
    else:
        matched_google_songs, _ = mmw.get_google_songs()

        logger.info("")

        matched_local_songs, songs_to_filter, songs_to_exclude = mmw.get_local_songs(
            cli['input'],
            include_filters=include_filters,
            exclude_filters=exclude_filters,
            all_includes=cli['all-includes'],
            all_excludes=cli['all-excludes'],
            exclude_patterns=cli['exclude'],
            max_depth=cli['max-depth'])

        logger.info("\nFinding missing songs...")

        songs_to_upload = compare_song_collections(matched_local_songs,
                                                   matched_google_songs)

        # Sort lists for sensible output.
        songs_to_upload.sort()
        songs_to_exclude.sort()

        if cli['dry-run']:
            logger.info("\nFound {0} song(s) to upload".format(
                len(songs_to_upload)))

            if songs_to_upload:
                logger.info("\nSongs to upload:\n")

                for song in songs_to_upload:
                    logger.log(QUIET, song)
            else:
                logger.info("\nNo songs to upload")

            if songs_to_filter:
                logger.info("\nSongs to filter:\n")

                for song in songs_to_filter:
                    logger.log(QUIET, song)
            else:
                logger.info("\nNo songs to filter")

            if songs_to_exclude:
                logger.info("\nSongs to exclude:\n")

                for song in songs_to_exclude:
                    logger.log(QUIET, song)
            else:
                logger.info("\nNo songs to exclude")
        else:
            if songs_to_upload:
                logger.info("\nUploading {0} song(s) to Google Music\n".format(
                    len(songs_to_upload)))

                mmw.upload(songs_to_upload,
                           enable_matching=cli['match'],
                           delete_on_success=cli['delete-on-success'])
            else:
                logger.info("\nNo songs to upload")

                # Delete local files if they already exist on Google Music.
                if cli['delete-on-success']:
                    for song in matched_local_songs:
                        try:
                            os.remove(song)
                        except:
                            logger.warning(
                                "Failed to remove {} after successful upload".
                                format(song))

    mmw.logout()
    logger.info("\nAll done!")
Esempio n. 9
0
def main():
	cli = dict((key.lstrip("-<").rstrip(">"), value) for key, value in docopt(__doc__).items())

	if cli['no-recursion']:
		cli['max-depth'] = 0
	else:
		cli['max-depth'] = int(cli['max-depth']) if cli['max-depth'] else float('inf')

	if cli['quiet']:
		logger.setLevel(QUIET)
	else:
		logger.setLevel(logging.INFO)

	if not cli['input']:
		cli['input'] = [os.getcwd()]

	if not cli['output']:
		cli['output'] = os.getcwd()

	include_filters = [tuple(filt.split(':', 1)) for filt in cli['include-filter']]
	exclude_filters = [tuple(filt.split(':', 1)) for filt in cli['exclude-filter']]

	mmw = MusicManagerWrapper(enable_logging=cli['log'])
	mmw.login(oauth_filename=cli['cred'], uploader_id=cli['uploader-id'])

	if not mmw.is_authenticated:
		sys.exit()

	mcw = MobileClientWrapper(enable_logging=cli['log'])

	if cli['playlists']:
		login_mobile_client_from_cache(mcw, oauth_filename=cli['cred'])

		if not mcw.is_authenticated:
			sys.exit()

	if cli['down']:
		matched_google_songs, filtered_google_songs = mmw.get_google_songs(
			include_filters=include_filters, exclude_filters=exclude_filters,
			all_includes=cli['all-includes'], all_excludes=cli['all-excludes']
		)

		cli['input'] = [template_to_base_path(cli['output'], matched_google_songs)]

		matched_local_songs, filtered_local_songs, excluded_local_songs = mmw.get_local_songs(cli['input'], exclude_patterns=cli['exclude'])

		# keep track of all local songs
		all_local_songs_dict = dict()

		def add_to_local_songs (filepath):
			all_local_songs_dict[os.path.abspath(filepath)] = True

		def all_local_songs ():
			return list(all_local_songs_dict.keys())

		for filepath in matched_local_songs + filtered_local_songs + excluded_local_songs:
			metadata = _get_mutagen_metadata(filepath);
			songpath = template_to_filepath(cli['output'], metadata) + '.mp3'
			if filepath != songpath:
				utils.make_sure_path_exists(os.path.dirname(songpath), 0o700)
				print("{0} ~> {1}".format(filepath, songpath))
				shutil.move(filepath, songpath)

			add_to_local_songs(songpath)
			# add_to_local_songs(filepath)


		# for filepath in matched_local_songs + filtered_local_songs + excluded_local_songs:
		# 	add_to_local_songs(filepath)


		def download_songs(songs_to_download):
			if songs_to_download:
				if cli['dry-run']:
					logger.info("\nFound {0} song(s) to download".format(len(songs_to_download)))
					for song in songs_to_download:
						title = song.get('title', "<title>")
						artist = song.get('artist', "<artist>")
						album = song.get('album', "<album>")
						song_id = song['id']
						metadata = metadata_from_mobile_client_song(song)
						songpath = template_to_filepath(cli['output'], metadata) + '.mp3'
						logger.log(QUIET, "{0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
						add_to_local_songs(songpath)
				else:
					logger.info("\nDownloading {0} song(s) from Google Music\n".format(len(songs_to_download)))
					results = mmw.download(songs_to_download, template=cli['output'])
					# keep track of new filepaths
					for res in results:
						if res['result'] == 'downloaded':
							add_to_local_songs(res['filepath'])
			else:
				logger.info("\nNo songs to download")

		def download_missing_google_songs(mmw_songs):
			# recheck the local songs after any previous sync
			logger.info("\nFinding missing songs...")
			songs_to_download = compare_song_collections(mmw_songs, all_local_songs())
			songs_to_download.sort(key=lambda song: (song.get('artist'), song.get('album'), song.get('track_number')))
			return download_songs(songs_to_download)

		logger.info("\nFetching Library songs...")
		download_missing_google_songs(matched_google_songs)

		if cli['playlists']:
			logger.info("Syncing playlists...")
			# get all songs from mobileClient api (to include ratings)
			all_songs = mcw.api.get_all_songs()
			# get id, prioritize trackId over id
			def songid (track):
				return track['trackId'] if 'trackId' in track else track['id']
			# create a dictionary of all fetched google songs, indexed by id
			def songs_to_dict (songs, song):
				id = songid(song)
				songs[id] = song
				return songs
			# create lookup dicts for tracks (mmw) and songs (mcw)
			songs_dict = reduce(songs_to_dict, all_songs, {})
			tracks_dict = reduce(songs_to_dict, matched_google_songs + filtered_google_songs, {})

			# returns music manager wrapper tracks for list of objects with song id or trackId
			#  also removes duplicates
			def get_mmw_tracks (songs):
				tracks = []
				seen = {}
				for song in songs:
					id = songid(song)
					if id not in seen:
						tracks.append(tracks_dict[id])
						seen[id] = True
				return tracks;

			# path to save playlists
			playlists_dir = os.path.abspath(cli['playlists'])
			# ensure directory is there
			utils.make_sure_path_exists(playlists_dir, 0o700)

			def create_playlist_file (name, songs, outpath):
				filename = os.path.join(outpath, name + '.m3u')

				if not cli['dry-run']:
					m3u = [u'#EXTM3U']
					for track in songs:
						id = songid(track)
						song = songs_dict[id]
						artist = song['artist']
						title = song['title']
						duration = str(int(int(song['durationMillis']) / 1000)) if 'durationMillis' in song else '0'
						metadata = metadata_from_mobile_client_song(song)
						songpath = template_to_filepath(cli['output'], metadata) + '.mp3'
						m3u.append(u'#EXTINF,' + duration + ',' + song['artist'] + ' - ' + song['title'])
						m3u.append(os.path.relpath(songpath, outpath))
						# track this song as a local song to keep
						add_to_local_songs(songpath)
					# write m3u file
					contentstr = u'\n'.join(m3u)
					# write to temp file
					with tempfile.NamedTemporaryFile(suffix='.m3u', delete=False) as temp:
						temp.write(contentstr.encode('UTF-8-SIG'))
					# move tempfile into place
					utils.make_sure_path_exists(os.path.dirname(filename), 0o700)
					shutil.move(temp.name, filename)

				logger.log(QUIET, "Playlist ({0} tracks): {1}".format(len(songs), filename))
				return filename


			# get playlists with ordered lists of tracks
			playlists = mcw.api.get_all_user_playlist_contents()
			# concatenate all the playlist tracks into a single list
			playlist_tracks = reduce(lambda x, y: x + y, map(lambda x: x['tracks'], playlists)) if len(playlists) else []
			# remove duplicates and get mmw tracks to download
			playlist_tracks = get_mmw_tracks(playlist_tracks)
			# download any missing songs
			logger.info("\nFetching Playlist songs...")
			download_missing_google_songs(playlist_tracks)
			# create the m3u files for the playlists
			created_playlists = [];
			for playlist in playlists:
				playlist_filename = create_playlist_file(playlist['name'], playlist['tracks'], playlists_dir)
				created_playlists.append(playlist_filename)

			# create an m3u file for all favorited songs
			favorites_playlist_name = cli['favorites'] if 'favorites' in cli else '___auto_favorites___'
			# filter mobile client songs into favorites list
			thumbs_up = [t for t in all_songs if int(t['rating']) > 3]
			# most recent first
			thumbs_up.sort(key=lambda song: (int(song.get('lastModifiedTimestamp')) * -1))
			# get music_manager_wrapper style tracks to compare
			thumbs_up_tracks = get_mmw_tracks(thumbs_up)
			# download any missing favorited songs
			logger.info("\nFetching Favorited songs...")
			download_missing_google_songs(thumbs_up_tracks)
			# create favorites playlist
			created_playlist_filename = create_playlist_file(favorites_playlist_name, thumbs_up, playlists_dir)
			created_playlists.append(created_playlist_filename)


		if cli['removed']:
			logger.info("Moving Removed songs...")
			# path to move songs removed from google music
			removed_dir = os.path.abspath(cli['removed'])
			# ensure directory is there
			utils.make_sure_path_exists(removed_dir, 0o700)
			# local songs after sync
			all_google_songs = matched_google_songs + filtered_google_songs
			songs_to_move = compare_song_collections(all_local_songs(), all_google_songs)

			for filepath in songs_to_move:
				rel_file_path = os.path.relpath(filepath, cli['input'][0])
				removed_filepath = os.path.join(removed_dir, rel_file_path)
				utils.make_sure_path_exists(os.path.dirname(removed_filepath), 0o700)
				logger.info("Removing {0} ~> {1}".format(filepath, removed_filepath))
				if not cli['dry-run']:
					shutil.move(filepath, removed_filepath)

			# clean up empty folders
			logger.info(" ")
			if not cli['dry-run']:
				removeEmptyFolders(cli['input'][0], False)

			if cli['playlists']:
				logger.info("Moving Removed playlists...")
				# path to move songs removed from google music
				removed_playlists_dir = os.path.join(os.path.abspath(cli['removed']), cli['playlists'])
				# local playlists after sync
				local_playlists = [os.path.join(dp, f) for dp, dn, fn in os.walk(playlists_dir) for f in fn]
				playlists_to_remove = list(set(local_playlists) - set(created_playlists))

				for filepath in playlists_to_remove:
					rel_file_path = os.path.relpath(filepath, playlists_dir)
					removed_filepath = os.path.join(removed_playlists_dir, rel_file_path)
					utils.make_sure_path_exists(os.path.dirname(removed_filepath), 0o700)
					logger.info("Removing {0}".format(rel_file_path))
					if not cli['dry-run']:
						shutil.move(filepath, removed_filepath)

				# clean up empty folders
				logger.info(" ")
				if not cli['dry-run']:
					removeEmptyFolders(playlists_dir, False)

	else:
		matched_google_songs, _ = mmw.get_google_songs()

		logger.info("")

		matched_local_songs, songs_to_filter, songs_to_exclude = mmw.get_local_songs(
			cli['input'], include_filters=include_filters, exclude_filters=exclude_filters,
			all_includes=cli['all-includes'], all_excludes=cli['all-excludes'],
			exclude_patterns=cli['exclude'], max_depth=cli['max-depth']
		)

		logger.info("\nFinding missing songs...")

		songs_to_upload = compare_song_collections(matched_local_songs, matched_google_songs)

		# Sort lists for sensible output.
		songs_to_upload.sort()
		songs_to_exclude.sort()

		if cli['dry-run']:
			logger.info("\nFound {0} song(s) to upload".format(len(songs_to_upload)))

			if songs_to_upload:
				logger.info("\nSongs to upload:\n")

				for song in songs_to_upload:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to upload")

			if songs_to_filter:
				logger.info("\nSongs to filter:\n")

				for song in songs_to_filter:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to filter")

			if songs_to_exclude:
				logger.info("\nSongs to exclude:\n")

				for song in songs_to_exclude:
					logger.log(QUIET, song)
			else:
				logger.info("\nNo songs to exclude")
		else:
			if songs_to_upload:
				logger.info("\nUploading {0} song(s) to Google Music\n".format(len(songs_to_upload)))

				mmw.upload(songs_to_upload, enable_matching=cli['match'], delete_on_success=cli['delete-on-success'])
			else:
				logger.info("\nNo songs to upload")

				# Delete local files if they already exist on Google Music.
				if cli['delete-on-success']:
					for song in matched_local_songs:
						try:
							os.remove(song)
						except:
							logger.warning("Failed to remove {} after successful upload".format(song))

	mmw.logout()
	mcw.logout()
	logger.info("\nAll done!")
Esempio n. 10
0
def main():
    if len(sys.argv) != 3:
        print_help()
        sys.exit(1)
    else:
        username = sys.argv[1]
        path = sys.argv[2]
    password = getpass.getpass()

    pp = pprint.PrettyPrinter(indent=4)

    local_list = get_local_dirs(path)

    mob = Mobileclient()
    mob.login(username, password, Mobileclient.FROM_MAC_ADDRESS)
    if not mob.is_authenticated():
        sys.exit(1)

    mmw = MusicManagerWrapper(enable_logging=True)
    mmw.login()

    if not mmw.is_authenticated:
        sys.exit()

    total_items = 0
    partial_accepted_items = 0
    partial_rejected_items = 0
    partial_manual_items = 0
    exact_items = 0
    no_items = 0

    ACCEPT_RATIO = 0.33
    REJECT_RATIO = 0.66

    matched_albums = []
    unmatched_albums = []
    manual_albums = []

    for item in local_list:
        search_artist = item['artist']
        for search_album in item['albums']:
            total_items += 1
            albums = search_for_artist_and_album(mob, search_artist, search_album)
            sorted_albums = sorted(albums, key=lambda k:k[2])

            if len(sorted_albums) > 0:
                (artist, album, ratio, album_id) = sorted_albums[0]

                if ratio > 0:
                    if ratio < ACCEPT_RATIO:
                        partial_accepted_items += 1
                        partial_description = 'Partial Match (Accepted)'
                        matched_albums.append((artist, album, album_id))
                    elif ratio > REJECT_RATIO:
                        partial_rejected_items += 1
                        partial_description = 'Partial Match (Rejected)'
                        unmatched_albums.append((search_artist, search_album))
                    else:
                        partial_manual_items += 1
                        partial_description = 'Partial Match (Manual)'
                        manual_albums.append((search_artist, search_album, artist, album, album_id))
                    print_partial(partial_description, ratio, artist, album, search_artist, search_album)
                else:
                    exact_items += 1
                    print("{0: <30}: Artist: {1}, Album: {2}".format('Exact Match', artist, album))
                    matched_albums.append((artist, album, album_id))
            else:
                no_items += 1
                print("{0: <30}: Artist: {1}, Album: {2}".format('No Match', search_artist, search_album))
                unmatched_albums.append((search_artist, search_album))

    print_summary(total_items, partial_accepted_items, partial_rejected_items, partial_manual_items, exact_items, no_items)

    if (confirmation_dialog("Ok to proceed? (y/n)")):
        (manual_matched, manual_unmatched) = process_manual_albums(manual_albums)
        matched_albums += manual_matched
        unmatched_albums += manual_unmatched
        add_matched_albums_to_library(mob, matched_albums)
        upload_unmatched_albums_to_library(mmw, path, unmatched_albums)