HTML-filereport generator

15.10.2020, 12:04 - Autor: Mark B.
In case you go for multiple logical recovery attempts to maximize the count of useable files you need to merge folders and preserve the folder-structure but you also need to check if files differ from each other! This script merge the folders and check each files MD5-sum to differentiate between alternative versions of a file and duplicates.

To do that you slould create a folder-structure like that:

D:\DE\case12345\a
D:\DE\case12345\b
D:\DE\case12345\c

... each recovery with each tool into it's own folder and that folders collected in a case-folder.

The folder-names (a, b and c in that example) can be named as you like. They will be processed alphabetically and so if you prefer to start with an specific attempt you should make sure that's the first processed folder!

When you start the tool you get an propt to select the base-folder. That would be in that example from above D:\DE\case12345.

The tool will create a log-file with all MD5-checksums and a folder named 000_merged which will be skipped when processing. So in case you have to stop the tool and rerun it later your sorting will be fine and the tool will skip all previously processed files.

Source:

import os, codecs
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog

LOGO_URL = "https://data-recovery-prague.com/img/LOGO_FINAL.png"


def read_folder(folder, f):
    global ctr
    global fctr
    global sum_bytes
    
    ctr += 1
    
    try:
        dir_contents = os.listdir(folder)
        n = os.path.basename(folder)
        if n == "":
            n = "Root"
        
        f.write('<div class="f" id="d' + str(ctr) + '" onclick="t(' + str(ctr) + ');"><b>[+]</b> <span class="icn dir"></span> ' + n + "</div>")
        f.write('<div class="c" id="c' + str(ctr) + '">')
        print(f"#{ctr} ... {folder}")
        
        for directory in sorted(dir_contents):
            dir_path = os.path.join(folder, directory)
            if os.path.isdir(dir_path) and not os.path.islink(dir_path):
                read_folder(dir_path, f)
            elif os.path.isdir(dir_path) and os.path.islink(dir_path):
                f.write('<span class="icn dir" style="margin-left: 32px;"><span class="icn link" style="margin-left: 0px;"></span></span> ' + directory + " -> " + os.readlink(dir_path) + "<br>")

        for fname in sorted(dir_contents):
            if not os.path.isdir(os.path.join(folder, fname)):
                try:
                    try:
                        css_class = fname.split(".")[-1].lower()
                    except:
                        css_class= "none"
                        
                    if css_class in ("mov", "mp4", "avi", "3gp", "3g2", "m2v", "mkv", "m4v", "mpe", "mpg", "mpeg", "ogv", "rm", "vob", "webm", "wmv", "qt", "ra", "ram", "f4v", "flv"):
                        css_class = "mov"
                    elif css_class in ("mp3", "3ga", "aa", "aac", "aif", "aifc", "aiff", "amr", "asx", "au", "flac", "iff", "m3u", "m3u8", "m4a", "m4r", "mid", "midi", "mod", "mp2", "mpa", "mpga", "ogg", "wav", "wma"):
                        css_class = "snd"
                    elif css_class in ("exe", "com", "app", "apk", "jar", "pyc", "sys"):
                        css_class = "exe"
                    elif css_class in ("doc", "docb", "docm", "docx", "dot", "dotm", "dotx", "odt", "rtf"):
                        css_class = "doc"
                    elif css_class in ("xls", "xlb", "xlc", "xlm", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "ods"):
                        css_class = "xls"
                    elif css_class in ("potx", "pps", "ppsx", "ppt", "pptm", "pptx", "odp"):
                        css_class = "ppt"
                    elif css_class in ("raw", "cr2", "orf", "dng", "nef"):
                        css_class = "raw"
                    elif css_class in ("jpg", "png", "bmp", "bpg", "gif", "heic", "image", "jpe", "jpeg", "psd", "psp", "tif", "tiff", "tga", "webp", "xcf"):
                        css_class = "img"
                    elif css_class in ("pdf", "ps"):
                        css_class = "pdf"
                    elif css_class in ("zip", "rar", "tar", "7z", "ace", "bz2", "gz", "cab", "sit", "xz", "z"):
                        css_class = "zip"
                    elif css_class in ("htm", "html", "xml", "xsl", "xps", "xaml", "rdl", "dtd"):
                        css_class = "xml"
                    elif css_class in ("c", "cpp", "php", "py", "java", "lua", "js", "applescript", "asax", "ascx", "ashx", "asmx", "asp", "aspx", "bash", "sh", "bat", "cfm", "cfml", "class", "cs", "csh", "go", "h", "iml", "json", "jsp", "jsx", "lisp", "pl", "pm", "rb", "ru", "rub", "swift", "vb", "zsh", "asm"):
                        css_class = "code"
                    elif css_class in ("sql", "db", "accdb", "accdt", "adn", "dbf", "dsn", "mdb", "odb", "pdb", "sdf", "sqlite", "edb"):
                        css_class = "db"
                    elif css_class in ("deb", "rpm", "dmg", "msi", "msu", "pkg", "xrb"):
                        css_class = "pkg"
                    elif css_class in ("dwg", "cad", "dgn", "dxf", "stl", "scad", "step"):
                        css_class = "cad"
                    elif css_class in ("ai", "eps", "svg"):
                        css_class = "eps"
                    elif css_class in ("ttf", "otf", "eot", "fnt", "fon", "woff", "woff2"):
                        css_class = "fnt"
                    elif css_class in ("eml", "pst", "ost"):
                        css_class = "eml"
                    elif css_class in ("txt", "log", "ini", "yaml", "yml", "asc", "dist", "readme", "me", "pid", "rdf", "tex"):
                        css_class = "txt"
                    elif css_class in ("bin", "img", "dd", "iso"):
                        css_class = "bin"
                    else:
                        css_class = "other"

                    f.write('<p><span class="icn ' + css_class + '"></span> ' + fname + "</p>")

                    try:
                        fsize = os.path.getsize(os.path.join(folder, fname))
                    except FileNotFoundError:
                        fsize = 1
                    sum_bytes += fsize
                    fctr += 1
                except UnicodeEncodeError:
                    pass

        f.write('</div>')
    except PermissionError:
        f.write('<div class="f" id="d' + str(ctr) + '" onclick="t(' + str(ctr) + ');"><b>[+]</b> <span class="icn lock"></span> ' + os.path.basename(folder) + " :: PERMISSION DENIED</div>")

root = tk.Tk()
root.withdraw()

dirname = filedialog.askdirectory(parent=root, initialdir="/", title='Please select the restore-directory')
projectname = simpledialog.askstring(title="Please specify", prompt="Project name: ")
ctr = 0
fctr = 0
sum_bytes = 0

if dirname is not None:
    html_path = filedialog.asksaveasfilename(parent=root, initialdir=dirname, title='Select a place to save the HTML-File', defaultextension=".html")
    f = codecs.open(html_path, "w", "UTF-8")
    if f is not None:
        f.write('<!DOCTYPE html>')
        f.write('<html>')
        f.write('<head>')
        f.write('<meta charset="UTF-8">')
        f.write('<title>Recovery-Report for ' + dirname + '</title>')
        f.write('<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>')
        f.write('<link href="https://fonts.googleapis.com/css?family=PT+Mono&display=swap" rel="stylesheet" type="text/css">')
        #f.write('<link rel="stylesheet" href="https://rawcdn.githack.com/dmhendricks/file-icon-vectors/master/dist/file-icon-high-contrast.min.css">')
        f.write('<style>')
        f.write('body{ font-family: "PT Mono", monospace; font-size: 10pt; line-height: 135%; }')
        f.write('.f{ font-weight: bold; cursor: pointer; }')
        f.write('.c{ display: none; padding-left: 32px; margin-bottom: 12px; }')
        f.write('p{ margin-block-start: 0.1em; margin-block-end: 0.1em; }')
        f.write('.icn { position: relative; display: inline-block; margin-left: 32px; height: 1em; width: 1em; background-position: center center; background-size: 100% auto; }')
        # Movies
        f.write('.mov { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMCA3LjVoMTUuNXYxMi4zSDBWNy41em0yMC41IDB2ODVoNTkuMnYtODVIMjAuNXptMTQuNCAxOC45Yy41IDAgMSAuMSAxLjQuNGwxNSAxMC42IDE1IDEwLjZjMS4yLjggMS41IDIuNi44IDMuOS0uMi40LS41LjctLjguOWwtMTUgMTAuNi0xNSAxMC42Yy0xLjIuOC0yLjcuNC0zLjQtLjktLjMtLjUtLjQtMS0uNC0xLjVWMjkuMmMwLTEuNSAxLTIuNyAyLjQtMi44ek04NC44IDcuNUgxMDB2MTIuM0g4NC44VjcuNXpNMCAyNS40aDE1LjVWMzhIMFYyNS40em04NC44IDBIMTAwVjM4SDg0LjhWMjUuNHpNMCA0My43aDE1LjV2MTIuNkgwVjQzLjd6bTg0LjggMEgxMDB2MTIuNkg4NC44VjQzLjd6TTAgNjEuOWgxNS41djEyLjZIMFY2MS45em04NC44IDBIMTAwdjEyLjZIODQuOFY2MS45ek0wIDgwLjFoMTUuNXYxMi4zSDBWODAuMXptODQuOCAwSDEwMHYxMi4zSDg0LjhWODAuMXoiIGZpbGw9IiM2YWU1YjkiLz48L3N2Zz4=); }')
        # Sound
        f.write('.snd { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMTYuNyAyNi45SDB2NDYuM2gxNi43bDM5IDI2LjhWMGwtMzkgMjYuOU04OS42IDUwYzAgMTIuNi02LjkgMjMuNS0xNi45IDI5LjNsNS4yIDkuMWMxMy4xLTcuNiAyMi0yMS45IDIyLTM4LjMgMC0xNi4zLTguOS0zMC43LTIyLTM4LjNsLTUuMiA5LjFDODIuOCAyNi41IDg5LjYgMzcuNCA4OS42IDUwem0tMTguMSAwYzAgNS45LTMuMSAxMC45LTggMTMuN2w1IDguN2M3LjgtNC40IDEzLTEyLjggMTMtMjIuNHMtNS4yLTE4LTEzLTIyLjRsLTUgOC43YzQuOCAyLjggOCA3LjggOCAxMy43eiIgZmlsbD0iI2M2ZiIvPjwvc3ZnPg==); }')
        # Executable
        f.write('.exe { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTguMiA1OS44Yy00LjMtMS40LTYuOS01LjMtNi45LTkuOHMyLjktOC4zIDYuOS05LjhjMS4yLS40IDItMS44IDEuNi0zLjEtMS4yLTQuNy0zLjEtOS01LjUtMTMuMi0uNi0xLjItMi4yLTEuNi0zLjUtMS0xLjQuOC0zLjMgMS4yLTQuOSAxLjItNS43IDAtMTAuMi00LjctMTAuMi0xMC4yIDAtMS42LjQtMy41IDEuMi00LjkuNi0xLjIuMi0yLjYtMS0zLjVDNzIgMy4yIDY3LjUgMS40IDYyLjguMmMtMS4yLS40LTIuNi40LTMuMSAxLjYtMS40IDQuMy01LjMgNi45LTkuOCA2LjlzLTguMy0yLjktOS44LTYuOUMzOS43LjYgMzguMy0uMiAzNyAuMmMtNC43IDEuMi05IDMuMS0xMy4yIDUuNS0xLjIuNi0xLjYgMi4yLTEgMy41LjggMS40IDEuMiAzLjMgMS4yIDQuOSAwIDUuNy00LjcgMTAuMi0xMC4yIDEwLjItMS42IDAtMy41LS40LTQuOS0xLjItMS4yLS42LTIuNi0uMi0zLjUgMUMzIDI4LjIgMS4xIDMyLjctLjEgMzcuM2MtLjQgMS4yLjQgMi42IDEuNiAzLjEgNC4zIDEuNCA2LjkgNS4zIDYuOSA5LjhTNS41IDU4LjUgMS41IDYwYy0xLjIuNC0yIDEuOC0xLjYgMy4xIDEuMiA0LjcgMy4xIDkgNS41IDEzLjIuNiAxLjIgMi4yIDEuNiAzLjUgMSAxLjQtLjggMy4zLTEuMiA0LjktMS4yIDUuNyAwIDEwLjIgNC43IDEwLjIgMTAuMiAwIDEuNi0uNCAzLjUtMS4yIDQuOS0uNiAxLjItLjIgMi42IDEgMy41IDQuMSAyLjQgOC42IDQuMyAxMy4yIDUuNWguNmMxIDAgMi0uNiAyLjQtMS44IDEuNC00LjMgNS4zLTYuOSA5LjgtNi45czguMyAyLjkgOS44IDYuOWMuNCAxLjIgMS44IDIgMy4xIDEuNiA0LjctMS4yIDktMy4xIDEzLjItNS41IDEuMi0uNiAxLjYtMi4yIDEtMy41LS44LTEuNC0xLjItMy4zLTEuMi00LjkgMC01LjcgNC43LTEwLjIgMTAuMi0xMC4yIDEuNiAwIDMuNS40IDQuOSAxLjIgMS4yLjYgMi42LjIgMy41LTEgMi40LTQuMSA0LjMtOC42IDUuNS0xMy4yLjUtMS4yLS4xLTIuNy0xLjYtMy4xem0tNDggNS43Yy04LjYgMC0xNS41LTYuOS0xNS41LTE1LjVzNi45LTE1LjUgMTUuNS0xNS41UzY1LjcgNDEuNCA2NS43IDUwcy03IDE1LjUtMTUuNSAxNS41eiIgZmlsbD0iI2FiYjNkNiIvPjwvc3ZnPg==); }')
        # Documents
        f.write('.doc { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTIuOCA4Mi40SDUxLjVjLTEuNiAwLTIuOS0xLjMtMi45LTIuOVYyMC42YzAtMS42IDEuMy0yLjkgMi45LTIuOWg0MS4zYzEuNiAwIDIuOSAxLjMgMi45IDIuOXY1OC45YzAgMS42LTEuMyAyLjktMi45IDIuOXoiIGZpbGw9IiNlOGU4ZTgiLz48cGF0aCBkPSJNODEgMzUuM0g1MS41Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlzMS4zLTIuOSAyLjktMi45SDgxYzEuNiAwIDIuOSAxLjMgMi45IDIuOSAwIDEuNS0xLjMgMi45LTIuOSAyLjl6bTAgMTEuOEg1MS41Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlzMS4zLTIuOSAyLjktMi45SDgxYzEuNiAwIDIuOSAxLjMgMi45IDIuOXMtMS4zIDIuOS0yLjkgMi45em0wIDExLjdINTEuNWMtMS42IDAtMi45LTEuMy0yLjktMi45czEuMy0yLjkgMi45LTIuOUg4MWMxLjYgMCAyLjkgMS4zIDIuOSAyLjlzLTEuMyAyLjktMi45IDIuOXptMCAxMS44SDUxLjVjLTEuNiAwLTIuOS0xLjMtMi45LTIuOXMxLjMtMi45IDIuOS0yLjlIODFjMS42IDAgMi45IDEuMyAyLjkgMi45cy0xLjMgMi45LTIuOSAyLjl6IiBmaWxsPSIjYjJiMmIyIi8+PHBhdGggZD0iTTU5LjMgOTcuMmwtNTUtMTAuNVYxMy4ybDU1LTEwLjV2OTQuNXoiIGZpbGw9IiMwZDQ3YTEiLz48cGF0aCBkPSJNNDMuNyA2OGgtN2wtNC42LTIzLjFjLS4zLTEuMy0uNC0yLjctLjQtNGgtLjFjLS4xIDEuNi0uMyAzLS41IDRMMjYuMyA2OEgxOWwtNy4zLTM2aDYuOWwzLjkgMjRjLjIgMSAuMyAyLjQuNCA0LjFoLjFjMC0xLjMuMy0yLjcuNi00LjJsNS0yMy45aDYuN2w0LjYgMjQuMmMuMi45LjMgMi4yLjQgMy45aC4xYy4xLTEuMy4yLTIuNi40LTRsMy45LTI0SDUxTDQzLjcgNjh6IiBmaWxsPSIjZmZmIi8+PC9zdmc+); }')
        # Spreadsheets
        f.write('.xls { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmZmfTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjNGNhZjUwIi8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTcxIDI2LjRoMTguNHY3LjlINzF6bTAgMjYuMmgxOC40djcuOUg3MXptMCAxMy4xaDE4LjR2Ny45SDcxem0wLTI2LjJoMTguNHY3LjlINzF6TTUyLjYgMjYuNGgxMy4xdjcuOUg1Mi42em0wIDI2LjJoMTMuMXY3LjlINTIuNnptMCAxMy4xaDEzLjF2Ny45SDUyLjZ6bTAtMjYuMmgxMy4xdjcuOUg1Mi42eiIvPjxwYXRoIGZpbGw9IiMyZTdkMzIiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMzcuMSA2OGwtNi4yLTExLjdjLS4yLS40LS41LTEuMi0uNy0yLjRIMzBjLS4xLjYtLjQgMS40LS44IDIuNUwyMyA2OGgtOS43bDExLjUtMTgtMTAuNS0xOGg5LjlsNS4yIDEwLjhjLjQuOS44IDEuOSAxLjEgM2guMWMuMi0uNy42LTEuNyAxLjEtMy4xTDM3LjMgMzJoOUwzNS42IDQ5LjggNDYuNyA2OGgtOS42eiIvPjwvc3ZnPg==); }')
        # Presentations
        f.write('.ppt { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmJlOWU3fTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjZmY4YTY1Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTUwIDYzLjFoMzYuOHY1LjJINTB6bTAgMTAuNWgzNi44djUuM0g1MHptMTUuOC00Ny4yYy04LjcgMC0xNS44IDcuMS0xNS44IDE1LjhDNTAgNTAuOSA1Ny4xIDU4IDY1LjggNThzMTUuOC03LjEgMTUuOC0xNS44SDY1LjhWMjYuNHoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNzEgMjEuMXYxNS44aDE1LjhjMC04LjctNy4xLTE1LjgtMTUuOC0xNS44eiIvPjxwYXRoIGZpbGw9IiNlNjRhMTkiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBkPSJNMzEuMiAzMkgxOC44djM2aDcuN1Y1NS42aDRjNC4zIDAgNy43LTEuMSAxMC4yLTMuNCAyLjUtMi4yIDMuOC01LjIgMy44LTguOEM0NC41IDM1LjggNDAgMzIgMzEuMiAzMnptLTEuNCAxNy40aC0zLjNWMzguMmgzLjNjNC4yIDAgNi4zIDEuOCA2LjMgNS41IDAgMy45LTIuMSA1LjctNi4zIDUuN3oiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); }')
        # RAW Images
        f.write('.raw { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmJlOWU3fTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjZmY4YTY1Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTUwIDYzLjFoMzYuOHY1LjJINTB6bTAgMTAuNWgzNi44djUuM0g1MHptMTUuOC00Ny4yYy04LjcgMC0xNS44IDcuMS0xNS44IDE1LjhDNTAgNTAuOSA1Ny4xIDU4IDY1LjggNThzMTUuOC03LjEgMTUuOC0xNS44SDY1LjhWMjYuNHoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNzEgMjEuMXYxNS44aDE1LjhjMC04LjctNy4xLTE1LjgtMTUuOC0xNS44eiIvPjxwYXRoIGZpbGw9IiNlNjRhMTkiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBkPSJNMzEuMiAzMkgxOC44djM2aDcuN1Y1NS42aDRjNC4zIDAgNy43LTEuMSAxMC4yLTMuNCAyLjUtMi4yIDMuOC01LjIgMy44LTguOEM0NC41IDM1LjggNDAgMzIgMzEuMiAzMnptLTEuNCAxNy40aC0zLjNWMzguMmgzLjNjNC4yIDAgNi4zIDEuOCA2LjMgNS41IDAgMy45LTIuMSA1LjctNi4zIDUuN3oiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); }')
        # Images
        f.write('.img { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMTMuNiA0MC45YzMuOCAwIDctMS4zIDkuNy00IDIuNy0yLjcgNC01LjkgNC05LjcgMC0zLjgtMS4zLTctNC05LjctMi43LTIuNy01LjktNC05LjctNC0zLjggMC03IDEuMy05LjcgNC0yLjcgMi43LTQgNS45LTQgOS43IDAgMy44IDEuMyA3IDQgOS43IDIuNyAyLjcgNS45IDQgOS43IDR6bTIwLjUgMjAuNUwyMi43IDUwIDAgNzIuN3YxMy42aDEwMFY1NC41TDcwLjUgMjUgMzQuMSA2MS40eiIgZmlsbD0iI2U4OTEzMSIvPjwvc3ZnPg==); }')
        # Vector
        f.write('.eps { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMjYuNSAzNC44TDIuOCA4NS4zbDQuNSA0LjUgMjkuNi0yOS42Yy0xLjEtMi40LS43LTUuMyAxLjMtNy4zIDIuNS0yLjUgNi41LTIuNSA5LjEgMHMyLjUgNi41IDAgOS4xYy0yIDItNC45IDIuNC03LjMgMS4zTDEwLjQgOTIuN2w0LjUgNC41IDUwLjUtMjMuOCAxMC43LTMwLjItMTkuNC0xOS4zLTMwLjIgMTAuOXptNjkuMy02TDcxLjIgNC4yYy0yLTItNS4zLTItNy4zIDBMNTguMSAxMGMtMiAyLTIgNS4zIDAgNy4zbDI0LjUgMjQuNWMyIDIgNS4zIDIgNy4zIDBsNS44LTUuOGMyLTIgMi01LjIuMS03LjJ6IiBmaWxsPSIjZmVhNTAwIi8+PC9zdmc+); }')
        # Fonts
        f.write('.fnt { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDB7ZmlsbDojOTNkM2Y2fS5zdDF7ZmlsbDojNTZiNWYwfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTg3LjUgNzhsLS42LTMuMmgtLjNDODQgNzggNzkuNSA4MC4xIDc0IDgwLjFjLTguNSAwLTEzLjQtNi4zLTEzLjQtMTIuNyAwLTEwLjYgOC45LTE2LjMgMjUtMTYuMXYtLjZjMC0yLjctMS4xLTcuNC04LjUtNy40LTQuMiAwLTguNSAxLjMtMTEuMyAzLjFsLTIuMS02LjljMy4xLTEuOSA4LjktMy43IDE1LjUtMy43IDEzLjUgMCAxNy43IDguNSAxNy43IDE3Ljd2MTUuM2MwIDMuOS0uMyA3LjkuMiA5LjVoLTkuNWwtLjEtLjN6bS0xLjgtMjBjLTYuNC0uMi0xNC41IDEuNC0xNC41IDcuOSAwIDQuMiAyLjcgNi4xIDYuMSA2LjEgNC4yIDAgNy4zLTIuNyA4LjItNS44LjMtLjguMi0xLjYuMi0yLjRWNTh6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTk3IDY4LjVWNTMuMWMwLTMuNy0uNi03LjctMi42LTEwLjYtLjggNi4xLTMuOSAxMS44LTguNyAxNS44djUuM2MwIC42LjIgMS42LS4yIDIuNC0xIDMuMS00IDUuOC04LjIgNS44LTMuNCAwLTYuMS0xLjktNi4xLTYuMXYtLjZjLTEgLjItMS44LjItMi45LjItMi42IDAtNS0uMy03LjMtMS4xLS4yLjgtLjIgMS44LS4yIDIuNiAwIDYuNCA0LjggMTIuOSAxMy4yIDEyLjkgNS41IDAgOS44LTIuMSAxMi42LTUuM2guNGwuNiAzLjJoOS43Yy0uNi0xLjMtLjMtNS4zLS4zLTkuMXoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTguNyA2MS44bC01IDE2LjFoLTExbDE4LjctNThoMTMuN2wxOSA1OEg0Mi43bC01LjMtMTYuMUgxOC43em0xNi43LThsLTQuNy0xNC43Yy0xLjEtMy41LTIuMS02LjMtMi45LTExLjFoLS4yYy0uOCA0LjgtMS44IDcuNy0yLjcgMTEuMWwtNC41IDE0LjdoMTV6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQyLjUgNDIuOGMtMS42IDQtNCA3LjctNy4xIDEwLjZ2LjJoLS4yYy00IDQuOC05IDYuNC0xNC44IDguMWgxNi44bDUuMyAxNi4xaDExLjRsLTExLjQtMzV6Ii8+PC9zdmc+); }')
        # PDF
        f.write('.pdf { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTUuMiA2My4yYy0yLjgtMy04LjQtNC43LTE2LjQtNC43LTQuMyAwLTkuMi40LTE0LjYgMS40LTMtMy02LjEtNi41LTktMTAuNi0yLjEtMi45LTMuOS01LjktNS41LTguOSAzLjItOS45IDQuNy0xNy45IDQuNy0yMy43IDAtNi41LTIuMy0xMy4zLTkuMS0xMy4zLTIuMSAwLTQuMSAxLjMtNS4yIDMuMS0zIDUuNS0xLjcgMTcuNSAzLjYgMjkuMy0yIDUuOS00IDExLjYtNi42IDE3LjktMi4yIDUuMy00LjggMTAuOS03LjUgMTUuOS0xNS4yIDYuMi0yNSAxMy40LTI1LjkgMTktLjQgMi4xLjMgNC4xIDEuOCA1LjYuNS40IDIuNSAyLjEgNS44IDIuMSAxMC4xIDAgMjAuNy0xNi42IDI2LjEtMjYuNyA0LjEtMS40IDguMy0yLjcgMTIuNC0zLjkgNC41LTEuMyA5LjEtMi4zIDEzLjItM0M3My42IDcyLjQgODMgNzQgODcuNyA3NGM1LjggMCA3LjktMi40IDguNi00LjQgMS4xLTIuNS4zLTUuMy0xLTYuOGwtLjEuNHptLTUuNCA0LjFjLS40IDIuMS0yLjUgMy41LTUuNCAzLjUtLjggMC0xLjUtLjEtMi4zLS4zLTUuMy0xLjMtMTAuMi00LTE1LjItOC4yIDQuOS0uOCA5LTEgMTEuNi0xIDIuOSAwIDUuNC4xIDcgLjYgMS45LjQgNC45IDEuNyA0LjMgNS40em0tMjkuMy02LjZjLTMuNi43LTcuNCAxLjYtMTEuNCAyLjctMy4yLjktNi41IDEuOC05LjggMyAxLjgtMy41IDMuMy02LjkgNC43LTEwLjEgMS43LTQgMy04IDQuNC0xMS44IDEuNCAyLjQgMi45IDQuOCA0LjQgNi45IDIuNSAzLjMgNS4xIDYuNSA3LjcgOS4zek00Mi40IDguMmMuNi0xLjEgMS43LTEuNyAyLjYtMS43IDIuOSAwIDMuNCAzLjQgMy40IDYuMSAwIDQuNS0xLjQgMTEuNC0zLjcgMTkuMy00LTExLTQuMy0yMC4xLTIuMy0yMy43ek0yNy4zIDczLjljLTcgMTEuOC0xMy44IDE5LjItMTcuOSAxOS4yLS44IDAtMS41LS4zLTIuMS0uNy0uOC0uOC0xLjItMS44LTEtMyAuOC00LjIgOC43LTEwLjEgMjEtMTUuNXoiIGZpbGw9IiNlYjFkMjUiIHN0cm9rZT0iI2ViMWQyNSIgc3Ryb2tlLXdpZHRoPSIuNzUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPjwvc3ZnPg==); }')
        # XML
        f.write('.xml { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMSA0NC4zTDI4LjkgMTV2MTQuOWwtMTkgMTkuM3YuMmwxOC45IDE5LjN2MTQuOUwxIDU0LjJ2LTkuOXpNNTMuNiA3LjVINjFsLTE0LjQgODVoLTcuMmMtLjEgMCAxNC4yLTg1IDE0LjItODV6bTE3LjUgNjEuM0w5MCA0OS41di0uMkw3MS4xIDMwLjFWMTUuMkw5OSA0NC42djEwLjNMNzEuMSA4NC4xVjY4Ljh6IiBmaWxsPSIjYmFiYWJhIiBzdHJva2U9IiNiYWJhYmEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+PC9zdmc+); }')
        # Code
        f.write('.code { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMyA1NC45VjQ1YzIuMi0uMiAzLjktLjMgNC45LTEgMS0uMyAxLjgtMS4zIDIuNy0yLjMuOC0xLjIgMS4zLTIuNSAxLjctNC40LjItMS4zLjUtMy41LjUtNi43IDAtNS40LjItOSAuOC0xMS4yLjUtMiAxLjUtMy45IDIuNy01IDEuMy0xLjIgMy40LTIuMiA1LjktMyAxLjctLjMgNC40LS44IDguMi0uOGgyLjN2OS43Yy0zLjIgMC01LjQuMi02LjIuNy0uOC4zLTEuNS44LTIuMiAxLjctLjUuNy0uNyAxLjgtLjcgMy41cy0uMiA1LS41IDkuN2MtLjIgMi44LS41IDUtMSA2LjUtLjcgMS43LTEuNSAzLTIuMyA0LjItLjggMS0yLjMgMi4yLTQuMiAzLjQgMS43IDEgMy4yIDIgNC4yIDMuMiAxIDEuMiAxLjggMi44IDIuNSA0LjUuNyAxLjggMSA0LjIgMSA3LjIuMiA0LjUuMiA3LjQuMiA4LjcgMCAxLjguMiAzIC43IDMuOS41LjggMS4zIDEuMiAyLjIgMS43LjguMyAzIC43IDYuMi43djkuN2gtMi4zYy0zLjkgMC03LS4yLTguOS0uOC0yLjItLjctMy45LTEuNy01LjQtMy0xLjUtMS4zLTIuMy0zLTMtNS0uNS0yLS43LTUuMi0uNy05LjYgMC01LS4yLTguNC0uNy05LjctLjctMi4yLTEuNy0zLjktMy00LjktLjktMS0yLjktMS43LTUuNi0xLjd6bTkzLjcgMGMtMi4yLjItMy45LjMtNC45IDEtMSAuMy0xLjggMS4zLTIuNyAyLjMtLjggMS4yLTEuMyAyLjUtMS43IDQuNC0uMiAxLjMtLjUgMy41LS41IDYuNyAwIDUuNC0uMiA5LS44IDExLjItLjUgMi4yLTEuNSAzLjktMi43IDUtMS4zIDEuMi0zLjQgMi4yLTUuOSAzLTEuNy4zLTQuNC44LTguMi44SDY3di05LjdjMy4yIDAgNS0uMiA2LjItLjcgMS0uMyAxLjctMSAyLjItMS43cy43LTEuOC43LTMuNS4yLTQuOS41LTkuNmMuMi0yLjguNy01LjIgMS4zLTYuNy43LTEuOCAxLjUtMy4yIDIuNS00LjQgMS0xLjIgMi4zLTIuMiA0LTMuMi0yLjctMS43LTQuNC0yLjgtNS4yLTQtMS4zLTEuOC0yLjMtNC4yLTIuNy02LjctLjUtMi0uNy02LjItLjctMTIuNiAwLTItLjItMy40LS43LTQuMi0uNS0uNy0xLTEuMi0xLjgtMS43LS44LS4zLTMtLjctNi40LS43di05LjdoMi4zYzMuOSAwIDcgLjIgOC45LjggMi4yLjcgMy45IDEuNyA1LjQgMyAxLjUgMS4zIDIuMyAzIDMgNSAuNSAyIC44IDUuMi44IDkuNiAwIDUgLjIgOC4yLjcgOS43LjcgMi4yIDEuNyAzLjkgMyA0LjUgMS4zIDEgMy40IDEuMyA1LjkgMS43djkuOWwtLjIuNXoiIGZpbGw9IiM3MDU4YzYiIHN0cm9rZT0iIzYyNDlhNSIgc3Ryb2tlLXdpZHRoPSIuNzUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPjwvc3ZnPg==); }')
        # Databases
        f.write('.db { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDB7ZmlsbDojMGNmfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTMuMyA2MS43YzAgOC4zIDIwLjkgMTUgNDYuNyAxNSAyNS43IDAgNDYuNi02LjcgNDYuNy0xNVY0OS44Qzg3LjEgNTYuNyA2OC41IDYwIDUwIDYwYy0xOC41IDAtMzcuMS0zLjMtNDYuNy0xMC4zdjEyeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik05Ni43IDczQzg3LjEgODAgNjguNSA4My4zIDUwIDgzLjMgMzEuNSA4My4zIDEyLjkgODAgMy4zIDczdjEzLjZDNS45IDk0LjIgMjYgMTAwIDUwIDEwMHM0NC4xLTUuOCA0Ni43LTEzLjNWNzN6TTMuMyAzOC4zYzAgOC4zIDIwLjkgMTUgNDYuNyAxNSAyNS43IDAgNDYuNi02LjcgNDYuNy0xNVYyNi40Yy05LjYgNy0yOC4yIDEwLjMtNDYuNyAxMC4zLTE4LjUgMC0zNy4xLTMuMy00Ni43LTEwLjN2MTEuOXoiLz48ZWxsaXBzZSBjbGFzcz0ic3QwIiBjeD0iNTAiIGN5PSIxNSIgcng9IjQ2LjciIHJ5PSIxNSIvPjwvc3ZnPg==); }')
        # Compressed archive
        f.write('.zip { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTEuNiAyOC43SDc2LjlWMTQuMWwxNC43IDE0LjZ6TTUyLjEgMTQuMXY1My4zaDM5LjZWMzIuMkg3My40VjEzLjlINTIuMXYuMnpNNTguMiAwSDE0LjV2MTAuNGgxNy4ybC0xMC45IDguM3Y4LjlsMTUuOS0xMi4ydi01aDU1LjdWNi4xTDU4LjIgMHpNMzYuOSAyMi40TDIxIDM0LjZ2OC45bDE1LjktMTIuMnYtOC45em0tMTYuMSAzN2wxNS45LTEyLjJ2LTguOUwyMC44IDUwLjZ2OC44em0xNi4xIDMuN3YtOC45TDIxIDY2LjV2NC44aC02LjN2MTAuNGg5Ljh2N2gtNS45Yy0xLjEtMS45LTMtMy01LjItMy0zLjMgMC01LjkgMi42LTUuOSA1LjkgMCAzLjMgMi42IDUuOSA1LjkgNS45IDIuMiAwIDQuMS0xLjEgNS4yLTNoNS43djUuNGg4Ljl2LTUuNEgzOWMxLjEgMS45IDMgMyA1LjIgMyAzLjMgMCA1LjktMi42IDUuOS01LjkgMC0zLjMtMi42LTUuOS01LjktNS45LTIuMiAwLTQuMSAxLjEtNS4yIDNoLTUuN3YtN2gyNWwzNC4zLTYuMXYtNC4zSDI2LjJsMTAuNy04LjJ6IiBmaWxsPSIjZmMzIi8+PC9zdmc+); }')
        # Package file
        f.write('.pkg { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNjUuOCA1My45TDUwIDQ2LjVsMzEuNS0xNC43IDE1LjggNy40LTE1LjggNy40YzAtLjEtMTUuNyA3LjMtMTUuNyA3LjN6bTE1LjctMzYuN0w2NS44IDkuOCA1MCAxNy4ybDMxLjUgMTQuNyAxNS44LTcuNC0xNS44LTcuM3pNMzQuMiAzOS4xbC0xNS43LTcuNC0xNS43IDcuNCAzMS41IDE0LjdMNTAgNDYuNWwtMTUuOC03LjR6bTAtMTQuNkw1MCAxNy4yIDM0LjIgOS44IDIuOCAyNC41bDE1LjcgNy40IDE1LjctNy40em00Ny4zIDI2LjNsLTE0LjEgNi41LTEuNy44LTEuNy0uOC0xNC02LjUtMTQuMSA2LjUtMS43LjgtMS43LS44LTE0LjEtNi41djIzTDUwIDkwLjJsMzEuNS0xNi40di0yM3oiIGZpbGw9IiNkY2U2NzUiLz48L3N2Zz4=); }')
        # Email
        f.write('.eml { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNjIuMyA1Mkw1MCA2NC4xIDM3LjcgNTJsLTMxIDM0LjJoODYuNUw2Mi4zIDUyek0yLjggMTcuOHY2NC41bDMxLTM0LjItMzEtMzAuM3ptNjMuNSAzMC4zbDMxIDM0LjJWMTcuOGwtMzEgMzAuM3pNNi42IDEzLjhMNTAgNTYuM2w0My40LTQyLjQtODYuOC0uMXoiIGZpbGw9IiM5MGM5YzQiLz48L3N2Zz4=); }')
        # Text
        f.write('.txt { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMCA4NC44aDU2LjlWMTAwSDBWODQuOG0wLTU2LjVoMTAwdjE1LjJIMFYyOC4zek0wIDBoMTAwdjE1LjJIMFYwem0wIDU2LjZoMTAwdjE1LjJIMFY1Ni42eiIgZmlsbD0iI2JhYmFiYSIvPjwvc3ZnPg==); }')
        # Binary files / binary images
        f.write('.bin { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMjAuNCA5LjRoLTEwdjEwaDV2MjUuMWgxMHYtMzBjMC0yLjgtMi4yLTUuMS01LTUuMXptMzkuNiAwSDQwYy0yLjggMC01IDIuMi01IDV2MjUuMWMwIDIuOCAyLjIgNSA1IDVoMjBjMi44IDAgNS0yLjIgNS01di0yNWMwLTIuOC0yLjItNS4xLTUtNS4xem0tNSAyNS4xSDQ1di0xNWgxMHYxNXpNODIuOCA5LjRoLTEwdjEwaDV2MjUuMWgxMHYtMzBjMC0yLjgtMi4yLTUuMS01LTUuMXptLTUyLjcgNDZIMTBjLTIuOCAwLTUgMi4yLTUgNXYyNS4xYzAgMi44IDIuMiA1IDUgNWgyMC4xYzIuOCAwIDUtMi4yIDUtNXYtMjVjMC0yLjgtMi4yLTUuMS01LTUuMXptLTUgMjUuMUgxNXYtMTVoMTBsLjEgMTV6bTI2LjMtMjVoLTEwdjEwaDV2MjUuMWgxMFY2MC41Yy4xLTIuOC0yLjItNS01LTV6bTM4LjYgMEg2OS45Yy0yLjggMC01IDIuMi01IDV2MjUuMWMwIDIuOCAyLjIgNSA1IDVIOTBjMi44IDAgNS0yLjIgNS01VjYwLjVjMC0yLjgtMi4zLTUtNS01em0tNSAyNUg3NXYtMTVoMTB2MTV6IiBmaWxsPSIjYmFiYWJhIi8+PC9zdmc+); }')
        # CAD
        f.write('.cad { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODkuMSA1MC45Yy0xLjItLjUtMi43IDAtMy4yIDEuMi0yLjcgNi4xLTYuOSAxMS40LTEyLjMgMTUuNUw1Ny40IDM0LjdjMi41LTIgMy45LTQuOCAzLjktOC4yIDAtNS4yLTMuNi05LjQtOC41LTEwLjNWOGMwLTEuMi0uOS0yLjUtMi41LTIuNS0xLjIgMC0yLjUuOS0yLjUgMi41djguMmMtNC44LjktOC41IDUuMy04LjUgMTAuMyAwIDMuNCAxLjQgNi4yIDMuOSA4LjJMMjcgNjcuNmMtNS4zLTQuMS05LjYtOS4zLTEyLjMtMTUuNS0uNS0xLjItMi0xLjgtMy4yLTEuMi0xLjIuNS0xLjggMi0xLjIgMy4yIDMuMiA3LjMgOC4yIDEzIDE0LjYgMTcuNmwtOS42IDE5LjRjLS41IDEuMiAwIDIuNy45IDMuMi4yIDAgLjcuMi45LjIuNyAwIDEuOC0uNSAyLjEtMS4ybDkuMy0xOC45YzYuNiAzLjYgMTMuNSA1LjMgMjEgNS4zczE0LjYtMiAyMS01LjNsOS4zIDE4LjljLjIuNyAxLjIgMS4yIDIuMSAxLjIuMiAwIC43IDAgLjktLjIgMS4yLS41IDEuOC0yIC45LTMuMmwtOS40LTE5LjRjNi4yLTQuMyAxMS40LTEwLjcgMTQuNi0xNy42IDEuNi0xLjMgMS4xLTIuNy4yLTMuMnpNNTAuMyAyMC41YzMuNCAwIDYuMSAyLjcgNi4xIDYuMXMtMi43IDYuMS02LjEgNi4xLTYuMS0yLjctNi4xLTYuMSAzLjEtNi4xIDYuMS02LjF6bTAgNTQuNmMtNi44IDAtMTMtMS44LTE4LjktNC44bDE2LjQtMzMuMWMuNy4yIDEuOC4yIDIuNy4yczEuOCAwIDIuNy0uMmwxNi42IDMzLjFjLTYuMSAzLjItMTIuNyA0LjgtMTkuNSA0Ljh6IiBmaWxsPSIjNDk5MmM0IiBzdHJva2U9IiM0OTkyYzQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+PC9zdmc+); }')
        # Link
        f.write('.link { width: 0.75em; height: 0.75em; background-position: bottom right; margin-left: 0.2em !important; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNTQuNCAxMC43TDM4IDI3LjFjNC44LTEuNCAxMC0xLjQgMTUtLjIuNy4yIDEuNC41IDEuOS43bDguMS04LjFjNC44LTQuOCAxMi42LTQuOCAxNy40IDAgNC44IDQuOCA0LjggMTIuNiAwIDE3LjRsLTExIDExLTYuNCA2LjRjLTEuNiAxLjYtMy40IDIuNi01LjUgMy4xLTQuMSAxLTguNi4yLTExLjktMy4xLTIuMi0yLjItMy4zLTUtMy40LTcuOC0xIC4zLTEuOS45LTIuNiAxLjdMMzIgNTUuOWMxLjIgMi42IDIuOCA1LjIgNSA3LjIgMy4xIDMuMSA3LjEgNS4zIDExIDYuNCA2LjQgMS43IDEzLjMuOSAxOC45LTIuNiAxLjctMSAzLjQtMi4yIDQuOC0zLjhsMTcuNC0xNy40YzkuNi05LjYgOS42LTI1LjMgMC0zNS05LjQtOS42LTI1LjEtOS42LTM0LjcgMHpNNjIgNzIuOWMtNS41IDEuNi0xMS40IDEuNC0xNi45LS41TDM3IDgwLjVjLTQuOCA0LjgtMTIuNiA0LjgtMTcuNCAwcy00LjgtMTIuNiAwLTE3LjRMMzcgNDUuN2MxLjYtMS42IDMuNC0yLjYgNS41LTMuMSA0LjEtMSA4LjYtLjIgMTEuOSAzLjEgMi4yIDIuMiAzLjMgNSAzLjQgNy45LjktLjMgMS43LTEgMi42LTEuN2w3LjYtNy42Yy0xLjItMi42LTIuOC01LjItNS03LjItMy4zLTMuMS03LjEtNS4zLTExLTYuNC02LjQtMS43LTEzLjMtLjktMTkgMi42LTEuNyAxLTMuNCAyLjItNC44IDMuOEwxMC44IDU0LjNjLTkuNiA5LjYtOS42IDI1LjMgMCAzNXMyNS4zIDkuNiAzNSAwTDYyIDcyLjl6IiBmaWxsPSIjNjY2NjY2Ii8+PC9zdmc+); }')
        # Others
        f.write('.other { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODYgMjYuNUw2My4zIDMuOGMtLjctLjctMS41LTEtMi40LTFIMTYuM2MtMS45IDAtMy40IDEuNS0zLjQgMy40djg3LjZjMCAxLjkgMS41IDMuNCAzLjQgMy40aDY3LjRjMS45IDAgMy40LTEuNSAzLjQtMy40di02NWMtLjEtLjgtLjQtMS42LTEuMS0yLjN6bS02LjcgMy45SDU5LjRWMTAuNWwxOS45IDE5Ljl6bS4yIDU5LjJoLTU5VjEwLjNoMzEuN3YyMi44YzAgMi40IDIuMSA0LjUgNC41IDQuNWgyMi44djUyeiIgZmlsbD0iI2JhYmFiYSIgc3Ryb2tlPSIjYmFiYWJhIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz48L3N2Zz4=); }')
        # Directory
        f.write('.dir{ margin-left: 0px; background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojOTY3YTQ0fTwvc3R5bGU+PHBhdGggZmlsbD0iI2RiYjA2NSIgZD0iTTEuMyA5MC44VjkuMmgyNy4xbDcuOSA3LjloNjIuNHY3My43eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yNy45IDEwLjVsNy4xIDcuMS44LjhoNjEuNnY3MS4xSDIuNnYtNzloMjUuM20xLTIuNkgwdjg0LjJoMTAwVjE1LjhIMzYuOGwtNy45LTcuOXoiLz48cGF0aCBmaWxsPSIjZjVjZTg1IiBkPSJNMS4zIDkwLjhWMjIuNGgyOGw3LjktNS4zaDYxLjV2NzMuN3oiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNOTcuNCAxOC40djcxLjFIMi42VjIzLjdoMjcuMWwuNy0uNCA3LjItNC44aDU5LjhtMi42LTIuN0gzNi44bC03LjkgNS4zSDB2NzEuMWgxMDBWMTUuOHoiLz48L3N2Zz4=); }')
        # Locked
        f.write('.lock{ margin-left: 0px; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODMuNCAxNi42Yy0xOC41LTE4LjUtNDguMy0xOC41LTY2LjggMHMtMTguNSA0OC4zIDAgNjYuOCA0OC4zIDE4LjUgNjYuOCAwIDE4LjMtNDguMyAwLTY2Ljh6TTIwLjggNjguOWMtOC43LTEzLjQtNy4yLTMxLjcgNC43LTQzLjQgMTEuOS0xMS45IDMwLTEzLjQgNDMuNC00LjdMMjAuOCA2OC45em0xMC40IDEwLjNsNDguMS00OC4xYzguNyAxMy40IDcuMiAzMS43LTQuNyA0My40LTExLjcgMTEuOS0zMCAxMy40LTQzLjQgNC43eiIgZmlsbD0iIzY2NjY2NiIvPjwvc3ZnPg==); }')
        f.write('</style>')
        f.write('<script>')
        # Toggle sign and search function
        f.write("""
function t(nr){
    $('#c' + nr).slideToggle('fast', function(){
        var display = $("#c" + nr).css("display");
        if(display == "none"){
            $('#d' + nr + " b").html("[+]");
        }
        else{
            $('#d' + nr + " b").html("[-]");
        }
    });
}

function clearPath(inner_html){
    inner_html = inner_html.replace(/<[^>]*>?/gm, '');
    inner_html = inner_html.replace('[+]', '');
    inner_html = inner_html.replace('[-]', '');
    inner_html = inner_html.trim();
    return inner_html;
}

function doSearch(event){
    event.preventDefault();
    document.getElementById("searchOutput").innerHTML = "Searching ...<br><br>";

    setTimeout(runSearch, 1000);
    return False;
}

function genDropdown(){
    var fList = document.getElementById("c1").childNodes;
    var dd = document.getElementById("dd");
    var form = document.forms[0];

    for(var i = 0; i < fList.length; i++){ 
        if(fList[i].className == "f"){ 
            id = fList[i].id.replace("d", "c");
            txt = "Root\\\\" + clearPath(fList[i].innerHTML) + "\\\\";
            e = document.createElement("option");
            e.value = id;
            e.innerHTML = txt;
            dd.appendChild(e); 
        } 
    }
}

function runSearch(event){
    var out = document.getElementById("searchOutput");
    var dd  = document.getElementById("dd");
    var all = document.getElementById(dd.value).getElementsByTagName("p"); 

    var ctr = 0;
    var color = "";

    var q = document.getElementById("q").value;
    if(q == ""){
        out.innerHTML = '<b style="color: #900;">Enter a search-text first...</b><br><br>';
        return False;
    }
    if(q.includes(".")){
        q = q + "$";
    }
    q = q.replace(".", "\\.");
    q = q.replace("*", ".*");
    var re = new RegExp(q, "i");

    var out2 = document.createElement("div");

    for(var i=0; i < all.length; i++){ 
        if(clearPath(all[i].innerHTML).search(re) != -1){ 
            ctr++;
            var path = clearPath(all[i].innerHTML);
            var id = "";
            var elem = all[i]
            while(id != "d1"){
                id = elem.parentElement.id;
                id = id.replace("c", "d");
                elem = document.getElementById(id);
                path = path + "/:/" + clearPath(elem.innerHTML);
            }

            tmp = path.split("/:/");
            path = tmp[tmp.length - 1]
            for(var j = tmp.length - 2; j >= 0; j--){
                path = path + '<b style="color: #900;">\\\\</b>' + tmp[j];
            }

            if(ctr % 2 == 0){
                color = "#eee";
            }
            else{
                color = "#fff";
            }
            var div = document.createElement("div");
            div.innerHTML = path;
            div.style.backgroundColor = color;
            out2.appendChild(div);
        }
    }

    if(out2.innerHTML == ""){
        out.innerHTML = '<b style="color: #900;">No files found!</b><br><br>';
    }
    else{
        var br = document.createElement("br");
        out2.appendChild(br);
        out2.appendChild(br);

        out.innerHTML = "";
        out.appendChild(out2);
    }
}""")
        f.write('</script>')
        f.write('</head>')
        f.write('<body onload="genDropdown()">')

        f.write('<img src="' + LOGO_URL + '" style="width: 200px;"><br>')
        f.write('<h1>FILE-REPORT</h1>')
        f.write('<h2>PROJECT: ' + projectname + '</h2><br><hr><br><br>')
        
        f.write('<form onsubmit="return doSearch(event);" style="margin-bottom: 25px;">')
        f.write('<input type="text" name="q" id="q" style="min-width: 200px;"> ')
        f.write('<select size="1" name="dd" id="dd" style="min-width: 200px;"><option value="c1">Root\\</option></select> ')
        f.write('<input type="submit" value="search...">')
        f.write('</form>')
        f.write('<div id="searchOutput"></div>')

        read_folder(dirname, f)

        f.write("<br><hr><br>")
        f.write(f"<table><tr><td><b>Files:</b> </td><td>{fctr}</td></tr> <tr><td><b>Folders:</b> </td><td>{ctr}</td></tr> <tr><td><b>Recovered:</b> </td><td>{sum_bytes/1024/1024/1024:.2f} GB</td></tr></table>")
        f.write("</body>")
        f.write("</html>")
        f.close()

        messagebox.showinfo("Finnish", f"HTML-report was generated successfully!\n\nFiles: {fctr}\nFolders: {ctr}")

Download     DEMO report

System requrements:

Windows, OSX or Linux with