mirror of
https://github.com/ow-mods/ow-mod-db.git
synced 2025-12-11 20:15:24 +01:00
Thumbnail property again (#1043)
* Reapply "Reapply "Specify mod thumbnail in database (#1036)"" This reverts commit a7567248da0f1cf0b100eafbf4972f8e67b83ee5. * keep previous mod thumbnail
This commit is contained in:
parent
5f144a8267
commit
e4571d4441
8
.github/ISSUE_TEMPLATE/add-mod.yml
vendored
8
.github/ISSUE_TEMPLATE/add-mod.yml
vendored
@ -33,6 +33,14 @@ body:
|
||||
placeholder: https://github.com/Raicuparta/ow-mod-template
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: thumbnailUrl
|
||||
attributes:
|
||||
label: Thumbnail URL
|
||||
description: "Full URL to a thumbnail image that will be used on the website and mod manager. Ideally in a 3:1 ratio (example: 900 by 300 pixels)"
|
||||
placeholder: https://user-images.githubusercontent.com/22628069/154112130-b777f618-245f-44c9-9408-e11141fc5fde.png
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: tags
|
||||
validations:
|
||||
|
||||
@ -3457,7 +3457,8 @@
|
||||
"tags": [
|
||||
"content"
|
||||
],
|
||||
"authorDisplay": "Vambok"
|
||||
"authorDisplay": "Vambok",
|
||||
"thumbnailUrl": "https://github.com/user-attachments/assets/199e06ff-891e-48b3-86a7-3c3ad3c7a48d"
|
||||
},
|
||||
{
|
||||
"name": "Mouse Fix",
|
||||
|
||||
@ -40,6 +40,10 @@
|
||||
"type": "boolean",
|
||||
"description": "True if this mod isn't useful by itself, and only serves as a dependency for other mods."
|
||||
},
|
||||
"thumbnailUrl": {
|
||||
"type": "string",
|
||||
"description": "Full URL to a thumbnail image that will be used on the website and mod manager. Ideally in a 3:1 ratio (example: 900 by 300 pixels)"
|
||||
},
|
||||
"authorDisplay": {
|
||||
"type": "string",
|
||||
"description": "Custom name to show in the author field for this mod. Useful if your mod is in an organization, or made by multiple people. Leave blank to use the repository owner name."
|
||||
@ -83,7 +87,7 @@
|
||||
"type": "array",
|
||||
"description": "List of previous GitHub repository names. Used for merging download count history. Do not use if current repo is fork of original repo.",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,5 +31,6 @@
|
||||
"node-fetch": "^3.3.2",
|
||||
"sharp": "^0.33.4",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a"
|
||||
}
|
||||
|
||||
2946
scripts/pnpm-lock.yaml
generated
2946
scripts/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1
scripts/src/mod-info.d.ts
vendored
1
scripts/src/mod-info.d.ts
vendored
@ -7,6 +7,7 @@ export type ModInfo = {
|
||||
name: string;
|
||||
uniqueName: string;
|
||||
repo: string;
|
||||
thumbnailUrl?: string;
|
||||
alpha?: boolean;
|
||||
required?: boolean;
|
||||
utility?: boolean;
|
||||
|
||||
@ -20,6 +20,7 @@ type IssueForm = {
|
||||
name?: string;
|
||||
uniqueName?: string;
|
||||
repoUrl?: string;
|
||||
thumbnailUrl?: string;
|
||||
alpha?: string;
|
||||
dlc?: string;
|
||||
utility?: string;
|
||||
@ -39,6 +40,7 @@ async function run() {
|
||||
dlc,
|
||||
authorDisplay,
|
||||
tags,
|
||||
thumbnailUrl,
|
||||
}: IssueForm = JSON.parse(core.getInput(Input.form));
|
||||
|
||||
if (!name || !repoUrl || !uniqueName) {
|
||||
@ -89,6 +91,10 @@ async function run() {
|
||||
newMod.tags.push("requires-dlc");
|
||||
}
|
||||
|
||||
if (thumbnailUrl) {
|
||||
newMod.thumbnailUrl = thumbnailUrl;
|
||||
}
|
||||
|
||||
const existingMod = mods.find(
|
||||
(modFromList) => uniqueName === modFromList.uniqueName
|
||||
);
|
||||
@ -101,6 +107,7 @@ async function run() {
|
||||
existingMod.alpha = newMod.alpha;
|
||||
existingMod.authorDisplay = newMod.authorDisplay;
|
||||
existingMod.tags = newMod.tags;
|
||||
existingMod.thumbnailUrl = newMod.thumbnailUrl;
|
||||
}
|
||||
|
||||
const newModDb: ModList = {
|
||||
|
||||
@ -56,14 +56,14 @@ export async function fetchMods(
|
||||
|
||||
const slug = modInfo.name.replace(/\W/g, "").toLowerCase();
|
||||
|
||||
const thumbnailInfo =
|
||||
readme && readme.downloadUrl
|
||||
? await generateModThumbnail(
|
||||
slug,
|
||||
readme.downloadUrl,
|
||||
outputDirectory
|
||||
)
|
||||
: {};
|
||||
const thumbnailInfo = requiresUpdate
|
||||
? await generateModThumbnail(
|
||||
slug,
|
||||
modInfo.thumbnailUrl,
|
||||
readme?.downloadUrl,
|
||||
outputDirectory
|
||||
)
|
||||
: previousMod.thumbnail;
|
||||
|
||||
const repoURL = `${REPO_URL_BASE}/${modInfo.repo}`;
|
||||
const repoVariations = modInfo.repoVariations
|
||||
@ -82,7 +82,7 @@ export async function fetchMods(
|
||||
repo: repoURL,
|
||||
authorDisplay: modInfo.authorDisplay,
|
||||
tags: modInfo.tags,
|
||||
thumbnail: thumbnailInfo ?? {},
|
||||
thumbnail: thumbnailInfo,
|
||||
repoVariations,
|
||||
};
|
||||
}
|
||||
|
||||
@ -18,23 +18,16 @@ type ThumbnailInfo = {
|
||||
|
||||
export async function generateModThumbnail(
|
||||
slug: string,
|
||||
readmeUrl: string,
|
||||
thumbnailUrl: string | undefined,
|
||||
readmeUrl: string | undefined,
|
||||
outputDirectory: string
|
||||
): Promise<ThumbnailInfo> {
|
||||
const readme = await getReadmeMarkdown(readmeUrl);
|
||||
|
||||
if (!readme) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const firstImageUrl = getFirstImageUrl(readme, getRawContentUrl(readmeUrl));
|
||||
|
||||
if (firstImageUrl == null) return {};
|
||||
|
||||
const rawImageFilePath = await downloadImage(firstImageUrl, slug);
|
||||
const rawImageFilePath =
|
||||
(await downloadImage(thumbnailUrl, slug)) ??
|
||||
(await downloadImage(await getFirstImageUrl(readmeUrl), slug));
|
||||
|
||||
if (rawImageFilePath == null) {
|
||||
console.log(`Failed to download image ${firstImageUrl} for ${slug}`);
|
||||
console.log(`Failed to download any thumbnail for ${slug}`);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -110,10 +103,22 @@ export function getRawContentUrl(readmeUrl: string) {
|
||||
return readmeUrl.replace(/\/(?!.*\/).+/, "");
|
||||
}
|
||||
|
||||
export function getFirstImageUrl(
|
||||
markdown: string,
|
||||
baseUrl: string
|
||||
): string | null {
|
||||
function tryGetUrl(url: string): URL | null {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getFirstImageUrl(
|
||||
readmeUrl: string | undefined
|
||||
): Promise<string | null> {
|
||||
if (!readmeUrl) return null;
|
||||
|
||||
const markdown = await getReadmeMarkdown(readmeUrl);
|
||||
const baseUrl = getRawContentUrl(readmeUrl);
|
||||
|
||||
if (!markdown) return null;
|
||||
|
||||
const parsed = new Parser().parse(markdown);
|
||||
@ -121,18 +126,17 @@ export function getFirstImageUrl(
|
||||
let event;
|
||||
while ((event = walker.next())) {
|
||||
const node = event.node;
|
||||
if (
|
||||
node.type === "image" &&
|
||||
node.destination &&
|
||||
!node.destination.endsWith(".svg") &&
|
||||
!node.destination.startsWith("https://img.shields.io/") &&
|
||||
!node.destination.startsWith("http://img.shields.io/")
|
||||
) {
|
||||
const imageUrl = node.destination;
|
||||
if (node.type !== "image" || !node.destination) continue;
|
||||
|
||||
const fullUrl = imageUrl.startsWith("http")
|
||||
const imageUrl = tryGetUrl(node.destination);
|
||||
|
||||
if (
|
||||
!imageUrl?.pathname.endsWith(".svg") &&
|
||||
imageUrl?.host !== "img.shields.io"
|
||||
) {
|
||||
const fullUrl = imageUrl
|
||||
? // GitHub allows embedding images that actually point to webpages on github.com, so we have to replace the URLs here
|
||||
imageUrl.replace(
|
||||
node.destination.replace(
|
||||
/^https?:\/\/github.com\/(.+)\/(.+)\/blob\/(.+)\//gm,
|
||||
`${GITHUB_RAW_CONTENT_URL}/$1/$2/$3/`
|
||||
)
|
||||
@ -146,27 +150,34 @@ export function getFirstImageUrl(
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function downloadImage(
|
||||
imageUrl: string,
|
||||
async function downloadImage(
|
||||
imageUrl: string | undefined | null,
|
||||
fileName: string
|
||||
): Promise<string | null> {
|
||||
const response = await fetch(imageUrl);
|
||||
if (!imageUrl) return null;
|
||||
|
||||
if (!response.ok) {
|
||||
try {
|
||||
const response = await fetch(imageUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const temporaryDirectory = "tmp/raw-thumbnails";
|
||||
|
||||
if (!fs.existsSync(temporaryDirectory)) {
|
||||
await fsp.mkdir(temporaryDirectory, { recursive: true });
|
||||
}
|
||||
|
||||
const relativeImagePath = `${temporaryDirectory}/${fileName}`;
|
||||
const fullImagePath = getPath(relativeImagePath);
|
||||
|
||||
const image = await response.arrayBuffer();
|
||||
await fsp.writeFile(fullImagePath, Buffer.from(image));
|
||||
|
||||
return fullImagePath;
|
||||
} catch (error) {
|
||||
console.error(`Failed to download image from url ${imageUrl}: ${error}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const temporaryDirectory = "tmp/raw-thumbnails";
|
||||
|
||||
if (!fs.existsSync(temporaryDirectory)) {
|
||||
await fsp.mkdir(temporaryDirectory, { recursive: true });
|
||||
}
|
||||
|
||||
const relativeImagePath = `${temporaryDirectory}/${fileName}`;
|
||||
const fullImagePath = getPath(relativeImagePath);
|
||||
|
||||
const image = await response.arrayBuffer();
|
||||
await fsp.writeFile(fullImagePath, Buffer.from(image));
|
||||
|
||||
return fullImagePath;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user