niconico-gay/app.py

86 lines
2.8 KiB
Python
Raw Normal View History

2025-01-31 12:57:32 -05:00
import http.cookiejar
import json
2025-01-31 12:37:28 -05:00
import requests
from bs4 import BeautifulSoup
2025-01-31 14:26:14 -05:00
from flask import Flask, Response
from diskcache import Cache
2025-01-31 14:32:19 -05:00
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
2025-01-31 12:37:28 -05:00
app = Flask(__name__)
2025-01-31 12:57:32 -05:00
2025-01-31 14:26:14 -05:00
CACHE_EXPIRATION_SECONDS = 3600 # 1 hour
CACHE_SIZE_LIMIT = 100 * 1024 * 1024 # 100 MB
cache = Cache("disk_cache", size_limit=CACHE_SIZE_LIMIT)
2025-01-31 12:57:32 -05:00
cookie_jar = http.cookiejar.MozillaCookieJar('cookies.txt')
try:
cookie_jar.load(ignore_discard=True, ignore_expires=True)
except FileNotFoundError:
2025-01-31 14:32:19 -05:00
logger.warning("cookies.txt not found, starting with empty cookie jar")
2025-01-31 12:57:32 -05:00
2025-01-31 12:37:28 -05:00
s = requests.Session()
s.headers.update({
"User-Agent": "Twitterbot/1.0"
})
2025-01-31 12:57:32 -05:00
s.cookies = cookie_jar # type: ignore
2025-01-31 12:37:28 -05:00
@app.route("/watch/<video_id>")
def proxy(video_id):
2025-01-31 14:32:19 -05:00
logger.info(f"Received request for video ID: {video_id}")
2025-01-31 14:26:14 -05:00
cached_html = cache.get(video_id)
if cached_html is not None:
2025-01-31 14:32:19 -05:00
logger.info(f"Using cached response for video ID: {video_id}")
2025-01-31 14:26:14 -05:00
return Response(cached_html, mimetype="text/html") # type: ignore
2025-01-31 12:37:28 -05:00
2025-01-31 14:26:14 -05:00
# Not in cache or cache expired; fetch from nicovideo.jp
real_url = f"https://www.nicovideo.jp/watch/{video_id}"
2025-01-31 12:37:28 -05:00
try:
2025-01-31 14:32:19 -05:00
logger.info(f"Fetching content from URL: {real_url}")
2025-01-31 12:37:28 -05:00
r = s.get(real_url, timeout=10)
except requests.RequestException as e:
2025-01-31 14:32:19 -05:00
logger.error(f"Error fetching the page for video ID '{video_id}': {e}")
return Response(status=500)
2025-01-31 12:37:28 -05:00
soup = BeautifulSoup(r.text, "html.parser")
thumbnail_url = None
2025-01-31 14:19:01 -05:00
try:
2025-01-31 14:26:14 -05:00
server_response = soup.find("meta", {"name": "server-response"})
if server_response:
params = json.loads(server_response["content"])["data"]["response"] # type: ignore
thumbnail_url = (
params["video"]["thumbnail"].get("ogp") or
params["video"]["thumbnail"].get("player") or
params["video"]["thumbnail"].get("largeUrl") or
params["video"]["thumbnail"].get("middleUrl") or
params["video"]["thumbnail"].get("url")
2025-01-31 14:19:01 -05:00
)
2025-01-31 14:32:19 -05:00
except (KeyError, json.JSONDecodeError) as e:
logger.warning(f"Failed to extract thumbnail info for video ID '{video_id}': {e}")
2025-01-31 14:19:01 -05:00
pass
2025-01-31 14:26:14 -05:00
og_tags = soup.find_all("meta", property=lambda x: x) # type: ignore
for tag in og_tags:
2025-01-31 14:19:01 -05:00
if tag.get("property") == "og:image" and thumbnail_url:
tag["content"] = thumbnail_url
2025-01-31 14:26:14 -05:00
2025-01-31 12:37:28 -05:00
og_tags_str = "\n".join(str(tag) for tag in og_tags)
html_response = f"""
<!DOCTYPE html>
<html lang="en">
<head>
2025-01-31 14:26:14 -05:00
<meta charset="UTF-8">
{og_tags_str}
2025-01-31 12:37:28 -05:00
</head>
<body>
</body>
</html>
"""
2025-01-31 14:26:14 -05:00
cache.set(video_id, html_response, expire=CACHE_EXPIRATION_SECONDS)
2025-01-31 12:37:28 -05:00
2025-01-31 14:26:14 -05:00
return Response(html_response, mimetype="text/html")