diff --git a/frontend/src/api/actions/logOut.ts b/frontend/src/api/actions/logOut.ts
index 63e10ee9..4e99c02c 100644
--- a/frontend/src/api/actions/logOut.ts
+++ b/frontend/src/api/actions/logOut.ts
@@ -1,7 +1,7 @@
import defaultHeaders from '../../configuration/defaultHeaders';
-import getApiUrl from "../../configuration/getApiUrl"
-import getFetchCredentials from "../../configuration/getFetchCredentials";
-import getCookie from "../../functions/getCookie";
+import getApiUrl from '../../configuration/getApiUrl';
+import getFetchCredentials from '../../configuration/getFetchCredentials';
+import getCookie from '../../functions/getCookie';
const logOut = async () => {
const apiUrl = getApiUrl();
@@ -14,9 +14,9 @@ const logOut = async () => {
'X-CSRFToken': csrfCookie || '',
},
credentials: getFetchCredentials(),
- })
-
+ });
+
return response;
-}
+};
export default logOut;
diff --git a/frontend/src/api/actions/updateChannelOverwrite.ts b/frontend/src/api/actions/updateChannelOverwrite.ts
index 2e76b442..1611fa6a 100644
--- a/frontend/src/api/actions/updateChannelOverwrite.ts
+++ b/frontend/src/api/actions/updateChannelOverwrite.ts
@@ -1,7 +1,7 @@
import defaultHeaders from '../../configuration/defaultHeaders';
-import getApiUrl from "../../configuration/getApiUrl"
+import getApiUrl from '../../configuration/getApiUrl';
import getFetchCredentials from '../../configuration/getFetchCredentials';
-import getCookie from "../../functions/getCookie";
+import getCookie from '../../functions/getCookie';
const updateChannelOverwrites = async (channelId: string, configKey: string, configValue: any) => {
const apiUrl = getApiUrl();
@@ -9,8 +9,8 @@ const updateChannelOverwrites = async (channelId: string, configKey: string, con
const data = {
channel_overwrites: {
- [configKey]: configValue
- }
+ [configKey]: configValue,
+ },
};
const response = await fetch(`${apiUrl}/api/channel/${channelId}/`, {
@@ -26,8 +26,8 @@ const updateChannelOverwrites = async (channelId: string, configKey: string, con
const channelSubscription = await response.json();
console.log('updateChannelOverwrites', channelSubscription);
-
+
return channelSubscription;
-}
+};
export default updateChannelOverwrites;
diff --git a/frontend/src/components/Navigation.tsx b/frontend/src/components/Navigation.tsx
index 1bccc441..683aa378 100644
--- a/frontend/src/components/Navigation.tsx
+++ b/frontend/src/components/Navigation.tsx
@@ -11,13 +11,12 @@ interface NavigationProps {
}
const Navigation = ({ isAdmin }: NavigationProps) => {
-
const navigate = useNavigate();
const handleLogout = async (event: { preventDefault: () => void }) => {
event.preventDefault();
await logOut();
- navigate(Routes.Login)
- }
+ navigate(Routes.Login);
+ };
return (
@@ -39,7 +38,13 @@ const Navigation = ({ isAdmin }: NavigationProps) => {

-

+
diff --git a/frontend/src/pages/ChannelAbout.tsx b/frontend/src/pages/ChannelAbout.tsx
index bfee643f..9ffa127a 100644
--- a/frontend/src/pages/ChannelAbout.tsx
+++ b/frontend/src/pages/ChannelAbout.tsx
@@ -1,444 +1,550 @@
-import { useNavigate, useOutletContext, useParams } from 'react-router-dom';
-import ChannelOverview from '../components/ChannelOverview';
-import { useEffect, useState } from 'react';
-import loadChannelById from '../api/loader/loadChannelById';
-import { ChannelResponseType } from './ChannelBase';
-import Linkify from '../components/Linkify';
-import deleteChannel from '../api/actions/deleteChannel';
-import Routes from '../configuration/routes/RouteList';
-import queueReindex, { ReindexType, ReindexTypeEnum } from '../api/actions/queueReindex';
-import formatDate from '../functions/formatDates';
-import PaginationDummy from '../components/PaginationDummy';
-import FormattedNumber from '../components/FormattedNumber';
-import Button from '../components/Button';
-import updateChannelOverwrites from '../api/actions/updateChannelOverwrite';
-
-export type ChannelBaseOutletContextType = {
- isAdmin: boolean;
- currentPage: number;
- setCurrentPage: (page: number) => void;
- startNotification: boolean;
- setStartNotification: (status: boolean) => void;
-};
-
-export type OutletContextType = {
- isAdmin: boolean;
- currentPage: number;
- setCurrentPage: (page: number) => void;
-};
-
-type ChannelAboutParams = {
- channelId: string;
-};
-
-const ChannelAbout = () => {
- const { channelId } = useParams() as ChannelAboutParams;
- const { isAdmin, setStartNotification } = useOutletContext() as ChannelBaseOutletContextType;
- const navigate = useNavigate();
-
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
- const [descriptionExpanded, setDescriptionExpanded] = useState(false);
- const [reindex, setReindex] = useState(false);
- const [refresh, setRefresh] = useState(true);
-
- const [channelResponse, setChannelResponse] = useState();
-
- const [downloadFormat, setDownloadFormat] = useState("");
- const [autoDeleteAfter, setAutoDeleteAfter] = useState(null);
- const [indexPlaylists, setIndexPlaylists] = useState(false);
- const [enableSponsorblock, setEnableSponsorblock] = useState(null)
- const [pageSizeVideo, setPageSizeVideo] = useState(null)
- const [pageSizeShorts, setPageSizeShorts] = useState(null)
- const [pageSizeStreams, setPageSizeStreams] = useState(null)
-
- const channel = channelResponse?.data;
-
- useEffect(() => {
- (async () => {
- if (refresh) {
- const channelResponse = await loadChannelById(channelId);
-
- setChannelResponse(channelResponse);
- setDownloadFormat(channelResponse?.data?.channel_overwrites?.download_format || "")
- setAutoDeleteAfter(channelResponse?.data?.channel_overwrites?.autodelete_days)
- setIndexPlaylists(channelResponse?.data?.channel_overwrites?.index_playlists || false)
- setEnableSponsorblock(channelResponse?.data?.channel_overwrites?.integrate_sponsorblock)
- setPageSizeVideo(channelResponse?.data?.channel_overwrites?.subscriptions_channel_size)
- setPageSizeShorts(channelResponse?.data?.channel_overwrites?.subscriptions_shorts_channel_size)
- setPageSizeStreams(channelResponse?.data?.channel_overwrites?.subscriptions_live_channel_size)
-
- setRefresh(false);
- }
- })();
- }, [refresh, channelId]);
-
- const handleUpdateConfig = async (configKey: string, configValue: any) => {
- if (!channel) return
- await updateChannelOverwrites(channel.channel_id, configKey, configValue)
- setRefresh(true)
- }
-
- const handleNumberChange = (
- setValue: React.Dispatch>
- ) => (e: React.ChangeEvent) => {
- const inputValue = e.target.value;
-
- if (inputValue === "") {
- setValue(null);
- } else {
- const numericValue = Number(inputValue);
- setValue(isNaN(numericValue) ? null : numericValue);
- }
- };
-
- const handleToggleSponsorBlock = async (isEnabled: boolean) => {
- if (isEnabled) {
- setEnableSponsorblock(true);
- await handleUpdateConfig('integrate_sponsorblock', false);
- } else {
- await handleUpdateConfig('integrate_sponsorblock', null);
- setEnableSponsorblock(null);
- }
- }
-
- if (!channel) {
- return 'Channel not found!';
- }
-
- return (
- <>
- {`TA | Channel: About ${channel.channel_name}`}
-
-
-
-
-
-
-
Last refreshed: {formatDate(channel.channel_last_refresh)}
- {channel.channel_active && (
-
- Youtube:{' '}
-
- Active
-
-
- )}
- {!channel.channel_active &&
Youtube: Deactivated
}
-
-
-
-
-
- {channel.channel_views > 0 && (
-
- )}
-
- {isAdmin && (
- <>
-
- {!showDeleteConfirm && (
-
-
- {reindex &&
Reindex scheduled
}
- {!reindex && (
-
- {
- await queueReindex(channelId, ReindexTypeEnum.channel as ReindexType);
-
- setReindex(true);
- setStartNotification(true);
- }}
- />{' '}
- {
- await queueReindex(
- channelId,
- ReindexTypeEnum.channel as ReindexType,
- true,
- );
-
- setReindex(true);
- setStartNotification(true);
- }}
- />
-
- )}
- >
- )}
-
-
-
-
- {channel.channel_description && (
-
-
- {channel.channel_description}
-
-
-
setDescriptionExpanded(!descriptionExpanded)}
- />
-
- )}
-
- {channel.channel_tags && (
-
-
- {channel.channel_tags.map(tag => {
- return (
-
- {tag}
-
- );
- })}
-
-
- )}
-
- {isAdmin && (
-
-
-
Channel Customization
-
-
-
-
{
- setDownloadFormat(event.target.value);
- }}
- />
-
- {downloadFormat && downloadFormat !== channel.channel_overwrites?.download_format && (
- <>
- handleUpdateConfig('download_format', downloadFormat)}>Update
- setDownloadFormat(channel.channel_overwrites?.download_format || "")}>Cancel
- >
- )}
- {channel.channel_overwrites?.download_format !== undefined && (
- handleUpdateConfig('download_format', null)}>reset
- )}
-
-
-
-
-
-
Auto delete watched videos after x days
-
-
-
-
- {autoDeleteAfter !== null && autoDeleteAfter !== channel.channel_overwrites?.autodelete_days && (
- <>
- handleUpdateConfig('autodelete_days', autoDeleteAfter)}>Update
- setAutoDeleteAfter(channel.channel_overwrites?.autodelete_days || null)}>Cancel
- >
- )}
- {channel.channel_overwrites?.autodelete_days !== undefined && (
- handleUpdateConfig('autodelete_days', null)}>Reset
- )}
-
-
-
-
-
-
-
-
- {
- handleUpdateConfig('index_playlists', event.target.checked || null)
- }}
- />
- {!indexPlaylists && (
-
- )}
- {indexPlaylists && (
-
- )}
-
-
-
-
-
-
-
- {enableSponsorblock !== undefined ? (
-
-
- {
- handleUpdateConfig('integrate_sponsorblock', event.target.checked)
- }}
- />
- {!enableSponsorblock && (
-
- )}
- {enableSponsorblock && (
-
- )}
-
-
handleToggleSponsorBlock(false)}>Reset
-
- ) : (
-
handleToggleSponsorBlock(true)}>Configure
- )}
-
-
-
-
-
Page Size Overrides
-
Disable standard videos, shorts, or streams for this channel by setting their page size to 0 (zero).
-
-
-
-
-
- {pageSizeVideo !== null && pageSizeVideo !== channel.channel_overwrites?.subscriptions_channel_size && (
- <>
- handleUpdateConfig('subscriptions_channel_size', pageSizeVideo)}>Update
- setPageSizeVideo(channel.channel_overwrites?.subscriptions_channel_size || null)}>Cancel
- >
- )}
- {channel.channel_overwrites?.subscriptions_channel_size !== undefined && (
- handleUpdateConfig('subscriptions_channel_size', null)}>Reset
- )}
-
-
-
-
-
-
-
-
- {pageSizeShorts !== null && pageSizeShorts !== channel.channel_overwrites?.subscriptions_shorts_channel_size && (
- <>
- handleUpdateConfig('subscriptions_shorts_channel_size', pageSizeShorts)}>Update
- setPageSizeShorts(channel.channel_overwrites?.subscriptions_shorts_channel_size || null)}>Cancel
- >
- )}
- {channel.channel_overwrites?.subscriptions_shorts_channel_size !== undefined && (
- handleUpdateConfig('subscriptions_shorts_channel_size', null)}>Reset
- )}
-
-
-
-
-
-
Live streams page size
-
-
-
-
- {pageSizeStreams !== null && pageSizeStreams !== channel.channel_overwrites?.subscriptions_live_channel_size && (
- <>
- handleUpdateConfig('subscriptions_live_channel_size', pageSizeStreams)}>Update
- setPageSizeStreams(channel.channel_overwrites?.subscriptions_live_channel_size || null)}>Cancel
- >
- )}
- {channel.channel_overwrites?.subscriptions_live_channel_size !== undefined && (
- handleUpdateConfig('subscriptions_live_channel_size', null)}>Reset
- )}
-
-
-
-
-
- )}
-
-
-
- >
- );
-};
-
-export default ChannelAbout;
+import { useNavigate, useOutletContext, useParams } from 'react-router-dom';
+import ChannelOverview from '../components/ChannelOverview';
+import { useEffect, useState } from 'react';
+import loadChannelById from '../api/loader/loadChannelById';
+import { ChannelResponseType } from './ChannelBase';
+import Linkify from '../components/Linkify';
+import deleteChannel from '../api/actions/deleteChannel';
+import Routes from '../configuration/routes/RouteList';
+import queueReindex, { ReindexType, ReindexTypeEnum } from '../api/actions/queueReindex';
+import formatDate from '../functions/formatDates';
+import PaginationDummy from '../components/PaginationDummy';
+import FormattedNumber from '../components/FormattedNumber';
+import Button from '../components/Button';
+import updateChannelOverwrites from '../api/actions/updateChannelOverwrite';
+
+export type ChannelBaseOutletContextType = {
+ isAdmin: boolean;
+ currentPage: number;
+ setCurrentPage: (page: number) => void;
+ startNotification: boolean;
+ setStartNotification: (status: boolean) => void;
+};
+
+export type OutletContextType = {
+ isAdmin: boolean;
+ currentPage: number;
+ setCurrentPage: (page: number) => void;
+};
+
+type ChannelAboutParams = {
+ channelId: string;
+};
+
+const ChannelAbout = () => {
+ const { channelId } = useParams() as ChannelAboutParams;
+ const { isAdmin, setStartNotification } = useOutletContext() as ChannelBaseOutletContextType;
+ const navigate = useNavigate();
+
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
+ const [descriptionExpanded, setDescriptionExpanded] = useState(false);
+ const [reindex, setReindex] = useState(false);
+ const [refresh, setRefresh] = useState(true);
+
+ const [channelResponse, setChannelResponse] = useState();
+
+ const [downloadFormat, setDownloadFormat] = useState('');
+ const [autoDeleteAfter, setAutoDeleteAfter] = useState(null);
+ const [indexPlaylists, setIndexPlaylists] = useState(false);
+ const [enableSponsorblock, setEnableSponsorblock] = useState(null);
+ const [pageSizeVideo, setPageSizeVideo] = useState(null);
+ const [pageSizeShorts, setPageSizeShorts] = useState(null);
+ const [pageSizeStreams, setPageSizeStreams] = useState(null);
+
+ const channel = channelResponse?.data;
+
+ useEffect(() => {
+ (async () => {
+ if (refresh) {
+ const channelResponse = await loadChannelById(channelId);
+
+ setChannelResponse(channelResponse);
+ setDownloadFormat(channelResponse?.data?.channel_overwrites?.download_format || '');
+ setAutoDeleteAfter(channelResponse?.data?.channel_overwrites?.autodelete_days);
+ setIndexPlaylists(channelResponse?.data?.channel_overwrites?.index_playlists || false);
+ setEnableSponsorblock(channelResponse?.data?.channel_overwrites?.integrate_sponsorblock);
+ setPageSizeVideo(channelResponse?.data?.channel_overwrites?.subscriptions_channel_size);
+ setPageSizeShorts(
+ channelResponse?.data?.channel_overwrites?.subscriptions_shorts_channel_size,
+ );
+ setPageSizeStreams(
+ channelResponse?.data?.channel_overwrites?.subscriptions_live_channel_size,
+ );
+
+ setRefresh(false);
+ }
+ })();
+ }, [refresh, channelId]);
+
+ const handleUpdateConfig = async (configKey: string, configValue: any) => {
+ if (!channel) return;
+ await updateChannelOverwrites(channel.channel_id, configKey, configValue);
+ setRefresh(true);
+ };
+
+ const handleNumberChange =
+ (setValue: React.Dispatch>) =>
+ (e: React.ChangeEvent) => {
+ const inputValue = e.target.value;
+
+ if (inputValue === '') {
+ setValue(null);
+ } else {
+ const numericValue = Number(inputValue);
+ setValue(isNaN(numericValue) ? null : numericValue);
+ }
+ };
+
+ const handleToggleSponsorBlock = async (isEnabled: boolean) => {
+ if (isEnabled) {
+ setEnableSponsorblock(true);
+ await handleUpdateConfig('integrate_sponsorblock', false);
+ } else {
+ await handleUpdateConfig('integrate_sponsorblock', null);
+ setEnableSponsorblock(null);
+ }
+ };
+
+ if (!channel) {
+ return 'Channel not found!';
+ }
+
+ return (
+ <>
+ {`TA | Channel: About ${channel.channel_name}`}
+
+
+
+
+
+
+
Last refreshed: {formatDate(channel.channel_last_refresh)}
+ {channel.channel_active && (
+
+ Youtube:{' '}
+
+ Active
+
+
+ )}
+ {!channel.channel_active &&
Youtube: Deactivated
}
+
+
+
+
+
+ {channel.channel_views > 0 && (
+
+ )}
+
+ {isAdmin && (
+ <>
+
+ {!showDeleteConfirm && (
+
setShowDeleteConfirm(!showDeleteConfirm)}
+ />
+ )}
+
+ {showDeleteConfirm && (
+
+ Delete {channel.channel_name} including all videos?
+ {
+ await deleteChannel(channelId);
+ navigate(Routes.Channels);
+ }}
+ />{' '}
+ setShowDeleteConfirm(!showDeleteConfirm)}
+ />
+
+ )}
+
+
+ {reindex &&
Reindex scheduled
}
+ {!reindex && (
+
+ {
+ await queueReindex(channelId, ReindexTypeEnum.channel as ReindexType);
+
+ setReindex(true);
+ setStartNotification(true);
+ }}
+ />{' '}
+ {
+ await queueReindex(
+ channelId,
+ ReindexTypeEnum.channel as ReindexType,
+ true,
+ );
+
+ setReindex(true);
+ setStartNotification(true);
+ }}
+ />
+
+ )}
+ >
+ )}
+
+
+
+
+ {channel.channel_description && (
+
+
+ {channel.channel_description}
+
+
+
setDescriptionExpanded(!descriptionExpanded)}
+ />
+
+ )}
+
+ {channel.channel_tags && (
+
+
+ {channel.channel_tags.map(tag => {
+ return (
+
+ {tag}
+
+ );
+ })}
+
+
+ )}
+
+ {isAdmin && (
+
+
+
Channel Customization
+
+
+
+
{
+ setDownloadFormat(event.target.value);
+ }}
+ />
+
+ {downloadFormat &&
+ downloadFormat !== channel.channel_overwrites?.download_format && (
+ <>
+ handleUpdateConfig('download_format', downloadFormat)}
+ >
+ Update
+
+
+ setDownloadFormat(channel.channel_overwrites?.download_format || '')
+ }
+ >
+ Cancel
+
+ >
+ )}
+ {channel.channel_overwrites?.download_format !== undefined && (
+ handleUpdateConfig('download_format', null)}>
+ reset
+
+ )}
+
+
+
+
+
+
Auto delete watched videos after x days
+
+
+
+
+ {autoDeleteAfter !== null &&
+ autoDeleteAfter !== channel.channel_overwrites?.autodelete_days && (
+ <>
+ handleUpdateConfig('autodelete_days', autoDeleteAfter)}
+ >
+ Update
+
+
+ setAutoDeleteAfter(
+ channel.channel_overwrites?.autodelete_days || null,
+ )
+ }
+ >
+ Cancel
+
+ >
+ )}
+ {channel.channel_overwrites?.autodelete_days !== undefined && (
+ handleUpdateConfig('autodelete_days', null)}>
+ Reset
+
+ )}
+
+
+
+
+
+
+
+
+ {
+ handleUpdateConfig('index_playlists', event.target.checked || null);
+ }}
+ />
+ {!indexPlaylists && (
+
+ )}
+ {indexPlaylists && (
+
+ )}
+
+
+
+
+
+
+
+ {enableSponsorblock !== undefined ? (
+
+
+ {
+ handleUpdateConfig('integrate_sponsorblock', event.target.checked);
+ }}
+ />
+ {!enableSponsorblock && (
+
+ )}
+ {enableSponsorblock && (
+
+ )}
+
+
handleToggleSponsorBlock(false)}>Reset
+
+ ) : (
+
handleToggleSponsorBlock(true)}>Configure
+ )}
+
+
+
+
+
Page Size Overrides
+
+ Disable standard videos, shorts, or streams for this channel by setting their page
+ size to 0 (zero).
+
+
+
+
+
+
+ {pageSizeVideo !== null &&
+ pageSizeVideo !== channel.channel_overwrites?.subscriptions_channel_size && (
+ <>
+
+ handleUpdateConfig('subscriptions_channel_size', pageSizeVideo)
+ }
+ >
+ Update
+
+
+ setPageSizeVideo(
+ channel.channel_overwrites?.subscriptions_channel_size || null,
+ )
+ }
+ >
+ Cancel
+
+ >
+ )}
+ {channel.channel_overwrites?.subscriptions_channel_size !== undefined && (
+ handleUpdateConfig('subscriptions_channel_size', null)}
+ >
+ Reset
+
+ )}
+
+
+
+
+
+
+
+
+ {pageSizeShorts !== null &&
+ pageSizeShorts !==
+ channel.channel_overwrites?.subscriptions_shorts_channel_size && (
+ <>
+
+ handleUpdateConfig(
+ 'subscriptions_shorts_channel_size',
+ pageSizeShorts,
+ )
+ }
+ >
+ Update
+
+
+ setPageSizeShorts(
+ channel.channel_overwrites?.subscriptions_shorts_channel_size ||
+ null,
+ )
+ }
+ >
+ Cancel
+
+ >
+ )}
+ {channel.channel_overwrites?.subscriptions_shorts_channel_size !==
+ undefined && (
+
+ handleUpdateConfig('subscriptions_shorts_channel_size', null)
+ }
+ >
+ Reset
+
+ )}
+
+
+
+
+
+
Live streams page size
+
+
+
+
+ {pageSizeStreams !== null &&
+ pageSizeStreams !==
+ channel.channel_overwrites?.subscriptions_live_channel_size && (
+ <>
+
+ handleUpdateConfig('subscriptions_live_channel_size', pageSizeStreams)
+ }
+ >
+ Update
+
+
+ setPageSizeStreams(
+ channel.channel_overwrites?.subscriptions_live_channel_size || null,
+ )
+ }
+ >
+ Cancel
+
+ >
+ )}
+ {channel.channel_overwrites?.subscriptions_live_channel_size !== undefined && (
+ handleUpdateConfig('subscriptions_live_channel_size', null)}
+ >
+ Reset
+
+ )}
+
+
+
+
+
+ )}
+
+
+
+ >
+ );
+};
+
+export default ChannelAbout;