mirror of
https://github.com/agregarr/agregarr.git
synced 2025-12-30 14:59:41 -06:00
feat: add version checking
This commit is contained in:
133
server/api/github.ts
Normal file
133
server/api/github.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import cacheManager from '@server/lib/cache';
|
||||
import logger from '@server/logger';
|
||||
import ExternalAPI from './externalapi';
|
||||
|
||||
interface GitHubRelease {
|
||||
url: string;
|
||||
assets_url: string;
|
||||
upload_url: string;
|
||||
html_url: string;
|
||||
id: number;
|
||||
node_id: string;
|
||||
tag_name: string;
|
||||
target_commitish: string;
|
||||
name: string;
|
||||
draft: boolean;
|
||||
prerelease: boolean;
|
||||
created_at: string;
|
||||
published_at: string;
|
||||
tarball_url: string;
|
||||
zipball_url: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
interface GithubCommit {
|
||||
sha: string;
|
||||
node_id: string;
|
||||
commit: {
|
||||
author: {
|
||||
name: string;
|
||||
email: string;
|
||||
date: string;
|
||||
};
|
||||
committer: {
|
||||
name: string;
|
||||
email: string;
|
||||
date: string;
|
||||
};
|
||||
message: string;
|
||||
tree: {
|
||||
sha: string;
|
||||
url: string;
|
||||
};
|
||||
url: string;
|
||||
comment_count: number;
|
||||
verification: {
|
||||
verified: boolean;
|
||||
reason: string;
|
||||
signature: string;
|
||||
payload: string;
|
||||
};
|
||||
};
|
||||
url: string;
|
||||
html_url: string;
|
||||
comments_url: string;
|
||||
parents: [
|
||||
{
|
||||
sha: string;
|
||||
url: string;
|
||||
html_url: string;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
class GithubAPI extends ExternalAPI {
|
||||
constructor() {
|
||||
super(
|
||||
'https://api.github.com',
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
nodeCache: cacheManager.getCache('github').data,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async getAgregarrReleases({
|
||||
take = 20,
|
||||
}: {
|
||||
take?: number;
|
||||
} = {}): Promise<GitHubRelease[]> {
|
||||
try {
|
||||
const data = await this.get<GitHubRelease[]>(
|
||||
'/repos/agregarr/agregarr/releases',
|
||||
{
|
||||
params: {
|
||||
per_page: take,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
logger.warn(
|
||||
"Failed to retrieve GitHub releases. This may be an issue on GitHub's end. Agregarr can't check if it's on the latest version.",
|
||||
{ label: 'GitHub API', errorMessage: e.message }
|
||||
);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public async getAgregarrCommits({
|
||||
take = 20,
|
||||
branch = 'develop',
|
||||
}: {
|
||||
take?: number;
|
||||
branch?: string;
|
||||
} = {}): Promise<GithubCommit[]> {
|
||||
try {
|
||||
const data = await this.get<GithubCommit[]>(
|
||||
'/repos/agregarr/agregarr/commits',
|
||||
{
|
||||
params: {
|
||||
per_page: take,
|
||||
branch,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
logger.warn(
|
||||
"Failed to retrieve GitHub commits. This may be an issue on GitHub's end. Agregarr can't check if it's on the latest version.",
|
||||
{ label: 'GitHub API', errorMessage: e.message }
|
||||
);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GithubAPI;
|
||||
@@ -6,6 +6,7 @@ import { startJobs } from '@server/job/schedule';
|
||||
import { getSettings } from '@server/lib/settings';
|
||||
import logger from '@server/logger';
|
||||
import routes from '@server/routes';
|
||||
import restartFlag from '@server/utils/restartFlag';
|
||||
// imageproxy removed - not needed for collections-only app
|
||||
import { getAppVersion } from '@server/utils/appVersion';
|
||||
import { getClientIp } from '@supercharge/request-ip';
|
||||
@@ -44,6 +45,9 @@ app
|
||||
// Load Settings
|
||||
const settings = getSettings().load();
|
||||
|
||||
// Initialize RestartFlag with current settings
|
||||
restartFlag.initializeSettings(settings.main);
|
||||
|
||||
// Initialize sync status for existing collections (one-time migration)
|
||||
settings.initializeSyncStatusForExistingCollections();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// PushoverAPI removed - notification system not needed
|
||||
import GithubAPI from '@server/api/github';
|
||||
import TheMovieDb from '@server/api/themoviedb';
|
||||
import type {
|
||||
TmdbMovieResult,
|
||||
@@ -12,6 +13,7 @@ import { mapNetwork } from '@server/models/Tv';
|
||||
import settingsRoutes from '@server/routes/settings';
|
||||
import { appDataPath, appDataStatus } from '@server/utils/appDataVolume';
|
||||
import { getAppVersion, getCommitTag } from '@server/utils/appVersion';
|
||||
import restartFlag from '@server/utils/restartFlag';
|
||||
import { isPerson } from '@server/utils/typeHelpers';
|
||||
import { Router } from 'express';
|
||||
import authRoutes from './auth';
|
||||
@@ -39,14 +41,51 @@ const router = Router();
|
||||
|
||||
router.use(checkUser);
|
||||
|
||||
router.get('/status', (_req, res) => {
|
||||
router.get('/status', async (_req, res) => {
|
||||
const githubApi = new GithubAPI();
|
||||
|
||||
const currentVersion = getAppVersion();
|
||||
const commitTag = getCommitTag();
|
||||
let updateAvailable = false;
|
||||
let commitsBehind = 0;
|
||||
|
||||
if (currentVersion.startsWith('develop-') && commitTag !== 'local') {
|
||||
const commits = await githubApi.getAgregarrCommits();
|
||||
|
||||
if (commits.length) {
|
||||
const filteredCommits = commits.filter(
|
||||
(commit) => !commit.commit.message.includes('[skip ci]')
|
||||
);
|
||||
if (filteredCommits[0].sha !== commitTag) {
|
||||
updateAvailable = true;
|
||||
}
|
||||
|
||||
const commitIndex = filteredCommits.findIndex(
|
||||
(commit) => commit.sha === commitTag
|
||||
);
|
||||
|
||||
if (updateAvailable) {
|
||||
commitsBehind = commitIndex;
|
||||
}
|
||||
}
|
||||
} else if (commitTag !== 'local') {
|
||||
const releases = await githubApi.getAgregarrReleases();
|
||||
|
||||
if (releases.length) {
|
||||
const latestVersion = releases[0];
|
||||
|
||||
if (!latestVersion.name.includes(currentVersion)) {
|
||||
updateAvailable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
version: getAppVersion(),
|
||||
status: 'ok',
|
||||
commitTag: getCommitTag(),
|
||||
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
appData: appDataStatus(),
|
||||
appDataPath: appDataPath(),
|
||||
updateAvailable,
|
||||
commitsBehind,
|
||||
restartRequired: restartFlag.isSet(),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
23
server/utils/restartFlag.ts
Normal file
23
server/utils/restartFlag.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { MainSettings } from '@server/lib/settings';
|
||||
import { getSettings } from '@server/lib/settings';
|
||||
|
||||
class RestartFlag {
|
||||
private settings: MainSettings;
|
||||
|
||||
public initializeSettings(settings: MainSettings): void {
|
||||
this.settings = { ...settings };
|
||||
}
|
||||
|
||||
public isSet(): boolean {
|
||||
const settings = getSettings().main;
|
||||
|
||||
return (
|
||||
this.settings.csrfProtection !== settings.csrfProtection ||
|
||||
this.settings.trustProxy !== settings.trustProxy
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const restartFlag = new RestartFlag();
|
||||
|
||||
export default restartFlag;
|
||||
Reference in New Issue
Block a user