init tmp homepage template
@@ -0,0 +1 @@
|
|||||||
|
.venv
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
FROM nginx:1.31.3
|
||||||
|
COPY src /usr/share/nginx/html
|
||||||
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 229 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 190 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 241 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 176 KiB |
|
After Width: | Height: | Size: 308 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 372 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 494 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 231 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 245 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 333 KiB |
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 252 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 215 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 289 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 233 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 263 KiB |
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 179 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>EBUSMPTE temp homepage</title>
|
||||||
|
<link rel="stylesheet" href="main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="content">
|
||||||
|
<p> Good night, sweet <s>jitten.site</s> addinput.ru </p>
|
||||||
|
<img id="comic-img" alt="Random Comic" />
|
||||||
|
</section>
|
||||||
|
<script src="main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: #1e1e2e;
|
||||||
|
color: #cdd6f4;
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column; /* Stacks image and text vertically */
|
||||||
|
align-items: center; /* Centers image and text horizontally inside .content */
|
||||||
|
justify-content: center;/* Centers content vertically if .content has a fixed height */
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
const comics = [
|
||||||
|
'250th-independence-day-stonetoss-comic.png',
|
||||||
|
'SPLC-fraud-stonetoss-comic.png',
|
||||||
|
'ai-golem-stonetoss-comic.png',
|
||||||
|
'ai-job-replacement-stonetoss-comic.png',
|
||||||
|
'ai-slop-stonetoss-comic.png',
|
||||||
|
'ai-stealing-stonetoss-comic.png',
|
||||||
|
'ai-underclass-stonetoss-comic.png',
|
||||||
|
'air-conditioning-stonetoss-comic.png',
|
||||||
|
'backrooms-movie-stonetoss-comic.png',
|
||||||
|
'capn-crunch-cereal-stonetoss-comic.png',
|
||||||
|
'christian-denominations-stonetoss-comic.png',
|
||||||
|
'chudjak-easter-stonetoss-comic.png',
|
||||||
|
'crab-rangoon-stonetoss-comic.png',
|
||||||
|
'data-center-stonetoss-comic.png',
|
||||||
|
'diarrhea-produce-stonetoss-comic.png',
|
||||||
|
'easter-the-amazing-digital-circus-stonetoss-comic.png',
|
||||||
|
'fallout-iran-war-stonetoss-comic.png',
|
||||||
|
'flock-camera-stonetoss-comic.png',
|
||||||
|
'god-emperor-and-monitoring-the-situation-stonetoss-comic.png',
|
||||||
|
'halo-female-marine-stonetoss-comic.png',
|
||||||
|
'hantavirus-stonetoss-comic.png',
|
||||||
|
'immigration-wages-stonetoss-comic.png',
|
||||||
|
'invincible-animation-ai-stonetoss-comic.png',
|
||||||
|
'invincible-race-mixing-stonetoss-comic.png',
|
||||||
|
'invincible-stonetoss-comic.png',
|
||||||
|
'iran-negotiations-stonetoss-comic.png',
|
||||||
|
'iran-war-midterms-stonetoss-comic.png',
|
||||||
|
'israel-iran-gas-prices-stonetoss-comic.png',
|
||||||
|
'jango-fett-stonetoss-comic.png',
|
||||||
|
'mcdonalds-self-serve-sodas-stonetoss-comic.png',
|
||||||
|
'obsession-movie-stonetoss-comic.png',
|
||||||
|
'old-and-new-testament-stonetoss-comic.png',
|
||||||
|
'pokemon-scalpers-stonetoss-comic.png',
|
||||||
|
'psychiatry-stonetoss-comic.png',
|
||||||
|
'punch-monkey-stonetoss-comic.png',
|
||||||
|
'refugees-japanese-stonetoss-comic.png',
|
||||||
|
'streamer-simps-stonetoss-comic.png',
|
||||||
|
'synthetic-data-stonetoss-comic.png',
|
||||||
|
'the-amazing-digital-circus-film-stonetoss-comic.png',
|
||||||
|
'the-odyssey-stonetoss-comic.png',
|
||||||
|
'transgender-genie-stonetoss-comic.png',
|
||||||
|
'trump-assassin-stonetoss-comic.png',
|
||||||
|
'trump-china-wall-stonetoss-comic.png',
|
||||||
|
'urban-living-stonetoss-comic.png',
|
||||||
|
'war-with-iran-israel-stonetoss-comic.png',
|
||||||
|
'war-with-iran-stonetoss-comic.png',
|
||||||
|
'women-literature-stonetoss-comic.png',
|
||||||
|
'womens-chess-stonetoss-comic.png',
|
||||||
|
'x-men-sentinel-stonetoss-comic.png',
|
||||||
|
'yuri-stonetoss-comic.png'
|
||||||
|
];
|
||||||
|
|
||||||
|
const randomIndex = Math.floor(Math.random() * comics.length);
|
||||||
|
const imgElement = document.getElementById('comic-img');
|
||||||
|
imgElement.src = `img/comic/${comics[randomIndex]}`;
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
from time import sleep
|
||||||
|
from urllib.parse import urlparse, urljoin
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def download_comic(url, download_dir):
|
||||||
|
"""Download a comic and return the previous comic URL"""
|
||||||
|
if not url:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Fetch the page
|
||||||
|
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
|
||||||
|
response = requests.get(url, headers=headers, timeout=15)
|
||||||
|
response.raise_for_status()
|
||||||
|
html_text = response.text
|
||||||
|
except requests.RequestException as e:
|
||||||
|
print(f"❌ Error fetching {url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
soup = BeautifulSoup(html_text, "html.parser")
|
||||||
|
|
||||||
|
# Get previous comic URL
|
||||||
|
prev_link = soup.find("a", class_="previous-comic", href=True)
|
||||||
|
if prev_link is None:
|
||||||
|
print("⚠️ No previous comic link found (might be the first comic)")
|
||||||
|
return None
|
||||||
|
|
||||||
|
prev_url = prev_link["href"]
|
||||||
|
# Make absolute URL if needed
|
||||||
|
if not prev_url.startswith('http'):
|
||||||
|
prev_url = urljoin(url, prev_url)
|
||||||
|
print(f"🔗 Previous: {prev_url}")
|
||||||
|
|
||||||
|
# Find comic image in spliced-comic div
|
||||||
|
comic_div = soup.find("div", {"id": "spliced-comic"})
|
||||||
|
if comic_div is None:
|
||||||
|
print("❌ Can't find div#spliced-comic")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
img_tag = comic_div.find("img")
|
||||||
|
if img_tag is None:
|
||||||
|
print("❌ No img tag found in div#spliced-comic")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
img_url = img_tag.get("src") or img_tag.get("data-src")
|
||||||
|
if not img_url:
|
||||||
|
print("❌ No src or data-src attribute found")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
# Make absolute URL
|
||||||
|
if not img_url.startswith('http'):
|
||||||
|
img_url = urljoin(url, img_url)
|
||||||
|
|
||||||
|
print(f"🖼️ Image: {img_url}")
|
||||||
|
|
||||||
|
# Download the image
|
||||||
|
try:
|
||||||
|
img_data = requests.get(img_url, headers=headers, timeout=30)
|
||||||
|
img_data.raise_for_status()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
print(f"❌ Failed to download image: {e}")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
# Create download directory if it doesn't exist
|
||||||
|
os.makedirs(download_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Get filename from URL
|
||||||
|
parsed_url = urlparse(img_url)
|
||||||
|
filename = os.path.basename(parsed_url.path)
|
||||||
|
|
||||||
|
# If filename is empty or has no extension, create one
|
||||||
|
if not filename or '.' not in filename:
|
||||||
|
filename = f"comic_{len(os.listdir(download_dir)) + 1:03d}.jpg"
|
||||||
|
|
||||||
|
# Save the file
|
||||||
|
filepath = os.path.join(download_dir, filename)
|
||||||
|
|
||||||
|
# Check if file already exists
|
||||||
|
if os.path.exists(filepath):
|
||||||
|
print(f"⏭️ {filename} already exists, skipping")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filepath, "wb") as handler:
|
||||||
|
handler.write(img_data.content)
|
||||||
|
print(f"✅ {filename} downloaded ({len(img_data.content)} bytes)")
|
||||||
|
except IOError as e:
|
||||||
|
print(f"❌ Failed to save {filename}: {e}")
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
return prev_url
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("╔═══════════════════════════════════╗")
|
||||||
|
print("║ StoneToss Comic Downloader ║")
|
||||||
|
print("╚═══════════════════════════════════╝")
|
||||||
|
print()
|
||||||
|
|
||||||
|
url = "https://stonetoss.com/"
|
||||||
|
download_dir = "comic"
|
||||||
|
max_comics = 50
|
||||||
|
downloaded = 0
|
||||||
|
|
||||||
|
print(f"📚 Downloading up to {max_comics} comics...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
for i in range(max_comics):
|
||||||
|
print(f"[{i+1}/{max_comics}] Processing...")
|
||||||
|
|
||||||
|
# Download the comic and get the previous URL
|
||||||
|
prev_url = download_comic(url, download_dir)
|
||||||
|
|
||||||
|
if prev_url is None:
|
||||||
|
print("🏁 Reached the first comic or encountered an error")
|
||||||
|
break
|
||||||
|
|
||||||
|
downloaded += 1
|
||||||
|
url = prev_url
|
||||||
|
sleep(1) # Be nice to the server
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("╔═══════════════════════════════════╗")
|
||||||
|
print(f"║ ✅ Downloaded {downloaded} comics ║")
|
||||||
|
print(f"║ 📁 Saved to: ./{download_dir}/ ║")
|
||||||
|
print("╚═══════════════════════════════════╝")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n⏹️ Interrupted by user")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ Unexpected error: {e}")
|
||||||
|
sys.exit(1)
|
||||||