Skip to content

Commit

Permalink
feat: add overseerr version and update availability status to sidebar
Browse files Browse the repository at this point in the history
sort of experimental so may be kinda broken. :)
  • Loading branch information
sct committed Apr 13, 2021
1 parent a035d60 commit ecf1312
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 25 deletions.
133 changes: 133 additions & 0 deletions server/api/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import cacheManager from '../lib/cache';
import logger from '../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 getOverseerrReleases({
take = 20,
}: {
take?: number;
} = {}): Promise<GitHubRelease[]> {
try {
const data = await this.get<GitHubRelease[]>(
'/repos/sct/overseerr/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. Overseerr can't check if it's on the latest version.",
{ label: 'GitHub API', errorMessage: e.message }
);
return [];
}
}

public async getOverseerrCommits({
take = 20,
branch = 'develop',
}: {
take?: number;
branch?: string;
} = {}): Promise<GithubCommit[]> {
try {
const data = await this.get<GithubCommit[]>(
'/repos/sct/overseerr/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. Overseerr can't check if it's on the latest version.",
{ label: 'GitHub API', errorMessage: e.message }
);
return [];
}
}
}

export default GithubAPI;
7 changes: 7 additions & 0 deletions server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@ export interface CacheItem {
vsize: number;
};
}

export interface StatusResponse {
version: string;
commitTag: string;
updateAvailable: boolean;
commitsBehind: number;
}
6 changes: 5 additions & 1 deletion server/lib/cache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import NodeCache from 'node-cache';

export type AvailableCacheIds = 'tmdb' | 'radarr' | 'sonarr' | 'rt';
export type AvailableCacheIds = 'tmdb' | 'radarr' | 'sonarr' | 'rt' | 'github';

const DEFAULT_TTL = 300;
const DEFAULT_CHECK_PERIOD = 120;
Expand Down Expand Up @@ -44,6 +44,10 @@ class CacheManager {
stdTtl: 43200,
checkPeriod: 60 * 30,
}),
github: new Cache('github', 'GitHub API', {
stdTtl: 21600,
checkPeriod: 60 * 30,
}),
};

public getCache(id: AvailableCacheIds): Cache {
Expand Down
74 changes: 58 additions & 16 deletions server/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,75 @@
import { Router } from 'express';
import user from './user';
import authRoutes from './auth';
import { checkUser, isAuthenticated } from '../middleware/auth';
import settingsRoutes from './settings';
import GithubAPI from '../api/github';
import TheMovieDb from '../api/themoviedb';
import { StatusResponse } from '../interfaces/api/settingsInterfaces';
import { Permission } from '../lib/permissions';
import { getSettings } from '../lib/settings';
import searchRoutes from './search';
import { checkUser, isAuthenticated } from '../middleware/auth';
import { mapProductionCompany } from '../models/Movie';
import { mapNetwork } from '../models/Tv';
import { appDataPath, appDataStatus } from '../utils/appDataVolume';
import { getAppVersion, getCommitTag } from '../utils/appVersion';
import authRoutes from './auth';
import collectionRoutes from './collection';
import discoverRoutes from './discover';
import requestRoutes from './request';
import movieRoutes from './movie';
import tvRoutes from './tv';
import mediaRoutes from './media';
import movieRoutes from './movie';
import personRoutes from './person';
import collectionRoutes from './collection';
import { getAppVersion, getCommitTag } from '../utils/appVersion';
import requestRoutes from './request';
import searchRoutes from './search';
import serviceRoutes from './service';
import { appDataStatus, appDataPath } from '../utils/appDataVolume';
import TheMovieDb from '../api/themoviedb';
import { mapProductionCompany } from '../models/Movie';
import { mapNetwork } from '../models/Tv';
import settingsRoutes from './settings';
import tvRoutes from './tv';
import user from './user';

const router = Router();

router.use(checkUser);

router.get('/status', (req, res) => {
router.get<unknown, StatusResponse>('/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.getOverseerrCommits();

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.getOverseerrReleases();

if (releases.length) {
const latestVersion = releases[0];

if (latestVersion.name !== currentVersion) {
updateAvailable = true;
}
}
}

return res.status(200).json({
version: getAppVersion(),
commitTag: getCommitTag(),
updateAvailable,
commitsBehind,
});
});

Expand All @@ -39,7 +81,7 @@ router.get('/status/appdata', (_req, res) => {
});

router.use('/user', isAuthenticated(), user);
router.get('/settings/public', (_req, res) => {
router.get('/settings/public', async (_req, res) => {
const settings = getSettings();

return res.status(200).json(settings.fullPublicSettings);
Expand Down
8 changes: 6 additions & 2 deletions src/components/Layout/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defineMessages, useIntl } from 'react-intl';
import useClickOutside from '../../../hooks/useClickOutside';
import { Permission, useUser } from '../../../hooks/useUser';
import Transition from '../../Transition';
import VersionStatus from '../VersionStatus';

const messages = defineMessages({
dashboard: 'Discover',
Expand Down Expand Up @@ -122,6 +123,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
const intl = useIntl();
const { hasPermission } = useUser();
useClickOutside(navRef, () => setClosed());

return (
<>
<div className="md:hidden">
Expand Down Expand Up @@ -172,7 +174,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
</div>
<div
ref={navRef}
className="flex-1 h-0 pt-5 pb-4 overflow-y-auto"
className="flex flex-col flex-1 h-0 pt-5 pb-4 overflow-y-auto"
>
<div className="flex items-center flex-shrink-0 px-4">
<span className="text-xl text-gray-50">
Expand All @@ -181,7 +183,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
</a>
</span>
</div>
<nav className="px-2 mt-5 space-y-1">
<nav className="flex-1 px-2 mt-5 space-y-1">
{SidebarLinks.filter((link) =>
link.requiredPermission
? hasPermission(link.requiredPermission)
Expand Down Expand Up @@ -221,6 +223,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
);
})}
</nav>
{hasPermission(Permission.ADMIN) && <VersionStatus />}
</div>
</div>
<div className="flex-shrink-0 w-14">
Expand Down Expand Up @@ -273,6 +276,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
);
})}
</nav>
{hasPermission(Permission.ADMIN) && <VersionStatus />}
</div>
</div>
</div>
Expand Down

0 comments on commit ecf1312

Please sign in to comment.