0

How do I detect the file extension of a media file missing its file extension? I accidentally removed it.

Self-Answer. The question has been asked already here and here, but the questions have been closed.

4
  • There are already many existing file identifiers that do the job better than your Python script, I use TrIDNet and it is far more well-written than your script and supports many more file types. Feb 7, 2021 at 3:29
  • This is typical for Stack Overflow. Close, close, close. This is sabotage. Feb 7, 2021 at 5:16
  • Hey, relax, don't be so mad, I didn't cast the close votes bro. Feb 7, 2021 at 5:47
  • Added another duplicate which isn't closed.
    – Mokubai
    Feb 8, 2021 at 10:28

1 Answer 1

0

The following Python script does the job. It will replace / append the proper filetype, if it can detect it.

  • Install Python
  • run pip install filetype in a console (more info)
  • Move the script and the media files to be checked to a separate directory
  • Double-click the script
  • follow the instructions

Tested on Windows 7. Improve the answer if you find errors. Public domain.

Other possible solutions.

The script, name it for example fix_fileextensions.py:

if __name__ == '__main__':

    # make the commandline window stay open on error
    from contextlib import contextmanager
    from traceback import format_exc
    stay_open = False
    @contextmanager
    def stay_open_on_error():
        global stay_open
        try:
            yield
        except SystemExit:
            stay_open = True
        except:
            print(format_exc())
            stay_open = True
        if stay_open:
            input('Press key to close')

    with stay_open_on_error():

        # import some modules from the Python standard lib
        import sys, os
        from time import sleep
        from pathlib import Path

        # import the filetype package or inform user what to do
        try:
            from filetype import guess
        except ModuleNotFoundError:
            print(
                'This script uses the "filetype" package '
                'to guess the file type. '
                'Please open a console and type:\n\n'
                '    pip install filetype\n\n'
                'More info here: https://pypi.org/project/filetype/\n\n'
                'Nothing was changed.\n'
            )
            sys.exit(1)

        # define scriptpath and workdir
        scriptpath = Path(__file__).resolve()
        scriptargs = sys.argv
        if len(scriptargs) > 1:
            workdir = Path(scriptargs[1]).resolve()
            if not workdir.exists():
                raise Exception(f'Directory {workdir} does not exist')
            elif workdir.is_file():
                raise Exception('{workdir} is not a directory')
        else:
            workdir = scriptpath.parent
        scriptpath = str(scriptpath)

        # define movetodir
        c = 2
        movetodir = workdir / 'renamed'
        while movetodir.exists():
            movetodir = workdir / f'renamed ({c})'
            c += 1
        movetodir.mkdir()

        # define filesbytype
        filesbytype = {}
        for entry in os.scandir(workdir):
            filepath = entry.path
            if entry.is_dir() or filepath == scriptpath:
                continue
            else:
                info = guess(filepath)
                if info is not None:
                    info = info.extension, info.mime
                if info not in filesbytype:
                    filesbytype[info] = []
                filesbytype[info].append(entry.name)

        if filesbytype:

            # tool for printing unprintable filenames
            def safeprint(filename):
                try:
                    print(filename)
                except UnicodeEncodeError:
                    print(filename.encode('ascii', 'replace').decode())

            # tool to print a prettyprinted list of filenames
            def print_filenames(filenames):
                sep = 0
                for name in filenames:
                    sep = max(sep, len(name))
                sep = (sep + 2) * '-'
                print(sep)
                for filename in filenames:
                    safeprint('* ' + filename)
                print(sep)

            # print these filenames and optionally rename them
            for info, filenames in sorted(filesbytype.items()):
                if info is not None:
                    print_filenames(filenames)
                    filetype, mime = info
                    print(
                        "\nThese files seemingly have the file type "
                        f"'.{filetype}' and the MIME type '{mime}'."
                    )
                    ok = input(
                        'Do you want me to append/change their extension '
                        f'to ".{filetype}"? (y/n)\n> '
                    )
                    if ok.lower() == 'y':
                        for filename in filenames:
                            now = workdir / filename
                            then = (movetodir / filename).with_suffix(
                                f'.{filetype}'
                            )
                            now.rename(then)
                        print(
                            f'Ok, {len(filenames)} files were renamed '
                            f'and moved to {movetodir}'
                        )
                    else:
                        print('Ok, will not rename these files')
                    print()

            # Maybe show the files for which the type could not be detected
            if None in filesbytype:
                print_filenames(filesbytype[None])
                print(
                    '\nSorry, could not detect the file type '
                    'for these files.\n'
                )

        # When the workdir is empty, print message and do nothing
        else:
            print(f'Found no files to rename in {workdir}')

        # remove the output directory when no files have been renamed
        try:
            movetodir.rmdir()
        except OSError:
            pass

        print('DONE')
        sleep(2)

Not the answer you're looking for? Browse other questions tagged .