refactor(icons): move walkxcode/dashboard-icons to homarr-labs/dashboard-icons (#1883)

This commit is contained in:
Meier Lukas
2025-01-10 14:46:31 +01:00
committed by GitHub
parent 546c824888
commit 39171ac76a
6 changed files with 92 additions and 66 deletions

View File

@@ -5,29 +5,29 @@ import { splitToNChunks } from "@homarr/common";
import classes from "./hero-banner.module.css"; import classes from "./hero-banner.module.css";
const icons = [ const icons = [
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/homarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/homarr.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/sabnzbd.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/sabnzbd.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/deluge.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/deluge.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/radarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/radarr.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/sonarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/sonarr.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/lidarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/lidarr.svg",
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/pihole.svg", "https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/pihole.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/dashdot.png", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/dashdot.png",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/overseerr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/overseerr.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/plex.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/plex.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/jellyfin.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/jellyfin.svg",
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/homeassistant.svg", "https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/homeassistant.svg",
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/freshrss.svg", "https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/freshrss.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/readarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/readarr.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/transmission.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/transmission.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/qbittorrent.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/qbittorrent.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nzbget.png", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/nzbget.png",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/openmediavault.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/openmediavault.svg",
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/docker.svg", "https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/docker.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/jellyseerr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/jellyseerr.svg",
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/adguardhome.svg", "https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/adguardhome.svg",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/tdarr.png", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/tdarr.png",
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/prowlarr.svg", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/prowlarr.svg",
]; ];
const countIconGroups = 3; const countIconGroups = 3;

View File

@@ -10,7 +10,7 @@ import { convertIntersectionToZodObject } from "../schema-merger";
import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc";
import { canUserSeeAppAsync } from "./app/app-access-control"; import { canUserSeeAppAsync } from "./app/app-access-control";
const defaultIcon = "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/svg/homarr.svg"; const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/homarr.svg";
export const appRouter = createTRPCRouter({ export const appRouter = createTRPCRouter({
getPaginated: protectedProcedure getPaginated: protectedProcedure

View File

@@ -240,7 +240,7 @@ describe("create should create a new integration", () => {
expect(dbSearchEngine!.short).toBe("j"); expect(dbSearchEngine!.short).toBe("j");
expect(dbSearchEngine!.name).toBe(input.name); expect(dbSearchEngine!.name).toBe(input.name);
expect(dbSearchEngine!.iconUrl).toBe( expect(dbSearchEngine!.iconUrl).toBe(
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyseerr.png",
); );
}); });

View File

@@ -1,7 +1,7 @@
import { splitToNChunks, Stopwatch } from "@homarr/common"; import { splitToNChunks, Stopwatch } from "@homarr/common";
import { EVERY_WEEK } from "@homarr/cron-jobs-core/expressions"; import { EVERY_WEEK } from "@homarr/cron-jobs-core/expressions";
import type { InferInsertModel } from "@homarr/db"; import type { InferInsertModel } from "@homarr/db";
import { db, inArray } from "@homarr/db"; import { db, inArray, sql } from "@homarr/db";
import { createId } from "@homarr/db/client"; import { createId } from "@homarr/db/client";
import { iconRepositories, icons } from "@homarr/db/schema"; import { iconRepositories, icons } from "@homarr/db/schema";
import { fetchIconsAsync } from "@homarr/icons"; import { fetchIconsAsync } from "@homarr/icons";
@@ -22,13 +22,13 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, {
`Successfully fetched ${countIcons} icons from ${repositoryIconGroups.length} repositories within ${stopWatch.getElapsedInHumanWords()}`, `Successfully fetched ${countIcons} icons from ${repositoryIconGroups.length} repositories within ${stopWatch.getElapsedInHumanWords()}`,
); );
const databaseIconGroups = await db.query.iconRepositories.findMany({ const databaseIconRepositories = await db.query.iconRepositories.findMany({
with: { with: {
icons: true, icons: true,
}, },
}); });
const skippedChecksums: string[] = []; const skippedChecksums: `${string}.${string}`[] = [];
let countDeleted = 0; let countDeleted = 0;
let countInserted = 0; let countInserted = 0;
@@ -43,18 +43,24 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, {
continue; continue;
} }
const repositoryInDb = databaseIconGroups.find((dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug); const repositoryInDb = databaseIconRepositories.find(
const repositoryIconGroupId: string = repositoryInDb?.id ?? createId(); (dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug,
);
const iconRepositoryId: string = repositoryInDb?.id ?? createId();
if (!repositoryInDb?.id) { if (!repositoryInDb?.id) {
newIconRepositories.push({ newIconRepositories.push({
id: repositoryIconGroupId, id: iconRepositoryId,
slug: repositoryIconGroup.slug, slug: repositoryIconGroup.slug,
}); });
} }
for (const icon of repositoryIconGroup.icons) { for (const icon of repositoryIconGroup.icons) {
if (databaseIconGroups.flatMap((group) => group.icons).some((dbIcon) => dbIcon.checksum === icon.checksum)) { if (
skippedChecksums.push(icon.checksum); databaseIconRepositories
.flatMap((repository) => repository.icons)
.some((dbIcon) => dbIcon.checksum === icon.checksum && dbIcon.iconRepositoryId === iconRepositoryId)
) {
skippedChecksums.push(`${iconRepositoryId}.${icon.checksum}`);
continue; continue;
} }
@@ -63,34 +69,54 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, {
checksum: icon.checksum, checksum: icon.checksum,
name: icon.fileNameWithExtension, name: icon.fileNameWithExtension,
url: icon.imageUrl, url: icon.imageUrl,
iconRepositoryId: repositoryIconGroupId, iconRepositoryId,
}); });
countInserted++; countInserted++;
} }
} }
const deadIcons = databaseIconGroups const deadIcons = databaseIconRepositories
.flatMap((group) => group.icons) .flatMap((repository) => repository.icons)
.filter((icon) => !skippedChecksums.includes(icon.checksum)); .filter((icon) => !skippedChecksums.includes(`${icon.iconRepositoryId}.${icon.checksum}`));
await db.transaction(async (transaction) => { const deadIconRepositories = databaseIconRepositories.filter(
(iconRepository) => !repositoryIconGroups.some((group) => group.slug === iconRepository.slug),
);
db.transaction((transaction) => {
if (newIconRepositories.length >= 1) { if (newIconRepositories.length >= 1) {
await transaction.insert(iconRepositories).values(newIconRepositories); transaction.insert(iconRepositories).values(newIconRepositories).run();
} }
if (newIcons.length >= 1) { if (newIcons.length >= 1) {
// We only insert 5000 icons at a time to avoid SQLite limitations // We only insert 5000 icons at a time to avoid SQLite limitations
for (const chunck of splitToNChunks(newIcons, Math.ceil(newIcons.length / 5000))) { for (const chunck of splitToNChunks(newIcons, Math.ceil(newIcons.length / 5000))) {
await transaction.insert(icons).values(chunck); transaction.insert(icons).values(chunck).run();
} }
} }
if (deadIcons.length >= 1) { if (deadIcons.length >= 1) {
await transaction.delete(icons).where( transaction
inArray( .delete(icons)
icons.checksum, .where(
deadIcons.map((icon) => icon.checksum), inArray(
), // Combine iconRepositoryId and checksum to allow same icons on different repositories
); sql`concat(${icons.iconRepositoryId}, '.', ${icons.checksum})`,
deadIcons.map((icon) => `${icon.iconRepositoryId}.${icon.checksum}`),
),
)
.run();
}
if (deadIconRepositories.length >= 1) {
transaction
.delete(iconRepositories)
.where(
inArray(
iconRepositories.id,
deadIconRepositories.map((iconRepository) => iconRepository.id),
),
)
.run();
} }
countDeleted += deadIcons.length; countDeleted += deadIcons.length;

View File

@@ -20,122 +20,122 @@ export const integrationDefs = {
sabNzbd: { sabNzbd: {
name: "SABnzbd", name: "SABnzbd",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sabnzbd.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/sabnzbd.png",
category: ["downloadClient", "usenet"], category: ["downloadClient", "usenet"],
}, },
nzbGet: { nzbGet: {
name: "NZBGet", name: "NZBGet",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/nzbget.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/nzbget.png",
category: ["downloadClient", "usenet"], category: ["downloadClient", "usenet"],
}, },
deluge: { deluge: {
name: "Deluge", name: "Deluge",
secretKinds: [["password"]], secretKinds: [["password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/deluge.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/deluge.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
}, },
transmission: { transmission: {
name: "Transmission", name: "Transmission",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/transmission.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/transmission.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
}, },
qBittorrent: { qBittorrent: {
name: "qBittorrent", name: "qBittorrent",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/qbittorrent.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/qbittorrent.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
}, },
sonarr: { sonarr: {
name: "Sonarr", name: "Sonarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sonarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/sonarr.png",
category: ["calendar"], category: ["calendar"],
}, },
radarr: { radarr: {
name: "Radarr", name: "Radarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/radarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/radarr.png",
category: ["calendar"], category: ["calendar"],
}, },
lidarr: { lidarr: {
name: "Lidarr", name: "Lidarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/lidarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/lidarr.png",
category: ["calendar"], category: ["calendar"],
}, },
readarr: { readarr: {
name: "Readarr", name: "Readarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/readarr.png",
category: ["calendar"], category: ["calendar"],
}, },
prowlarr: { prowlarr: {
name: "Prowlarr", name: "Prowlarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/prowlarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/prowlarr.png",
category: ["indexerManager"], category: ["indexerManager"],
}, },
jellyfin: { jellyfin: {
name: "Jellyfin", name: "Jellyfin",
secretKinds: [["username", "password"], ["apiKey"]], secretKinds: [["username", "password"], ["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyfin.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyfin.png",
category: ["mediaService"], category: ["mediaService"],
}, },
plex: { plex: {
name: "Plex", name: "Plex",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/plex.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/plex.png",
category: ["mediaService"], category: ["mediaService"],
}, },
jellyseerr: { jellyseerr: {
name: "Jellyseerr", name: "Jellyseerr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyseerr.png",
category: ["mediaSearch", "mediaRequest", "search"], category: ["mediaSearch", "mediaRequest", "search"],
}, },
overseerr: { overseerr: {
name: "Overseerr", name: "Overseerr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/overseerr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/overseerr.png",
category: ["mediaSearch", "mediaRequest", "search"], category: ["mediaSearch", "mediaRequest", "search"],
}, },
piHole: { piHole: {
name: "Pi-hole", name: "Pi-hole",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/pi-hole.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/pi-hole.png",
category: ["dnsHole"], category: ["dnsHole"],
}, },
adGuardHome: { adGuardHome: {
name: "AdGuard Home", name: "AdGuard Home",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/adguard-home.png",
category: ["dnsHole"], category: ["dnsHole"],
}, },
homeAssistant: { homeAssistant: {
name: "Home Assistant", name: "Home Assistant",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/home-assistant.png",
category: ["smartHomeServer"], category: ["smartHomeServer"],
}, },
openmediavault: { openmediavault: {
name: "OpenMediaVault", name: "OpenMediaVault",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/openmediavault.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/openmediavault.png",
category: ["healthMonitoring"], category: ["healthMonitoring"],
}, },
dashDot: { dashDot: {
name: "Dash.", name: "Dash.",
secretKinds: [[]], secretKinds: [[]],
category: ["healthMonitoring"], category: ["healthMonitoring"],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/dashdot.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/dashdot.png",
}, },
tdarr: { tdarr: {
name: "Tdarr", name: "Tdarr",
secretKinds: [[]], secretKinds: [[]],
category: ["mediaTranscoding"], category: ["mediaTranscoding"],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/tdarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/tdarr.png",
}, },
} as const satisfies Record<string, integrationDefinition>; } as const satisfies Record<string, integrationDefinition>;

View File

@@ -5,12 +5,12 @@ import type { RepositoryIconGroup } from "./types";
const repositories = [ const repositories = [
new GitHubIconRepository( new GitHubIconRepository(
"Walkxcode", "Dashboard Icons",
"walkxcode/dashboard-icons", "homarr-labs/dashboard-icons",
undefined, undefined,
new URL("https://github.com/walkxcode/dashboard-icons"), new URL("https://github.com/homarr-labs/dashboard-icons"),
new URL("https://api.github.com/repos/walkxcode/dashboard-icons/git/trees/main?recursive=true"), new URL("https://api.github.com/repos/homarr-labs/dashboard-icons/git/trees/main?recursive=true"),
"https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/{0}", "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/{0}",
), ),
new GitHubIconRepository( new GitHubIconRepository(
"selfh.st", "selfh.st",