feat: add playlist page

This commit is contained in:
Sean Norwood 2022-04-13 18:08:07 +00:00
parent 2e4cd0b914
commit 3efd651db3
3 changed files with 301 additions and 0 deletions

View File

@ -0,0 +1,19 @@
import { Playlist } from "../types/playlist";
export const getPlaylists = async (token: string): Promise<Playlist> => {
const response = await fetch(
`${process.env.NEXT_PUBLIC_TUBEARCHIVIST_URL}/api/playlist/`,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Token ${token}`,
mode: "no-cors",
},
}
);
if (!response.ok) {
throw new Error("Error getting channel information");
}
return response.json();
};

View File

@ -0,0 +1,178 @@
import { GetServerSideProps } from "next";
import NextImage from "next/image";
import { getSession, useSession } from "next-auth/react";
import { useState } from "react";
import { dehydrate, QueryClient, useQuery } from "react-query";
import { CustomHead } from "../components/CustomHead";
import { Layout } from "../components/Layout";
import { TA_BASE_URL } from "../lib/constants";
import { getPlaylists } from "../lib/getPlaylists";
import IconAdd from "../images/icon-add.svg";
import IconListView from "../images/icon-listview.svg";
import IconGridView from "../images/icon-gridview.svg";
type ViewStyle = "grid" | "list";
export const getServerSideProps: GetServerSideProps = async (context) => {
const queryClient = new QueryClient();
const session = await getSession(context);
if (!session) {
return {
redirect: {
destination: "/auth/login",
permanent: false,
},
};
}
await queryClient.prefetchQuery("playlists", () =>
getPlaylists(session.ta_token.token)
);
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
};
const Playlist = () => {
const { data: session } = useSession();
const {
data: { data: playlists },
} = useQuery("playlists", () => getPlaylists(session.ta_token.token));
const [viewStyle, setViewStyle] = useState<ViewStyle>("grid");
const handleSetViewstyle = (selectedViewStyle: ViewStyle) => {
setViewStyle(selectedViewStyle);
};
return (
<Layout>
<CustomHead title="Playlist" />
<div className="boxed-content">
<div className="title-split">
<div className="title-bar">
<h1>Playlists</h1>
</div>
<div className="title-split-form">
<NextImage
id="animate-icon"
// onClick="showForm()"
src={IconAdd}
width={45}
height={40}
alt="add-icon"
title="Subscribe to Playlists"
/>
<div className="show-form">
<form id="hidden-form" action="/playlist/" method="post">
{/* {% csrf_token %}
{{ subscribe_form }} */}
<button type="submit">Subscribe</button>
</form>
</div>
</div>
</div>
{/* <div id="notifications" data="playlist"></div> */}
<div className="view-controls">
<div className="toggle">
<span>Show subscribed only:</span>
<div className="toggleBox">
<input
id="show_subed_only"
// onClick="toggleCheckbox(this)"
type="checkbox"
checked
/>
{/* {% if not show_subed_only %} */}
<label htmlFor="" className="ofbtn">
Off
</label>
{/* {% else %} */}
<label htmlFor="" className="onbtn">
On
</label>
{/* {% endif %} */}
</div>
</div>
<div className="view-icons">
<NextImage
src={IconGridView}
width={35}
height={30}
onClick={() => handleSetViewstyle("grid")}
alt="grid view"
/>
<NextImage
src={IconListView}
width={35}
height={30}
onClick={() => handleSetViewstyle("list")}
alt="list view"
/>
</div>
</div>
<div className={`playlist-list ${viewStyle}`}>
{/* {% if results %}
{% for playlist in results %} */}
{!playlists ? (
<h2>No playlists found...</h2>
) : (
playlists?.map((playlist) => {
return (
<div
key={playlist.playlist_id}
className={`playlist-item ${viewStyle}`}
>
<div className="playlist-thumbnail">
<a href="{% url 'playlist_id' playlist.source.playlist_id %}">
<img
src={`${TA_BASE_URL}/${playlist.playlist_thumbnail}`}
alt={`${playlist.playlist_id}-thumbnail`}
/>
</a>
</div>
<div className={`playlist-desc ${viewStyle}`}>
<a href="{% url 'channel_id' playlist.source.playlist_channel_id %}">
<h3> {playlist.playlist_channel} </h3>
</a>
<a href="{% url 'playlist_id' playlist.source.playlist_id %}">
<h2> {playlist.playlist_name} </h2>
</a>
<p>Last refreshed: {playlist.playlist_last_refresh} </p>
{/* {% if playlist.source.playlist_subscribed %} */}
<button
className="unsubscribe"
type="button"
id="{{ playlist.source.playlist_id }}"
// onClick="unsubscribe(this.id)"
title="Unsubscribe from {{ playlist.source.playlist_name }}"
>
Unsubscribe
</button>
{/* {% else %} */}
<button
type="button"
id="{{ playlist.source.playlist_id }}"
// onClick="subscribe(this.id)"
title="Subscribe to {{ playlist.source.playlist_name }}"
>
Subscribe
</button>
{/* {% endif %} */}
</div>
</div>
);
})
)}
</div>
</div>
</Layout>
);
};
export default Playlist;

View File

@ -0,0 +1,104 @@
export interface Playlist {
data: Datum[];
config: Config;
paginate: boolean;
}
export interface Config {
archive: Archive;
default_view: DefaultView;
subscriptions: Subscriptions;
downloads: Downloads;
application: Application;
scheduler: Scheduler;
}
export interface Application {
app_root: string;
cache_dir: string;
videos: string;
file_template: string;
colors: string;
enable_cast: boolean;
REDIS_HOST: string;
es_url: string;
es_auth: string[];
HOST_UID: number;
HOST_GID: number;
}
export interface Archive {
sort_by: string;
sort_order: string;
page_size: number;
}
export interface DefaultView {
home: string;
channel: string;
downloads: string;
playlist: string;
}
export interface Downloads {
limit_count: boolean;
limit_speed: boolean;
sleep_interval: number;
autodelete_days: boolean;
format: boolean;
add_metadata: boolean;
add_thumbnail: boolean;
subtitle: boolean;
subtitle_source: boolean;
subtitle_index: boolean;
throttledratelimit: boolean;
integrate_ryd: boolean;
integrate_sponsorblock: boolean;
}
export interface Scheduler {
update_subscribed: boolean;
download_pending: boolean;
check_reindex: CheckReindex;
check_reindex_days: number;
thumbnail_check: CheckReindex;
run_backup: CheckReindex;
run_backup_rotate: number;
}
export interface CheckReindex {
minute: string;
hour: string;
day_of_week: string;
}
export interface Subscriptions {
auto_search: boolean;
auto_download: boolean;
channel_size: number;
}
export interface Datum {
playlist_active: boolean;
playlist_channel: PlaylistChannel;
playlist_channel_id: string;
playlist_description: boolean;
playlist_entries: PlaylistEntry[];
playlist_id: string;
playlist_last_refresh: string;
playlist_name: string;
playlist_subscribed: boolean;
playlist_thumbnail: string;
}
export enum PlaylistChannel {
NileRed = "NileRed",
}
export interface PlaylistEntry {
youtube_id: string;
title: string;
uploader: PlaylistChannel;
idx: number;
downloaded: boolean;
}