Skip to content

Commit

Permalink
chore: release
Browse files Browse the repository at this point in the history
  • Loading branch information
RaunoT authored Jul 21, 2024
2 parents 2078128 + 50e0cf9 commit f13a852
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 40 deletions.
32 changes: 25 additions & 7 deletions src/actions/update-connection-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,25 @@ export async function saveConnectionSettings(
try {
// Test Tautulli
try {
await fetch(
const res = await fetch(
`${data.tautulliUrl}/api/v2?apikey=${data.tautulliApiKey}&cmd=status`,
{
cache: 'no-store',
},
)

if (!res.ok) {
console.error('Error testing Tautulli connection!', res.status)
return {
message: 'Tautulli - invalid API key!',
status: 'error',
fields: data,
}
}
} catch (error) {
console.error('Error testing Tautulli connection!', error)
return {
message: 'Unable to connect to Tautulli!',
message: 'Tautulli - unable to connect!',
status: 'error',
fields: data,
}
Expand All @@ -48,16 +57,25 @@ export async function saveConnectionSettings(
// Test Overseerr
if (data.overseerrUrl && data.overseerrApiKey) {
try {
await fetch(`${data.overseerrUrl}/api/v1/status`, {
const res = await fetch(`${data.overseerrUrl}/api/v1/user`, {
headers: {
'X-API-KEY': data.overseerrApiKey,
},
cache: 'no-store',
})

if (!res.ok) {
console.error('Error testing Overseerr connection!', res.status)
return {
message: 'Overseerr - invalid API key!',
status: 'error',
fields: data,
}
}
} catch (error) {
console.error('Error testing Overseerr connection!', error)
return {
message: 'Unable to connect to Overseerr!',
message: 'Overseerr - unable to connect!',
status: 'error',
fields: data,
}
Expand All @@ -76,23 +94,23 @@ export async function saveConnectionSettings(
if (!res.ok) {
console.error('Error testing TMDB connection!', res.status)
return {
message: 'Invalid TMDB API key!',
message: 'TMDB - invalid API key!',
status: 'error',
fields: data,
}
}
} catch (error) {
console.error('Error testing TMDB connection!', error)
return {
message: 'Error testing TMDB connection!',
message: 'TMDB - unable to connect!',
status: 'error',
fields: data,
}
}
} catch (error) {
console.error('Error testing connection!', error)
return {
message: 'Unable to connect!',
message: 'Something went wrong!',
status: 'error',
fields: data,
}
Expand Down
3 changes: 2 additions & 1 deletion src/actions/update-feature-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const schema = z.object({
return number > 1 && number <= 3000
},
{
message: 'Dashboard: default period must be > 1 and <= 3000',
message: 'Dashboard - default period must be > 1 and <= 3000',
},
),
googleAnalyticsId: z.string(),
Expand All @@ -45,6 +45,7 @@ export async function saveFeaturesSettings(
// Save settings
try {
const settings = await getSettings()

schema.parse(data)
settings.features = data

Expand Down
49 changes: 33 additions & 16 deletions src/app/_components/AppProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'use client'

import { Settings } from '@/types'
import { CogIcon, XCircleIcon } from '@heroicons/react/24/outline'
import { Settings, Version } from '@/types'
import {
ArrowPathIcon,
CogIcon,
XCircleIcon,
} from '@heroicons/react/24/outline'
import clsx from 'clsx'
import { useSession } from 'next-auth/react'
import Image from 'next/image'
Expand All @@ -13,9 +17,10 @@ import stars from '../_assets/stars.png'
type Props = {
children: ReactNode
settings: Settings
version: Version
}

export default function AppProvider({ children, settings }: Props) {
export default function AppProvider({ children, settings, version }: Props) {
const pathname = usePathname()
const { data: session } = useSession()
const [isSettings, setIsSettings] = useState(pathname.startsWith('/settings'))
Expand Down Expand Up @@ -49,19 +54,31 @@ export default function AppProvider({ children, settings }: Props) {
<div className='bg-clouds sm:opacity-50' />
</div>

{settings.test && session?.user?.isAdmin && (
<Link
href={isSettings ? '/' : '/settings/features'}
className='absolute right-3 top-3 sm:right-4 sm:top-4'
aria-label={isSettings ? 'Close settings' : 'Open settings'}
>
{isSettings ? (
<XCircleIcon className='size-6' />
) : (
<CogIcon className='size-6' />
)}
</Link>
)}
<div className='absolute right-3 top-3 flex items-center gap-3 sm:right-4 sm:top-4'>
{version.hasUpdate && (
<a
href='https://github.com/RaunoT/plex-rewind/releases'
aria-label='Update available'
target='_blank'
className='link-light'
>
<ArrowPathIcon className='size-6' />
</a>
)}
{settings.test && session?.user?.isAdmin && (
<Link
href={isSettings ? '/' : '/settings/features'}
aria-label={isSettings ? 'Close settings' : 'Open settings'}
className='link-light'
>
{isSettings ? (
<XCircleIcon className='size-6' />
) : (
<CogIcon className='size-6' />
)}
</Link>
)}
</div>

{children}
</main>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/PageTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function PageTitle({ title, noBack }: Props) {
<Link
href='/'
className={clsx(
'ml-5 block w-5 transition-transform hover:translate-x-0.5 hover:opacity-75 aria-disabled:pointer-events-none aria-disabled:opacity-75',
'link-light ml-5 block w-5 transition-transform hover:translate-x-0.5 aria-disabled:pointer-events-none aria-disabled:opacity-75',
{
'absolute left-0 top-1/2 my-auto -translate-y-1/2': title,
},
Expand Down
6 changes: 5 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
META_TITLE_TEMPLATE,
} from '@/utils/constants'
import getSettings from '@/utils/getSettings'
import getVersion from '@/utils/getVersion'
import { Metadata, Viewport } from 'next'
import { PublicEnvScript } from 'next-runtime-env'
import { ReactNode } from 'react'
Expand Down Expand Up @@ -56,6 +57,7 @@ type Props = {

export default async function RootLayout({ children }: Props) {
const settings = await getSettings()
const version = await getVersion()

return (
<html lang='en'>
Expand All @@ -67,7 +69,9 @@ export default async function RootLayout({ children }: Props) {
<GoogleAnalytics id={settings.features.googleAnalyticsId} />
)}
<SessionProviderWrapper>
<AppProvider settings={settings}>{children}</AppProvider>
<AppProvider settings={settings} version={version}>
{children}
</AppProvider>
</SessionProviderWrapper>
</body>
</html>
Expand Down
42 changes: 32 additions & 10 deletions src/app/settings/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import githubSvg from '@/assets/github.svg'
import { authOptions } from '@/lib/auth'
import getSettings from '@/utils/getSettings'
import getVersion from '@/utils/getVersion'
import { CurrencyEuroIcon, HeartIcon } from '@heroicons/react/24/outline'
import { getServerSession } from 'next-auth'
import { env } from 'next-runtime-env'
import Image from 'next/image'
import { redirect } from 'next/navigation'
import { ReactNode } from 'react'
Expand All @@ -16,6 +17,7 @@ type Props = {
export default async function SettingsLayout({ children }: Props) {
const session = await getServerSession(authOptions)
const settings = await getSettings()
const version = await getVersion()

if (!session?.user?.isAdmin && settings.test) {
redirect('/')
Expand All @@ -29,24 +31,44 @@ export default async function SettingsLayout({ children }: Props) {
/>
{settings.test && <SettingsNav />}
{children}
<div className='mt-8 flex flex-col items-center gap-2'>

<div className='glass-sheet mt-4 flex flex-col flex-wrap justify-between gap-3 py-4 sm:flex-row'>
<a
href='https://github.com/RaunoT/plex-rewind/issues'
href='https://www.paypal.com/paypalme/raunot'
target='_blank'
className='link inline-flex gap-2'
className='link-light inline-flex items-center gap-2'
>
<Image src={githubSvg} alt='GitHub' className='size-6' />
Report an issue on GitHub
<CurrencyEuroIcon className='size-6 text-yellow-500' />
Buy me a coffee
</a>
<a
href='https://www.patreon.com/PlexRewind'
target='_blank'
className='link-light inline-flex items-center gap-2'
>
<HeartIcon className='size-6 text-red-500' />
Become a sponsor
</a>

<a
className='w-fit font-mono text-xs text-white/25'
href='https://github.com/RaunoT/plex-rewind/releases'
href='https://github.com/RaunoT/plex-rewind/issues'
target='_blank'
className='link-light inline-flex items-center gap-2'
>
{env('NEXT_PUBLIC_VERSION_TAG') || 'local'}
<Image src={githubSvg} alt='GitHub' className='size-[24px] p-0.5' />
Report an issue
</a>
</div>
<a
className='link mx-auto mt-4 block w-fit text-center text-sm'
href='https://github.com/RaunoT/plex-rewind/releases'
target='_blank'
>
{version.hasUpdate && <span className='block'>Update available</span>}
<span className='font-mono text-xs'>
{version.currentVersion}
{version.hasUpdate && ` → ${version.latestVersion}`}
</span>
</a>
</div>
)
}
4 changes: 4 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
@apply text-neutral-400 hover:text-neutral-500;
}

.link-light {
@apply hover:opacity-80;
}

.nav {
@apply flex flex-wrap items-center justify-center gap-3 gap-y-1 text-xs font-medium uppercase sm:gap-4 sm:text-sm 2xl:text-base;
}
Expand Down
6 changes: 6 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,9 @@ export type Settings = {
features: FeaturesSettings
test: boolean
}

export type Version = {
hasUpdate: boolean
latestVersion: string
currentVersion: string
}
8 changes: 4 additions & 4 deletions src/utils/fetchOverseerr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type OverseerrResponse<T> = {

export default async function fetchOverseerr<T>(
endpoint: string,
cache: boolean = true,
cache: boolean = false,
): Promise<T | null> {
const settings = await getSettings()

Expand Down Expand Up @@ -64,7 +64,7 @@ type User = {
export async function fetchOverseerrUserId(
plexId: string,
): Promise<number | null> {
const users = await fetchOverseerr<OverseerrResponse<User[]>>('user')
const users = await fetchOverseerr<OverseerrResponse<User[]>>('user', true)
const user = users?.results?.find((user) => String(user.plexId) === plexId)

return user ? user.id : null
Expand All @@ -91,8 +91,8 @@ export async function fetchPaginatedOverseerrStats(
const requestsData =
await fetchOverseerr<OverseerrResponse<PaginatedRequestItem[]>>(reqUrl)

if (requestsData) {
const requestsDataFiltered = requestsData.results?.filter(
if (requestsData && requestsData.results) {
const requestsDataFiltered = requestsData.results.filter(
(request) => request.createdAt > timeframe,
)
requestsArr = [...requestsDataFiltered, ...requestsArr]
Expand Down
53 changes: 53 additions & 0 deletions src/utils/getVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Version } from '@/types'
import { env } from 'next-runtime-env'

type GitHubRelease = {
tag_name: string
draft: boolean
prerelease: boolean
}

export default async function getVersion(): Promise<Version> {
const currentVersion = env('NEXT_PUBLIC_VERSION_TAG')
? `v${env('NEXT_PUBLIC_VERSION_TAG')}`
: 'local'
const isDevelop = currentVersion.includes('develop')
let latestVersion = currentVersion

if (currentVersion !== 'local') {
try {
const res = await fetch(
'https://api.github.com/repos/RaunoT/plex-rewind/releases',
{
next: {
revalidate: 3600,
},
},
)
const data = await res.json()

if (!res.ok) {
console.error(
`GitHub API request failed: ${res.status} ${res.statusText}`,
)
}

if (data) {
const latestRelease = data.find(
(release: GitHubRelease) =>
!release.draft && (!isDevelop ? !release.prerelease : true),
)

latestVersion = latestRelease.tag_name
}
} catch (error) {
console.error('Error fetching latest version:', error)
}
}

return {
hasUpdate: latestVersion !== currentVersion,
latestVersion,
currentVersion,
}
}

0 comments on commit f13a852

Please sign in to comment.