kemono2/src/pages/post.py
2025-04-02 16:32:47 +02:00

215 lines
9.0 KiB
Python

import datetime
import re
from pathlib import PurePath
from src.config import Configuration
from src.lib.artist import get_artist
from src.lib.post import (
get_fileserver_for_value,
get_post,
get_post_comments,
get_post_revisions,
get_posts_incomplete_rewards,
is_post_flagged,
patch_inline_img,
)
from src.lib.posts import Post
from src.utils.utils import images_pattern, sanitize_html
from flask import session
video_extensions = Configuration().webserver["ui"]["video_extensions"]
def ready_post_props(post: Post):
service = post["service"]
artist_id = post["user"]
post_id = post["id"]
if service in ("patreon",):
if post["file"] and post["attachments"] and post["file"] == post["attachments"][0]:
post["attachments"] = post["attachments"][1:]
if service in ("fansly", "onlyfans"):
posts_incomplete_rewards = get_posts_incomplete_rewards(post_id, artist_id, service)
if posts_incomplete_rewards:
post["incomplete_rewards"] = "This post is missing paid rewards from a higher tier or payment."
if post["service"] == "onlyfans":
try:
rewards_info_text = (
f"{posts_incomplete_rewards["incomplete_attachments_info"]["media_count"]} media, "
f"{posts_incomplete_rewards["incomplete_attachments_info"]["photo_count"]} photos, "
f"{posts_incomplete_rewards["incomplete_attachments_info"]["video_count"]} videos, "
f"for {posts_incomplete_rewards["incomplete_attachments_info"]["price"]}$."
)
post["incomplete_rewards"] += "\n" + rewards_info_text
except Exception:
pass
elif post["service"] == "fansly":
try:
rewards_info_text = (
f"Downloaded:{posts_incomplete_rewards["incomplete_attachments_info"]["complete"]} "
f"Missing:{posts_incomplete_rewards["incomplete_attachments_info"]["incomplete"]}"
)
post["incomplete_rewards"] += "\n" + rewards_info_text
except Exception:
pass
previews = []
attachments = []
videos = []
if "path" in post["file"]:
if images_pattern.search(post["file"]["path"]):
previews.append(
{
"type": "thumbnail",
"server": get_fileserver_for_value(f"/data{post["file"]["path"]}"),
"name": post["file"].get("name"),
"path": post["file"]["path"],
}
)
else:
file_extension = PurePath(post["file"]["path"]).suffix
name_extension = PurePath(post["file"].get("name") or "").suffix
# filename without extension
stem = PurePath(post["file"]["path"]).stem
attachments.append(
{
"server": get_fileserver_for_value(f"/data{post["file"]["path"]}"),
"name": post["file"].get("name"),
"extension": file_extension,
"name_extension": name_extension,
"stem": stem,
"path": post["file"]["path"],
}
)
if len(post.get("embed") or []):
previews.append(
{
"type": "embed",
"url": post["embed"]["url"],
"subject": post["embed"]["subject"],
"description": post["embed"]["description"],
}
)
for attachment in post["attachments"]:
if images_pattern.search(attachment["path"]):
previews.append(
{
"type": "thumbnail",
"server": get_fileserver_for_value(f"/data{attachment["path"]}"),
"name": attachment["name"],
"path": attachment["path"],
}
)
else:
file_extension = PurePath(attachment["path"]).suffix
name_extension = PurePath(attachment.get("name") or "").suffix
# filename without extension
stem = PurePath(attachment["path"]).stem
attachments.append(
{
"server": get_fileserver_for_value(f"/data{attachment["path"]}"),
"name": attachment.get("name"),
"extension": file_extension,
"name_extension": name_extension,
"stem": stem,
"path": attachment["path"],
}
)
for i, attachment in enumerate(attachments):
if attachment["extension"] in video_extensions:
videos.append(
{
"index": i,
"path": attachment["path"],
"name": attachment.get("name"),
"extension": attachment["extension"],
"name_extension": attachment["name_extension"],
"server": get_fileserver_for_value(f"/data{attachment["path"]}"),
}
)
if post.get("poll") is not None:
post["poll"]["total_votes"] = sum(choice["votes"] for choice in post["poll"]["choices"])
post["poll"]["created_at"] = datetime.datetime.fromisoformat(post["poll"]["created_at"])
if post["poll"]["closes_at"]:
post["poll"]["closes_at"] = datetime.datetime.fromisoformat(post["poll"]["closes_at"])
if (captions := post.get("captions")) is not None:
for file_hash, caption_data in captions.items():
for preview_data in [preview for preview in previews if preview.get("path") == file_hash]:
if isinstance(caption_data, dict):
preview_data["caption"] = caption_data.get("text") or ""
elif isinstance(caption_data, list):
preview_data["caption"] = " ".join(each.get("text") or "" for each in caption_data)
for video in [video for video in videos if video["path"] == file_hash]:
if isinstance(caption_data, dict):
video["caption"] = caption_data.get("text") or ""
elif isinstance(caption_data, list):
video["caption"] = " ".join(each.get("text") or "" for each in caption_data)
props = {
"service": service,
"artist": get_artist(service, artist_id),
"flagged": is_post_flagged(service, artist_id, post_id),
"revisions": get_post_revisions(service, artist_id, post_id),
}
real_post = post if not post.get("revision_id") else get_post(service, artist_id, post_id)
all_revisions = [real_post] + props["revisions"]
for set_prev_next_revision in (post, *props["revisions"]):
set_prev_next_revision["prev"] = real_post["prev"]
set_prev_next_revision["next"] = real_post["next"]
if props["revisions"]:
last_date = real_post["added"]
for i, rev in enumerate(all_revisions[:-1]):
rev["added"] = all_revisions[i + 1]["added"]
props["revisions"][-1]["added"] = last_date
if real_post["service"] == "fanbox":
top_rev_stripped = all_revisions[0].copy()
top_rev_stripped.pop("file")
top_rev_stripped.pop("added")
top_rev_stripped.pop("revision_id", None)
for fanbox_attachment in top_rev_stripped["attachments"]:
if 41 >= len(fanbox_attachment["name"]) >= 39:
fanbox_attachment.pop("name", None)
for duplicated_check_rev in all_revisions[1:]:
duplicated_check_rev_file_stripped = duplicated_check_rev.copy()
duplicated_check_rev_file_stripped.pop("file")
duplicated_check_rev_file_stripped.pop("added")
duplicated_check_rev_file_stripped.pop("revision_id", None)
for fanbox_attachment in duplicated_check_rev_file_stripped["attachments"]:
if 41 >= len(fanbox_attachment["name"]) >= 39:
fanbox_attachment.pop("name", None)
if duplicated_check_rev_file_stripped == top_rev_stripped:
all_revisions.remove(duplicated_check_rev)
else:
top_rev_stripped = duplicated_check_rev_file_stripped
if isinstance(post["tags"], str):
post["tags"] = [tag.strip('"') for tag in post["tags"][1:-1].split(",")]
props["revisions"] = list(reversed([(i, rev) for i, rev in enumerate(reversed(all_revisions))]))
comments = get_post_comments(post_id, service)
if post["service"] == "fanbox":
post["content"] = DOWNLOAD_URL_FANBOX_REGEX.sub("", post["content"])
post["content"] = sanitize_html(post["content"], allow_iframe=post["service"] == "fanbox")
if post["service"] == "boosty":
post["content"] = patch_inline_img(post["content"])
return attachments, comments, previews, videos, props
DOWNLOAD_URL_FANBOX_REGEX = re.compile(r"<img\s+src=[\"']https:\/\/downloads\.fanbox\.cc\/.*?['\"]\/>")