Migrate deploy-lftp script to tsx
Also change assets directory to `assets` and add default `.htaccess` file
This commit is contained in:
parent
405ad38f5d
commit
d01594f456
19 changed files with 172 additions and 97 deletions
|
|
@ -165,7 +165,6 @@ const { instance, user, postId } = Astro.props;
|
|||
commentBoxPostLink.href = comment.url;
|
||||
commentBoxPostLink.target = "_blank";
|
||||
const publishDate = commentBoxPostLink.querySelector<HTMLSpanElement>("[data-publish-date]")!;
|
||||
// TO-DO Pretty format date
|
||||
publishDate.innerText = new Date(Date.parse(comment.created_at)).toLocaleString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
|
|
|
|||
|
|
@ -10,24 +10,50 @@ export const WEBSITE_LIST = [
|
|||
"weasyl",
|
||||
"inkbunny",
|
||||
"sofurry",
|
||||
"twitter",
|
||||
"mastodon",
|
||||
"twitter",
|
||||
"bluesky",
|
||||
"itaku",
|
||||
] as const;
|
||||
|
||||
const localUrlRegex = /^((\/?\.\.(?=\/))+|(\.(?=\/)))?\/?[a-z0-9_-]+(\/[a-z0-9_-]+)*\/?$/;
|
||||
const ekaPostUrlRegex = /^(?:https:\/\/)(?:www\.)?aryion\.com\/g4\/view\/([1-9]\d*)\/?$/;
|
||||
const furaffinityPostUrlRegex = /^(?:https:\/\/)(?:www\.)?furaffinity\.net\/view\/([1-9]\d*)\/?$/;
|
||||
const weasylPostUrlRegex =
|
||||
/^(?:https:\/\/)(?:www\.)?weasyl\.com\/~([a-zA-Z][a-zA-Z0-9_-]+)\/submissions\/([1-9]\d*(?:\/[a-zA-Z0-9_-]+)?)\/?$/;
|
||||
const inkbunnyPostUrlRegex = /^(?:https:\/\/)(?:www\.)?inkbunny\.net\/s\/([1-9]\d*)\/?$/;
|
||||
const sofurryPostUrlRegex = /^(?:https:\/\/)www\.sofurry\.com\/view\/([1-9]\d*)\/?$/;
|
||||
const mastodonPostUrlRegex = /^(?:https:\/\/)((?:[a-zA-Z0-9_-]+\.)+[a-z]+)\/@([a-zA-Z][a-zA-Z0-9_-]+)\/([1-9]\d*)\/?$/;
|
||||
|
||||
const refineAuthors = (value: { id: any } | any[]) => "id" in value || value.length > 0;
|
||||
const refineCopyrightedCharacters = (value: Record<string, any>) => !("" in value) || Object.keys(value).length == 1;
|
||||
|
||||
const lang = z.enum(["eng", "tok"]).default("eng");
|
||||
const website = z.enum(WEBSITE_LIST);
|
||||
const platform = z.enum(["web", "windows", "linux", "macos", "android", "ios"]);
|
||||
const mastodonPost = z.object({
|
||||
instance: z.string(),
|
||||
user: z.string(),
|
||||
postId: z.string(),
|
||||
});
|
||||
const mastodonPost = z
|
||||
.object({
|
||||
instance: z.string(),
|
||||
user: z.string(),
|
||||
postId: z.string(),
|
||||
})
|
||||
.or(
|
||||
z.string().transform((mastodonPost, ctx) => {
|
||||
const match = mastodonPostUrlRegex.exec(mastodonPost);
|
||||
if (!match) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `"mastodonPost" contains an invalid URL`,
|
||||
});
|
||||
return z.NEVER;
|
||||
}
|
||||
return {
|
||||
instance: match[1],
|
||||
user: match[2],
|
||||
postId: match[3],
|
||||
};
|
||||
}),
|
||||
);
|
||||
const copyrightedCharacters = z
|
||||
.record(z.string(), reference("users"))
|
||||
.default({})
|
||||
|
|
@ -71,6 +97,11 @@ const storiesCollection = defineCollection({
|
|||
relatedGames: z.array(reference("games")).default([]),
|
||||
posts: z
|
||||
.object({
|
||||
eka: z.string().regex(ekaPostUrlRegex).optional(),
|
||||
furaffinity: z.string().regex(furaffinityPostUrlRegex).optional(),
|
||||
weasyl: z.string().regex(weasylPostUrlRegex).optional(),
|
||||
inkbunny: z.string().regex(inkbunnyPostUrlRegex).optional(),
|
||||
sofurry: z.string().regex(sofurryPostUrlRegex).optional(),
|
||||
mastodon: mastodonPost.optional(),
|
||||
})
|
||||
.default({}),
|
||||
|
|
@ -105,6 +136,11 @@ const gamesCollection = defineCollection({
|
|||
relatedGames: z.array(reference("games")).default([]),
|
||||
posts: z
|
||||
.object({
|
||||
eka: z.string().regex(ekaPostUrlRegex).optional(),
|
||||
furaffinity: z.string().regex(furaffinityPostUrlRegex).optional(),
|
||||
weasyl: z.string().regex(weasylPostUrlRegex).optional(),
|
||||
inkbunny: z.string().regex(inkbunnyPostUrlRegex).optional(),
|
||||
sofurry: z.string().regex(sofurryPostUrlRegex).optional(),
|
||||
mastodon: mastodonPost.optional(),
|
||||
})
|
||||
.default({}),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ pubDate: 2024-06-23
|
|||
authors: bad-manners
|
||||
wordCount: 2600
|
||||
contentWarning: >
|
||||
Contains: Non-fatal unbirth and oral vore, with willing anthro maned wolf predator and willing anthro mimic x maned wolf hybrid prey. Also includes gay sex, masturbation, and sleep play.
|
||||
Contains: Non-fatal unbirth and oral vore, with willing anthro male maned wolf predator and willing micro anthro male mimic x maned wolf hybrid prey. Also includes gay sex, masturbation, and sleep play.
|
||||
thumbnail: /src/assets/thumbnails/bm_19_woofer_exploration.png
|
||||
description: |
|
||||
The Director wakes up in the middle of the night to a little intruder, and decides to have some fun with him.
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ tags:
|
|||
- daddy play
|
||||
- BDSM
|
||||
- dubcon
|
||||
- plushie
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ const thumbnail =
|
|||
</Fragment>
|
||||
<div
|
||||
id="top"
|
||||
class="min-w-screen relative min-h-screen bg-radial from-bm-300 to-bm-600 px-1 pb-16 pt-20 dark:from-green-700 dark:to-green-950 print:bg-none"
|
||||
class="min-w-screen relative min-h-screen bg-radial from-bm-300 to-bm-600 px-1 pb-16 pt-20 dark:from-green-700 dark:to-green-950 print:bg-none print:pb-0 print:pt-0"
|
||||
>
|
||||
<div
|
||||
id="toolbox-buttons"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ const wordCount = props.wordCount ? `${props.wordCount}` : "???";
|
|||
</Fragment>
|
||||
<div
|
||||
id="top"
|
||||
class="min-w-screen relative min-h-screen bg-radial from-bm-300 to-bm-600 px-1 pb-16 pt-20 dark:from-green-700 dark:to-green-950 print:bg-none"
|
||||
class="min-w-screen relative min-h-screen bg-radial from-bm-300 to-bm-600 px-1 pb-16 pt-20 dark:from-green-700 dark:to-green-950 print:bg-none print:pb-0 print:pt-0"
|
||||
>
|
||||
<div
|
||||
id="toolbox-buttons"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ The Noto Sans and Noto Serif typefaces are copyrighted to the Noto Project Autho
|
|||
|
||||
The generic SVG icons were created by Font Awesome and are distributed under the CC-BY-4.0 license.
|
||||
|
||||
All third-party trademarks belong to their respective owners, and I'm not affiliated with any of them.
|
||||
All third-party trademarks and attributed characters belong to their respective owners, and I'm not affiliated with any of them.
|
||||
`.trim();
|
||||
|
||||
export const GET: APIRoute = () => {
|
||||
|
|
|
|||
|
|
@ -11,49 +11,29 @@ const [stories, games, tagCategories] = await Promise.all([
|
|||
const tagsSet = new Set<string>();
|
||||
const draftOnlyTagsSet = new Set<string>();
|
||||
const seriesCollection = await getCollection("series");
|
||||
stories
|
||||
.filter((story) => !story.data.isDraft)
|
||||
.forEach((story) => {
|
||||
story.data.tags.forEach((tag) => {
|
||||
tagsSet.add(tag);
|
||||
});
|
||||
// Add tags from non-drafts to set; then, add tags only from drafts to separate set
|
||||
[stories, games]
|
||||
.flat()
|
||||
.sort((a, b) => (a.data.isDraft ? 1 : b.data.isDraft ? -1 : 0))
|
||||
.forEach((value) => {
|
||||
if (value.data.isDraft) {
|
||||
value.data.tags.forEach((tag) => {
|
||||
if (!tagsSet.has(tag)) {
|
||||
draftOnlyTagsSet.add(tag);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
value.data.tags.forEach((tag) => {
|
||||
tagsSet.add(tag);
|
||||
});
|
||||
}
|
||||
});
|
||||
games
|
||||
.filter((game) => !game.data.isDraft)
|
||||
.forEach((game) => {
|
||||
game.data.tags.forEach((tag) => {
|
||||
tagsSet.add(tag);
|
||||
});
|
||||
});
|
||||
stories
|
||||
.filter((story) => story.data.isDraft)
|
||||
.forEach((story) => {
|
||||
story.data.tags.forEach((tag) => {
|
||||
if (!tagsSet.has(tag)) {
|
||||
draftOnlyTagsSet.add(tag);
|
||||
}
|
||||
});
|
||||
});
|
||||
games
|
||||
.filter((game) => game.data.isDraft)
|
||||
.forEach((game) => {
|
||||
game.data.tags.forEach((tag) => {
|
||||
if (!tagsSet.has(tag)) {
|
||||
draftOnlyTagsSet.add(tag);
|
||||
}
|
||||
});
|
||||
});
|
||||
const uncategorizedTagsSet = new Set(tagsSet);
|
||||
|
||||
const uncategorizedTagsSet = new Set(tagsSet);
|
||||
const categorizedTags: Array<[string, string, string[]]> = tagCategories
|
||||
.sort((a, b) => a.data.index - b.data.index)
|
||||
.map((category) => {
|
||||
const tagList = category.data.tags.map((tag) => {
|
||||
if (typeof tag === "string") {
|
||||
return tag;
|
||||
}
|
||||
return tag["eng"]!;
|
||||
});
|
||||
const tagList = category.data.tags.map((tag) => (typeof tag === "string" ? tag : tag["eng"]!));
|
||||
tagList.forEach((tag, index) => {
|
||||
if (index !== tagList.findLastIndex((val) => tag == val)) {
|
||||
throw new Error(`Duplicated tag "${tag}" found in multiple tag-categories`);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,11 @@ type Params = {
|
|||
};
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = async () => {
|
||||
const [stories, games, series] = await Promise.all([getCollection("stories"), getCollection("games"), getCollection("series")]);
|
||||
const [stories, games, series] = await Promise.all([
|
||||
getCollection("stories"),
|
||||
getCollection("games"),
|
||||
getCollection("series"),
|
||||
]);
|
||||
const seriesTags = new Set(series.map((s) => s.data.name));
|
||||
const tags = new Set<string>();
|
||||
stories.forEach((story) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue