Skip to content

Commit

Permalink
Updated updating mechanism and removed umami
Browse files Browse the repository at this point in the history
  • Loading branch information
notangelmario authored May 8, 2024
1 parent a1f522a commit 5f38d98
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 62 deletions.
16 changes: 0 additions & 16 deletions apps/com.webapicheck.json

This file was deleted.

169 changes: 126 additions & 43 deletions scripts/checkUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { App, AppSpec } from "@/types/App.ts";
import { CATEGORIES } from "@/lib/categories.ts";
import { WebAppManifest } from "https://esm.sh/v96/@types/[email protected]/index.d.ts";
import { DOMParser } from "https://deno.land/x/[email protected]/deno-dom-wasm.ts";
import { createApp, getApps, updateApp, removeApp } from "@/lib/db.ts";
import { createApp, getApps, removeApp, updateApp } from "@/lib/db.ts";

const ICONS_SIZES = [
"96x96",
Expand All @@ -25,6 +25,8 @@ export async function digest(message: string) {
return hashHex;
}

const objectContains = (object: object, keys: string[]) => keys.every(k => k in object)

export function slashSlashes(string: string) {
return string.replace(/^\/|\/$/g, "");
}
Expand All @@ -42,7 +44,9 @@ export function relativeToAbsolute(url: string, baseUrl: string) {
}
}

export const fetchManifestUrlFromIndex = async (url: string): Promise<string | null> => {
export const fetchManifestUrlFromIndex = async (
url: string,
): Promise<string | null> => {
const body = await fetch(url, {
headers: {
Accept: "text/html",
Expand All @@ -68,7 +72,9 @@ export const fetchManifestUrlFromIndex = async (url: string): Promise<string | n
);

if (!headParsed) {
console.error(`[fetchManifestUrlFromIndex] Could not parse head of ${url}`);
console.error(
`[fetchManifestUrlFromIndex] Could not parse head of ${url}`,
);
return null;
}

Expand All @@ -80,9 +86,11 @@ export const fetchManifestUrlFromIndex = async (url: string): Promise<string | n
: relativeToAbsolute(manifestValue, url);

return manifestUrl;
}
};

export const fetchManifest = async (manifestUrl: string): Promise<WebAppManifest | null> => {
export const fetchManifest = async (
manifestUrl: string,
): Promise<WebAppManifest | null> => {
let manifest: WebAppManifest | undefined;
try {
manifest = await fetch(manifestUrl, {
Expand All @@ -94,13 +102,17 @@ export const fetchManifest = async (manifestUrl: string): Promise<WebAppManifest
res,
) => res.json());
} catch {
console.error(`[fetchManifest] Could not fetch manifest from ${manifestUrl}`);
console.error(
`[fetchManifest] Could not fetch manifest from ${manifestUrl}`,
);
}

return manifest || null;
}
};

export const fetchIndexProps = async (url: string): Promise<Pick<App, "author" | "description" | "cover"> | null> => {
export const fetchIndexProps = async (
url: string,
): Promise<Pick<App, "author" | "description" | "cover"> | null> => {
const body = await fetch(url, {
headers: {
Accept: "text/html",
Expand Down Expand Up @@ -130,24 +142,42 @@ export const fetchIndexProps = async (url: string): Promise<Pick<App, "author" |
return null;
}

const author = headParsed.querySelector("meta[name='author']")?.getAttribute("content") || "";
const description = headParsed.querySelector("meta[name='description']")?.getAttribute("content") || "";
const cover = headParsed.querySelector("meta[property='og:image']")?.getAttribute("content") || "";
const author =
headParsed.querySelector('meta[name="author"]')?.getAttribute(
"content",
) || "";
const description =
headParsed.querySelector('meta[name="description"]')?.getAttribute(
"content",
) || "";
const cover =
headParsed.querySelector('meta[property="og:image"]')?.getAttribute(
"content",
) || "";

return { author, description, cover };
}
};

export const getIcon = (manifest: WebAppManifest, manifestUrl: string): string | null => {
export const getIcon = (
manifest: WebAppManifest,
manifestUrl: string,
): string | null => {
const manifestSplit = manifestUrl.split("/");
manifestSplit.pop();
const manifestParent = manifestSplit.join("/");
const icons = manifest.icons || [];

const maskableIcons = icons.filter((icon) => icon.purpose === "maskable");
const pngIcons = icons.filter((icon) => icon.src.replace(/\?.*/, "").endsWith(".png"));
const svgIcons = icons.filter((icon) => icon.src.replace(/\?.*/, "").endsWith(".svg"))
const pngIcons = icons.filter((icon) =>
icon.src.replace(/\?.*/, "").endsWith(".png")
);
const svgIcons = icons.filter((icon) =>
icon.src.replace(/\?.*/, "").endsWith(".svg")
);

const maskableIconsBySize = ICONS_SIZES.map((size) => maskableIcons.find((icon) => icon.sizes === size));
const maskableIconsBySize = ICONS_SIZES.map((size) =>
maskableIcons.find((icon) => icon.sizes === size)
);
const maskableIcon = maskableIconsBySize.find((icon) => icon !== undefined);
if (maskableIcon) {
return relativeToAbsolute(maskableIcon.src, manifestParent);
Expand All @@ -159,48 +189,73 @@ export const getIcon = (manifest: WebAppManifest, manifestUrl: string): string |
return relativeToAbsolute(svgIcon.src, manifestParent);
}

const pngIconsBySize = ICONS_SIZES.map((size) => pngIcons.find((icon) => icon.sizes === size));
const pngIconsBySize = ICONS_SIZES.map((size) =>
pngIcons.find((icon) => icon.sizes === size)
);
const pngIcon = pngIconsBySize.find((icon) => icon !== undefined);
if (pngIcon) {
return relativeToAbsolute(pngIcon.src, manifestParent);
}

return null;
}
};

export const getScreenshots = (manifest: WebAppManifest, manifestUrl: string): string[] => {
export const getScreenshots = (
manifest: WebAppManifest,
manifestUrl: string,
): string[] => {
const manifestSplit = manifestUrl.split("/");
manifestSplit.pop();
const manifestParent = manifestSplit.join("/");
const screenshots = manifest.screenshots || [];
return screenshots.map((screenshot) => relativeToAbsolute(screenshot.src, manifestParent));
}
return screenshots.map((screenshot) =>
relativeToAbsolute(screenshot.src, manifestParent)
);
};

export const getCategories = (manifest: WebAppManifest): string[] => {
const categories = manifest.categories || [];
const manifestCategories = categories.map((category) => {
const foundCategory = CATEGORIES.find((c) => c.id === category || c.aliases?.includes(category));
const foundCategory = CATEGORIES.find((c) =>
c.id === category || c.aliases?.includes(category)
);
return foundCategory?.id || category;
});

return [...new Set(manifestCategories)];
}
};

export const getCoverUrl = async (coverUrl: string, baseUrl: string): Promise<string | null> => {
const res = await fetch(relativeToAbsolute(coverUrl, baseUrl));
export const getCoverUrl = async (
coverUrl: string,
): Promise<string | null> => {
const res = await fetch(coverUrl, {
headers: {
Accept: "image/*",
},
})
.catch(() => {
console.error(`Could not fetch cover image from ${coverUrl}`);
return null;
});

if (res.ok) {
relativeToAbsolute(coverUrl, baseUrl);
if (res?.ok) {
return coverUrl;
}

return null;
}

export const generateApp = async (appSpec: AppSpec, existingApp: App | null, manifest: WebAppManifest, manifestUrl: string, url: string): Promise<App> => {
};

export const generateApp = async (
appSpec: AppSpec,
existingApp: App | null,
manifest: WebAppManifest,
manifestUrl: string,
url: string,
): Promise<App | null> => {
const icon = getIcon(manifest, manifestUrl);
const screenshots = getScreenshots(manifest, manifestUrl);
const { author, description, cover } = await fetchIndexProps(url) || {};
const coverUrl = cover ? await getCoverUrl(cover, url) : undefined;
const coverUrl = cover ? await getCoverUrl(cover) : undefined;
const categories = getCategories(manifest);

const newApp: Partial<App> = {
Expand All @@ -221,20 +276,26 @@ export const generateApp = async (appSpec: AppSpec, existingApp: App | null, man
githubUrl: appSpec.githubUrl || undefined,
gitlabUrl: appSpec.gitlabUrl || undefined,
authorUrl: appSpec.authorUrl || undefined,
}
};

const updatedApp = { ...existingApp, ...newApp } as App;


if (!objectContains(updatedApp, ["id", "name", "author", "icon", "description"])) {
console.log(
`[generateApp] Missing required fields for ${appSpec.id}. Skipping.`,
);
return null;
}

return updatedApp;
}
};

export const updateApps = async (specificAppIds: string[] = []) => {
const appDir = Deno.readDir("./apps");
const appSpecs: AppSpec[] = [];
const allAppSpecIds: string[] = [];
const apps: App[] = await getApps();


for await (const dirEntry of appDir) {
if (!dirEntry.isFile || !dirEntry.name.endsWith(".json")) {
continue;
Expand All @@ -260,13 +321,20 @@ export const updateApps = async (specificAppIds: string[] = []) => {
if (!app) {
console.log(`Creating ${appSpec.id}`);

const manifestUrl = appSpec.manifestUrl || (await fetchManifestUrlFromIndex(appSpec.url));
const manifestUrl = appSpec.manifestUrl ||
(await fetchManifestUrlFromIndex(appSpec.url));
if (!manifestUrl) continue;

const manifest = await fetchManifest(manifestUrl);
if (!manifest) continue;

const appData = await generateApp(appSpec, null, manifest, manifestUrl, appSpec.url);
const appData = await generateApp(
appSpec,
null,
manifest,
manifestUrl,
appSpec.url,
);

if (!appData) continue;

Expand All @@ -280,13 +348,27 @@ export const updateApps = async (specificAppIds: string[] = []) => {

const manifestHash = await digest(JSON.stringify(manifest));

if ((app.manifestHash !== manifestHash) || specificAppIds.includes(appSpec.id)) {
console.log(`Updating ${appSpec.id} ${specificAppIds.includes(appSpec.id) ? "FORCEFULLY" : ""}`);

const manifestUrl = appSpec.manifestUrl || (await fetchManifestUrlFromIndex(appSpec.url));
if (
(app.manifestHash !== manifestHash) ||
specificAppIds.includes(appSpec.id)
) {
console.log(
`Updating ${appSpec.id} ${
specificAppIds.includes(appSpec.id) ? "FORCEFULLY" : ""
}`,
);

const manifestUrl = appSpec.manifestUrl ||
(await fetchManifestUrlFromIndex(appSpec.url));
if (!manifestUrl) continue;

const appData = await generateApp(appSpec, app, manifest, manifestUrl, app.url);
const appData = await generateApp(
appSpec,
app,
manifest,
manifestUrl,
app.url,
);

if (!appData) continue;

Expand All @@ -304,4 +386,5 @@ export const updateApps = async (specificAppIds: string[] = []) => {
console.log(`Deleting ${appId}`);
removeApp(appId);
}
}
};

4 changes: 1 addition & 3 deletions src/lib/app.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import "dotenv";

export const APP = {
version: "6.1.1",
version: "6.2.0",
codename: "Gabriela",
githubRepo: "https://github.com/notangelmario/paquet",
umamiUrl: Deno.env.get("UMAMI_URL"),
umamiId: Deno.env.get("UMAMI_ID"),
};

export const DEV = !Deno.env.get("DENO_DEPLOYMENT_ID");

0 comments on commit 5f38d98

Please sign in to comment.