mirror of
https://github.com/gethomepage/homepage.git
synced 2025-12-05 21:47:48 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e1aeaf54c | ||
|
|
2e8717247d | ||
|
|
d17a17bd3c | ||
|
|
0afc1b96f1 | ||
|
|
5fbc6702bc | ||
|
|
75455a23e2 | ||
|
|
2aed46671f | ||
|
|
88934ec39a | ||
|
|
21c0c687cd | ||
|
|
9f63a5a1d5 | ||
|
|
679704949e | ||
|
|
6b90d3ef28 |
14
README.md
14
README.md
@@ -45,15 +45,17 @@
|
||||
- Container status (Running / Stopped) & statistics (CPU, Memory, Network)
|
||||
- Automatic service discovery (via labels)
|
||||
- Service Integration
|
||||
- Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli (Plex)
|
||||
- Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent
|
||||
- Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox
|
||||
- Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli, Plex and more
|
||||
- Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent and more
|
||||
- Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox and more
|
||||
- Information Providers
|
||||
- Coin Market Cap, Mastodon
|
||||
- Coin Market Cap, Mastodon and more
|
||||
- Information & Utility Widgets
|
||||
- System Stats (Disk, CPU, Memory)
|
||||
- Weather via [OpenWeatherMap](https://openweathermap.org/) or [Open-Meteo](https://open-meteo.com/)
|
||||
- Search Bar
|
||||
- Web Search Bar
|
||||
- UniFi Console, Glances and more
|
||||
- Instant "Quick-launch" search
|
||||
- Customizable
|
||||
- 21 theme colors with light and dark mode support
|
||||
- Background image support
|
||||
@@ -63,7 +65,7 @@
|
||||
|
||||
If you have any questions, suggestions, or general issues, please start a discussion on the [Discussions](https://github.com/benphelps/homepage/discussions) page.
|
||||
|
||||
If you have a more specific issue, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page.
|
||||
For bug reports, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page.
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
||||
@@ -394,14 +394,14 @@
|
||||
"numberOfLeases": "Alquileres"
|
||||
},
|
||||
"xteve": {
|
||||
"streams_all": "All Streams",
|
||||
"streams_active": "Active Streams",
|
||||
"streams_xepg": "XEPG Channels"
|
||||
"streams_all": "Todas las corrientes",
|
||||
"streams_active": "Corrientes activas",
|
||||
"streams_xepg": "Canales XEPG"
|
||||
},
|
||||
"opnsense": {
|
||||
"cpu": "CPU Load",
|
||||
"memory": "Active Memory",
|
||||
"wanUpload": "WAN Upload",
|
||||
"wanDownload": "WAN Download"
|
||||
"cpu": "Carga de la CPU",
|
||||
"memory": "Memoria activa",
|
||||
"wanUpload": "Carga WAN",
|
||||
"wanDownload": "Descargar WAN"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,9 +399,9 @@
|
||||
"streams_xepg": "Canal XEPG"
|
||||
},
|
||||
"opnsense": {
|
||||
"cpu": "CPU Load",
|
||||
"memory": "Active Memory",
|
||||
"wanUpload": "WAN Upload",
|
||||
"wanDownload": "WAN Download"
|
||||
"cpu": "Charge CPU",
|
||||
"memory": "Mém. Utilisée",
|
||||
"wanUpload": "WAN Envoi",
|
||||
"wanDownload": "WAN Récep."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ import useSWR from "swr";
|
||||
import { compareVersions } from "compare-versions";
|
||||
import { MdNewReleases } from "react-icons/md";
|
||||
|
||||
import cachedFetch from "utils/proxy/cached-fetch";
|
||||
|
||||
export default function Version() {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
@@ -12,9 +10,7 @@ export default function Version() {
|
||||
const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev";
|
||||
const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev";
|
||||
|
||||
const cachedFetcher = (resource) => cachedFetch(resource, 5).then((res) => res.json());
|
||||
|
||||
const { data: releaseData } = useSWR("https://api.github.com/repos/benphelps/homepage/releases", cachedFetcher);
|
||||
const { data: releaseData } = useSWR("/api/releases");
|
||||
|
||||
// use Intl.DateTimeFormat to format the date
|
||||
const formatDate = (date) => {
|
||||
@@ -48,7 +44,7 @@ export default function Version() {
|
||||
</span>
|
||||
{version === "main" || version === "dev" || version === "nightly"
|
||||
? null
|
||||
: releaseData &&
|
||||
: releaseData && latestRelease &&
|
||||
compareVersions(latestRelease.tag_name, version) > 0 && (
|
||||
<a
|
||||
href={latestRelease.html_url}
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function Cpu({ expanded }) {
|
||||
<div className="pr-1">{t("resources.load")}</div>
|
||||
</div>
|
||||
)}
|
||||
<UsageBar percent={100} />
|
||||
<UsageBar percent={0} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function Disk({ options, expanded }) {
|
||||
<div className="pr-1">{t("resources.total")}</div>
|
||||
</span>
|
||||
)}
|
||||
<UsageBar percent={100} />
|
||||
<UsageBar percent={0} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function Memory({ expanded }) {
|
||||
<div className="pr-1">{t("resources.total")}</div>
|
||||
</span>
|
||||
)}
|
||||
<UsageBar percent={100} />
|
||||
<UsageBar percent={0} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
6
src/pages/api/releases.js
Normal file
6
src/pages/api/releases.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import cachedFetch from "utils/proxy/cached-fetch";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
const releasesURL = "https://api.github.com/repos/benphelps/homepage/releases";
|
||||
return res.send(await cachedFetch(releasesURL, 5));
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export async function servicesResponse() {
|
||||
discoveredServices = cleanServiceGroups(await servicesFromDocker());
|
||||
} catch (e) {
|
||||
console.error("Failed to discover services, please check docker.yaml for errors or remove example entries.");
|
||||
if (e) console.error(e);
|
||||
if (e) console.error(e.toString());
|
||||
discoveredServices = [];
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export async function servicesResponse() {
|
||||
configuredServices = cleanServiceGroups(await servicesFromConfig());
|
||||
} catch (e) {
|
||||
console.error("Failed to load services.yaml, please check for errors");
|
||||
if (e) console.error(e);
|
||||
if (e) console.error(e.toString());
|
||||
configuredServices = [];
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export async function servicesResponse() {
|
||||
initialSettings = await getSettings();
|
||||
} catch (e) {
|
||||
console.error("Failed to load settings.yaml, please check for errors");
|
||||
if (e) console.error(e);
|
||||
if (e) console.error(e.toString());
|
||||
initialSettings = {};
|
||||
}
|
||||
|
||||
|
||||
@@ -44,39 +44,48 @@ export async function servicesFromDocker() {
|
||||
|
||||
const serviceServers = await Promise.all(
|
||||
Object.keys(servers).map(async (serverName) => {
|
||||
const docker = new Docker(getDockerArguments(serverName).conn);
|
||||
const containers = await docker.listContainers({
|
||||
all: true,
|
||||
});
|
||||
|
||||
// bad docker connections can result in a <Buffer ...> object?
|
||||
// in any case, this ensures the result is the expected array
|
||||
if (!Array.isArray(containers)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const discovered = containers.map((container) => {
|
||||
let constructedService = null;
|
||||
|
||||
Object.keys(container.Labels).forEach((label) => {
|
||||
if (label.startsWith("homepage.")) {
|
||||
if (!constructedService) {
|
||||
constructedService = {
|
||||
container: container.Names[0].replace(/^\//, ""),
|
||||
server: serverName,
|
||||
};
|
||||
}
|
||||
shvl.set(constructedService, label.replace("homepage.", ""), container.Labels[label]);
|
||||
}
|
||||
try {
|
||||
const docker = new Docker(getDockerArguments(serverName).conn);
|
||||
const containers = await docker.listContainers({
|
||||
all: true,
|
||||
});
|
||||
|
||||
return constructedService;
|
||||
});
|
||||
// bad docker connections can result in a <Buffer ...> object?
|
||||
// in any case, this ensures the result is the expected array
|
||||
if (!Array.isArray(containers)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return { server: serverName, services: discovered.filter((filteredService) => filteredService) };
|
||||
const discovered = containers.map((container) => {
|
||||
let constructedService = null;
|
||||
|
||||
Object.keys(container.Labels).forEach((label) => {
|
||||
if (label.startsWith("homepage.")) {
|
||||
if (!constructedService) {
|
||||
constructedService = {
|
||||
container: container.Names[0].replace(/^\//, ""),
|
||||
server: serverName,
|
||||
};
|
||||
}
|
||||
shvl.set(constructedService, label.replace("homepage.", ""), container.Labels[label]);
|
||||
}
|
||||
});
|
||||
|
||||
return constructedService;
|
||||
});
|
||||
|
||||
return { server: serverName, services: discovered.filter((filteredService) => filteredService) };
|
||||
} catch (e) {
|
||||
// a server failed, but others may succeed
|
||||
return { server: serverName, services: [] };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (serviceServers.every(server => server.services.length === 0)) {
|
||||
throw new Error('All docker servers failed to connect or returned no containers');
|
||||
}
|
||||
|
||||
const mappedServiceGroups = [];
|
||||
|
||||
serviceServers.forEach((server) => {
|
||||
|
||||
@@ -84,9 +84,9 @@ export default async function pyloadProxyHandler(req, res) {
|
||||
|
||||
if (data?.error || status !== 200) {
|
||||
try {
|
||||
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data: Buffer.from(data).toString()}});
|
||||
return res.status(status).send({error: {message: "HTTP error communicating with Pyload API", data: Buffer.from(data).toString()}});
|
||||
} catch (e) {
|
||||
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data}});
|
||||
return res.status(status).send({error: {message: "HTTP error communicating with Pyload API", data}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export default async function pyloadProxyHandler(req, res) {
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
return res.status(500).send({error: {message: `Error communicating with Plex API: ${e.toString()}`}});
|
||||
return res.status(500).send({error: {message: `Error communicating with Pyload API: ${e.toString()}`}});
|
||||
}
|
||||
|
||||
return res.status(400).json({ error: 'Invalid proxy service type' });
|
||||
|
||||
Reference in New Issue
Block a user