fixed stuff included a fully working downloader for webpages which inlines the css / js. images do not work because they are hosted on the server
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
__pycache__
|
__pycache__
|
||||||
env
|
env
|
||||||
target
|
target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
.idea
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-python.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-python.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-javascript.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-javascript.min.js"></script>
|
||||||
|
|
||||||
|
<!-- JSZip for downloading the files as ZIP -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.11.0/jszip.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
|
||||||
|
|
||||||
<!-- remove if causing issues -->
|
<!-- remove if causing issues -->
|
||||||
<script src="../js/post/lazyimg.js"></script>
|
<script src="../js/post/lazyimg.js"></script>
|
||||||
<script src="../js/shared/theme.js"></script>
|
<script src="../js/shared/theme.js"></script>
|
||||||
@@ -50,8 +54,15 @@
|
|||||||
<img src="../css/icons/magnifier.webp" width="16" height="16" alt="Hash2" loading="lazy" style="display:inline; vertical-align:middle;" />
|
<img src="../css/icons/magnifier.webp" width="16" height="16" alt="Hash2" loading="lazy" style="display:inline; vertical-align:middle;" />
|
||||||
Hash 2 (<b>Windows-1252</b>)<i>:{{ hash2 }}</i><br />
|
Hash 2 (<b>Windows-1252</b>)<i>:{{ hash2 }}</i><br />
|
||||||
|
|
||||||
<img src="../css/icons/save.webp" width="16" height="16" alt="Hash2" loading="lazy" style="display:inline; vertical-align:middle;" />
|
<span style="display: inline-flex; align-items: center; gap: 8px;">
|
||||||
<a id="download-md">Download as Markdown <noscript>Enable JavaScript for downloads</noscript></a>
|
<img src="../css/icons/save.webp" width="16" height="16" alt="Save" loading="lazy" />
|
||||||
|
<a id="download-md">Download as Markdown <noscript>Enable JavaScript for downloads</noscript></a>
|
||||||
|
|
||||||
|
<span style="border-left: 1px solid #888; height: 16px;"></span> <!-- Vertical separator -->
|
||||||
|
|
||||||
|
<img src="../css/icons/script.webp" width="16" height="16" alt="Script" loading="lazy" />
|
||||||
|
<a id="download-html">Download as HTML <noscript>Enable JavaScript for downloads</noscript></a>
|
||||||
|
</span>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,18 +1,50 @@
|
|||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
// current page URL
|
const htmlDownload = document.getElementById("download-html");
|
||||||
let url = window.location.href;
|
|
||||||
|
|
||||||
// replace `/html/` with `/markdown/`
|
htmlDownload.addEventListener("click", async (e) => {
|
||||||
url = url.replace("/html/", "/markdown/");
|
e.preventDefault();
|
||||||
|
|
||||||
// replace `.html` with `.md`
|
const linkElements = document.querySelectorAll('link[rel="stylesheet"]');
|
||||||
url = url.replace(/\.html$/, ".md");
|
for (const link of linkElements) {
|
||||||
|
const href = link.getAttribute("href");
|
||||||
|
try {
|
||||||
|
const res = await fetch(href);
|
||||||
|
const cssText = await res.text();
|
||||||
|
const styleEl = document.createElement("style");
|
||||||
|
styleEl.textContent = cssText;
|
||||||
|
document.head.appendChild(styleEl);
|
||||||
|
link.remove(); // remove original link
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to inline CSS:", href, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// assign to <a>
|
const scriptElements = document.querySelectorAll('script[src]');
|
||||||
const a = document.getElementById("download-md");
|
for (const script of scriptElements) {
|
||||||
a.href = url;
|
const src = script.getAttribute("src");
|
||||||
|
try {
|
||||||
|
const res = await fetch(src);
|
||||||
|
const jsText = await res.text();
|
||||||
|
const inlineScript = document.createElement("script");
|
||||||
|
inlineScript.textContent = jsText;
|
||||||
|
document.body.appendChild(inlineScript);
|
||||||
|
script.remove(); // remove original script
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to inline JS:", src, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// suggest filename
|
const htmlContent = document.documentElement.outerHTML;
|
||||||
const filename = url.split("/").pop(); // e.g. markdowntest.md
|
|
||||||
a.download = filename;
|
const blob = new Blob([htmlContent], { type: "text/html" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = "index.html"; // or derive from URL
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
10
webserver.py
10
webserver.py
@@ -139,8 +139,8 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||||||
logger.log_info(f"Served markdown file: {markdown_filename}")
|
logger.log_info(f"Served markdown file: {markdown_filename}")
|
||||||
return
|
return
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
logger.log_error(f"Error serving markdown file {markdown_filename}: {e}")
|
logger.log_error(f"Error serving markdown file {markdown_filename}: {err}")
|
||||||
self.send_response(500)
|
self.send_response(500)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"500 - Internal Server Error")
|
self.wfile.write(b"500 - Internal Server Error")
|
||||||
@@ -166,8 +166,8 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||||||
if mime_type == "application/javascript" or file_path.endswith(".js"):
|
if mime_type == "application/javascript" or file_path.endswith(".js"):
|
||||||
try:
|
try:
|
||||||
content = jsmin(content.decode("utf-8")).encode("utf-8")
|
content = jsmin(content.decode("utf-8")).encode("utf-8")
|
||||||
except Exception as e:
|
except Exception as err:
|
||||||
logger.log_error(f"Error minifying JS file {file_path}: {e}")
|
logger.log_error(f"Error minifying JS file {file_path}: {err}")
|
||||||
|
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header("Content-type", mime_type)
|
self.send_header("Content-type", mime_type)
|
||||||
@@ -190,7 +190,7 @@ if __name__ == "__main__":
|
|||||||
logger.log_debug("Started PyPost.py in background watcher thread.")
|
logger.log_debug("Started PyPost.py in background watcher thread.")
|
||||||
|
|
||||||
server_address = ("localhost", 8000)
|
server_address = ("localhost", 8000)
|
||||||
httpd = HTTPServer(server_address, MyHandler)
|
httpd: HTTPServer = HTTPServer(server_address, MyHandler) # type: ignore[arg-type]
|
||||||
logger.log_info(f"Serving on http://{server_address[0]}:{server_address[1]}")
|
logger.log_info(f"Serving on http://{server_address[0]}:{server_address[1]}")
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
except (Exception, KeyboardInterrupt) as e:
|
except (Exception, KeyboardInterrupt) as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user