예제 #1
0
 def on_btn_minify_clicked(self):
     try:
         try:
               from css_html_js_minify import css_minify
         except:
               _t = QMessageBox.question(self, "Can't minify", "Python package \"css_html_js_minify\" could not be loaded.\nDo you want to try installing it now?", QMessageBox.Yes, QMessageBox.No)
               if _t == QMessageBox.Yes:
                   from devtools import PluginInstaller
                   PluginInstaller().installPackages(['css_html_js_minify'])
                   self.on_btn_minify_clicked()
               return
               #import traceback; QMessageBox.Critical("Can't minify", traceback.format_exc()).exec_()
         index = self.tabWidget.currentIndex
         _old = ""
         if index == 0:
             _old = self.qssEditor.toPlainText()
         elif index == 1: _old = self.chatEditor.toPlainText()
         _minified = css_minify(_old,noprefix=True) # , encode=False
         if index == 0:
             QApplication.instance().styleSheet = _minified
             self.qssEditor.setPlainText(_minified)
         elif index == 1: self.chatEditor.setPlainText(_minified);return
         if QMessageBox(QMessageBox.Warning, "Use minified QSS?", "Your minified QSS code has been applied.\n\nIf you encounter any issues with the minified code you should click on cancel.", QMessageBox.Ok | QMessageBox.Cancel).exec_() == QMessageBox.Cancel:
             QApplication.instance().styleSheet = _old
             self.qssEditor.setPlainText(_old)
     except:
         try:
             from traceback import format_exc
             QMessageBox(QMessageBox.Critical, "Can't minify", format_exc()).exec_()
         except:
             print(format_exc())
예제 #2
0
    async def handler(self, url: str, browser: Browser) -> dict:
        """
        Handler get information about css styles
        and generate dict with results data
        """
        try:
            page = await browser.newPage()

            await page.coverage.startCSSCoverage()
            resp = await page.goto(url)

            if resp is None:
                await browser.close()
                return {
                    url: {
                        'is_valid': False,
                        'reason': 'Something went wrong'
                    }
                }

            if not hasattr(resp, 'url') or resp.url != url:
                await browser.close()
                return {url: {'is_valid': False, 'reason': 'Got redirect'}}

            css_coverage = await page.coverage.stopCSSCoverage()

            result = {url: {'is_valid': True}}
            for data in filter(lambda x: x['ranges'], css_coverage):
                css_slice = [
                    data['text'][x['start']:x['end']] for x in data['ranges']
                ]

                unused_css_percentage = await self.calc_unused_css_percentage(
                    css_minify(data['text']), data['ranges'])

                result[url].update(
                    dict(css=css_minify(''.join(css_slice)),
                         unused_css_percentage=unused_css_percentage))
        except (PageError, BrowserError, NetworkError, TimeoutError):
            result = {
                url: {
                    'is_valid': False,
                    'reason': 'Something went wrong'
                }
            }

        return result
예제 #3
0
파일: build.py 프로젝트: AlbertJunior/WEB
def build_css_file(app_css):
    built_css_file_name = 'style.css'
    created_file = get_built_file_name(built_css_file_name)

    with open(created_file, mode='w+') as file:
        file.write(css_minify(app_css))

    return '\t<link rel="stylesheet" type="text/css" href="/' + built_css_file_name + '">\n'
예제 #4
0
def process_css(filepath, source, dest, config):
    with open(filepath, 'r+', encoding='utf-8') as css:
        lines = css.readlines()
        dest = os.path.join(dest, filepath[len(source) + 1:])
        new_file = '\n'.join(lines)
        if config['MINIFY']['css'] == 'True':
            new_file = css_minify(new_file)
        save_file(new_file, dest)
예제 #5
0
def minify_css():
    content = ''
    urls = request.forms.get('urls').split(',')

    for url in urls:
        r = requests.get(url)
        content += r.text

    return css_minify(content)
예제 #6
0
파일: news.py 프로젝트: EnigmaCurry/news
def purge_css(css_path, html_glob):
    if not shutil.which('purgecss'):
        raise AssertionError('purgecss command not found. Install via: `yarn global add purgecss`')
    out_path = tempfile.mkstemp('.css')[1]
    cmd = f'purgecss --css {css_path} --content {html_glob} --output {out_path}'
    if subprocess.call(cmd, shell=True) != 0:
        raise RuntimeError('purgecss did not run sucessfully')
    with open(out_path, 'r', encoding='utf-8') as f:
        return css_minify(f.read())
예제 #7
0
def minify(file, content):
    if file.suffix == '.js':
        return jsmin(content)
    if file.suffix == '.html':
        return html_minify(content)
    if file.suffix == '.css':
        return css_minify(content)
    
    return content
예제 #8
0
def clean_css():
    if not os.path.exists(gitdir + "/../css"):
        print(" -!- clean_css: JavaScript directory not found.")
    allcss = ""
    livecss = ""
    for root, dirs, files in os.walk(gitdir + "/../css"):
        for f in files:
            fname = f.split('.')
            if fname[len(fname) -
                     1] == "css" and fname[len(fname) - 2] != "min":
                with open(root + "/" + f, "rb") as icss:
                    newcss = icss.read().decode() + "\n"
                    allcss += newcss
                    if f != "imitate_live.css":
                        livecss += newcss
    mincss = css_minify(allcss)
    with open(tgtdir + "/min.css", "wb") as ocss:
        ocss.write(mincss.encode())
    minlivecss = css_minify(livecss)
    with open(tgtdir + "/live.min.css", "wb") as ocss:
        ocss.write(minlivecss.encode())
예제 #9
0
def easy_minify(data, tool=None):
    try:
        if not tool:
            data = css_html_js_minify.html_minify(data)
        else:
            if tool == 'css':
                data = css_html_js_minify.css_minify(data)
            elif tool == 'js':
                data = css_html_js_minify.js_minify(data)
    except:
        data = re.sub('\n +<', '\n<', data)
        data = re.sub('>(\n| )+<', '> <', data)

    return last_change(data)
예제 #10
0
def build(files, file_type):
    for filename in files:
        # read file
        f = open(f'{path}/{filename}', "r")
        contents = f.read()
        f.close()
        # minify contents
        if file_type == 'js':
            contents = js_minify(contents)
        if file_type == 'css':
            contents = css_minify(contents, comments=False)
        contents = remove_spaces(contents)
        # save file
        f = open(f'{path}/build/{filename}', "x")
        f.write(contents)
        f.close()
        print(f'Created {path}/build/{filename}')
예제 #11
0
    def generate(self) -> None:
        package = self.__core.package
        output_dir = self.__core.directories.webfonts

        license_template_path = FILE_DIR.STYLESHEETS_TEMPLATE.joinpath(
            f"./{package.license}.css")
        if not license_template_path.exists():
            raise Exception(f"{package.license} is invalid license id.")
        with open(license_template_path, 'r',
                  encoding='utf-8') as license_template_read_io:
            license_template = pystache.parse(license_template_read_io.read())

        generated_style = ''
        for source in package.sources:
            for weight, font in source.fonts:
                if font is None:
                    continue
                generated_style += self.__generateStyleForWeight(weight=weight,
                                                                 font=font)

        with open(output_dir.joinpath('./style.min.css'), 'wb') as style_io:
            minified = pystache.render(license_template,
                                       {'css': css_minify(generated_style)})
            style_io.write(minified.encode('utf-8'))
예제 #12
0
 def compress_css(self, css):
     from css_html_js_minify import css_minify
     return css_minify(css)
예제 #13
0
for filename in os.listdir(webroot):
    basename = re.sub("[^0-9a-zA-Z]+", "_", filename)

    srcfile = webroot + "/" + filename
    dstfile = srcroot + "/" + basename + ".h"

    varname = basename.upper()

    with open(srcfile, encoding="utf-8") as f:
        content = f.read().replace("${version}", version)

    try:    
        if filename.endswith(".html"):
            content = html_minify(content)
        elif filename.endswith(".css"):
            content = css_minify(content)
        elif filename.endswith(".js") or filename.endswith(".json"):
            content = js_minify(content)
    except:
        print("WARN: Unable to minify")

    with open(dstfile, "w") as dst:
        dst.write("const char ")
        dst.write(varname)
        dst.write("[] PROGMEM = R\"==\"==(")
        dst.write(content)
        dst.write(")==\"==\";\n")
        dst.write("const int ");
        dst.write(varname)
        dst.write("_LEN PROGMEM = ");
        dst.write(str(len(content)))
예제 #14
0
                    print(
                        "  \033[91m\033[1mERROR: NO VALID FILE EXTENSION. SUPPORTED: .js\033[0m"
                    )

                fh.close()

        # generate css output (Input can be css and sass)
        elif isCss(outputFileName):
            print("Building css file '", outputFileName, "'")

            for file in contentFiles:
                print("   ", file)
                fh = open(os.path.join(resDir, file), "r")

                if isCss(file):
                    output += css_minify(fh.read())

                #elif isSass(file):
                #	output += css_minify(sass.compile(string=fh.read()))

                else:
                    print(
                        "  \033[91m\033[1mERROR: NO VALID FILE EXTENSION. SUPPORTED: .css\033[0m"
                    )

                fh.close()

        # generate css output (Input can be css and sass)
        elif isSvg(outputFileName):
            print("Building svg file '", outputFileName, "'")
예제 #15
0
def bundle():

    #Check to see if output files exist, if so remove them
    if os.path.exists(cssoutput):
        os.remove(cssoutput)

    if os.path.exists(jsoutput):
        os.remove(jsoutput)

    #This part is a WIP. Please don't judge too hard. Trying to look through node_modules to find javascript and css files in packages specified in the config.
    for module in modules:
        fullpath = './node_modules/' + module

        #This one checks if the node module exists or can be found
        if os.path.exists(fullpath):

            #Created a couple different paths to look for
            myfile = fullpath + '/dist/js/' + module + '.min.js'
            myfile2 = fullpath + '/dist/' + module + '.min.js'

            #Check if file exists, if found it performs same bundling operation as the javascript one documented below.
            if os.path.exists(myfile):
                output = "//FILE OUTPUT FROM: " + myfile + "\n"
                #output += js_minify(str(f.read()))
                os.makedirs(os.path.dirname(jsoutput), exist_ok=True)
                with open(myfile, 'r') as mf:
                    with open(jsoutput, 'a+') as out:
                        for line in mf:
                            out.write(line)
                success_msg('Processed: ', myfile)
            #Performing check of second directory
            elif os.path.exists(myfile2):
                f = open(myfile2, "r")
                output = "//FILE OUTPUT FROM: " + myfile2 + "\n"
                output += js_minify(str(f.read()))
                os.makedirs(os.path.dirname(jsoutput), exist_ok=True)
                with open(jsoutput, 'a+') as out:
                    out.write(output + '\n\n')
                f.close()
                success_msg('Processed: ', myfile2)
            else:
                #Lets user know both directories checked on fail.
                error_output('File not found: ', myfile)
                error_output('Also checked: ', myfile2)
        else:
            #Error when node module not found
            error_output('Node module could not be located: ', fullpath)

        checkcss = fullpath + '/dist/css/' + module + '.min.css'
        if os.path.exists(checkcss):
            f = open(checkcss, "r")
            output = "/*FILE OUTPUT FROM: " + checkcss + "*/\n"
            output += css_minify(str(f.read()))
            os.makedirs(os.path.dirname(cssoutput), exist_ok=True)
            with open(cssoutput, 'a+') as out:
                out.write(output + '\n\n')
            f.close()
            success_msg('Processed: ', checkcss)

    #loops through the javascript files specified in config
    for file in jsfiles:

        #create full path using js path in config
        fullpath = jspath + file

        if os.path.exists(fullpath):
            #Check to see if file exists, on success open file, minify, and append to output specified in config. Close files
            f = open(fullpath, "r")
            output = "//FILE OUTPUT FROM: " + fullpath + "\n"
            output += js_minify(str(f.read()))
            os.makedirs(os.path.dirname(jsoutput), exist_ok=True)
            with open(jsoutput, 'a+') as out:
                out.write(output + '\n\n')
            f.close()
            success_msg('Processed: ', fullpath)
        else:
            #File not found
            error_output('File not found: ', fullpath)

        #See if any paths were provided to be forced into bundle
    if forcejs:
        #Loop through paths
        for fullpath in forcejs:
            #Check if they exist
            if os.path.exists(fullpath):
                #Run file tasks
                f = open(fullpath, "r")
                output = "//FILE OUTPUT FROM: " + fullpath + "\n"
                output += js_minify(str(f.read()))
                os.makedirs(os.path.dirname(jsoutput), exist_ok=True)
                with open(jsoutput, 'a+') as out:
                    out.write(output + '\n\n')
                f.close()
                success_msg('Processed: ', fullpath)
            else:
                error_output('File not found: ', file)

    #This works identically to the javascript loop. Just uses the css vars from the config.
    for file in cssfiles:
        fullpath = csspath + file
        if os.path.exists(fullpath):
            f = open(fullpath, "r")
            output = "/*FILE OUTPUT FROM: " + fullpath + "*/\n"
            output += css_minify(str(f.read()))
            os.makedirs(os.path.dirname(cssoutput), exist_ok=True)
            with open(cssoutput, 'a+') as out:
                out.write(output + '\n\n')
            f.close()
            success_msg('Processed: ', fullpath)
        else:
            error_output('File not found: ', fullpath)

    #Same as JS one
    if forcecss:
        for fullpath in forcecss:
            if os.path.exists(fullpath):
                f = open(fullpath, "r")
                output = "//FILE OUTPUT FROM: " + fullpath + "\n"
                output += css_minify(str(f.read()))
                os.makedirs(os.path.dirname(cssoutput), exist_ok=True)
                with open(cssoutput, 'a+') as out:
                    out.write(output + '\n\n')
                f.close()
                success_msg('Processed: ', fullpath)
            else:
                error_output('File not found: ', file)
예제 #16
0
def main():
    p = subprocess.Popen(["darkreader/host_with_flask.py"],
                         stdout=sys.stdout,
                         stderr=sys.stderr)
    # while True:
    #     stdout = str(p.stdout.readline(), encoding="UTF-8")
    #     print("stdout:", stdout)
    #     if "* Running on http://" in stdout:
    #         break
    # url = "http://" + stdout.split("http://")[1].split("/")[0]
    url = "http://127.0.0.1:5687/"
    # print(stdout, url)
    time.sleep(4)
    # print("received:", requests.get(url).text)

    options = Options()
    options.set_headless(headless=True)
    driver = webdriver.Firefox(firefox_options=options)
    js = """
    var callback = arguments[0];
    DarkReader.exportGeneratedCSS().then(function(result){callback(result);});
    """

    # Generate darkreader css for index.html:
    driver.get(url)
    time.sleep(3)
    darkreader_generated_css = driver.execute_async_script(js).replace(
        url, "https://phseiff.com/")
    with open("index.html.darkreader.css", "w") as f:
        f.write(darkreader_generated_css)
    with open("index.html", "r") as f:
        content = f.read()
        content = content.replace(
            """
    <script type="text/javascript" src="darkreader/darkreader.min.js"></script>
    <script>
        DarkReader.setFetchMethod(window.fetch);
        DarkReader.enable({ // <-- always use darkmode instead of, like previously, adapting to the system.
            brightness: 100,
            contrast: 90,
            sepia: 10
        });
    </script>""", "<style>" + css_html_js_minify.css_minify(
                darkreader_generated_css.split("/* Modified CSS */")[0]) +
            "</style>")
        content = content.replace(
            """
    <!-- Ensure dark reader is executed again after we updated the essays using javascript. -->
    <script>
        DarkReader.disable();
        DarkReader.enable({ // <-- always use darkmode instead of, like previously, adapting to the system.
            brightness: 100,
            contrast: 90,
            sepia: 10
        });
    </script>""",
            """<link type="text/css" rel="stylesheet" href="/index.html.darkreader.min.css">"""
        )
    with open("index.html", "w") as f:
        f.write(content)

    # Generate darkreader css for github card:
    driver.get(url + "//github-card/response.html")
    darkreader_generated_css = driver.execute_async_script(js).replace(
        url, "https://phseiff.com")
    with open("github-card/response.html.darkreader.css", "w") as f:
        f.write(darkreader_generated_css.split("/* Modified CSS */")[1])
    with open("github-card/response.html", "r+") as f:
        content = f.read()
        content = content.replace(
            """
<script type="text/javascript" src="../darkreader/darkreader.min.js"></script>
<script>
    DarkReader.setFetchMethod(window.fetch)
    DarkReader.enable({
        brightness: 100,
        contrast: 90,
        sepia: 10
    });
</script>""",
            """<link type="text/css" rel="stylesheet" href="/github-card/response.html.darkreader.min.css">"""
        )
    with open("github-card/response.modified.html", "w") as f:
        f.write(content)

    print("got all but error page!")
    # Generate css for 404 error page:
    driver.get(url + "//404-raw.html")
    darkreader_generated_css = driver.execute_async_script(js).replace(
        url, "https://phseiff.com")
    with open("404.html.darkreader.css", "w") as f:
        f.write(darkreader_generated_css)
    with open("404-raw.html", "r") as f:
        with open("404.html", "w") as f2:
            f2.write(f.read().replace(
                """
            <script type="text/javascript" src="/darkreader/darkreader.min.js"></script>
            <script>
                DarkReader.setFetchMethod(window.fetch);
                DarkReader.enable({
                    brightness: 100,
                    contrast: 90,
                    sepia: 10
                });
            </script>""",
                ("""<link type="text/css" rel="stylesheet" href="/404.html.darkreader.min.css">"""
                 if False else
                 """<link type="text/css" rel="stylesheet" href="/index.html.darkreader.min.css">"""
                 )))

    p.kill()
    driver.close()
예제 #17
0
 def run(self, text):
     from css_html_js_minify import css_minify
     return css_minify(text)
예제 #18
0
파일: __init__.py 프로젝트: Phuker/md2html
def render(args, md):
    logging.info('Start rendering')
    template = '''<!DOCTYPE html>
<!--
Generated with md2html {version}
Homepage: https://github.com/Phuker/md2html
-->
<html>
<head>
{head_insert}<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui">
<title>{title}</title>
{css_html_block}
{head_append}</head>
<body>
{body_insert}<div class="markdown-body">
{html_content}
</div>
{body_append}</body>
</html>
'''
    title = args.title

    head_insert = ''.join([_ + '\n' for _ in args.head_insert])
    head_append = ''.join([_ + '\n' for _ in args.head_append])
    body_insert = ''.join([_ + '\n' for _ in args.body_insert])
    body_append = ''.join([_ + '\n' for _ in args.body_append])

    css_file_list = [
        os.path.join(args.script_dir, 'github-markdown.css'),
        os.path.join(args.script_dir, 'pygments.css'),
        os.path.join(args.script_dir, 'main.css'),
    ]

    addon_styles = {
        'sidebar-toc': 'style-sidebar-toc.css',
        'dark': 'style-dark.css',
    }
    for style_name in args.style:
        css_file_list.append(
            os.path.join(args.script_dir, addon_styles[style_name]))

    css_file_list += args.append_css
    css_content_list = [read_file(_) for _ in css_file_list]

    if args.min_css:
        logging.info('Minify CSS')
        size_old = sum(map(len, css_content_list))
        css_content_list = [
            css_minify(_, comments=False) for _ in css_content_list
        ]
        size_new = sum(map(len, css_content_list))
        logging.info('Size shrunk %d B/%d B = %.2f %%', size_old - size_new,
                     size_old, (size_old - size_new) / size_old * 100)

    css_html_block = '\n'.join([
        '<style type="text/css">\n' + _ + '\n</style>'
        for _ in css_content_list
    ])

    logging.info('Converting Markdown')
    html_content = convert(md)

    if args.min_html:
        logging.info('Minify HTML')
        size_old = len(html_content)
        html_content = html_minify(html_content, comments=False)
        size_new = len(html_content)
        logging.info('Size shrunk %d B/%d B = %.2f %%', size_old - size_new,
                     size_old, (size_old - size_new) / size_old * 100)

    template_args = {
        'version': __version__,
        'title': escape(title),
        'css_html_block': css_html_block,
        'html_content': html_content,
        'head_insert': head_insert,
        'head_append': head_append,
        'body_insert': body_insert,
        'body_append': body_append,
    }
    return template.format(**template_args)
예제 #19
0
from css_html_js_minify import html_minify, css_minify
from jsmin import jsmin
import os
import shutil

files = os.listdir("./")
for f in files:
  ext = os.path.splitext(f)[1]
  with open(f, 'r', encoding="utf8") as webfile:
    web_raw = webfile.read()
    if ext == ".css":
      print(f + " ... CSS")
      css_minified = css_minify(web_raw).replace('@charset "utf-8";','')
      with open("../data/" + f, "w", encoding="utf8") as css_new:
          css_new.write(css_minified)
    if ext == ".js":
      print(f + " ... JS")  
      js_minified = jsmin(web_raw).replace('@charset "utf-8";','')
      with open("../data/" + f, "w", encoding="utf8") as js_new:
        js_new.write(js_minified)
 
    if ext == ".html":
      print(f + " ... HTML")  
      html_minified = html_minify(web_raw).replace('@charset "utf-8";','')
      with open("../data/" + f, "w", encoding="utf8") as html_new:
        html_new.write(html_minified)
 
    if ext == ".svg":
      print(f + " ... SVG")
      shutil.copy2(f, '../data/' + f)
예제 #20
0
def generate_fs():
    files = [
        p for p in sorted(fsdir.iterdir())
        if p.is_file() and p.suffix in extensions
    ]
    if all(file.stat().st_mtime < outfile.stat().st_mtime for file in files):
        print('generated file up to date')
        #return

    with outfile.open('w') as fout:
        fout.write('#include "stddef.h"\n')
        fout.write('#include "httpd-fsdata.h"\n\n')
        fout.write('#define file_NULL (struct fsdata_file *) NULL\n')

        filecount = 0

        for file in files:
            if (unify):
                if (file.suffix not in ['.htm', '.html']):
                    continue
                with file.open() as fin:
                    html = fin.read()
                    if (minify): html = html_minify(html)
                    soup = bs4.BeautifulSoup(html, 'html.parser')
                    for style in soup.findAll("link", {"rel": "stylesheet"}):
                        if (style["href"][0:4] == "http"):
                            continue
                        css_path = fsdir / style["href"]
                        if css_path.is_file():
                            with css_path.open() as css_file:
                                css = css_file.read()
                                if (minify): css = css_minify(css)
                                c = bs4.element.NavigableString(css)
                                tag = soup.new_tag('style')
                                tag.insert(0, c)
                                tag['type'] = 'text/css'
                                style.replaceWith(tag)
                    for script in soup.findAll("script"):
                        if not script.has_attr('src'): continue
                        if script['src'][0:4] == 'http': continue
                        js_path = fsdir / script["src"]
                        if js_path.is_file():
                            with js_path.open() as js_file:
                                js = js_file.read()
                                if (minify): js = js_minify(js)
                                j = bs4.element.NavigableString(js)
                                tag = soup.new_tag('script')
                                tag.insert(0, j)
                                script.replaceWith(tag)
                    for image in soup.findAll("img"):
                        if not image.has_attr('src'): continue
                        if image['src'][0:4] == 'http': continue
                        img_path = fsdir / image["src"]
                        if img_path.is_file():
                            with img_path.open() as img_file:
                                img_data = img_file.read()
                                if img_path.suffix == '.svg':
                                    img_tag = '<img src=\'data:image/svg+xml;utf8,{0}\'>'.format(
                                        img_data)
                                elif img_path.suffix == '.png':
                                    img_data = img_data.encode(
                                        'base64').replace('\n', '')
                                    img_tag = '<img src="data:image/png;base64,{0}">'.format(
                                        data_uri)
                                tag = bs4.BeautifulSoup(img_tag, 'html.parser')
                                image.replaceWith(tag)
                    data = soup.decode(formatter="html")
            else:
                with file.open() as fin:
                    data = fin.read()
                    if (minify):
                        if (file.suffix in ['.htm', '.html']):
                            data = html_minify(data)
                        elif (file.suffix in ['.js']):
                            data = js_minify(data)
                        elif (file.suffix in ['.css']):
                            data = css_minify(data)

            print(file.name)

            filename_enc = file.name.translate(str.maketrans('.-', '__'))
            filename_slash = '/' + file.name
            fout.write(
                'static const unsigned int dummy_align__{} = {};\n'.format(
                    filename_enc, filecount))
            fout.write('static const unsigned char data__{}[] = {{\n'.format(
                filename_enc))
            fout.write('\n\n')

            fout.write('/* /{} ({} chars) */\n'.format(file.name,
                                                       len(filename_slash) +
                                                       1))
            filename_hex = ",".join("0x{:02x}".format(c)
                                    for c in filename_slash.encode()) + ','
            filename_hex += '0x00,' * (4 - (len(filename_slash) % 4))
            fout.write('\n'.join(textwrap.wrap(filename_hex, 80)))
            fout.write('\n\n')

            data = data.encode()
            if (file.suffix in gzip_extensions):
                data = gzip_encode(data)
            data_hex = ",".join("0x{:02x}".format(c) for c in data)
            fout.write('/* raw file data ({} bytes) */\n'.format(len(data)))
            fout.write('\n'.join(textwrap.wrap(data_hex, 80)))
            fout.write(',\n};\n')
            fout.write('\n\n')

            filecount += 1

        last_file = ''
        for file in files:
            if (unify):
                if (file.suffix not in ['.htm', '.html']):
                    continue
            filename_enc = file.name.translate(str.maketrans('.-', '__'))
            filename_slash = '/' + file.name
            fout.write('const struct fsdata_file file__{}[] = {{ {{\n'.format(
                filename_enc))
            if last_file == '': fout.write('file_NULL,\n')
            else: fout.write('file__{},\n'.format(last_file))
            fout.write('data__{},\n'.format(filename_enc))
            fout.write('data__{} + {},\n'.format(
                filename_enc,
                len(filename_slash) + (4 - (len(filename_slash) % 4))))
            fout.write('sizeof(data__{}) - {},\n'.format(
                filename_enc,
                len(filename_slash) + (4 - (len(filename_slash) % 4))))
            fout.write('#ifdef HTTPD_FS_STATISTICS\n')
            fout.write('#if HTTPD_FS_STATISTICS == 1\n')
            fout.write('0,\n')
            fout.write('#endif /* HTTPD_FS_STATISTICS */\n')
            fout.write('#endif /* HTTPD_FS_STATISTICS */\n')
            fout.write('} };\n')
            fout.write('\n\n')
            last_file = filename_enc

        fout.write('const struct fsdata_file *fs_root = file__{};\n'.format(
            last_file))
        fout.write('#ifdef HTTPD_FS_STATISTICS\n')
        fout.write('#if HTTPD_FS_STATISTICS == 1\n')
        fout.write('uint16_t fs_count[{}];\n'.format(filecount))
        fout.write('#endif /* HTTPD_FS_STATISTICS */\n')
        fout.write('#endif /* HTTPD_FS_STATISTICS */\n')