示例#1
0
    def test_fields_partial(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1,
                                TEST_MAPPING_ITEMS_2,
                                fields=['artist', 'title']))
        expected = [TEST_MAPPING_1]

        assert existing == expected
示例#2
0
    def test_default_field_map_no_exist(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1,
                                TEST_MAPPING_ITEMS_2,
                                fields=['tracknumber', 'noexist']))
        expected = [TEST_MAPPING_1]

        assert existing == expected
示例#3
0
    def test_fields_same(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1,
                                TEST_MAPPING_ITEMS_1,
                                fields=['artist', 'album']))
        expected = TEST_MAPPING_ITEMS_1

        assert existing == expected
示例#4
0
    def test_fields_different(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_2,
                                TEST_MAPPING_ITEMS_3,
                                fields=['artist', 'album']))
        expected = []

        assert existing == expected
示例#5
0
    def test_custom_field_map(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1,
                                TEST_MAPPING_ITEMS_2,
                                fields=['tracknumber'],
                                field_map={'tracknumber': 'track_number'}))
        expected = [TEST_MAPPING_1]

        assert existing == expected
示例#6
0
def do_download(args):
    logger.success("Logging in to Music Manager")
    mm = google_music.musicmanager(args.username, uploader_id=args.uploader_id)
    if not mm.is_authenticated:
        sys.exit("Failed to authenticate Music Manager")

    logger.success("Logging in to Mobile Client")
    mc = google_music.mobileclient(args.username, device_id=args.device_id)
    if not mc.is_authenticated:
        sys.exit("Failed to authenticate Mobile Client")

    logger.success("Loading Google songs")

    google_songs = get_google_songs(mm, filters=args.filters)
    base_path = template_to_base_path(args.output, google_songs)
    filepaths = [base_path]
    if args.include:
        filepaths.extend(args.include)

    mc_songs = get_google_songs(mc, filters=args.filters)
    if any(
            args.get(option) for option in
        [
            'created_in', 'created_on', 'created_before', 'created_after',
            'modified_in', 'modified_on', 'modified_before', 'modified_after'
        ]):
        mc_songs = filter_google_dates(
            mc_songs,
            created_in=args.get('created_in'),
            created_on=args.get('created_on'),
            created_before=args.get('created_before'),
            created_after=args.get('created_after'),
            modified_in=args.get('modified_in'),
            modified_on=args.get('modified_on'),
            modified_before=args.get('modified_before'),
            modified_after=args.get('modified_after'))

    logger.success("Loading local songs")

    local_songs = get_local_songs(filepaths,
                                  filters=args.filters,
                                  max_depth=args.max_depth,
                                  exclude_paths=args.exclude_paths,
                                  exclude_regexes=args.exclude_regexes,
                                  exclude_globs=args.exclude_globs)

    missing_songs = []
    if args.use_hash:
        logger.success("Comparing hashes")

        existing_songs = []
        google_client_id_map = {
            song.get('clientId'): song
            for song in mc_songs
        }
        local_client_ids = {generate_client_id(song) for song in local_songs}
        for client_id, mc_song in google_client_id_map.items():
            song = first_true(
                (song for song in google_songs),
                pred=lambda song: song.get('id') == mc_song.get('id'))
            if client_id not in local_client_ids:
                missing_songs.append(song)
            else:
                existing_songs.append(song)

        logger.success(
            f"Found {len(existing_songs)} songs already exist by audio hash")
        if logger._min_level <= 20:
            for song in existing_songs:
                title = song.get('title', "<title>")
                artist = song.get('artist', "<artist>")
                album = song.get('album', "<album>")
                song_id = song['id']

                logger.info(f"{title} -- {artist} -- {album} ({song_id})")

    if args.use_metadata:
        if args.use_hash:
            google_songs = missing_songs

        if google_songs:
            logger.success("Comparing metadata")

            missing_songs = natsorted(
                gm_utils.find_missing_items(
                    google_songs,
                    local_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            existing_songs = natsorted(
                gm_utils.find_existing_items(
                    google_songs,
                    local_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            logger.success(
                f"Found {len(existing_songs)} songs already exist by metadata")
            if logger._min_level <= 20:
                for song in existing_songs:
                    title = song.get('title', "<title>")
                    artist = song.get('artist', "<artist>")
                    album = song.get('album', "<album>")
                    song_id = song['id']

                    logger.info(f"{title} -- {artist} -- {album} ({song_id})")

    if not args.use_hash and not args.use_metadata:
        missing_songs = google_songs

    to_download = natsorted(missing_songs)

    if not to_download:
        logger.success("No songs to download")
    elif args.dry_run:
        logger.success(f"Found {len(to_download)} songs to download")

        if logger._min_level <= 20:
            for song in to_download:
                title = song.get('title', "<title>")
                artist = song.get('artist', "<artist>")
                album = song.get('album', "<album>")
                song_id = song['id']

                logger.info(f"{title} -- {artist} -- {album} ({song_id})")
    else:
        download_songs(mm, to_download, template=args.output)

    mc.logout()
    mm.logout()
    logger.success("All done!")
示例#7
0
def do_upload(args):
    logger.success("Logging in to Music Manager")
    mm = google_music.musicmanager(args.username, uploader_id=args.uploader_id)
    if not mm.is_authenticated:
        sys.exit("Failed to authenticate Music Manager")

    logger.success("Logging in to Mobile Client")
    mc = google_music.mobileclient(args.username, device_id=args.device_id)
    if not mc.is_authenticated:
        sys.exit("Failed to authenticate Mobile Client")

    logger.success("Loading local songs")

    local_songs = get_local_songs(args.include,
                                  filters=args.filters,
                                  max_depth=args.max_depth,
                                  exclude_paths=args.exclude_paths,
                                  exclude_regexes=args.exclude_regexes,
                                  exclude_globs=args.exclude_globs)

    if any(
            args.get(option) for option in
        [
            'created_in', 'created_on', 'created_before', 'created_after',
            'modified_in', 'modified_on', 'modified_before', 'modified_after'
        ]):
        local_songs = filter_local_dates(
            local_songs,
            created_in=args.get('created_in'),
            created_on=args.get('created_on'),
            created_before=args.get('created_before'),
            created_after=args.get('created_after'),
            modified_in=args.get('modified_in'),
            modified_on=args.get('modified_on'),
            modified_before=args.get('modified_before'),
            modified_after=args.get('modified_after'))

    missing_songs = []
    if args.use_hash:
        logger.success("Comparing hashes")

        existing_songs = []
        google_client_ids = {
            song.get('clientId', '')
            for song in get_google_songs(mc)
        }
        for song in local_songs:
            if generate_client_id(song) not in google_client_ids:
                missing_songs.append(song)
            else:
                existing_songs.append(song)

        logger.success(
            f"Found {len(existing_songs)} songs already exist by audio hash")
        if logger._min_level <= 20:
            for song in natsorted(existing_songs):
                logger.info(song)

    if args.use_metadata:
        if args.use_hash:
            local_songs = missing_songs

        if local_songs:
            logger.success("Comparing metadata")

            google_songs = get_google_songs(mm, filters=args.filters)

            missing_songs = natsorted(
                gm_utils.find_missing_items(
                    local_songs,
                    google_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            existing_songs = natsorted(
                gm_utils.find_existing_items(
                    local_songs,
                    google_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            logger.success(
                f"Found {len(existing_songs)} songs already exist by metadata")
            if logger._min_level <= 20:
                for song in existing_songs:
                    logger.info(song)

    if not args.use_hash and not args.use_metadata:
        missing_songs = local_songs

    to_upload = natsorted(missing_songs)

    if not to_upload:
        logger.success("No songs to upload")
    elif args.dry_run:
        logger.success(f"Found {len(to_upload)} songs to upload")

        if logger._min_level <= 20:
            for song in to_upload:
                logger.info(song)
    else:
        upload_songs(mm,
                     to_upload,
                     album_art=args.album_art,
                     no_sample=args.no_sample,
                     delete_on_success=args.delete_on_success)

    mc.logout()
    mm.logout()
    logger.success("All done!")
示例#8
0
def do_download(args):
    logger.log('NORMAL', "Logging in to Music Manager")
    mm = google_music.musicmanager(args.username, uploader_id=args.uploader_id)
    if not mm.is_authenticated:
        sys.exit("Failed to authenticate Music Manager")

    logger.log('NORMAL', "Logging in to Mobile Client")
    mc = google_music.mobileclient(args.username, device_id=args.device_id)
    if not mc.is_authenticated:
        sys.exit("Failed to authenticate Mobile Client")

    google_songs = get_google_songs(mm, filters=args.filters)
    base_path = template_to_base_path(args.output, google_songs)
    filepaths = [base_path, *args.include]

    mc_songs = get_google_songs(mc, filters=args.filters)
    if any(
            args.get(option) for option in [
                'created_in',
                'created_on',
                'created_before',
                'created_after',
                'modified_in',
                'modified_on',
                'modified_before',
                'modified_after',
            ]):
        mc_songs = filter_google_dates(
            mc_songs,
            created_in=args.get('created_in'),
            created_on=args.get('created_on'),
            created_before=args.get('created_before'),
            created_after=args.get('created_after'),
            modified_in=args.get('modified_in'),
            modified_on=args.get('modified_on'),
            modified_before=args.get('modified_before'),
            modified_after=args.get('modified_after'))

    local_songs = get_local_songs(filepaths,
                                  filters=args.filters,
                                  max_depth=args.max_depth,
                                  exclude_paths=args.exclude_paths,
                                  exclude_regexes=args.exclude_regexes,
                                  exclude_globs=args.exclude_globs)

    missing_songs = []
    existing_songs = []
    if args.use_hash:
        if google_songs and local_songs:
            logger.log('NORMAL', "Comparing hashes")

            google_client_id_map = {
                mc_song.get('clientId'): mc_song
                for mc_song in mc_songs
            }
            local_client_ids = {
                generate_client_id(song)
                for song in local_songs
            }
            for client_id, mc_song in google_client_id_map.items():
                song = first_true(
                    (song for song in google_songs),
                    pred=lambda song: song.get('id') == mc_song.get('id'))

                if song is not None:
                    if client_id not in local_client_ids:
                        missing_songs.append(song)
                    else:
                        existing_songs.append(song)

            logger.info("Found {} songs already exist by audio hash",
                        len(existing_songs))

            if logger._min_level <= 5:
                for song in existing_songs:
                    title = song.get('title', "<title>")
                    artist = song.get('artist', "<artist>")
                    album = song.get('album', "<album>")
                    song_id = song['id']

                    logger.trace("{} -- {} -- {} ({})", title, artist, album,
                                 song_id)
        else:
            missing_songs = google_songs

            if not google_songs and not local_songs:
                logger.log('NORMAL', "No songs to compare hashes.")
            elif not google_songs:
                logger.log('NORMAL', "No Google songs to compare hashes.")
            elif not local_songs:
                logger.log('NORMAL', "No local songs to compare hashes.")

    if args.use_metadata:
        if args.use_hash:
            google_songs = missing_songs

        if google_songs and local_songs:
            logger.log('NORMAL', "Comparing metadata")

            missing_songs = natsorted(
                gm_utils.find_missing_items(
                    google_songs,
                    local_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            existing_songs = natsorted(
                gm_utils.find_existing_items(
                    google_songs,
                    local_songs,
                    fields=['artist', 'album', 'title', 'tracknumber'],
                    normalize_values=True))

            logger.info("Found {} songs already exist by metadata",
                        len(existing_songs))

            if logger._min_level <= 5:
                for song in existing_songs:
                    title = song.get('title', "<title>")
                    artist = song.get('artist', "<artist>")
                    album = song.get('album', "<album>")
                    song_id = song['id']

                    logger.trace("{} -- {} -- {} ({})", title, artist, album,
                                 song_id)
        else:
            if not google_songs and not local_songs:
                logger.log('NORMAL', "No songs to compare metadata.")
            elif not google_songs:
                logger.log('NORMAL', "No Google songs to compare metadata.")
            elif not local_songs:
                logger.log('NORMAL', "No local songs to compare metadata.")

    if not args.use_hash and not args.use_metadata:
        missing_songs = google_songs

    logger.log('NORMAL', "Sorting songs")

    to_download = natsorted(missing_songs)

    logger.info("Found {} songs to download", len(to_download))

    if not args.dry_run:
        download_songs(mm, to_download, template=args.output)
    elif logger._min_level <= 15:
        for song in to_download:
            title = song.get('title', "<title>")
            artist = song.get('artist', "<artist>")
            album = song.get('album', "<album>")
            song_id = song['id']

            logger.log('ACTION_SUCCESS', "{} -- {} -- {} ({})", title, artist,
                       album, song_id)
示例#9
0
    def test_no_fields_partial(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1, TEST_MAPPING_ITEMS_2))
        expected = [TEST_MAPPING_1]

        assert existing == expected
示例#10
0
    def test_no_fields_different(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_2, TEST_MAPPING_ITEMS_3))
        expected = []

        assert existing == expected
示例#11
0
    def test_no_fields_same(self):
        existing = list(
            find_existing_items(TEST_MAPPING_ITEMS_1, TEST_MAPPING_ITEMS_1))
        expected = TEST_MAPPING_ITEMS_1

        assert existing == expected
示例#12
0
    def test_unsupported_format(self, src, dst, expected):
        existing = list(find_existing_items(src, dst))

        assert existing == expected
示例#13
0
def do_upload(args):
	logger.log('NORMAL', "Logging in to Music Manager")
	mm = google_music.musicmanager(args.username, uploader_id=args.uploader_id)
	if not mm.is_authenticated:
		sys.exit("Failed to authenticate Music Manager")

	logger.log('NORMAL', "Logging in to Mobile Client")
	mc = google_music.mobileclient(args.username, device_id=args.device_id)
	if not mc.is_authenticated:
		sys.exit("Failed to authenticate Mobile Client")

	local_songs = get_local_songs(
		args.include,
		filters=args.filters,
		max_depth=args.max_depth,
		exclude_paths=args.exclude_paths,
		exclude_regexes=args.exclude_regexes,
		exclude_globs=args.exclude_globs
	)

	creation_dates = [
		args[option]
		for option in [
			'created_in',
			'created_on',
			'created_before',
			'created_after',
		]
		if option in args
	]

	modification_dates = [
		args[option]
		for option in [
			'modified_in',
			'modified_on',
			'modified_before',
			'modified_after',
		]
		if option in args
	]

	local_songs = filter_filepaths_by_dates(
		local_songs,
		creation_dates=creation_dates,
		modification_dates=modification_dates,
	)

	missing_songs = []
	if args.use_hash:
		logger.log('NORMAL', "Comparing hashes")

		existing_songs = []
		google_client_ids = {song.get('clientId', '') for song in get_google_songs(mc)}
		for song in local_songs:
			if generate_client_id(song) not in google_client_ids:
				missing_songs.append(song)
			else:
				existing_songs.append(song)

		logger.info("Found {} songs already exist by audio hash", len(existing_songs))

		if logger._core.min_level <= 5:
			for song in natsorted(existing_songs):
				logger.trace(song)

	if args.use_metadata:
		if args.use_hash:
			local_songs = missing_songs

		if local_songs:
			logger.log('NORMAL', "Comparing metadata")

			google_songs = get_google_songs(mm, filters=args.filters)

			missing_songs = natsorted(
				gm_utils.find_missing_items(
					local_songs,
					google_songs,
					fields=['artist', 'album', 'title', 'tracknumber'],
					normalize_values=True
				)
			)

			existing_songs = natsorted(
				gm_utils.find_existing_items(
					local_songs,
					google_songs,
					fields=['artist', 'album', 'title', 'tracknumber'],
					normalize_values=True
				)
			)

			logger.info("Found {} songs already exist by metadata", len(existing_songs))

			if logger._core.min_level <= 5:
				for song in existing_songs:
					logger.trace(song)

	if not args.use_hash and not args.use_metadata:
		missing_songs = local_songs

	logger.log('NORMAL', "Sorting songs")

	to_upload = natsorted(missing_songs)

	logger.info("Found {} songs to upload", len(to_upload))

	if not args.dry_run:
		upload_songs(
			mm,
			to_upload,
			album_art=args.album_art,
			no_sample=args.no_sample,
			delete_on_success=args.delete_on_success
		)
	elif logger._core.min_level <= 15:
		for song in to_upload:
			logger.log(
				'ACTION_SUCCESS',
				song
			)