Пример #1
0
def main() -> None:
	if '--organize-folder' in sys.argv:
		time_started = time.perf_counter()

		arg_index = sys.argv.index('--organize-folder')
		key = sys.argv[arg_index + 1]
		if '--name' in sys.argv:
			name_arg_index = sys.argv.index('--name')
			name = sys.argv[name_arg_index + 1]
		else:
			name = 'By ' + key

		missing_value: Optional[str]
		if '--missing-value' in sys.argv:
			missing_value_arg_index = sys.argv.index('--missing-value')
			missing_value = sys.argv[missing_value_arg_index + 1]
		else:
			missing_value = None

		for root, _, files in os.walk(main_config.output_folder):
			for f in files:
				path = Path(root, f)
				if path.suffix == '.desktop':
					desktop = get_desktop(path)
					move_into_extra_subfolder(path, desktop, sanitize_name(name, safe_for_fat32=True), key, missing_value)
		if main_config.print_times:
			time_ended = time.perf_counter()
			print('Folder organization finished in', str(datetime.timedelta(seconds=time_ended - time_started)))
		
	else:
		move_into_folders()
Пример #2
0
def _iter_existing_seriesless_launchers(
) -> Iterator[tuple[ConfigParser, Path]]:
    for path in main_config.output_folder.iterdir():
        desktop = get_desktop(path)

        if get_field(desktop, 'Series'):
            #Don't need to do this if it already exists
            continue

        yield desktop, path
Пример #3
0
def _find_existing_serieses() -> Collection[str]:
    serieses = set()
    for path in main_config.output_folder.iterdir():
        desktop = get_desktop(path)

        series = get_field(desktop, 'Series')
        if series:
            serieses.add(series)

    return serieses
Пример #4
0
def _detect_series_index_for_things_with_series():
    for path in main_config.output_folder.iterdir():
        desktop = get_desktop(path)

        existing_series = get_field(desktop, 'Series')
        if not existing_series:
            continue

        if get_field(desktop, 'Series-Index'):
            continue

        name = _get_usable_name(desktop)
        name.removeprefix('The ')
        name_chunks = _get_name_chunks(name)
        if len(name_chunks) > 1:
            if name_chunks[0] == existing_series:
                series_index = name_chunks[1]
                series_index = chapter_matcher.sub('', series_index).strip()
                series_index = convert_roman_numerals_in_title(series_index)
                _add_series(desktop, path, None, series_index)
            elif name_chunks[0].startswith(existing_series):
                series_index = _get_series_from_whole_thing(
                    existing_series, name_chunks[0].strip())
                _add_series(desktop, path, None, series_index)
            else:
                #This handles the case where it's like "Blah Bloo - Chapter Zabityzoo" but the series in Steam is listed as some abbreviation/alternate spelling of Blah Bloo so it doesn't get picked up otherwise
                chapter_index = None
                try:
                    chapter_index = name.index('Ch.') + len('Ch.')
                except ValueError:
                    chapter_matcherooni = chapter_matcher.search(name)
                    if chapter_matcherooni:
                        chapter_index = chapter_matcherooni.end()
                if chapter_index is not None:
                    #Could also do just a word match starting from chapter_index I guess
                    _add_series(
                        desktop, path, None,
                        convert_roman_numerals_in_title(
                            name[chapter_index:].strip()))
        elif len(name_chunks) == 1:
            if name_chunks[0].startswith(existing_series):
                _add_series(
                    desktop, path, None,
                    _get_series_from_whole_thing(existing_series,
                                                 name_chunks[0].strip()))
Пример #5
0
def _fix_duplicate_names(method: str, format_function: Optional[FormatFunction]=None, ignore_missing_values: bool=False, field_section: str=metadata_section_name):
	#TODO: output_folder needs to be unambigulously Path, that's the issue here
	files = ((cast(Path, path), get_desktop(path)) for path in main_config.output_folder.iterdir())
	if method == 'dev-status':
		_resolve_duplicates_by_dev_status(files)
		return

	#TODO: Handle this null check properly, it _should_ be impossible for Desktop Entry to not exist in a .desktop file, but that doesn't stop some joker putting them in there
	#Why did I call the variable "f"? Oh well
	keyfunc: Callable[[DesktopWithPath], str] = (lambda f: cast(str, get_field(f[1], 'Name', 'Desktop Entry')).lower()) \
		if method == 'check' \
		else (lambda f: normalize_name(cast(str, get_field(f[1], 'Name', 'Desktop Entry')), care_about_numerals=True))
	duplicates = {}
	#TODO: Is using keyfunc twice there really needed? Is that how that works?
	for key, group in itertools.groupby(sorted(files, key=keyfunc), key=keyfunc):
		g = tuple(group)
		if len(g) > 1:
			duplicates[key] = g

	for k, v in duplicates.items():
		if method == 'check':
			print('Duplicate name still remains: ', k, tuple(get_field(d[1], 'Original-Name', junk_section_name) for d in v))
		else:
			_resolve_duplicates(v, method, format_function, ignore_missing_values, field_section)
Пример #6
0
def remove_nonexistent_games() -> None:
    #If not doing a full rescan, we want to remove games that are no longer there

    time_started = time.perf_counter()

    output_folder: Path = main_config.output_folder
    for path in output_folder.iterdir():
        launcher = get_desktop(path)
        game_type = get_field(launcher, 'Type', id_section_name)
        game_id = get_field(launcher, 'Unique-ID', id_section_name)
        if not game_type or not game_id:
            if main_config.debug:
                print('Interesting', path, 'has no type or no ID')
            continue

        should_remove = False
        game_source = game_types.get(game_type)
        if game_source:
            should_remove = game_source.no_longer_exists(game_id)
        elif game_type == 'Steam':
            should_remove = steam.no_longer_exists(game_id)
        elif game_type == 'GOG':
            should_remove = not os.path.exists(game_id)
        elif game_type == 'itch.io':
            should_remove = not os.path.exists(game_id)
        #Hmm, not sure what I should do if game_type is unrecognized. I guess ignore it, it might be from somewhere else and therefore not my business

        if should_remove:
            if main_config.debug:
                print(game_type, game_id, 'no longer exists, removing')
            os.remove(path)

    if main_config.print_times:
        time_ended = time.perf_counter()
        print('Removal of non-existent items finished in',
              str(datetime.timedelta(seconds=time_ended - time_started)))
Пример #7
0
def move_into_subfolders(path: Path) -> None:
	desktop = get_desktop(path)
	platform = get_field(desktop, 'Platform')
	categories = get_array(desktop, 'Categories')
	languages = get_array(desktop, 'Languages')
	year = get_field(desktop, 'Year')

	category = categories[0] if categories else 'Uncategorized'

	copy_to_folder(path, main_config.organized_output_folder, 'By platform', sanitize_name(platform))
	copy_to_folder(path, main_config.organized_output_folder, 'By category', sanitize_name(category))

	if not languages:
		copy_to_folder(path, main_config.organized_output_folder, 'By language', 'Unknown')
	for language in languages:
		copy_to_folder(path, main_config.organized_output_folder, 'By language', sanitize_name(language))

	if year:
		copy_to_folder(path, main_config.organized_output_folder, 'By year', sanitize_name(year.replace('x', '?')))

	copy_to_folder(path, main_config.organized_output_folder, 'By platform and category', sanitize_name(platform) + ' - ' + sanitize_name(category))
	copy_to_folder(path, main_config.organized_output_folder, 'By category and platform', sanitize_name(category) + ' - ' + sanitize_name(platform))

	move_into_extra_subfolder(path, desktop, 'By genre', 'Genre')
	move_into_extra_subfolder(path, desktop, 'By subgenre', 'Genre,Subgenre')
	move_into_extra_subfolder(path, desktop, 'By developer', 'Developer')
	move_into_extra_subfolder(path, desktop, 'By publisher', 'Publisher')
	#move_into_extra_subfolder(path, desktop, 'By platform and category', 'Platform,Categories*') #We might just only care about first category...
	move_into_extra_subfolder(path, desktop, 'By platform and genre', 'Platform,Genre')
	move_into_extra_subfolder(path, desktop, 'By series', 'Series')
	move_into_extra_subfolder(path, desktop, 'By arcade system', 'Arcade-System')
	move_into_extra_subfolder(path, desktop, 'By emulator', 'Emulator')
	move_into_extra_subfolder(path, desktop, 'By engine', 'Engine')

	if len(languages) == 1:
		copy_to_folder(path, main_config.organized_output_folder, 'By language', sanitize_name(languages[0]) + ' only')