Exemplo n.º 1
0
 def login(user, pwd):
     mcw = MobileClientWrapper()
     print 'lit'
     logged_in = mcw.login(user, pwd)
     print 'lit2'
     if logged_in:
         data['client'] = mcw
     return logged_in
Exemplo 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)

	mcw = MobileClientWrapper(enable_logging=cli['log'])
	mcw.login(username=cli['user'], password=cli['pass'], android_id=cli['android-id'])

	if not mcw.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']]

	logger.info("Scanning for songs...\n")
	search_results, _ = mcw.get_google_songs(
		include_filters=include_filters, exclude_filters=exclude_filters,
		all_includes=cli['all-includes'], all_excludes=cli['all-excludes']
	)

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

	if search_results:
		confirm = cli['yes'] or cli['quiet']
		logger.info("")

		if confirm or input("Display {} results? (y/n) ".format(len(search_results))) in ("y", "Y"):
			logger.log(QUIET, "")

			for song in search_results:
				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 found matching query")

	mcw.logout()
	logger.info("\nAll done!")
Exemplo 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)

	mcw = MobileClientWrapper()
	mcw.login(cli['user'], cli['pass'], cli['android-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']]

	logger.info("Scanning for songs...\n")
	search_results, _ = mcw.get_google_songs(include_filters, exclude_filters, cli['include-all'], cli['exclude-all'])
	search_results.sort(key=lambda song: (song.get('artist'), song.get('album'), song.get('trackNumber')))

	if search_results:
		confirm = cli['yes'] or cli['quiet']
		logger.info("")

		if confirm or raw_input("Display {} results? (y/n) ".format(len(search_results))) in ("y", "Y"):
			logger.log(QUIET, "")

			for song in search_results:
				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 found matching query")

	mcw.logout()
	logger.info("\nAll done!")
Exemplo n.º 4
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)

	mcw = MobileClientWrapper()
	mcw.login(cli['user'], cli['pass'], cli['android-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_delete, _ = mcw.get_google_songs(include_filters, exclude_filters, cli['include-all'], cli['exclude-all'])

	if cli['dry-run']:
		logger.info("Found {0} songs to delete".format(len(songs_to_delete)))

		if songs_to_delete:
			logger.info("\nSongs to delete:\n")

			for song in songs_to_delete:
				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 delete")
	else:
		if songs_to_delete:
			confirm = cli['yes'] or cli['quiet']
			logger.info("")

			if confirm or raw_input("Are you sure you want to delete {0} song(s) from Google Music? (y/n) ".format(len(songs_to_delete))) in ("y", "Y"):
				logger.info("\nDeleting {0} songs from Google Music\n".format(len(songs_to_delete)))

				songnum = 0
				total = len(songs_to_delete)
				pad = len(str(total))

				for song in songs_to_delete:
					mcw.api.delete_songs(song['id'])
					songnum += 1

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

					logger.debug("Deleting {0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
					logger.info("Deleted {num:>{pad}}/{total} song(s) from Google Music".format(num=songnum, pad=pad, total=total))
			else:
				logger.info("\nNo songs deleted.")
		else:
			logger.info("\nNo songs to delete")

	mcw.logout()
	logger.info("\nAll done!")
Exemplo 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)

    mcw = MobileClientWrapper(enable_logging=cli["log"])
    mcw.login(cli["user"], cli["pass"], cli["android-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_delete, _ = mcw.get_google_songs(
        include_filters, exclude_filters, cli["all-includes"], cli["all-excludes"]
    )

    if cli["dry-run"]:
        logger.info("Found {0} songs to delete".format(len(songs_to_delete)))

        if songs_to_delete:
            logger.info("\nSongs to delete:\n")

            for song in songs_to_delete:
                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 delete")
    else:
        if songs_to_delete:
            confirm = cli["yes"] or cli["quiet"]
            logger.info("")

            if confirm or input(
                "Are you sure you want to delete {0} song(s) from Google Music? (y/n) ".format(len(songs_to_delete))
            ) in ("y", "Y"):
                logger.info("\nDeleting {0} songs from Google Music\n".format(len(songs_to_delete)))

                songnum = 0
                total = len(songs_to_delete)
                pad = len(str(total))

                for song in songs_to_delete:
                    mcw.api.delete_songs(song["id"])
                    songnum += 1

                    title = song.get("title", "<empty>")
                    artist = song.get("artist", "<empty>")
                    album = song.get("album", "<empty>")
                    song_id = song["id"]

                    logger.debug("Deleting {0} -- {1} -- {2} ({3})".format(title, artist, album, song_id))
                    logger.info(
                        "Deleted {num:>{pad}}/{total} song(s) from Google Music".format(
                            num=songnum, pad=pad, total=total
                        )
                    )
            else:
                logger.info("\nNo songs deleted.")
        else:
            logger.info("\nNo songs to delete")

    mcw.logout()
    logger.info("\nAll done!")
Exemplo n.º 6
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!")