Created
March 29, 2024 06:49
-
-
Save dreness/6ecb67e4795dd0dc42a148493ef42e15 to your computer and use it in GitHub Desktop.
Favicon Force-feeder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import http.server | |
import socketserver | |
import random | |
import os | |
import uuid | |
from http import HTTPStatus | |
''' | |
I wanted a quick way to spawn a bunch of Safari tabs with distinct favicons, so made a little webserver | |
to rotate through some PNGs. A substantially smaller program was sufficient for Chrome, which does what | |
I expect when I manually reload a page. | |
Safari loads the favicon once per window, regardless of the number of tabs or reload attempts, because | |
Safari assumes it's safe to re-use. An 'empty cache' yields one subsequent favicon load. More importantly, | |
Safari looks down at you for having the temerity to engage in what might be deemed 'wasteful' behavior by | |
trying to generate a bunch of 'useless' network traffic, so your commands are silently degraded. | |
Anywho, to get Safari to load a distinct favicon in each tab, it's not enough to advertise a unique favicon | |
name in the rel="icon" link, you also need each tab to use a unique request URI. | |
''' | |
PORT = 9876 | |
FAVICONS_DIR = "/Users/andre/Desktop/stuff/favs_48" # Directory where your PNG images are stored | |
class MyWebServer(http.server.SimpleHTTPRequestHandler): | |
def do_GET(self): | |
if self.path == '/': | |
self.redirect_to_uuid() | |
elif self.path.endswith('.ico'): | |
self.next_favicon() | |
else: | |
self.serve_main_page() | |
def redirect_to_uuid(self): | |
# Generate a fresh UUID | |
new_path = '/' + str(uuid.uuid4()) | |
self.send_response(HTTPStatus.FOUND) | |
self.send_header("Location", new_path) | |
self.end_headers() | |
def serve_main_page(self): | |
# Serve a simple HTML page with a title and a favicon | |
# Use in-line css to make the text large, with a nice font. | |
favname = '/' + str(uuid.uuid4()) | |
content = """ | |
<html> | |
<head> | |
<title>MyFavs!</title> | |
<link rel="icon" type="image/png" href="http://127.0.0.1:9876{favname}.ico"> | |
<style> | |
h1 {{ | |
font-family: 'Arial', sans-serif; | |
font-size: 1em; | |
color: #333; | |
text-align: center; | |
margin-top: 20vh; | |
}} | |
a {{ | |
color: #007bff; | |
text-decoration: none; | |
}} | |
a:hover {{ | |
text-decoration: underline; | |
}} | |
</style> | |
</head> | |
<body> | |
<h1>Press on it for a random <a href="/" target="_blank">favicon</a>!</h1> | |
</body> | |
</html> | |
""".format(favname=favname) | |
content = bytes(content, 'utf-8') | |
self.send_response(HTTPStatus.OK) | |
self.send_header("Content-type", "text/html; charset=utf-8") | |
self.end_headers() | |
self.wfile.write(content) | |
def next_favicon(self): | |
try: | |
# Select the next favicon file | |
global n | |
n += 1 | |
if n >= len(files): | |
n = 0 | |
favicon_path = os.path.join(FAVICONS_DIR, files[n]) | |
# Read and serve the selected file | |
with open(favicon_path, 'rb') as file: | |
self.send_response(HTTPStatus.OK) | |
self.send_header("Content-type", "image/png") | |
self.end_headers() | |
self.wfile.write(file.read()) | |
# log the name of the file we sent | |
print(f"Sent favicon: {favicon_path}") | |
except Exception as e: | |
self.send_error(HTTPStatus.INTERNAL_SERVER_ERROR, f"Error serving favicon: {e}") | |
httpd = socketserver.TCPServer(("", PORT), MyWebServer) | |
print(f"Serving at port {PORT}") | |
# List all PNG files in the specified directory | |
files = [f for f in os.listdir(FAVICONS_DIR) if f.endswith('.png')] | |
if not files: | |
raise FileNotFoundError("No PNG files found in the directory") | |
n = 0 | |
httpd.serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment