def test_validate_lastfm_artist_tags_fallback(self): validator = ReleaseValidator(get_lastfmcache(genres_release=OrderedDict())) release = create_test_release(genres=["genre 1"]) violations = validator.validate(release) assert len(violations) == 1
def test_validate_lastfm_release_tags(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(genres=["genre 1"]) violations = validator.validate(release) assert len(violations) == 1
def test_fix(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(release_title="mezzanine", date="") fixed = validator.fix(release) assert fixed != release mockito.unstub()
def test_validate_release_title_whitespace(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(release_title=" Mezzanine") violations = validator.validate(release) assert len(violations) == len(release.tracks) mockito.unstub()
def test_validate_release_artist_whitespace(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(release_artists=[" Massive Attack"]) violations = validator.validate(release) assert len(violations) == len(release.tracks) + 1 mockito.unstub()
def test_lastfm_fix_track_title_lowercase(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).track_title = "angel" fixed = validator.fix(release) assert fixed != release mockito.unstub()
def test_validate_release_date(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(date="") violations = validator.validate(release) assert len(violations) == 2 mockito.unstub()
def test_validate_lastfm_release_title(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(release_title="mezzanine") violations = validator.validate(release) assert len(violations) == 1 mockito.unstub()
def test_validate_genre_whitespace(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release(genres=[" Bass"]) violations = validator.validate(release) assert len(violations) == len(release.tracks) + 1 mockito.unstub()
def test_validate_artist_whitespace(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).artists[0] = " Massive Attack" violations = validator.validate(release) assert len(violations) == 2 mockito.unstub()
def test_validate_tag_types(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).stream_info.tag_type = TagType.FLAC violations = validator.validate(release) assert len(violations) > 0 mockito.unstub()
def test_validate_invalid_disc_numbers(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).disc_number = 3 violations = validator.validate(release) assert len(violations) > 0 mockito.unstub()
def test_validate_missing_total_tracks(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).total_tracks = None violations = validator.validate(release) assert len(violations) == 1 mockito.unstub()
def test_validate_release_artists(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).release_artists = [] violations = validator.validate(release) assert len(violations) == 1 mockito.unstub()
def test_validate_track_title_whitespace(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).track_title = " A Bad Track Title" violations = validator.validate(release) assert len(violations) == 2 mockito.unstub()
def test_validate_cbr_bitrates(self): validator = ReleaseValidator(get_lastfmcache()) release = create_test_release() next(iter(release.tracks.values())).stream_info.bitrate = 160000 violations = validator.validate(release) assert len(violations) == 1 mockito.unstub()
def validate_releases(validator: ReleaseValidator, release_dirs: List[str], args: argparse.Namespace) -> None: """Validate releases found in the scan directory""" # assemble_discs(release_dirs, False) for curr_dir in release_dirs: audio, non_audio, unreadable = load_directory(curr_dir) release = Release(audio, guess_category_from_path(curr_dir), guess_source_from_path(curr_dir)) codec_short = not args.full_codec_names violations = validator.validate(release) validate_folder_name(release, violations, os.path.split(curr_dir)[1], False, codec_short) add_unreadable_files(violations, unreadable) print("{0} violations: {1}".format(format_violations_str(violations), curr_dir)) if args.show_violations: print_list(violations)
def main(): args = parse_args() src_folder = os.path.abspath(args.path) if not os.path.isdir(src_folder): raise ValueError("Invalid source folder: {0}".format(src_folder)) dest_folder = None if args.move_fixed: dest_folder = os.path.abspath(src_folder) elif args.move_fixed_to: dest_folder = os.path.abspath(args.move_fixed_to) if not os.path.isdir(dest_folder): raise ValueError( "Invalid destination folder: {0}".format(dest_folder)) invalid_folder = None if args.move_invalid: if args.move_invalid not in [v.value for v in ViolationType]: raise ValueError( "Invalid violation type '{0}', must be one of {1}".format( args.move_invalid, ", ".join([v.value for v in ViolationType]))) if not args.move_invalid_to: raise ValueError( "--move-invalid must be accompanied by --move-invalid-to") invalid_folder = os.path.abspath(args.move_invalid_to) if not os.path.isdir(invalid_folder): raise ValueError( "Destination folder for invalid releases does not exist") duplicate_folder = None if args.move_duplicate_to: duplicate_folder = os.path.abspath(args.move_duplicate_to) if not os.path.isdir(duplicate_folder): raise ValueError( "Invalid duplicates folder: {0}".format(duplicate_folder)) # guess group_by_category, if it was not set, using the contents of the destination folder if not args.group_by_category: args.group_by_category = guess_group_by_category( src_folder, dest_folder) if args.mode == "releases": list_releases(get_release_dirs(src_folder)) elif args.mode in ["validate", "fix"]: lastfm = LastfmCache(lastfmcache_api_url=get_lastfmcache_api_url()) lastfm.enable_file_cache(86400 * 365 * 5) validator = ReleaseValidator(lastfm) validator.disable_lastfm_track_title_validation() if args.expunge_comments_with_substring: validator.add_forbidden_comment_substring( args.expunge_comments_with_substring) if args.mode == "validate": validate_releases(validator, get_release_dirs(src_folder), args) elif args.mode == "fix": assemble_discs(get_release_dirs(src_folder), True) fix_releases(validator, get_release_dirs(src_folder), args, dest_folder, invalid_folder, duplicate_folder)
def fix_releases(validator: ReleaseValidator, release_dirs: Iterator[str], args: argparse.Namespace, dest_folder: str, invalid_folder: str, duplicate_folder: str) -> None: """Fix releases found in the scan directory""" unique_releases = set() for curr_dir in release_dirs: if not can_lock_path(curr_dir): logging.getLogger(__name__).error( "Could not lock directory {0}".format(curr_dir)) continue audio, non_audio, unreadable = load_directory(curr_dir) release = Release(audio, guess_category_from_path(curr_dir), guess_source_from_path(curr_dir)) fixed = validator.fix(release, os.path.split(curr_dir)[1]) if not args.dry_run: for x in fixed.tracks: if fixed.tracks[x] != release.tracks[x] or fixed.tracks[ x].always_write: cleartag.write_tags(os.path.join(curr_dir, x), fixed.tracks[x]) # rename files rename_files(fixed, curr_dir, args.dry_run) new_tracks = OrderedDict() for x in fixed.tracks: correct_filename = fixed.tracks[x].get_filename(fixed.is_va()) if correct_filename: new_tracks[correct_filename] = fixed.tracks[x] else: new_tracks[x] = fixed.tracks[x] fixed.tracks = new_tracks # calculate violations before and after fixing codec_short = not args.full_codec_names old_violations = validator.validate(release) validate_folder_name(release, old_violations, os.path.split(curr_dir)[1], False, args.group_by_category, codec_short) add_unreadable_files(old_violations, unreadable) violations = validator.validate(fixed) validate_folder_name(fixed, violations, os.path.split(curr_dir)[1], True, args.group_by_category, codec_short) add_unreadable_files(violations, unreadable) if len(violations) == 0: moved_dir = move_rename_folder(fixed, unique_releases, curr_dir, dest_folder, duplicate_folder, args) else: moved_dir = move_invalid_folder(curr_dir, invalid_folder, violations, args.move_invalid) enforce_max_path(moved_dir) print("{0} violations: {1}".format( format_violations_str(old_violations, violations), moved_dir)) if args.show_violations: if old_violations: print("Before") print_list(old_violations) if violations: print("After:") print_list(violations)