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

View File

@ -1,14 +1,28 @@
import NextImage from "next/image";
import NextLink from "next/link";
import ReactPlayer from "react-player";
import IconClose from "../../images/icon-close.svg";
import { TA_BASE_URL } from "../../lib/constants";
import { formatNumbers } from "../../lib/utils";
import IconClose from "../../images/icon-close.svg";
import { Data } from "../../types/video";
const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
if (!selectedVideoUrl) return;
type VideoPlayerProps = {
selectedVideo: Data;
handleRemoveVideoPlayer?: () => void;
isHome?: boolean;
showStats?: boolean;
};
const VideoPlayer = ({
selectedVideo,
handleRemoveVideoPlayer,
isHome = true,
showStats = true,
}: VideoPlayerProps) => {
if (!selectedVideo) return;
return (
<>
{selectedVideoUrl && (
{selectedVideo && (
<div className="player-wrapper">
<div className="video-player">
<ReactPlayer
@ -18,44 +32,50 @@ const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
light={false}
playing // TODO: Not currently working
playsinline
url={`${TA_BASE_URL}/media/${selectedVideoUrl?.media_url}`}
url={
isHome
? `${TA_BASE_URL}/media/${selectedVideo?.media_url}`
: `${TA_BASE_URL}/${selectedVideo?.media_url}`
}
/>
<div className="player-title boxed-content">
<NextImage
className="close-button"
src={IconClose}
width={30}
height={30}
alt="close-icon"
onClick={handleRemoveVideoPlayer}
title="Close player"
/>
{/* ${watchStatusIndicator}
${castButton}
*/}
<div className="thumb-icon player-stats">
<img src="/img/icon-eye.svg" alt="views icon" />
<span>
{formatNumbers(selectedVideoUrl.stats.view_count.toString())}
</span>
<span>|</span>
<img src="/img/icon-thumb.svg" alt="thumbs-up" />
<span>
{formatNumbers(selectedVideoUrl.stats.like_count.toString())}
</span>
</div>
<div className="player-channel-playlist">
<h3>
<a href="/channel/${channelId}/">
{selectedVideoUrl.channel.channel_name}
<SponsorBlock />
{showStats ? (
<div className="player-title boxed-content">
<NextImage
className="close-button"
src={IconClose}
width={30}
height={30}
alt="close-icon"
onClick={handleRemoveVideoPlayer}
title="Close player"
/>
<div className="thumb-icon player-stats">
<img src="/img/icon-eye.svg" alt="views icon" />
<span>
{formatNumbers(selectedVideo.stats.view_count.toString())}
</span>
<span>|</span>
<img src="/img/icon-thumb.svg" alt="thumbs-up" />
<span>
{formatNumbers(selectedVideo.stats.like_count.toString())}
</span>
</div>
<div className="player-channel-playlist">
<h3>
<a href="/channel/${channelId}/">
{selectedVideo.channel.channel_name}
</a>
</h3>
{/* ${playlist} */}
</div>
<NextLink href={`/video/${selectedVideo.youtube_id}/`}>
<a>
<h2 id="video-title">{selectedVideo.title}</h2>
</a>
</h3>
{/* ${playlist} */}
</NextLink>
</div>
<a href="/video/${videoId}/">
<h2 id="video-title">{selectedVideoUrl.title}</h2>
</a>
</div>
) : null}
</div>
</div>
)}
@ -64,3 +84,45 @@ const VideoPlayer = ({ selectedVideoUrl, handleRemoveVideoPlayer }) => {
};
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 { TA_BASE_URL } from "./constants";
import { getTAUrl } from "./constants";
const TA_BASE_URL = getTAUrl();
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: {
Accept: "application/json",
"Content-Type": "application/json",

View File

@ -1,7 +1,12 @@
import { Playlist } from "../types/playlist";
import { Playlists } from "../types/playlists";
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/`, {
headers: {
Accept: "application/json",
@ -11,7 +16,35 @@ export const getPlaylists = async (token: string): Promise<Playlist> => {
},
});
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();
};

View File

@ -1,11 +1,37 @@
import { Videos } from "../types/video";
import { TA_BASE_URL } from "./constants";
import { Video } from "../types/video";
import { Videos } from "../types/videos";
import { getTAUrl } from "./constants";
const TA_BASE_URL = getTAUrl();
export const getVideos = async (token: string): Promise<Videos> => {
if (!token) {
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: {
Accept: "application/json",
"Content-Type": "application/json",

View File

@ -1,6 +1,8 @@
import NextAuth from "next-auth";
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 = {
token: string;
@ -30,7 +32,7 @@ export default NextAuth({
password: credentials.password,
};
const res = await fetch(`${TA_BASE_URL}/api/login/`, {
const res = await fetch(`${TA_BASE_URL.server}/api/login/`, {
method: "POST",
body: JSON.stringify(payload),
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 { getCsrfToken } from "next-auth/react";
import NextImage from "next/image";
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) {
return {

View File

@ -4,9 +4,11 @@ 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 { getTAUrl } from "../lib/constants";
import { getChannels } from "../lib/getChannels";
const TA_BASE_URL = getTAUrl();
type ViewStyle = "grid" | "list";
export const getServerSideProps: GetServerSideProps = async (context) => {
@ -54,6 +56,23 @@ const Channel: NextPage = () => {
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 (
<>
<CustomHead title="Channels" />
@ -128,7 +147,7 @@ const Channel: NextPage = () => {
<div className={`channel-banner ${viewStyle}`}>
<a href="{% url 'channel_id' channel.source.channel_id %}">
<img
src={`${TA_BASE_URL}${channel?.channel_banner_url}`}
src={`${TA_BASE_URL.client}${channel?.channel_banner_url}`}
alt="{{ channel.source.channel_id }}-banner"
/>
</a>
@ -138,7 +157,7 @@ const Channel: NextPage = () => {
<div className="round-img">
<a href="{% url 'channel_id' channel.source.channel_id %}">
<img
src={`${TA_BASE_URL}${channel?.channel_thumb_url}`}
src={`${TA_BASE_URL.client}${channel?.channel_thumb_url}`}
alt="channel-thumb"
/>
</a>