chore: more code cleanup and use better env vars

This commit is contained in:
Sean Norwood 2022-04-17 00:49:20 +00:00
parent 526c98ca8a
commit df30173ba3
9 changed files with 225 additions and 65 deletions

View File

@ -3,15 +3,17 @@ import NextImage from "next/image";
import { useState } from "react"; import { useState } from "react";
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import IconPlay from "../../images/icon-play.svg"; import IconPlay from "../../images/icon-play.svg";
import { TA_BASE_URL } from "../../lib/constants"; import { getTAUrl } from "../../lib/constants";
import { getVideos } from "../../lib/getVideos"; import { getVideos } from "../../lib/getVideos";
import type { Datum } from "../../types/video"; import type { Data } from "../../types/video";
import VideoPlayer from "../VideoPlayer"; import VideoPlayer from "../VideoPlayer";
type ViewStyle = "grid" | "list"; type ViewStyle = "grid" | "list";
const TA_BASE_URL = getTAUrl();
const VideoList = () => { const VideoList = () => {
const [selectedVideoUrl, setSelectedVideoUrl] = useState<Datum>(); const [selectedVideoUrl, setSelectedVideoUrl] = useState<Data>();
const [viewStyle, setViewStyle] = useState<ViewStyle>("grid"); const [viewStyle, setViewStyle] = useState<ViewStyle>("grid");
const { data: session } = useSession(); const { data: session } = useSession();
const { data, error, isLoading } = useQuery( const { data, error, isLoading } = useQuery(
@ -22,7 +24,7 @@ const VideoList = () => {
} }
); );
const handleSelectedVideo = (video: Datum) => { const handleSelectedVideo = (video: Data) => {
setSelectedVideoUrl(video); setSelectedVideoUrl(video);
}; };
@ -51,7 +53,7 @@ const VideoList = () => {
<> <>
<VideoPlayer <VideoPlayer
handleRemoveVideoPlayer={handleRemoveVideoPlayer} handleRemoveVideoPlayer={handleRemoveVideoPlayer}
selectedVideoUrl={selectedVideoUrl} selectedVideo={selectedVideoUrl}
/> />
<div className="boxed-content"> <div className="boxed-content">
@ -135,10 +137,10 @@ const VideoList = () => {
<div className="video-thumb-wrap list"> <div className="video-thumb-wrap list">
<div className="video-thumb"> <div className="video-thumb">
<NextImage <NextImage
src={`${TA_BASE_URL}/cache/${video.vid_thumb_url}`} src={`${TA_BASE_URL.client}/cache/${video.vid_thumb_url}`}
alt="video-thumb" alt="video-thumb"
width={325} width={640}
height={190} height={360}
blurDataURL={video.vid_thumb_base64} blurDataURL={video.vid_thumb_base64}
placeholder="blur" placeholder="blur"
/> />

View File

@ -1,14 +1,28 @@
import NextImage from "next/image"; import NextImage from "next/image";
import NextLink from "next/link";
import ReactPlayer from "react-player"; import ReactPlayer from "react-player";
import IconClose from "../../images/icon-close.svg";
import { TA_BASE_URL } from "../../lib/constants"; import { TA_BASE_URL } from "../../lib/constants";
import { formatNumbers } from "../../lib/utils"; import { formatNumbers } from "../../lib/utils";
import IconClose from "../../images/icon-close.svg"; import { Data } from "../../types/video";
const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => { type VideoPlayerProps = {
if (!selectedVideoUrl) return; selectedVideo: Data;
handleRemoveVideoPlayer?: () => void;
isHome?: boolean;
showStats?: boolean;
};
const VideoPlayer = ({
selectedVideo,
handleRemoveVideoPlayer,
isHome = true,
showStats = true,
}: VideoPlayerProps) => {
if (!selectedVideo) return;
return ( return (
<> <>
{selectedVideoUrl && ( {selectedVideo && (
<div className="player-wrapper"> <div className="player-wrapper">
<div className="video-player"> <div className="video-player">
<ReactPlayer <ReactPlayer
@ -18,8 +32,14 @@ const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
light={false} light={false}
playing // TODO: Not currently working playing // TODO: Not currently working
playsinline playsinline
url={`${TA_BASE_URL}/media/${selectedVideoUrl?.media_url}`} url={
isHome
? `${TA_BASE_URL}/media/${selectedVideo?.media_url}`
: `${TA_BASE_URL}/${selectedVideo?.media_url}`
}
/> />
<SponsorBlock />
{showStats ? (
<div className="player-title boxed-content"> <div className="player-title boxed-content">
<NextImage <NextImage
className="close-button" className="close-button"
@ -30,32 +50,32 @@ const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
onClick={handleRemoveVideoPlayer} onClick={handleRemoveVideoPlayer}
title="Close player" title="Close player"
/> />
{/* ${watchStatusIndicator}
${castButton}
*/}
<div className="thumb-icon player-stats"> <div className="thumb-icon player-stats">
<img src="/img/icon-eye.svg" alt="views icon" /> <img src="/img/icon-eye.svg" alt="views icon" />
<span> <span>
{formatNumbers(selectedVideoUrl.stats.view_count.toString())} {formatNumbers(selectedVideo.stats.view_count.toString())}
</span> </span>
<span>|</span> <span>|</span>
<img src="/img/icon-thumb.svg" alt="thumbs-up" /> <img src="/img/icon-thumb.svg" alt="thumbs-up" />
<span> <span>
{formatNumbers(selectedVideoUrl.stats.like_count.toString())} {formatNumbers(selectedVideo.stats.like_count.toString())}
</span> </span>
</div> </div>
<div className="player-channel-playlist"> <div className="player-channel-playlist">
<h3> <h3>
<a href="/channel/${channelId}/"> <a href="/channel/${channelId}/">
{selectedVideoUrl.channel.channel_name} {selectedVideo.channel.channel_name}
</a> </a>
</h3> </h3>
{/* ${playlist} */} {/* ${playlist} */}
</div> </div>
<a href="/video/${videoId}/"> <NextLink href={`/video/${selectedVideo.youtube_id}/`}>
<h2 id="video-title">{selectedVideoUrl.title}</h2> <a>
<h2 id="video-title">{selectedVideo.title}</h2>
</a> </a>
</NextLink>
</div> </div>
) : null}
</div> </div>
</div> </div>
)} )}
@ -64,3 +84,45 @@ const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
}; };
export default VideoPlayer; export default VideoPlayer;
function SponsorBlock() {
return (
<>
{/* <div className="notifications" id="notifications"></div> */}
<div className="sponsorblock" id="sponsorblock">
{/* {% if video.sponsorblock.is_enabled %} */}
{/* {% if video.sponsorblock.segments|length == 0 %} */}
<h4>
This video doesn&apos;t have any sponsor segments added. To add a
segment go to{" "}
<u>
<a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">
this video on YouTube
</a>
</u>{" "}
and add a segment using the{" "}
<u>
<a href="https://sponsor.ajay.app/">SponsorBlock</a>
</u>{" "}
extension.
</h4>
{/* {% elif video.sponsorblock.has_unlocked %} */}
<h4>
This video has unlocked sponsor segments. Go to{" "}
<u>
<a href="https://www.youtube.com/watch?v={{ video.youtube_id }}">
this video on YouTube
</a>
</u>{" "}
and vote on the segments using the{" "}
<u>
<a href="https://sponsor.ajay.app/">SponsorBlock</a>
</u>{" "}
extension.
</h4>
{/* {% endif %} */}
{/* {% endif %} */}
</div>
</>
);
}

View File

@ -1 +1,12 @@
export const TA_BASE_URL = process.env.NEXT_PUBLIC_TUBEARCHIVIST_URL; export const getTAUrl = () => {
if (process.env.NODE_ENV === "development") {
return {
client: process.env.NEXT_PUBLIC_TUBEARCHIVIST_URL,
server: process.env.NEXT_PUBLIC_TUBEARCHIVIST_URL,
};
}
return {
client: process.env.NEXT_PUBLIC_TUBEARCHIVIST_URL,
server: process.env.TUBEARCHIVIST_URL,
};
};

View File

@ -1,8 +1,14 @@
import { Channel } from "../types/channel"; import { Channel } from "../types/channel";
import { TA_BASE_URL } from "./constants"; import { getTAUrl } from "./constants";
const TA_BASE_URL = getTAUrl();
export const getChannels = async (token: string): Promise<Channel> => { export const getChannels = async (token: string): Promise<Channel> => {
const response = await fetch(`${TA_BASE_URL}/api/channel/`, { if (!token) {
throw new Error(`Unable to fetch channels, no token provided`);
}
const response = await fetch(`${TA_BASE_URL.server}/api/channel/`, {
headers: { headers: {
Accept: "application/json", Accept: "application/json",
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@ -1,7 +1,12 @@
import { Playlist } from "../types/playlist"; import { Playlist } from "../types/playlist";
import { Playlists } from "../types/playlists";
import { TA_BASE_URL } from "./constants"; import { TA_BASE_URL } from "./constants";
export const getPlaylists = async (token: string): Promise<Playlist> => { export const getPlaylists = async (token: string): Promise<Playlists> => {
if (!token) {
throw new Error(`No token provided when fetching a playlists`);
}
const response = await fetch(`${TA_BASE_URL}/api/playlist/`, { const response = await fetch(`${TA_BASE_URL}/api/playlist/`, {
headers: { headers: {
Accept: "application/json", Accept: "application/json",
@ -11,7 +16,35 @@ export const getPlaylists = async (token: string): Promise<Playlist> => {
}, },
}); });
if (!response.ok) { if (!response.ok) {
throw new Error("Error getting channel information"); throw new Error(
`Error getting playlists information: ${response.statusText}`
);
}
return response.json();
};
export const getPlaylist = async (
token: string,
playlistId: string
): Promise<Playlist> => {
if (!token) {
throw new Error(
`No token provided when fetching a playlist: ${playlistId}`
);
}
const response = await fetch(`${TA_BASE_URL}/api/playlist/${playlistId}`, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Token ${token}`,
mode: "no-cors",
},
});
if (!response.ok) {
throw new Error(
`Error getting playlists information: ${response.statusText}`
);
} }
return response.json(); return response.json();
}; };

View File

@ -1,11 +1,37 @@
import { Videos } from "../types/video"; import { Video } from "../types/video";
import { TA_BASE_URL } from "./constants"; import { Videos } from "../types/videos";
import { getTAUrl } from "./constants";
const TA_BASE_URL = getTAUrl();
export const getVideos = async (token: string): Promise<Videos> => { export const getVideos = async (token: string): Promise<Videos> => {
if (!token) { if (!token) {
throw new Error("Missing API token in request to get videos"); throw new Error("Missing API token in request to get videos");
} }
const response = await fetch(`${TA_BASE_URL}/api/video/`, { const response = await fetch(`${TA_BASE_URL.server}/api/video/`, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Token ${token}`,
mode: "no-cors",
},
});
if (!response.ok) {
throw new Error("Failed to fetch videos");
}
return response.json();
};
export const getVideo = async (
token: string,
videoId: string
): Promise<Video> => {
if (!token) {
throw new Error("Missing API token in request to get video");
}
const response = await fetch(`${TA_BASE_URL.server}/api/video/${videoId}`, {
headers: { headers: {
Accept: "application/json", Accept: "application/json",
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@ -1,6 +1,8 @@
import NextAuth from "next-auth"; import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials"; import CredentialsProvider from "next-auth/providers/credentials";
import { TA_BASE_URL } from "../../../lib/constants"; import { getTAUrl } from "../../../lib/constants";
const TA_BASE_URL = getTAUrl();
type TA_Token = { type TA_Token = {
token: string; token: string;
@ -30,7 +32,7 @@ export default NextAuth({
password: credentials.password, password: credentials.password,
}; };
const res = await fetch(`${TA_BASE_URL}/api/login/`, { const res = await fetch(`${TA_BASE_URL.server}/api/login/`, {
method: "POST", method: "POST",
body: JSON.stringify(payload), body: JSON.stringify(payload),
headers: { headers: {

View File

@ -1,10 +1,9 @@
import { CustomHead } from "../../components/CustomHead";
import { Layout } from "../../components/Layout";
import NextImage from "next/image";
import Logo from "../../images/logo-tube-archivist-dark.png";
import { getCsrfToken } from "next-auth/react";
import { NextPageContext } from "next"; import { NextPageContext } from "next";
import { getCsrfToken } from "next-auth/react";
import NextImage from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { CustomHead } from "../../components/CustomHead";
import Logo from "../../images/logo-tube-archivist-dark.png";
export async function getServerSideProps(context: NextPageContext) { export async function getServerSideProps(context: NextPageContext) {
return { return {

View File

@ -4,9 +4,11 @@ import { useState } from "react";
import { dehydrate, QueryClient, useQuery } from "react-query"; import { dehydrate, QueryClient, useQuery } from "react-query";
import { CustomHead } from "../components/CustomHead"; import { CustomHead } from "../components/CustomHead";
import { Layout } from "../components/Layout"; import { Layout } from "../components/Layout";
import { TA_BASE_URL } from "../lib/constants"; import { getTAUrl } from "../lib/constants";
import { getChannels } from "../lib/getChannels"; import { getChannels } from "../lib/getChannels";
const TA_BASE_URL = getTAUrl();
type ViewStyle = "grid" | "list"; type ViewStyle = "grid" | "list";
export const getServerSideProps: GetServerSideProps = async (context) => { export const getServerSideProps: GetServerSideProps = async (context) => {
@ -54,6 +56,23 @@ const Channel: NextPage = () => {
setViewStyle(selectedViewStyle); setViewStyle(selectedViewStyle);
}; };
if (isLoading) {
return (
<Layout>
<h1>Loading...</h1>
</Layout>
);
}
if (error) {
return (
<Layout>
<h1>Error</h1>
<pre>{JSON.stringify(error, null, 2)}</pre>
</Layout>
);
}
return ( return (
<> <>
<CustomHead title="Channels" /> <CustomHead title="Channels" />
@ -128,7 +147,7 @@ const Channel: NextPage = () => {
<div className={`channel-banner ${viewStyle}`}> <div className={`channel-banner ${viewStyle}`}>
<a href="{% url 'channel_id' channel.source.channel_id %}"> <a href="{% url 'channel_id' channel.source.channel_id %}">
<img <img
src={`${TA_BASE_URL}${channel?.channel_banner_url}`} src={`${TA_BASE_URL.client}${channel?.channel_banner_url}`}
alt="{{ channel.source.channel_id }}-banner" alt="{{ channel.source.channel_id }}-banner"
/> />
</a> </a>
@ -138,7 +157,7 @@ const Channel: NextPage = () => {
<div className="round-img"> <div className="round-img">
<a href="{% url 'channel_id' channel.source.channel_id %}"> <a href="{% url 'channel_id' channel.source.channel_id %}">
<img <img
src={`${TA_BASE_URL}${channel?.channel_thumb_url}`} src={`${TA_BASE_URL.client}${channel?.channel_thumb_url}`}
alt="channel-thumb" alt="channel-thumb"
/> />
</a> </a>