Skip to content

Commit

Permalink
chore: release
Browse files Browse the repository at this point in the history
  • Loading branch information
RaunoT authored Jul 28, 2024
2 parents 7c9fdd3 + 5c9e316 commit 26d799b
Show file tree
Hide file tree
Showing 25 changed files with 516 additions and 208 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Present [Plex](https://plex.tv) user statistics and habits in a beautiful and or
- 📆 Rewind - allows your Plex users view their statistics and habits for a given year.
- 👀 Dashboard - provides an easily glanceable overview of activity on your server for all your libraries.
- ✨ Beautiful animations with [Framer Motion](https://www.framer.com/motion).
- 🔗 Integrates with [Overseerr](https://overseerr.dev) & [Tautulli](https://tautulli.com).
- 📊 Fuelled by data from [Tautulli](https://tautulli.com) - the backbone responsible for the heavy lifting regarding stats.
- 🔗 Integrates with [Overseerr](https://overseerr.dev) - show request breakdowns and totals.
- 🔐 Log in with Plex - uses [NextAuth.js](https://next-auth.js.org) to enable secure login and session management with your Plex account.
- 🚀 PWA support - installable on mobile devices and desktops thanks to [Serwist](https://github.com/serwist/serwist).
- 🐳 Easy deployment - run the application in a containerized environment with [Docker](https://www.docker.com).
Expand Down Expand Up @@ -53,6 +54,12 @@ services:
> _NOTE: If you run into authentication issues, try setting `NEXTAUTH_URL` and `NEXT_PUBLIC_SITE_URL` to your external Docker IP, instead of localhost. For example `http://192.168.1.1:8383`._

### Unraid

Plex Rewind is available in the Community Apps store for Unraid. Search for "Plex Rewind" and install it from grtgbln's repository.

As noted in the installation instructions, you will need to download a copy of "settings.json" into the associated settings path **before** running the application. To download the file, you can open a terminal, enter the directory and run `curl -o settings.json https://raw.githubusercontent.com/RaunoT/plex-rewind/main/config/settings.example.json`.

## Updating

To update, run `docker compose pull` and then `docker compose up -d`.
Expand Down
28 changes: 28 additions & 0 deletions config/settings.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"connection": {
"tautulliUrl": "",
"tautulliApiKey": "",
"overseerrUrl": "",
"overseerrApiKey": "",
"tmdbApiKey": ""
},
"features": {
"isRewindActive": true,
"isDashboardActive": true,
"isUsersPageActive": true,
"activeLibraries": [],
"activeDashboardItemStatistics": [
"year",
"rating",
"duration",
"plays",
"users",
"requests"
],
"activeDashboardTotalStatistics": ["size", "duration", "count", "requests"],
"dashboardDefaultPeriod": "custom",
"dashboardCustomPeriod": "30",
"googleAnalyticsId": ""
},
"test": false
}
14 changes: 9 additions & 5 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ const nextConfig = {
protocol: 'https',
hostname: 'plex.tv',
},
{
protocol: 'https',
hostname: 'image.tmdb.org',
},
],
},
logging: {
fetches: {
fullUrl: true,
},
},
// logging: {
// fetches: {
// fullUrl: true,
// },
// },
async headers() {
return [
{
Expand Down
22 changes: 16 additions & 6 deletions src/actions/update-feature-settings.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
'use server'

import { SettingsFormInitialState } from '@/types'
import {
DashboardItemStatistics,
DashboardTotalStatistics,
SettingsFormInitialState,
} from '@/types'
import { SETTINGS_PATH } from '@/utils/constants'
import getSettings from '@/utils/getSettings'
import { promises as fs } from 'fs'
Expand All @@ -12,8 +16,10 @@ const schema = z.object({
isDashboardActive: z.boolean(),
isUsersPageActive: z.boolean(),
activeLibraries: z.array(z.string()),
activeDashboardStatistics: z.array(z.string()),
dashboardDefaultPeriod: z.string().refine(
activeDashboardItemStatistics: z.array(z.string()),
activeDashboardTotalStatistics: z.array(z.string()),
dashboardDefaultPeriod: z.string(),
dashboardCustomPeriod: z.string().refine(
(value) => {
const number = parseFloat(value)

Expand All @@ -35,10 +41,14 @@ export async function saveFeaturesSettings(
isDashboardActive: formData.get('isDashboardActive') === 'on',
isUsersPageActive: formData.get('isUsersPageActive') === 'on',
activeLibraries: formData.getAll('activeLibraries') as string[],
activeDashboardStatistics: formData.getAll(
'activeDashboardStatistics',
) as string[],
activeDashboardItemStatistics: formData.getAll(
'activeDashboardItemStatistics',
) as DashboardItemStatistics,
activeDashboardTotalStatistics: formData.getAll(
'activeDashboardTotalStatistics',
) as DashboardTotalStatistics,
dashboardDefaultPeriod: formData.get('dashboardDefaultPeriod') as string,
dashboardCustomPeriod: formData.get('dashboardCustomPeriod') as string,
googleAnalyticsId: formData.get('googleAnalyticsId') as string,
}

Expand Down
22 changes: 10 additions & 12 deletions src/app/_components/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default function Home({ settings }: Props) {
return (
<div className='flex flex-col items-center text-center'>
{session?.user?.image && (
<div className='animate-fade-up relative mb-5 size-24'>
<div className='animate-fade-up relative mb-6 size-24'>
<Image
src={session?.user?.image}
alt={`${session?.user?.name} profile picture`}
Expand All @@ -118,17 +118,15 @@ export default function Home({ settings }: Props) {
</div>
)}

<div className='animate-fade-up animation-delay-300 mb-4'>
<h1 className='flex items-center gap-3 text-[2.5rem] font-bold'>
<Image
src={plexSvg}
className='-mb-1.5 h-[2.3rem] w-auto sm:-mb-2'
alt='Plex logo'
priority
/>
<span>rewind</span>
</h1>
</div>
<h1 className='animate-fade-up animation-delay-300 mb-6 text-[2.5rem] font-bold leading-none'>
<Image
src={plexSvg}
className='mb-0.5 mr-3 inline h-[2.25rem] w-auto'
alt='Plex logo'
priority
/>
<span>rewind</span>
</h1>

<div className='animate-fade-in animation-delay-600'>
{!isLoggedIn && (
Expand Down
28 changes: 28 additions & 0 deletions src/app/api/image/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url)
const url = searchParams.get('url')

if (!url) {
return new Response('URL parameter is missing', { status: 400 })
}

const res = await fetch(url)

if (!res.ok) {
return new Response('Failed to fetch the image', {
status: res.status,
})
}

const headers = new Headers(res.headers)
const body = await res.arrayBuffer()

return new Response(body, {
status: res.status,
headers: headers,
})
} catch (error) {
return new Response('An error occurred', { status: 500 })
}
}
17 changes: 10 additions & 7 deletions src/app/dashboard/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,17 @@ async function DashboardContent({ params, searchParams }: Props) {
const period = getPeriod(searchParams, settings)
const [items, totalDuration, totalSize, serverId] = await Promise.all([
getItems(library, period.daysAgo),
getTotalDuration(library, period.string),
getTotalSize(library),
getTotalDuration(library, period.string, settings),
getTotalSize(library, settings),
getServerId(),
])
const isCountActive =
settings.features.activeDashboardTotalStatistics.includes('count')
const countValue =
library.section_type === 'movie'
? Number(library.count)
: Number(library.child_count)
const count = isCountActive ? countValue.toLocaleString('en-US') : undefined

return (
<Dashboard
Expand All @@ -55,11 +62,7 @@ async function DashboardContent({ params, searchParams }: Props) {
totalSize={totalSize}
type={library.section_type}
serverId={serverId}
count={
library.section_type === 'movie'
? Number(library.count).toLocaleString('en-US')
: Number(library.child_count).toLocaleString('en-US')
}
count={count}
settings={settings}
/>
)
Expand Down
25 changes: 9 additions & 16 deletions src/app/dashboard/_components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ type Props = {
title: string
items?: TautulliItemRow[]
totalDuration?: string
totalSize?: string | null
totalRequests?: number
type?: string
totalSize?: string | number
type: 'movie' | 'show' | 'artist' | 'users'
serverId?: string
count?: string
settings: Settings
Expand All @@ -27,8 +26,7 @@ export default function Dashboard({
items,
totalDuration,
totalSize,
totalRequests,
type = '',
type,
serverId = '',
count,
settings,
Expand All @@ -42,8 +40,9 @@ export default function Dashboard({
<ul className='icon-stats-container mb-1 sm:gap-x-3'>
{totalSize && (
<li className='icon-stat-wrapper icon-stat-wrapper--clean'>
<FolderIcon />
{type === 'users' ? <UserIcon /> : <FolderIcon />}
{totalSize}
{type === 'users' && ' users'}
</li>
)}
{count && (
Expand All @@ -58,7 +57,7 @@ export default function Dashboard({
? 'episodes'
: type === 'artist'
? 'tracks'
: 'users'}
: 'requests'}
</span>
</span>
</li>
Expand All @@ -69,12 +68,6 @@ export default function Dashboard({
{totalDuration}
</li>
)}
{!!totalRequests && (
<li className='icon-stat-wrapper icon-stat-wrapper--clean'>
<QuestionMarkCircleIcon />
{totalRequests} requests
</li>
)}
</ul>

{items?.length ? (
Expand Down Expand Up @@ -105,7 +98,7 @@ function getTitleIcon(type: string) {
return <PlayCircleIcon className={className} />
case 'artist':
return <MusicalNoteIcon className={className} />
default:
case 'users':
return <UserIcon className={className} />
}
}
Expand All @@ -118,7 +111,7 @@ function getCountIcon(type: string) {
return <PlayCircleIcon />
case 'artist':
return <MusicalNoteIcon />
default:
return <UserIcon />
case 'users':
return <QuestionMarkCircleIcon />
}
}
Loading

0 comments on commit 26d799b

Please sign in to comment.