5 Commits

Author SHA1 Message Date
6c636905e2 added missing documentation 2024-09-17 11:37:26 +02:00
c79473d646 modified themes and added logging to preview generator 2024-09-17 11:33:36 +02:00
3cb5269985 log start and end 2024-09-16 22:42:58 +02:00
3bde09aebc info → debug 2024-09-16 22:40:44 +02:00
effc05826a additional logging 2024-09-16 22:39:31 +02:00
30 changed files with 99 additions and 62 deletions

View File

@@ -1 +1 @@
2.3.0
2.3.2

View File

@@ -101,8 +101,8 @@ def copy_static_files(_args: Args) -> None:
logger.info("found foldericon", extra={"foldericon": foldericon})
break
if "url" in foldericon:
shutil.copyfile(_args.theme_path, os.path.join(static_dir, "theme.css"))
logger.info("foldericon in theme file, using it")
shutil.copyfile(_args.theme_path, os.path.join(static_dir, "theme.css"))
return
with open(os.path.join(SCRIPTDIR, foldericon), "r", encoding="utf-8") as f:
logger.info("Reading foldericon svg")
@@ -110,10 +110,8 @@ def copy_static_files(_args: Args) -> None:
if "svg.j2" in foldericon:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(_args.theme_path)
svg = svg.replace("{{ color1 }}", colorscheme["color1"])
svg = svg.replace("{{ color2 }}", colorscheme["color2"])
svg = svg.replace("{{ color3 }}", colorscheme["color3"])
svg = svg.replace("{{ color4 }}", colorscheme["color4"])
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
with open(os.path.join(static_dir, "theme.css"), "x", encoding="utf-8") as f:
@@ -152,7 +150,7 @@ def generate_thumbnail(arguments: Tuple[str, str, str]) -> None:
print(f"Failed to generate thumbnail for {image}")
return
else:
logger.info("thumbnail already exists for %s", item, extra={"path": image})
logger.debug("thumbnail already exists for %s", item, extra={"path": image})
def get_total_folders(folder: str, _args: Args, _total: int = 0) -> int:
@@ -190,6 +188,7 @@ def main() -> None:
"""
Main function to process images and generate a static image hosting website.
"""
logger.info("starting builder", extra={"version": VERSION})
thumbnails: List[Tuple[str, str, str, bool]] = []
args = parse_arguments(VERSION)
@@ -249,6 +248,7 @@ def main() -> None:
pass
finally:
os.remove(lock_file)
logger.info("finished builder", extra={"version": VERSION})
return

View File

@@ -4,21 +4,18 @@ import sys
import time
import shutil
import base64
import logging
import fileinput
import urllib.parse
import urllib.request
from typing import List
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from modules.logger import consolelogger as logger
from modules.css_color import extract_colorscheme
# Set up logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
def replace_all(file, search_exp, replace_exp):
for line in fileinput.input(file, inplace=1):
@@ -36,11 +33,14 @@ def take_screenshot(html_file_path: str, css_file: str, output_file: str, driver
output_file (str): Path where the screenshot will be saved.
driver (webdriver.Chrome): The Chrome WebDriver instance.
"""
logger.info("taking screenshot for %s", css_file)
try:
# Open the HTML file or URL
if html_file_path.startswith(("http://", "https://")):
logger.info("opening URL: %s", html_file_path)
driver.get(html_file_path)
else:
logger.info("opening file: %s", html_file_path)
driver.get(f"file://{os.path.abspath(html_file_path)}")
# Remove current theme.css
@@ -52,9 +52,11 @@ def take_screenshot(html_file_path: str, css_file: str, output_file: str, driver
}
});
"""
logger.info("removing current theme.css")
driver.execute_script(remove_css_script)
with open(css_file, "r", encoding="utf-8") as f:
logger.info("reading CSS file: %s", css_file)
css_content = f.read()
# Extract folder icon content
@@ -65,20 +67,26 @@ def take_screenshot(html_file_path: str, css_file: str, output_file: str, driver
folder_icon_content = re.sub(r"/\*.*\*/", "", folder_icon_content)
for match in re.finditer(r"content: (.*);", folder_icon_content):
logger.info("found foldericon", extra={"foldericon": folder_icon_content})
folder_icon_content = match.group(1).replace('"', "")
break
if "url" not in folder_icon_content:
logger.info("Reading foldericon svg")
with open(folder_icon_content, "r", encoding="utf-8") as f:
svg = f.read()
if "svg.j2" in folder_icon_content:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(css_file)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
css_content = f'{css_head}\n.foldericon {{\n content: url("data:image/svg+xml,{svg}");\n}}\n{css_tail}'
# Encode CSS content as Base64
logger.info("encoding css content as base64")
encoded_css = base64.b64encode(css_content.encode("utf-8")).decode("utf-8")
# Inject CSS into HTML using JavaScript
@@ -87,24 +95,28 @@ def take_screenshot(html_file_path: str, css_file: str, output_file: str, driver
style.innerHTML = atob('{encoded_css}');
document.head.appendChild(style);
"""
logger.info("injecting CSS into HTML")
driver.execute_script(apply_css_script)
# Wait for a while to ensure CSS is applied
time.sleep(2)
# time.sleep(1)
# Move mouse to info
logger.info("moving mouse to info")
hoverable = driver.find_element(By.CLASS_NAME, "tooltip")
webdriver.ActionChains(driver).move_to_element(hoverable).perform()
# Capture screenshot
logger.info("taking screenshot")
driver.save_screenshot(output_file)
logging.info("Screenshot saved to %s", output_file)
logger.info("screenshot saved to %s", output_file)
except Exception as e:
logging.error("Failed to take screenshot for %s: %s", css_file, e)
logger.error("failed to take screenshot for %s: %s", css_file, e)
def create_preview(html_file_path: str, css_file: str, previews_folder: str):
logger.info("creating preview for %s", css_file)
out_file = os.path.basename(css_file).removesuffix(".css") + ".html"
urllib.request.urlretrieve(html_file_path, os.path.join(previews_folder, out_file))
basename = os.path.basename(css_file)
@@ -127,21 +139,25 @@ def create_preview(html_file_path: str, css_file: str, previews_folder: str):
foldericon = foldericon.replace('"', "")
break
if "url" in foldericon:
logger.info("foldericon in theme file, using it")
shutil.copyfile(css_file, os.path.join(path, "previews", basename))
else:
with open(os.path.join(path, foldericon.removeprefix("themes/")), "r", encoding="utf-8") as f:
svg = f.read()
if "svg.j2" in foldericon:
colorscheme = extract_colorscheme(css_file)
svg = svg.replace("{{ color1 }}", colorscheme["color1"])
svg = svg.replace("{{ color2 }}", colorscheme["color2"])
svg = svg.replace("{{ color3 }}", colorscheme["color3"])
svg = svg.replace("{{ color4 }}", colorscheme["color4"])
svg = urllib.parse.quote(svg)
if os.path.exists(os.path.join(path, "previews", basename)):
os.remove(os.path.join(path, "previews", basename))
with open(os.path.join(path, "previews", basename), "x", encoding="utf-8") as f:
f.write(themehead + '\n.foldericon {\n content: url("data:image/svg+xml,' + svg + '");\n}\n' + themetail)
return
with open(os.path.join(path, foldericon.removeprefix("themes/")), "r", encoding="utf-8") as f:
logger.info("Reading foldericon svg")
svg = f.read()
if "svg.j2" in foldericon:
logger.info("foldericon in theme file is a jinja2 template")
colorscheme = extract_colorscheme(css_file)
for color_key, color_value in colorscheme.items():
svg = svg.replace(f"{{{{ {color_key} }}}}", color_value)
logger.info("replaced colors in svg")
svg = urllib.parse.quote(svg)
if os.path.exists(os.path.join(path, "previews", basename)):
os.remove(os.path.join(path, "previews", basename))
with open(os.path.join(path, "previews", basename), "x", encoding="utf-8") as f:
logger.info("writing theme file")
f.write(themehead + '\n.foldericon {\n content: url("data:image/svg+xml,' + svg + '");\n}\n' + themetail)
logger.info("preview created for %s", css_file)
def write_readme(directory_path: str, themes: List[str]) -> None:
@@ -155,6 +171,7 @@ def write_readme(directory_path: str, themes: List[str]) -> None:
readme_path = os.path.join(directory_path, "README.md")
try:
with open(readme_path, "r", encoding="utf-8") as f:
logger.info("reading README.md", extra={"file": readme_path})
readme = f.read()
readme_head = readme.split("## Previews of included themes")[0]
@@ -162,14 +179,15 @@ def write_readme(directory_path: str, themes: List[str]) -> None:
readme_head += "".join([f"\n### {theme}\n\n![{theme}](screenshots/{theme}.png)\n" for theme in themes])
with open(readme_path, "w", encoding="utf-8") as f:
logger.info("writing README.md", extra={"file": readme_path})
f.write(readme_head)
logging.info("README.md updated with previews of included themes.")
logger.info("README.md updated with previews of included themes.")
except FileNotFoundError:
logging.error("README.md not found in %s", directory_path)
logger.error("README.md not found in %s", directory_path)
except Exception as e:
logging.error("Failed to write README.md: %s", e)
logger.error("failed to write README.md: %s", e)
def write_index(directory_path: str, themes: List[str]) -> None:
@@ -198,7 +216,7 @@ def main(directory_path: str, html_file_path: str) -> None:
html_file_path (str): Path to the HTML file or URL for rendering.
"""
if not os.path.exists(directory_path):
logging.error('Error: Folder path "%s" does not exist.', directory_path)
logger.error('Error: Folder path "%s" does not exist.', directory_path)
return
# Setup Chrome options
@@ -207,8 +225,9 @@ def main(directory_path: str, html_file_path: str) -> None:
chrome_options.add_argument("--window-size=1920,1080") # Set window size to at least 1920x1080
# Initialize Chrome WebDriver
chromedriver_path = "/usr/bin/chromedriver" # Replace with your actual path
chromedriver_path = "/usr/bin/chromedriver"
service = Service(chromedriver_path)
logger.info("Using chromedriver at %s", chromedriver_path, extra={"chrome_options": chrome_options})
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
@@ -235,13 +254,16 @@ def main(directory_path: str, html_file_path: str) -> None:
write_index(directory_path, themes)
finally:
logger.info("closing chrome webdriver")
driver.quit()
if __name__ == "__main__":
if len(sys.argv) != 3:
logging.error("Usage: python script_name.py directory_path html_file_path")
logger.error("Usage: python script_name.py directory_path html_file_path")
else:
dir_path = sys.argv[1]
html_path = sys.argv[2]
logger.info("Starting script", extra={"directory_path": dir_path, "html_file_path": html_path})
main(dir_path, html_path)
logger.info("Done!", extra={"directory_path": dir_path})

View File

@@ -33,8 +33,7 @@ def extract_colorscheme(theme_path: str) -> Dict[str, str]:
color_value = match[1]
hex_color_value = css_color_to_hex(color_value)
colorscheme[variable_name] = hex_color_value
logger.debug("extracted variable", extra={"variable": variable_name, "value": hex_color_value})
logger.info("extracted color scheme", extra={"colorscheme": colorscheme})
logger.debug("extracted variable", extra={"variable": variable_name, "value": hex_color_value})
return colorscheme

View File

@@ -174,6 +174,7 @@ def generate_html(folder: str, title: str, _args: Args, raw: List[str], version:
_args (Args): Parsed command line arguments.
raw (List[str]): Raw image file names.
"""
logger.info("processing folder", extra={"folder": folder})
if _args.regenerate_thumbnails:
if os.path.exists(os.path.join(folder, ".sizelist.json")):
logger.info("removing .sizelist.json", extra={"folder": folder})
@@ -193,6 +194,7 @@ def generate_html(folder: str, title: str, _args: Args, raw: List[str], version:
if not _args.non_interactive_mode:
pbardict[folder] = tqdm(total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True)
logger.info("processing contents", extra={"folder": folder})
for item in items:
if item not in EXCLUDES and not item.startswith("."):
if os.path.isdir(os.path.join(folder, item)):

View File

@@ -9,6 +9,7 @@ Functions:
- log_format(keys): Generates the logging format string based on the list of keys.
- rotate_log_file(): Handles renaming the existing log file to a timestamp-based name.
- setup_logger(): Configures the logging system, applies a JSON format, and returns a logger instance.
- setup_consolelogger(): Configures the logging system to output logs in console format.
"""
import logging
@@ -77,7 +78,7 @@ def setup_logger():
logging.Logger: A configured logger instance that can be used to log messages.
"""
rotate_log_file()
app_logger = logging.getLogger()
_logger = logging.getLogger()
supported_keys = ["asctime", "created", "filename", "funcName", "levelname", "levelno", "lineno", "module", "msecs", "message", "name", "pathname", "process", "processName", "relativeCreated", "thread", "threadName", "taskName"]
@@ -87,10 +88,23 @@ def setup_logger():
log_handler = logging.FileHandler(LATEST_LOG_FILE)
log_handler.setFormatter(formatter)
app_logger.addHandler(log_handler)
app_logger.setLevel(logging.INFO)
_logger.addHandler(log_handler)
_logger.setLevel(logging.INFO)
return app_logger
return _logger
def setup_consolelogger():
"""
Configures the logging system to output logs in console format.
Returns:
logging.Logger: A configured logger instance that can be used to log messages.
"""
_logger = setup_logger()
_logger.addHandler(logging.StreamHandler())
return _logger
logger = setup_logger()
consolelogger = setup_consolelogger()

View File

@@ -5,22 +5,22 @@
--color2: #b22222;
--color3: #ff4500;
--color4: #6e0000;
--bcolor1: #ebebeb;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #171717;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
color: var(--bcolor3);
}
/* Change the link color on hover */
@@ -30,7 +30,7 @@
}
.footer {
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}

View File

@@ -5,22 +5,22 @@
--color2: #1346a4;
--color3: #0e3377;
--color4: #3674e7;
--bcolor1: #ebebeb;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #171717;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
color: var(--bcolor3);
}
/* Change the link color on hover */
@@ -30,7 +30,7 @@
}
.footer {
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}

View File

@@ -1,6 +1,6 @@
<svg width='64' height='64' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path d='M20 6H10L8 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V8C22 6.89543 21.1046 6 20 6Z' fill='{{ color1 }}' />
<path d='M4 4H8L10 6H20C21.1046 6 22 6.89543 22 8H2C2 6.89543 2.89543 6 4 6V4Z' fill='{{ color4 }}' />
<path d='M10 6H14L12 4H8L10 6Z' fill='{{ color2 }}' />
<path d='M14 6H18L16 4H12L14 6Z' fill='{{ color3 }}' />
<path d='M10 6H14L12 4H8L10 6Z' fill='{{ color3 }}' />
<path d='M14 6H18L16 4H12L14 6Z' fill='{{ color2 }}' />
</svg>

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 493 B

View File

@@ -5,22 +5,22 @@
--color2: #008000;
--color3: #32cd32;
--color4: #004300;
--bcolor1: #ebebeb;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #171717;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
.navbar {
font-weight: bold;
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color1);
font-weight: 900;
}
.navbar li a {
font-weight: 800;
color: var(--bcolor1);
color: var(--bcolor3);
}
/* Change the link color on hover */
@@ -30,7 +30,7 @@
}
.footer {
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--color3);
font-weight: 700;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -5,9 +5,9 @@
--color2: #ffd700;
--color3: #ffe135;
--color4: #ce8c00;
--bcolor1: #ebebeb;
--bcolor1: #171717;
--bcolor2: #191919;
--bcolor3: #171717;
--bcolor3: #ebebeb;
--bcolor4: #0a0a0a;
}
@@ -60,7 +60,7 @@
.row a {
font-weight: 800;
color: var(--color2);
color: var(--color1);
text-decoration: none;
}
@@ -70,7 +70,7 @@
.tooltiptext {
font-weight: 600;
color: var(--bcolor1);
color: var(--bcolor3);
background-color: var(--bcolor2);
}