+
{{ props.MPAA }}
Ends at 6:23pm
@@ -164,6 +189,7 @@ const props = defineProps({
backdrop-filter: blur(2.6px);
-webkit-backdrop-filter: blur(2.6px);
border: 1px solid rgba(255, 255, 255, 0.2);
+ border-right: none;
text-align: center;
transition: all var(--hover-animation-speed) ease 0.2s;
opacity: 100%;
@@ -216,7 +242,7 @@ const props = defineProps({
gap: 2em;
min-height: 95%;
}
-.scroller-item:hover .info-box-content {
+.scroller-item-img:hover .info-box-content {
max-height: 240px;
transition-delay: 0.05s;
}
diff --git a/src/feed.ts b/src/feed.ts
index 5d0853d..6602a03 100644
--- a/src/feed.ts
+++ b/src/feed.ts
@@ -1,53 +1,53 @@
-const ContinueWatching: FeedItem[] = [
- {
- title: 'Bloom Into You',
- subtext: 'S1:E7 - Secrets Galore / Sparks',
- image: 'biy_ep.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace. This is more content than there was before.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'The Bear',
- subtext: 'S3:E9 - Apologies',
- image: 'bear_ep.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'BOCCHI THE ROCK!',
- subtext: 'S1:E12 - Morning Light Falls on You',
- image: 'bocchi_ep.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'Twenty Five Twenty One',
- subtext: 'S1:E5 - Episode 5',
- image: '2521_ep.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
-]
+// const ContinueWatching: FeedItem[] = [
+// {
+// title: 'Bloom Into You',
+// subtext: 'S1:E7 - Secrets Galore / Sparks',
+// image: 'biy_ep.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace. This is more content than there was before.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'The Bear',
+// subtext: 'S3:E9 - Apologies',
+// image: 'bear_ep.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'BOCCHI THE ROCK!',
+// subtext: 'S1:E12 - Morning Light Falls on You',
+// image: 'bocchi_ep.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'Twenty Five Twenty One',
+// subtext: 'S1:E5 - Episode 5',
+// image: '2521_ep.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// ]
type FeedItem = {
title: string
@@ -60,265 +60,266 @@ type FeedItem = {
date: string
MPAA: string
tag: string
+ itemId: string
}
-const LatestMovies: FeedItem[] = [
- {
- title: 'Alien',
- subtext: '1979',
- image: 'alien.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Your Name',
- subtext: '2017',
- image: 'yourname.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'SoulMate',
- subtext: '2016',
- image: 'soulmate.jpg',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- tag: '',
- },
- {
- title: 'Burning',
- subtext: '2018',
- image: 'burning.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Better Days',
- subtext: '2019',
- image: 'betterdays.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'House of Hummingbird',
- subtext: '2019',
- image: 'hummingbird.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Where We Belong',
- subtext: '2019',
- image: 'wwb.jpg',
- summary: `Will there be someone like you where i'm going?\n
-A teenager creates a checklist to complete before she studies abroad and realizes that her toughest task is leaving behind her best friend.`,
- infoSubtext: 'ที่ตรงนั้น มีฉันหรือเปล่า',
- imdbRating: '7.6',
- runtime: '2h 12m',
- date: '2019',
- MPAA: 'R',
- tag: '',
- },
- {
- title: '1917',
- subtext: '2019',
- image: '1917.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Life of Brian',
- subtext: '1979',
- image: 'lob.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Shoplifters',
- subtext: '2018',
- image: 'shoplifters.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'The Lobster',
- subtext: '2016',
- image: 'lobster.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
- {
- title: 'Her',
- subtext: '2013',
- image: 'her.jpg',
- tag: '',
- summary:
- 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
- infoSubtext: '七月与安生',
- imdbRating: '7.3',
- runtime: '1h 50m',
- date: '2016',
- MPAA: 'PG-13',
- },
-]
+// const LatestMovies: FeedItem[] = [
+// {
+// title: 'Alien',
+// subtext: '1979',
+// image: 'alien.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Your Name',
+// subtext: '2017',
+// image: 'yourname.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'SoulMate',
+// subtext: '2016',
+// image: 'soulmate.jpg',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// tag: '',
+// },
+// {
+// title: 'Burning',
+// subtext: '2018',
+// image: 'burning.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Better Days',
+// subtext: '2019',
+// image: 'betterdays.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'House of Hummingbird',
+// subtext: '2019',
+// image: 'hummingbird.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Where We Belong',
+// subtext: '2019',
+// image: 'wwb.jpg',
+// summary: `Will there be someone like you where i'm going?\n
+// A teenager creates a checklist to complete before she studies abroad and realizes that her toughest task is leaving behind her best friend.`,
+// infoSubtext: 'ที่ตรงนั้น มีฉันหรือเปล่า',
+// imdbRating: '7.6',
+// runtime: '2h 12m',
+// date: '2019',
+// MPAA: 'R',
+// tag: '',
+// },
+// {
+// title: '1917',
+// subtext: '2019',
+// image: '1917.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Life of Brian',
+// subtext: '1979',
+// image: 'lob.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Shoplifters',
+// subtext: '2018',
+// image: 'shoplifters.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'The Lobster',
+// subtext: '2016',
+// image: 'lobster.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// {
+// title: 'Her',
+// subtext: '2013',
+// image: 'her.jpg',
+// tag: '',
+// summary:
+// 'The films spans two decades as the story unfolds in a series of flashbacks that begin when Qiyue and Ansheng were just thirteen. The two became inseparable until they met a boy who ended up tearing their lives apart.',
+// infoSubtext: '七月与安生',
+// imdbRating: '7.3',
+// runtime: '1h 50m',
+// date: '2016',
+// MPAA: 'PG-13',
+// },
+// ]
-const LatestAnime: FeedItem[] = [
- {
- title: 'Re:Zero - Starting Life in Another World',
- subtext: 'S3:E6 - Conditions of the Life We Live In',
- image: 'rezero.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'Serial Experiments Lain',
- subtext: '1998',
- image: 'lain.jpg',
- tag: '8',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- },
- {
- title: 'Monster',
- subtext: '2004-2005',
- image: 'monster.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'Bloom Into You',
- subtext: '2018',
- image: 'biy.jpg',
- tag: '13',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- },
- {
- title: 'Attack on Titan',
- subtext: '2013-2022',
- image: 'aot.jpg',
- tag: '99+',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- },
- {
- title: "Frieren: Beyond Journey's End",
- subtext: '2023-2024',
- image: 'frieren.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'Lycoris Recoil',
- subtext: '2022',
- image: 'lycoris.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
- {
- title: 'Tengoku Daimakyo',
- subtext: '2023 - Present',
- image: 'tengoku.jpg',
- summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
- infoSubtext: 'S1:E5 - Episode 5',
- imdbRating: '8.7',
- runtime: '1h 16m',
- date: '2022',
- MPAA: 'TV-14',
- tag: '',
- },
-]
+// const LatestAnime: FeedItem[] = [
+// {
+// title: 'Re:Zero - Starting Life in Another World',
+// subtext: 'S3:E6 - Conditions of the Life We Live In',
+// image: 'rezero.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'Serial Experiments Lain',
+// subtext: '1998',
+// image: 'lain.jpg',
+// tag: '8',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// },
+// {
+// title: 'Monster',
+// subtext: '2004-2005',
+// image: 'monster.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'Bloom Into You',
+// subtext: '2018',
+// image: 'biy.jpg',
+// tag: '13',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// },
+// {
+// title: 'Attack on Titan',
+// subtext: '2013-2022',
+// image: 'aot.jpg',
+// tag: '99+',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// },
+// {
+// title: "Frieren: Beyond Journey's End",
+// subtext: '2023-2024',
+// image: 'frieren.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'Lycoris Recoil',
+// subtext: '2022',
+// image: 'lycoris.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// {
+// title: 'Tengoku Daimakyo',
+// subtext: '2023 - Present',
+// image: 'tengoku.jpg',
+// summary: `Hee-do takes one giant leap closer to her dream. She's eager to tell Yi-jin the good news — but realizes he's disappeared without a trace.`,
+// infoSubtext: 'S1:E5 - Episode 5',
+// imdbRating: '8.7',
+// runtime: '1h 16m',
+// date: '2022',
+// MPAA: 'TV-14',
+// tag: '',
+// },
+// ]
export type { FeedItem }
-export { ContinueWatching, LatestMovies, LatestAnime }
+// export { ContinueWatching, LatestMovies, LatestAnime }
diff --git a/src/jfapi.ts b/src/jfapi.ts
index 01eed64..5b57604 100644
--- a/src/jfapi.ts
+++ b/src/jfapi.ts
@@ -1,6 +1,3 @@
-import { Jellyfin } from '@jellyfin/sdk'
-import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api'
-
function detectBrowser() {
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edg') > -1) {
@@ -20,162 +17,179 @@ function detectBrowser() {
return 'Unknown'
}
-const jellyfin = new Jellyfin({
- clientInfo: {
- name: 'Featherfin',
- version: '0.0.1',
- },
- deviceInfo: {
- name: detectBrowser(),
- id: 'abc123',
- },
-})
-
-const JF = jellyfin.createApi('http://192.168.0.63:30013')
+type Endpoint = {
+ resource: string
+ method: string
+}
-export const Libraries = async () => {
- const libs = await getLibraryApi(JF).getMediaFolders()
- console.log(libs.data)
- return libs.data
+type View = {
+ Id: string
+ Name: string
+ CollectionType: string
+ ParentId: string
}
-export default JF
+type ViewList = {
+ Items: View[]
+}
-// import { useDataStore } from '@/stores/data'
+type NextUp = {
+ Items: Item[]
+}
-// type Endpoint = {
-// resource: string
-// method: string
-// }
+type Item = {
+ Name: string
+ OriginalTitle: string
+ Id: string
+ Type: string
+ OfficialRating: string
+ ImageTags: ImageTags
+ CommunityRating: number
+ ProductionYear: number
+ IndexNumber?: number
+ ParentIndexNumber?: number
+ SeriesName?: string
+ SeriesId?: string
+ Overview: string
+ RunTimeTicks: number
+ ParentThumbItemId?: string
+ ParentThumbImageTag?: string
+ ParentBackdropItemId?: string
+ ParentBackdropImageTags?: string[]
+ SeriesPrimaryImageTag?: string
+ UserData?: UserData
+}
-// type View = {
-// Id: string
-// Name: string
-// CollectionType: string
-// ParentId: string
-// }
+type UserData = {
+ UnplayedItemCount: number
+}
-// type NextUp = {
-// Items: [Item]
-// }
+type ImageTags = {
+ Primary?: string
+ Thumb?: string
+}
-// type Item = {
-// Name: string
-// Id: string
-// Type: string
-// OfficialRating?: string
-// ImageTags: ImageTags
-// CommunityRating?: number
-// ProductionYear?: number
-// IndexNumber?: number
-// ParentIndexNumber?: number
-// SeriesName?: string
-// Overview?: string
-// RunTimeTicks: number
-// }
+type User = {
+ Name: string
+ Host: string
+ Id: string
+ Views?: View[]
+}
-// type ImageTags = {
-// Primary?: string
-// Thumb?: string
-// }
+export type { User, View, Item, ViewList }
-// class JFApi {
-// request
(host: string, endpoint: Endpoint) {
-// return fetch(`${host}${endpoint.resource}`, {
-// method: endpoint?.method,
-// })
-// .then(async (response) => {
-// const data = await response.json()
-// return data as T
-// })
-// .catch((error) => {
-// return error
-// })
-// }
-// LoadViews(host: string, userid: string) {
-// const { setViews } = useDataStore()
-// return this.request(host, {
-// resource: `/UserViews?userId=${userid}`,
-// method: 'GET',
-// })
-// .then((data) => {
-// setViews(data)
-// return data
-// })
-// .catch((err) => {
-// return err
-// })
-// }
-// GetLatest(host: string, view: View): Promise<[Item]> {
-// return this.request(host, {
-// resource: `/Latest&ParentId=${view.Id}`,
-// method: 'GET',
-// })
-// .then((data) => {
-// return data
-// })
-// .catch((err) => {
-// return err
-// })
-// }
-// GetNextUp(host: string): Promise {
-// return this.request(host, {
-// resource: `/Shows/NextUp?Limit=24&Fields=PrimaryImageAspectRatio%2CDateCreated%2CPath%2CMediaSourceCount&UserId=f7967316db8e46b4960690d0df2c0163&ImageTypeLimit=1&EnableImageTypes=Primary%2CBackdrop%2CBanner%2CThumb&EnableTotalRecordCount=false&DisableFirstEpisode=false&NextUpDateCutoff=2023-12-03T21%3A55%3A33.690Z&EnableResumable=false&EnableRewatching=false`,
-// method: 'GET',
-// })
-// .then((data) => {
-// return data
-// })
-// .catch((err) => {
-// return err
-// })
-// }
-// GetItem(host: string, userid: string, itemId: string): Promise- {
-// return this.request(host, {
-// resource: `/User/${userid}/Items/${itemId}`,
-// method: 'GET',
-// })
-// .then((data) => {
-// return data
-// })
-// .catch((err) => {
-// return err
-// })
-// }
-// ThumbImageUrl(host: string, itemId: string, imgTag: string) {
-// return `${host}/Items/${itemId}/Images/Thumb?fillHeight=267&fillWidth=474&quality=96&tag=${imgTag}`
-// }
-// PrimaryImageUrl(host: string, itemId: string, imgTag: string) {
-// return `${host}/Items/${itemId}/Images/Primary?fillHeight=446&fillWidth=297&quality=96&tag=${imgTag}`
-// }
-// Login(host: string, username: string, password: string) {
-// return fetch(`${host}/Users/authenticatebyname`, {
-// method: 'POST',
-// body: JSON.stringify({ Username: username, Pw: password }),
-// headers: {
-// 'Content-Type': 'application/json',
-// Authorization:
-// 'MediaBrowser Client="Jellyfin Web", Device="Chrome", DeviceId="TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzEyNC4wLjAuMCBTYWZhcmkvNTM3LjM2fDE3MTQ1MzI1OTIxODU1", Version="10.10.3"',
-// },
-// })
-// .then((data) => data.json())
-// .then((data) => console.log(data))
-// }
-// }
+class JFApi {
+ request(endpoint: Endpoint): Promise {
+ const host = localStorage.getItem('jf_host') === null ? '' : localStorage.getItem('jf_host')
+ return new Promise((resolve) => {
+ fetch(`${host}${endpoint.resource}`, {
+ method: endpoint?.method,
+ headers: {
+ Authorization: `MediaBrowser Client="Featherfin", Device="${detectBrowser()}", DeviceId="abc123", Version="v0.0.1", Token="${localStorage.getItem('jfauth_token')}"`,
+ },
+ })
+ .then(async (response) => {
+ const data = await response.json()
+ resolve(data as T)
+ })
+ .catch((error) => {
+ console.log(error)
+ resolve(null)
+ })
+ })
+ }
+ LoadViews(userid: string): Promise {
+ return this.request({
+ resource: `/UserViews?userId=${userid}`,
+ method: 'GET',
+ })
+ }
+ GetLatest(userid: string, view: View): Promise
- {
+ return this.request({
+ resource: `/Users/${userid}/Items/Latest?Limit=16&Fields=PrimaryImageAspectRatio%2CPath&ImageTypeLimit=1&EnableImageTypes=Primary%2CBackdrop%2CThumb&ParentId=${view.Id}`,
+ method: 'GET',
+ })
+ }
+ GetNextUp(): Promise {
+ return this.request({
+ resource: `/Shows/NextUp?Limit=24&Fields=PrimaryImageAspectRatio%2CDateCreated%2CPath%2CMediaSourceCount&UserId=f7967316db8e46b4960690d0df2c0163&ImageTypeLimit=1&EnableImageTypes=Primary%2CBackdrop%2CBanner%2CThumb&EnableTotalRecordCount=false&DisableFirstEpisode=false&NextUpDateCutoff=2023-12-03T21%3A55%3A33.690Z&EnableResumable=false&EnableRewatching=false`,
+ method: 'GET',
+ })
+ }
+ GetItem(userid: string, itemId: string): Promise
- {
+ return this.request({
+ resource: `/Items/${itemId}?userId=${userid}`,
+ method: 'GET',
+ })
+ }
+ ThumbImageUrl(itemId: string, imgTag: string) {
+ const host = localStorage.getItem('jf_host') === null ? '' : localStorage.getItem('jf_host')
+ return `${host}/Items/${itemId}/Images/Thumb?fillHeight=267&fillWidth=474&quality=96&tag=${imgTag}`
+ }
+ BackdropImageUrl(itemId: string, imgTag: string) {
+ const host = localStorage.getItem('jf_host') === null ? '' : localStorage.getItem('jf_host')
+ return `${host}/Items/${itemId}/Images/Backdrop?fillHeight=267&fillWidth=474&quality=96&tag=${imgTag}`
+ }
+ PrimaryImageUrl(itemId: string, imgTag: string) {
+ const host = localStorage.getItem('jf_host') === null ? '' : localStorage.getItem('jf_host')
+ return `${host}/Items/${itemId}/Images/Primary?fillHeight=446&fillWidth=297&quality=96&tag=${imgTag}`
+ }
+ Login(host: string, username: string, password: string): Promise {
+ return new Promise((resolve) => {
+ fetch(`${host}/Users/authenticatebyname`, {
+ method: 'POST',
+ body: JSON.stringify({ Username: username, Pw: password }),
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `MediaBrowser Client="Featherfin", Device="${detectBrowser()}", DeviceId="abc123", Version="v0.0.1", Token="${localStorage.getItem('jfauth_token')}"`,
+ },
+ })
+ .then((r) => r.json().then((data) => ({ status: r.status, body: data })))
+ .then((data) => {
+ console.log(data)
+ if (data.status !== 200) {
+ // bad
+ resolve(null)
+ } else {
+ localStorage.setItem('jfauth_token', data.body.AccessToken)
+ resolve({
+ Name: data.body.User.Name,
+ Id: data.body.User.Id,
+ Host: 'http://192.168.0.63:30013',
+ })
+ }
+ })
+ })
+ }
+ Logout() {
+ return this.request({
+ resource: '/Sessions/Logout',
+ method: 'POST',
+ })
+ .then((data) => {
+ localStorage.removeItem('jfauth_token')
+ return data
+ })
+ .catch((err) => {
+ return err
+ })
+ }
+}
-// export default new JFApi()
+export default new JFApi()
-// /*
-// - /UserViews?userId=XYZ - returns [Library]
-// - /Latest?...&ParentId=Library.Id - returns latest in library
-// - /Resume?...&MediaTypes=Video - returns unfinished playback
-// - /NextUp?... - returns [Episode]
-// - /Users/authenticatebyname body:{Username: "xyz", Pw: "xyz123"} returns: AccessToken, User, SessionInfo
-// Authentication is done by appending 'Token="MyTokenXYZ123"' to Authorization header
-// - /Users/User.Id - returns: User
-// - /Users/User.Id/Items?SortBy=DateCreated%2CSortName%2CProductionYear&SortOrder=Descending&IncludeItemTypes=Movie&Recursive=true&Fields=PrimaryImageAspectRatio%2CMediaSourceCount&ImageTypeLimit=1&EnableImageTypes=Primary%2CBackdrop%2CBanner%2CThumb&StartIndex=0&ParentId=f137a2dd21bbc1b99aa5c0f6bf02a805&Limit=100 - returns [Item]
-// - /Users/User.Id/Items/Item.Id - FullItem
-// - /Items/Item.Id/Similar?userId=User.Id&limit=12&fields=PrimaryImageAspectRatio - returns similar items
-// - /Items/Item.Id/Images/Primary?fillHeight=713&fillWidth=500&quality=96&tag=Item.ImageTags.Primary - returns Primary Image
-// - /.../Images/Thumb?...&tag=Episode.ParentThumbImageTag
-// */
+/*
+- /UserViews?userId=XYZ - returns [Library]
+- /Latest?...&ParentId=Library.Id - returns latest in library
+- /Resume?...&MediaTypes=Video - returns unfinished playback
+- /NextUp?... - returns [Episode]
+- /Users/authenticatebyname body:{Username: "xyz", Pw: "xyz123"} returns: AccessToken, User, SessionInfo
+Authentication is done by appending 'Token="MyTokenXYZ123"' to Authorization header
+- /Users/User.Id - returns: User
+- /Users/User.Id/Items?SortBy=DateCreated%2CSortName%2CProductionYear&SortOrder=Descending&IncludeItemTypes=Movie&Recursive=true&Fields=PrimaryImageAspectRatio%2CMediaSourceCount&ImageTypeLimit=1&EnableImageTypes=Primary%2CBackdrop%2CBanner%2CThumb&StartIndex=0&ParentId=f137a2dd21bbc1b99aa5c0f6bf02a805&Limit=100 - returns [Item]
+- /Users/User.Id/Items/Item.Id - FullItem
+- /Items/Item.Id/Similar?userId=User.Id&limit=12&fields=PrimaryImageAspectRatio - returns similar items
+- /Items/Item.Id/Images/Primary?fillHeight=713&fillWidth=500&quality=96&tag=Item.ImageTags.Primary - returns Primary Image
+- /.../Images/Thumb?...&tag=Episode.ParentThumbImageTag
+- /Sessions/Logout - logout
+*/
diff --git a/src/router/index.ts b/src/router/index.ts
index ca77e9d..0eac29c 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -14,7 +14,7 @@ const router = createRouter({
name: 'login',
component: () => import(/* webpackChunkName: 'login' */ '@/views/LoginView.vue'),
meta: {
- hideNavbar: true,
+ isLoginPage: true,
},
},
],
diff --git a/src/stores/data.ts b/src/stores/data.ts
index 119f4fb..3d99bdb 100644
--- a/src/stores/data.ts
+++ b/src/stores/data.ts
@@ -1,29 +1,22 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
-
-type UserData = {
- host?: string
- id?: string
- name?: string
- views?: [View]
-}
-type View = {
- name: string
- mediaType: string
- id: string
-}
+import type { User, View } from '@/jfapi'
export const useDataStore = defineStore('data', () => {
- const data = ref({})
- function setServerHost(host: string) {
- data.value.host = host
- }
- function setViews(views: [View]) {
- data.value.views = views
- }
- function setUser(id: string, name: string) {
- data.value.id = id
- data.value.name = name
+ const data = ref({
+ Name: '',
+ Host: '',
+ Id: '',
+ })
+ // function setServerHost(host: string) {
+ // data.value.Host = host
+ // }
+ function setViews(views: View[]) {
+ data.value.Views = views
}
- return { data, setServerHost, setViews, setUser }
+ // function setUser(id: string, name: string) {
+ // data.value.Id = id
+ // data.value.Name = name
+ // }
+ return { setViews }
})
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 5246f72..a2919ee 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -1,11 +1,29 @@
@@ -13,14 +31,14 @@ console.log('Libraries =>', Libraries())
Home
-
4k Movies
-
Anime
-
Movies
-
Shows
+
{{ view.Name }}
+
+
+
+
+
-
-
-
@@ -28,7 +46,6 @@ console.log('Libraries =>', Libraries())
.home-nav {
display: flex;
justify-content: center;
- margin-right: 11.5%;
margin-top: 1.5em;
gap: 3em;
align-items: center;
@@ -47,4 +64,7 @@ console.log('Libraries =>', Libraries())
.home-nav-item.active:hover {
background-color: var(--color-text-faded);
}
+.media {
+ margin: 0 10%;
+}
diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue
index 72c7101..bc18573 100644
--- a/src/views/LoginView.vue
+++ b/src/views/LoginView.vue
@@ -1,18 +1,28 @@