UI: fixes

This commit is contained in:
ZhymabekRoman 2024-06-07 15:20:52 +05:00
parent 1fe36ab574
commit fab920caaf
7 changed files with 173 additions and 173 deletions

View file

@ -47,7 +47,6 @@ class MediumParser:
logger.debug("...maybe it's URL. Let's checkout...")
return await cls.from_url(unknown, cache=cache, timeout=timeout, host_address=host_address, auth_cookies=auth_cookies)
@classmethod
async def from_url(cls, url: str, cache: "SQLiteCacheBackend", timeout: int, host_address: str, auth_cookies: str = None) -> "MediumParser":
sanitized_url = correct_url(url)
@ -171,7 +170,7 @@ class MediumParser:
async def _parse_and_render_content_html_post(self, content: dict, title: str, subtitle: str, preview_image_id: str, highlights: list, tags: list) -> tuple[list, str, str]:
paragraphs = content["bodyModel"]["paragraphs"]
tags_list = [tag["displayTitle"] for tag in tags]
out_paragraphs = []
out_paragraphs: list[str] = []
current_pos = 0
def parse_paragraph_text(text: str, markups: list, is_code: bool = False) -> str:
@ -240,7 +239,7 @@ class MediumParser:
if highlight_paragraph["text"] != text_formater.get_text():
logger.warning("Highlighted text and paragraph text are not the same! Skip...")
break
quote_markup_template = '<mark style="background-color: rgb(200 227 200);">{{ text }}</mark>'
quote_markup_template = '<mark class="bg-emerald-300">{{ text }}</mark>'
text_formater.set_template(
highlight["startOffset"],
highlight["endOffset"],
@ -271,7 +270,7 @@ class MediumParser:
out_paragraphs.append(header_template_rendered)
elif paragraph["type"] == "IMG":
image_template = jinja_env.from_string(
'<div class="mt-7"><img alt="{{ paragraph.metadata.alt }}" style="margin: auto;" class="pt-5 lazy" role="presentation" data-src="https://miro.medium.com/v2/resize:fit:700/{{ paragraph.metadata.id }}"></div>'
'<div class="mt-7"><img alt="{{ paragraph.metadata.alt }}" class="pt-5 lazy m-auto" role="presentation" data-src="https://miro.medium.com/v2/resize:fit:700/{{ paragraph.metadata.id }}"></div>'
)
image_caption_template = jinja_env.from_string("<figcaption class='mt-3 text-sm text-center text-gray-500 dark:text-gray-200'>{{ text }}</figcaption>")
if paragraph["layout"] == "OUTSET_ROW":
@ -355,14 +354,15 @@ class MediumParser:
current_pos = _tmp_current_pos - 1
elif paragraph["type"] == "PRE":
pre_template = jinja_env.from_string('<pre class="p-4 mt-7 bg-gray-100 dark:bg-gray-900 flex flex-col justify-center">{{code_block}}</pre>')
code_block_template = jinja_env.from_string('<code class="overflow-x-auto mt-1 {{ code_css_class }} bg-gray-100 dark:bg-gray-900">{{ text }}</code>')
pre_template = jinja_env.from_string('<pre class="mt-7 flex flex-col justify-center border dark:border-gray-700">{{code_block}}</pre>')
code_block_template = jinja_env.from_string('<code class="p-2 bg-gray-100 dark:bg-gray-900 overflow-x-auto {{ code_css_class }}">{{ text }}</code>')
code_css_class = []
if paragraph["codeBlockMetadata"] and paragraph["codeBlockMetadata"]["lang"] is not None:
code_css_class.append(f'language-{paragraph["codeBlockMetadata"]["lang"]}')
else:
code_css_class.append("nohighlight")
# code_css_class.append("auto")
code_list = []
_tmp_current_pos = current_pos
@ -382,7 +382,9 @@ class MediumParser:
out_paragraphs.append(pre_template_rendered)
current_pos = _tmp_current_pos - 1
elif paragraph["type"] == "BQ":
bq_template = jinja_env.from_string('<blockquote class="px-5 pt-3 pb-3 mt-5 shadow-lf"><p style="font-style: italic;">{{ text }}</p></blockquote>')
bq_template = jinja_env.from_string(
'<blockquote style="box-shadow: inset 3px 0 0 0 rgb(209 207 239 / var(--tw-bg-opacity));" class="px-5 pt-3 pb-3 mt-5"><p class="font-italic">{{ text }}</p></blockquote>'
)
bq_template_rendered = await bq_template.render_async(text=text_formater.get_text())
logger.trace(bq_template_rendered)
out_paragraphs.append(bq_template_rendered)
@ -394,9 +396,7 @@ class MediumParser:
elif paragraph["type"] == "MIXTAPE_EMBED":
# TODO: redirect all Medium embeding articles to Fredium
embed_template = jinja_env.from_string(
"""
<div class="border border-gray-300 p-2 mt-7 items-center overflow-hidden"><a rel="noopener follow" href="{{ url }}" target="_blank"> <div class="flex flex-row justify-between p-2 overflow-hidden"><div class="flex flex-col justify-center p-2"><h2 class="text-black dark:text-gray-100 text-base font-bold">{{ embed_title }}</h2><div class="mt-2 block"><h3 class="text-grey-darker text-sm">{{ embed_description }}</h3></div><div class="mt-5" style=""><p class="text-grey-darker text-xs">{{ embed_site }}</p></div></div><div class="relative flex flew-row h-40 w-60"><div class="lazy absolute inset-0 bg-cover bg-center" data-bg="https://miro.medium.com/v2/resize:fit:320/{{ paragraph.mixtapeMetadata.thumbnailImageId }}"></div></div></div> </a></div>
"""
'<div class="border border-gray-300 p-2 mt-7 items-center overflow-hidden"><a rel="noopener follow" href="{{ url }}" target="_blank"> <div class="flex flex-row justify-between p-2 overflow-hidden"><div class="flex flex-col justify-center p-2"><h2 class="text-black dark:text-gray-100 text-base font-bold">{{ embed_title }}</h2><div class="mt-2 block"><h3 class="text-grey-darker text-sm">{{ embed_description }}</h3></div><div class="mt-5"><p class="text-grey-darker text-xs">{{ embed_site }}</p></div></div><div class="relative flex flew-row h-40 w-60"><div class="lazy absolute inset-0 bg-cover bg-center" data-bg="https://miro.medium.com/v2/resize:fit:320/{{ paragraph.mixtapeMetadata.thumbnailImageId }}"></div></div></div> </a></div>'
)
if paragraph.get("mixtapeMetadata") is not None:
url = paragraph["mixtapeMetadata"]["href"]
@ -437,7 +437,7 @@ class MediumParser:
out_paragraphs.append(embed_template_rendered)
elif paragraph["type"] == "IFRAME":
iframe_template = jinja_env.from_string(
'<div class="mt-7"><iframe class="lazy w-full h-full" data-src="{{ host_address }}/render_iframe/{{ iframe_id }}" allowfullscreen="" frameborder="0" scrolling="no"></iframe></div>'
'<div class="mt-7"><iframe class="lazy w-full" data-src="{{ host_address }}/render_iframe/{{ iframe_id }}" allowfullscreen="" frameborder="0" scrolling="no"></iframe></div>'
)
iframe_template_rendered = await iframe_template.render_async(host_address=self.host_address, iframe_id=paragraph["iframe"]["mediaResource"]["id"])
out_paragraphs.append(iframe_template_rendered)

View file

@ -49,7 +49,7 @@ KNOWN_MEDIUM_DOMAINS = (
"towardsdatascience.com",
"thetaoist.online",
"devopsquare.com",
"www.laceydearie.com",
"laceydearie.com",
"bettermarketing.pub",
"itnext.io",
"eand.co",
@ -72,23 +72,20 @@ NOT_MEDIUM_DOMAINS = (
"yandex.ru",
"yandex.kz",
"youtube.com",
"www.nytimes.com",
"nytimes.com",
"wsj.com",
"www.forbes.com",
"www.wsj.com",
"reddit.com",
"elpais.com",
"forbes.com",
"bloomberg.com",
"www.lesechos.fr",
"www.otz.de",
"www.businessinsider.com",
"lesechos.fr",
"otz.de",
"businessinsider.com",
"buff.ly",
"www.delish.com",
"www.economist.com",
"www.wired.com",
"www.rollingstone.com",
"delish.com",
"economist.com",
"wired.com",
"rollingstone.com",
)
@ -138,7 +135,7 @@ def get_unix_ms() -> int:
return milliseconds_since_epoch
def unquerify_url(url):
def unquerify_url(url: str) -> str:
"""
Sanitizes a URL by removing all query parameters.
@ -157,6 +154,13 @@ def unquerify_url(url):
return sanitized_url.removesuffix("/")
@lru_cache(maxsize=500)
def un_wwwify(url: str):
if url.startswith("www."):
return url.removeprefix("www.")
return url
def correct_url(url: str) -> str:
# Workaround for Safari bug. We don't known by what condition this happens, but sometimes we get
# some broken URL, for example like "", and all of them based on user-agent comes from Safari browser engine,
@ -247,12 +251,13 @@ async def resolve_medium_short_link(short_url_id: str, timeout: int = 5) -> str:
async def resolve_medium_url(url: str, timeout: int = 5) -> str:
logger.debug(f"Trying resolve {url=}, with {timeout=}")
parsed_url = urlparse(url)
parsed_netloc = un_wwwify(parsed_url.netloc)
if parsed_url.path.startswith("/p/"):
logger.debug("URL is Medium 'mobile' link")
post_id = parsed_url.path.rsplit("/p/")[1]
elif parsed_url.netloc == "l.facebook.com" and parsed_url.path.startswith("/l.php"):
elif parsed_netloc == "l.facebook.com" and parsed_url.path.startswith("/l.php"):
logger.debug("URL seems like is Facebook redirect (tracking) link")
parsed_query = parse_qs(parsed_url.query)
@ -263,7 +268,7 @@ async def resolve_medium_url(url: str, timeout: int = 5) -> str:
logger.debug("...but we get fucked up...")
return False
elif parsed_url.netloc == "webcache.googleusercontent.com" and parsed_url.path.startswith("/search"):
elif parsed_netloc == "webcache.googleusercontent.com" and parsed_url.path.startswith("/search"):
logger.debug("URL seems like is Google Web Archive page link")
parsed_query = parse_qs(parsed_url.query)
@ -274,7 +279,7 @@ async def resolve_medium_url(url: str, timeout: int = 5) -> str:
logger.debug("...but we get fucked up...")
return False
elif parsed_url.netloc == "www.google.com" and parsed_url.path.startswith("/url"):
elif parsed_netloc == "google.com" and parsed_url.path.startswith("/url"):
logger.debug("URL seems like is Google redirect (tracking) link")
parsed_query = parse_qs(parsed_url.query)
@ -290,7 +295,7 @@ async def resolve_medium_url(url: str, timeout: int = 5) -> str:
logger.debug("...but we get fucked up...")
return False
elif parsed_url.netloc == "12ft.io":
elif parsed_netloc == "12ft.io":
logger.debug("URL seems like is from our partner named 12ft.io")
parsed_query = parse_qs(parsed_url.query)
@ -314,7 +319,7 @@ async def resolve_medium_url(url: str, timeout: int = 5) -> str:
logger.debug("...but we get fucked up...")
return False
elif parsed_url.netloc == "link.medium.com":
elif parsed_netloc == "link.medium.com":
logger.debug("URL seems like is Medium short (SHORT) redirect (tracking) link. Make resolve them...")
short_url_id = parsed_url.path.removeprefix("/")
post_url = await resolve_medium_short_link(short_url_id, timeout)
@ -337,13 +342,16 @@ async def resolve_medium_url_old(url: str, timeout: int = 5) -> str:
retry_client = RetryClient(client_session=session, raise_for_status=False, retry_options=retry_options)
request = await retry_client.get(url, timeout=timeout)
response = await request.text()
soup = BeautifulSoup(response, "html.parser")
type_meta_tag = soup.head.find("meta", property="og:type")
if not type_meta_tag or type_meta_tag.get("content") != "article":
return False
url_meta_tag = soup.head.find("meta", property="al:android:url")
if not url_meta_tag or not url_meta_tag.get("content"):
return False
parsed_url = urlparse(url_meta_tag["content"])
path = parsed_url.path.strip("/")
parsed_value = path.split("/")[-1]
@ -394,16 +402,17 @@ async def is_valid_medium_url(url: str) -> bool:
"""
domain = get_fld(url)
parsed_url = urlparse(url)
domain_netloc = un_wwwify(parsed_url.netloc)
# TODO: http://freedium.cfd/https://www.google.com.vn/url?sa=i&url=https%3A%2F%2Fmedium.com%2F%40dugguRK%2Fabout-android-hardware-abstraction-layer-hal-5d191dafeb2c&psig=AOvVaw17KP0U_haPMmhAByeMTxSg&ust=1711354113283000&source=images&cd=vfe&opi=89978449&ved=0CBQQjhxqFwoTCMCM_oG5jIUDFQAAAAAdAAAAABAa
if domain in ["12ft.io", "google.com", "facebook.com", "googleusercontent.com"]:
return True
if domain in NOT_MEDIUM_DOMAINS or parsed_url.netloc in NOT_MEDIUM_DOMAINS:
if domain in NOT_MEDIUM_DOMAINS or domain_netloc in NOT_MEDIUM_DOMAINS:
raise exceptions.NotValidMediumURL("100% not valid Medium URL")
if domain in KNOWN_MEDIUM_DOMAINS or parsed_url.netloc in KNOWN_MEDIUM_CUSTOM_DOMAINS:
if domain in KNOWN_MEDIUM_DOMAINS or domain_netloc in KNOWN_MEDIUM_CUSTOM_DOMAINS:
return True
logger.warning(f"url '{url}' wasn't detected in known Medium domains")
@ -411,7 +420,7 @@ async def is_valid_medium_url(url: str) -> bool:
# XXX: Unfourtunately, for now we don't know ALL Medium's domains, so we need resolve links
resolve_result = bool(await resolve_medium_url(url))
# send_message(f"We found that {domain=}, {parsed_url.netloc=} is not listed in out known Medium database.\nURL: {url}")
# send_message(f"We found that {domain=}, {domain_netloc=} is not listed in out known Medium database.\nURL: {url}")
return resolve_result

View file

@ -34,6 +34,7 @@ services:
# - ./.env:/app/.env
# - ./server/user_data/logs:/app/server/user_data/logs
- .:/app
- ./core/medium_parser/:/app/medium_parser
develop:
watch:
- action: rebuild
@ -65,23 +66,23 @@ services:
restart: always
mem_limit: 2g
dragonfly:
image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
ulimits:
memlock: -1
expose:
- 6379
networks:
- web_network
volumes:
- dragonflydata:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
start_period: 20s
timeout: 10s
retries: 3
restart: always
# dragonfly:
# image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
# ulimits:
# memlock: -1
# expose:
# - 6379
# networks:
# - web_network
# volumes:
# - dragonflydata:/data
# healthcheck:
# test: ["CMD", "redis-cli", "ping"]
# interval: 30s
# start_period: 20s
# timeout: 10s
# retries: 3
# restart: always
autoheal:
restart: always

View file

@ -4,8 +4,9 @@ from fastapi import Response
from server import config
from server.utils.logger_trace import trace
IFRAME_HEADERS = {"Access-Control-Allow-Origin": "*", "X-Frame-Options": "SAMEORIGIN"}
from bs4 import BeautifulSoup, Comment
IFRAME_HEADERS = {"Access-Control-Allow-Origin": "*", "X-Frame-Options": "SAMEORIGIN"}
@trace
async def iframe_proxy(iframe_id):
@ -17,8 +18,15 @@ async def iframe_proxy(iframe_id):
headers={"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"},
)
request_content = await request.text()
request_content = request_content.replace("document.domain = document.domain", "console.log('[FREEDIUM] iframe workaround')")
return Response(content=request_content, media_type="text/html", headers=IFRAME_HEADERS)
request_content = request_content.replace("document.domain = document.domain", 'console.log("[FREEDIUM] iframe workaround started")')
request_content_soup = BeautifulSoup(request_content, "html.parser")
iframe_hack_script = '<script src="https://cdn.jsdelivr.net/npm/@iframe-resizer/child"></script>'
new_script_tag = BeautifulSoup(iframe_hack_script, 'html.parser').script
request_content_soup.head.append(new_script_tag)
return Response(content=request_content_soup.prettify(), media_type="text/html", headers=IFRAME_HEADERS)
@trace
@ -31,4 +39,4 @@ async def miro_proxy(miro_data: str):
)
request_content = await request.read()
content_type = request.headers["Content-Type"]
return Response(content=request_content, media_type=content_type)
return Response(content=request_content, media_type=content_type)

View file

@ -8,8 +8,9 @@
{% if creator %}<meta name="author" content="{{ creator.name }}" />{% endif %}
<meta name="description" content="{{ description or 'Your paywall breakthrough for Medium!' }}" />
<meta name="keywords" content="medium, paywall, medium.com, paywall breakthrough" />
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
<!--<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>-->
<link href="https://glyph.medium.com/css/unbound.css" rel="stylesheet">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
@ -18,77 +19,13 @@
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9">
<meta name="msapplication-TileColor" content="#00aba9">
<meta name="theme-color" content="#ffffff">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.8.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
<script src="https://cdn.jsdelivr.net/npm/@iframe-resizer/parent"></script>
<script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.8.4/dist/lazyload.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lightense-images@1.0.17/dist/lightense.min.js"></script>
<script>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
//document.getElementById('darkIcon').classList.remove('hidden');
//document.getElementById('lightIcon').classList.add('hidden')
} else {
document.documentElement.classList.remove('dark')
//document.getElementById('lightIcon').classList.remove('hidden');
//document.getElementById('darkIcon').classList.add('hidden');
}
</script>
<style>
.overflow-hidden {
overflow: hidden !important;
}
.shadow-lf {
box-shadow: inset 3px 0 0 0 rgb(209 207 239 / var(--tw-bg-opacity));
}
</style>
<style>
.notification-container {
display: none;
position: fixed;
top: 20px;
padding: 2%;
max-height: 95vh; /* Set a maximum height for the container */
overflow-y: auto; /* Enable vertical scrolling */
}
.notification-card {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
border-radius: 5px;
text-align: center;
}
</style>
<script>
window._resizeIframe = function (iframeData)
{
iframeData.iframe.height = iframeData.height
_resizeIframeWidth()
}
function _resizeIframeWidth(){ var element = document.querySelector(".main-content");
var width = element.offsetWidth;
iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
iframes[i].width = width
}
window.onresize = _resizeIframeWidth
}
</script>
<!--
<script>
window.onload = function() {
window.parent.postMessage({
type: "URL_UPDATE",
url: window.location.href
}, "*");
}
</script>
-->
<script>iframeResize({ license: 'GPLv3' })</script>
</head>
<div class="fixed bottom-4 left-4" style="z-index: 999999;">
<button id="openProblemModal"
@ -111,8 +48,8 @@
</svg>
</button>
</div>
<div class="notification-container" style="z-index: 999999;">
<div class="notification-card dark:bg-gray-800 bg-white">
<div class="notification-container fixed top-5 p-2 max-h-[95vh] overflow-y-auto hidden" style="z-index: 999999;">
<div class="bg-white border border-gray-300 shadow-sm p-5 rounded-md text-center dark:bg-gray-800 bg-white">
<p class="text-2xl pb-5 text-black dark:text-white">Bad news</p>
<p class="pb-3 text-black dark:text-white">
We regret to inform you that our account on BuyMeACoffee has been suspended due to a violation of their terms of service. This was an unexpected development, and we are currently addressing the matter with utmost priority.
@ -203,7 +140,7 @@ Warm regards, The Freedium Team
class="modal hidden fixed inset-0 w-full h-full flex items-center justify-center overflow-y-auto bg-black bg-opacity-50"
style="z-index: 999999">
<div class="modal-container w-11/12 md:max-w-xl mx-auto rounded shadow-lg max-h-screen">
<div class="modal-content bg-white dark:bg-gray-800 dark:text-white my-8 py-4 text-left px-6">
<div class="modal-content bg-white dark:bg-gray-800 text-black dark:text-white my-8 py-4 text-left px-6">
<h1 class="text-3xl font-bold">Reporting a Problem</h1>
<div class="mt-3">
<p>
@ -238,35 +175,59 @@ Warm regards, The Freedium Team
darkMode: 'class',
}
function navigateToOrigin() {
window.location.href = window.location.origin;
}
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
// document.documentElement.classList.add('dark');
document.getElementById('darkIcon').classList.remove('hidden');
document.getElementById('lightIcon').classList.add('hidden')
} else {
// document.documentElement.classList.remove('dark')
document.getElementById('lightIcon').classList.remove('hidden');
document.getElementById('darkIcon').classList.add('hidden');
function changeTheme(themeName) {
// Source: https://stackoverflow.com/questions/59257368/how-to-dynamically-change-the-theme-using-highlight-js
console.log(`Applying theme: ${themeName}`);
const existingLink = document.querySelector('link[href*="highlight.js"]');
if (existingLink) {
existingLink.remove();
}
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/${themeName}.min.css`;
document.head.appendChild(link);
document.querySelector("span").textContent = themeName;
}
function navigateToOrigin() {
window.location.href = window.location.origin;
}
function updateThemeIcons() {
const isDarkMode = localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.getElementById('darkIcon').classList.toggle('hidden', !isDarkMode);
document.getElementById('lightIcon').classList.toggle('hidden', isDarkMode);
}
document.getElementById('darkModeToggle').addEventListener('click', function() {
updateThemeIcons();
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.remove('dark');
document.getElementById('darkIcon').classList.add('hidden');
document.getElementById('lightIcon').classList.remove('hidden')
document.documentElement.style.cssText = "--lightense-backdrop: white;";
localStorage.setItem("theme", "light")
} else {
document.documentElement.classList.add('dark')
document.getElementById('lightIcon').classList.add('hidden');
document.getElementById('darkIcon').classList.remove('hidden');
document.documentElement.style.cssText = "--lightense-backdrop: black;";
localStorage.setItem("theme", "dark")
}
});
document.getElementById('darkModeToggle').addEventListener('click', function () {
const isDarkMode = localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (isDarkMode) {
document.documentElement.classList.remove('dark');
document.documentElement.style.cssText = "--lightense-backdrop: white;";
localStorage.setItem("theme", "light");
changeTheme("a11y-light");
} else {
document.documentElement.classList.add('dark');
document.documentElement.style.cssText = "--lightense-backdrop: black;";
localStorage.setItem("theme", "dark");
changeTheme("androidstudio");
}
updateThemeIcons();
})
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
//document.getElementById('darkIcon').classList.remove('hidden');
//document.getElementById('lightIcon').classList.add('hidden')
changeTheme("androidstudio");
} else {
document.documentElement.classList.remove('dark')
//document.getElementById('lightIcon').classList.remove('hidden');
//document.getElementById('darkIcon').classList.add('hidden');
changeTheme("a11y-light");
}
</script>
<script>
const openModalButton = document.getElementById('openProblemModal');
@ -277,19 +238,19 @@ if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.match
const body = document.querySelector('body');
openModalButton.addEventListener('click', () => {
body.classList.add('overflow-hidden'); // Prevent scrolling on the body
body.classList.add('!overflow-hidden'); // Prevent scrolling on the body
modal.classList.remove('hidden');
});
closeModalButton.addEventListener('click', () => {
body.classList.remove('overflow-hidden'); // Re-enable scrolling on the body
body.classList.remove('!overflow-hidden'); // Re-enable scrolling on the body
modal.classList.add('hidden');
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.add('hidden');
body.classList.remove('overflow-hidden');
body.classList.remove('!overflow-hidden');
}
});
@ -360,22 +321,41 @@ document.addEventListener('scroll', function () {
Lightense('img:not(.no-lightense)');
}, false);
</script>
</body>
</html>
<script>
var lazyLoadInstance = new LazyLoad({
callback_loaded: function(element) {
Lightense(element);
},
callback_error: (img) => {
console.log(img);
if (img.hasAttribute("data-src")) {
if (img.attributes["data-src"].value.startsWith("https://miro.medium.com/v2/")) {
img.setAttribute("src", img.attributes["data-src"].value.replace("https://miro.medium.com/v2/", "{{HOST_ADDRESS}}/@miro/v2/" ));
}
}
}
});
console.log(element);
console.log(element.tagName);
switch (element.tagName) {
case "IMG":
console.log(`${element} is image, wrapping into lightense`);
Lightense(element);
break;
case "IFRAME":
const resizeIframe = () => {
console.log(`${element} is iframe, wrapping script`);
let iframeHeight = element.contentWindow.document.body.scrollHeight;
if (iframeHeight == 150) {
iframeHeight = 500;
}
element.style.height = iframeHeight + 'px';
};
window.addEventListener('resize', resizeIframe);
setInterval(resizeIframe, 4500);
resizeIframe();
break;
}
},
callback_error: (element) => {
console.log(element);
if (element.tagName === "IMG" && element.hasAttribute("data-src")) {
const srcAttribute = element.attributes["data-src"].value;
if (srcAttribute.startsWith("https://miro.medium.com/v2/")) {
element.setAttribute("src", srcAttribute.replace("https://miro.medium.com/v2/", "{{HOST_ADDRESS}}/@miro/v2/"));
}
}
}
});
</script>
<script>
function navigateToOrigin() {
@ -392,14 +372,14 @@ document.addEventListener('scroll', function () {
function showNotification() {
if (!localStorage.getItem(notificationFlagString)) {
notificationContainer.style.display = 'block';
body.classList.add('overflow-hidden');
body.classList.add('!overflow-hidden');
}
}
function hideNotification() {
localStorage.setItem(notificationFlagString, 'false');
notificationContainer.style.display = 'none';
body.classList.remove('overflow-hidden');
body.classList.remove('!overflow-hidden');
}
// Close button functionality
@ -410,3 +390,6 @@ document.addEventListener('scroll', function () {
showNotification();
});
</script>
</body>
</html>

View file

@ -90,9 +90,9 @@ document.addEventListener('DOMContentLoaded', (event) => {
hljs.highlightAll();
document.querySelectorAll('pre code').forEach((el) => {
code = el.textContent;
el = el.parentElement;
el.innerHTML = '<button class="hljs-copy p-1 bg-gray-300 dark:bg-black">Copy</button>' + el.innerHTML; // append copy button
code = el.textContent;
el = el.parentElement;
el.innerHTML = '<button class="hljs-copy p-1 bg-gray-300 dark:bg-zinc-800">Copy</button>' + el.innerHTML; // append copy button
el.getElementsByClassName('hljs-copy')[0].contentCopy = code;
el.getElementsByClassName('hljs-copy')[0].addEventListener("click", function () {
this.innerText = 'Copying..';

View file

@ -30,10 +30,9 @@ def enable_maintenance_mode():
def do_maintenance(sleep_time: int = 60 * 60 * 24):
while True:
sleep(sleep_time)
try:
enable_maintenance_mode()
except Exception as e:
logger.error(f"Error enabling maintenance mode: {e}")
send_message(f"Error enabling maintenance mode: {e}")
finally:
sleep(sleep_time)