mirror of
https://github.com/tubearchivist/tubearchivist.git
synced 2025-05-11 22:01:09 +00:00
Custom CSS, auto delete fixes, #build
Changed: - Re-added custom CSS functionality - Fixed playlist video type - Fixed autodelete channel overwrite - Fixed autodelete for watched state toggle - newest yt-dlp
This commit is contained in:
commit
f53988b826
@ -231,7 +231,13 @@ def ta_host_parser(ta_host: str) -> tuple[list[str], list[str]]:
|
||||
def get_stylesheets() -> list:
|
||||
"""Get all valid stylesheets from /static/css"""
|
||||
|
||||
stylesheets = ["dark.css", "light.css", "matrix.css", "midnight.css"]
|
||||
stylesheets = [
|
||||
"dark.css",
|
||||
"light.css",
|
||||
"matrix.css",
|
||||
"midnight.css",
|
||||
"custom.css",
|
||||
]
|
||||
return stylesheets
|
||||
|
||||
|
||||
|
@ -311,8 +311,19 @@ class DownloadPostProcess(DownloaderBase):
|
||||
|
||||
print(f"auto delete older than {autodelete_days} days")
|
||||
now_lte = str(self.now - autodelete_days * 24 * 60 * 60)
|
||||
channel_overwrite = "channel.channel_overwrites.autodelete_days"
|
||||
data = {
|
||||
"query": {"range": {"player.watched_date": {"lte": now_lte}}},
|
||||
"query": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"range": {"player.watched_date": {"lte": now_lte}}},
|
||||
{"term": {"player.watched": True}},
|
||||
],
|
||||
"must_not": [
|
||||
{"exists": {"field": channel_overwrite}},
|
||||
],
|
||||
}
|
||||
},
|
||||
"sort": [{"player.watched_date": {"order": "asc"}}],
|
||||
}
|
||||
self._auto_delete_watched(data)
|
||||
@ -327,6 +338,7 @@ class DownloadPostProcess(DownloaderBase):
|
||||
must_list = [
|
||||
{"range": {"player.watched_date": {"lte": now_lte}}},
|
||||
{"term": {"channel.channel_id": {"value": channel_id}}},
|
||||
{"term": {"player.watched": True}},
|
||||
]
|
||||
data = {
|
||||
"query": {"bool": {"must": must_list}},
|
||||
|
@ -1,8 +1,8 @@
|
||||
-r requirements.txt
|
||||
ipython==9.0.2
|
||||
ipython==9.2.0
|
||||
pre-commit==4.2.0
|
||||
pylint-django==2.6.1
|
||||
pylint==3.3.6
|
||||
pylint==3.3.7
|
||||
pytest-django==4.11.1
|
||||
pytest==8.3.5
|
||||
python-dotenv==1.1.0
|
||||
|
@ -1,15 +1,15 @@
|
||||
apprise==1.9.3
|
||||
celery==5.5.0
|
||||
django-auth-ldap==5.1.0
|
||||
django-celery-beat==2.7.0
|
||||
celery==5.5.2
|
||||
django-auth-ldap==5.2.0
|
||||
django-celery-beat==2.8.0
|
||||
django-cors-headers==4.7.0
|
||||
Django==5.1.8
|
||||
Django==5.2.1
|
||||
djangorestframework==3.16.0
|
||||
drf-spectacular==0.28.0
|
||||
Pillow==11.1.0
|
||||
redis==5.2.1
|
||||
Pillow==11.2.1
|
||||
redis==6.0.0
|
||||
requests==2.32.3
|
||||
ryd-client==0.0.6
|
||||
uvicorn==0.34.0
|
||||
uvicorn==0.34.2
|
||||
whitenoise==6.9.0
|
||||
yt-dlp[default]==2025.3.31
|
||||
yt-dlp[default]==2025.4.30
|
||||
|
1742
frontend/package-lock.json
generated
1742
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tubearchivist-frontend",
|
||||
"version": "0.1.0",
|
||||
"version": "0.5.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@ -11,27 +11,27 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"dompurify": "^3.2.4",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-router-dom": "^7.1.5",
|
||||
"zustand": "^5.0.3"
|
||||
"dompurify": "^3.2.5",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"zustand": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
||||
"@typescript-eslint/parser": "^8.24.0",
|
||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||
"eslint": "^9.20.1",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^15.15.0",
|
||||
"prettier": "3.5.1",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.24.0",
|
||||
"vite": ">=6.2.4",
|
||||
"vite-plugin-checker": "^0.8.0"
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
||||
"@typescript-eslint/parser": "^8.32.0",
|
||||
"@vitejs/plugin-react-swc": "^3.9.0",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.1.0",
|
||||
"prettier": "3.5.3",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.32.0",
|
||||
"vite": ">=6.3.5",
|
||||
"vite-plugin-checker": "^0.9.3"
|
||||
}
|
||||
}
|
||||
|
16
frontend/public/css/dark.css
Normal file
16
frontend/public/css/dark.css
Normal file
@ -0,0 +1,16 @@
|
||||
:root {
|
||||
--main-bg: #00202f;
|
||||
--highlight-bg: #00293b;
|
||||
--highlight-error: #990202;
|
||||
--highlight-error-light: #c44343;
|
||||
--highlight-bg-transparent: #00293baf;
|
||||
--main-font: #eeeeee;
|
||||
--accent-font-dark: #259485;
|
||||
--accent-font-light: #97d4c8;
|
||||
--img-filter: invert(50%) sepia(9%) saturate(2940%) hue-rotate(122deg) brightness(94%)
|
||||
contrast(90%);
|
||||
--img-filter-error: invert(16%) sepia(60%) saturate(3717%) hue-rotate(349deg) brightness(86%)
|
||||
contrast(120%);
|
||||
--banner: url('/img/banner-tube-archivist-dark.png');
|
||||
--logo: url('/img/logo-tube-archivist-dark.png');
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
import { SortByType, SortOrderType, ViewLayoutType } from '../../pages/Home';
|
||||
import APIClient from '../../functions/APIClient';
|
||||
|
||||
export type ColourVariants = 'dark.css' | 'light.css' | 'matrix.css' | 'midnight.css';
|
||||
export type ColourVariants =
|
||||
| 'dark.css'
|
||||
| 'light.css'
|
||||
| 'matrix.css'
|
||||
| 'midnight.css'
|
||||
| 'custom.css';
|
||||
|
||||
export const FileSizeUnits = {
|
||||
Binary: 'binary',
|
||||
|
34
frontend/src/configuration/colours/Colours.tsx
Normal file
34
frontend/src/configuration/colours/Colours.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { useUserConfigStore } from '../../stores/UserConfigStore';
|
||||
import { ColourConstant } from './colourConstant';
|
||||
import CustomStylesheet from './components/Custom';
|
||||
import DarkStylesheet from './components/Dark';
|
||||
import LightStylesheet from './components/Light';
|
||||
import MatrixStylesheet from './components/Matrix';
|
||||
import MidnightStylesheet from './components/Midnight';
|
||||
|
||||
const Colours = () => {
|
||||
const { userConfig } = useUserConfigStore();
|
||||
const stylesheet = userConfig?.stylesheet;
|
||||
|
||||
switch (stylesheet) {
|
||||
case ColourConstant.Dark:
|
||||
return <DarkStylesheet />;
|
||||
|
||||
case ColourConstant.Matrix:
|
||||
return <MatrixStylesheet />;
|
||||
|
||||
case ColourConstant.Midnight:
|
||||
return <MidnightStylesheet />;
|
||||
|
||||
case ColourConstant.Light:
|
||||
return <LightStylesheet />;
|
||||
|
||||
case ColourConstant.Custom:
|
||||
return <CustomStylesheet />;
|
||||
|
||||
default:
|
||||
return <DarkStylesheet />;
|
||||
}
|
||||
};
|
||||
|
||||
export default Colours;
|
7
frontend/src/configuration/colours/colourConstant.ts
Normal file
7
frontend/src/configuration/colours/colourConstant.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const ColourConstant = {
|
||||
Dark: 'dark.css',
|
||||
Light: 'light.css',
|
||||
Matrix: 'matrix.css',
|
||||
Midnight: 'midnight.css',
|
||||
Custom: 'custom.css',
|
||||
};
|
9
frontend/src/configuration/colours/components/Custom.tsx
Normal file
9
frontend/src/configuration/colours/components/Custom.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
const CustomStylesheet = () => {
|
||||
return (
|
||||
<head>
|
||||
<link rel="stylesheet" href="/css/custom.css" />
|
||||
</head>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomStylesheet;
|
@ -1,7 +1,9 @@
|
||||
import './css/dark.css';
|
||||
|
||||
const DarkStylesheet = () => {
|
||||
return <></>;
|
||||
return (
|
||||
<head>
|
||||
<link rel="stylesheet" href="/css/dark.css" />
|
||||
</head>
|
||||
);
|
||||
};
|
||||
|
||||
export default DarkStylesheet;
|
||||
|
@ -1,7 +1,9 @@
|
||||
import './css/light.css';
|
||||
|
||||
const LightStylesheet = () => {
|
||||
return <></>;
|
||||
return (
|
||||
<head>
|
||||
<link rel="stylesheet" href="/css/light.css" />
|
||||
</head>
|
||||
);
|
||||
};
|
||||
|
||||
export default LightStylesheet;
|
||||
|
@ -1,7 +1,9 @@
|
||||
import './css/matrix.css';
|
||||
|
||||
const MatrixStylesheet = () => {
|
||||
return <></>;
|
||||
return (
|
||||
<head>
|
||||
<link rel="stylesheet" href="/css/matrix.css" />
|
||||
</head>
|
||||
);
|
||||
};
|
||||
|
||||
export default MatrixStylesheet;
|
||||
|
@ -1,7 +1,9 @@
|
||||
import './css/midnight.css';
|
||||
|
||||
const MidnightStylesheet = () => {
|
||||
return <></>;
|
||||
return (
|
||||
<head>
|
||||
<link rel="stylesheet" href="/css/midnight.css" />
|
||||
</head>
|
||||
);
|
||||
};
|
||||
|
||||
export default MidnightStylesheet;
|
||||
|
@ -1,32 +0,0 @@
|
||||
import { useUserConfigStore } from '../../stores/UserConfigStore';
|
||||
|
||||
export const ColourConstant = {
|
||||
Dark: 'dark.css',
|
||||
Light: 'light.css',
|
||||
Matrix: 'matrix.css',
|
||||
Midnight: 'midnight.css',
|
||||
};
|
||||
|
||||
const useColours = () => {
|
||||
const { userConfig } = useUserConfigStore();
|
||||
const stylesheet = userConfig?.stylesheet;
|
||||
|
||||
switch (stylesheet) {
|
||||
case ColourConstant.Dark:
|
||||
return import('./components/Dark');
|
||||
|
||||
case ColourConstant.Matrix:
|
||||
return import('./components/Matrix');
|
||||
|
||||
case ColourConstant.Midnight:
|
||||
return import('./components/Midnight');
|
||||
|
||||
case ColourConstant.Light:
|
||||
return import('./components/Light');
|
||||
|
||||
default:
|
||||
return import('./components/Dark');
|
||||
}
|
||||
};
|
||||
|
||||
export default useColours;
|
@ -1,6 +1,6 @@
|
||||
import { Outlet, useLoaderData, useLocation, useSearchParams } from 'react-router-dom';
|
||||
import Footer from '../components/Footer';
|
||||
import useColours from '../configuration/colours/useColours';
|
||||
import Colours from '../configuration/colours/Colours';
|
||||
import { UserConfigType } from '../api/actions/updateUserConfig';
|
||||
import { useEffect, useState } from 'react';
|
||||
import Navigation from '../components/Navigation';
|
||||
@ -94,10 +94,9 @@ const Base = () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPage]);
|
||||
|
||||
useColours();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Colours />
|
||||
<div className="main-content">
|
||||
<Navigation />
|
||||
{/** Outlet: https://reactrouter.com/en/main/components/outlet */}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useRouteError } from 'react-router-dom';
|
||||
import useColours from '../configuration/colours/useColours';
|
||||
import Colours from '../configuration/colours/Colours';
|
||||
|
||||
// This is not always the correct response
|
||||
type ErrorType = {
|
||||
@ -9,13 +9,13 @@ type ErrorType = {
|
||||
|
||||
const ErrorPage = () => {
|
||||
const error = useRouteError() as ErrorType;
|
||||
useColours();
|
||||
|
||||
console.error('ErrorPage', error);
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>TA | Oops!</title>
|
||||
<Colours />
|
||||
|
||||
<div id="error-page" style={{ margin: '10%' }}>
|
||||
<h1>Oops!</h1>
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Routes from '../configuration/routes/RouteList';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import useColours from '../configuration/colours/useColours';
|
||||
import Colours from '../configuration/colours/Colours';
|
||||
import Button from '../components/Button';
|
||||
import signIn from '../api/actions/signIn';
|
||||
import loadAuth from '../api/loader/loadAuth';
|
||||
|
||||
const Login = () => {
|
||||
useColours();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [username, setUsername] = useState('');
|
||||
@ -76,6 +74,7 @@ const Login = () => {
|
||||
return (
|
||||
<>
|
||||
<title>TA | Welcome</title>
|
||||
<Colours />
|
||||
<div className="boxed-content login-page">
|
||||
<img alt="tube-archivist-logo" />
|
||||
<h1>Tube Archivist</h1>
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import useColours from '../configuration/colours/useColours';
|
||||
import Colours from '../configuration/colours/Colours';
|
||||
import Routes from '../configuration/routes/RouteList';
|
||||
|
||||
const NotFound = ({ failType = 'page' }) => {
|
||||
useColours();
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>404 | Not found</title>
|
||||
<Colours />
|
||||
<div id="error-page" style={{ margin: '10%' }}>
|
||||
<h1>Oops!</h1>
|
||||
<p>
|
||||
|
@ -60,7 +60,7 @@ const Playlist = () => {
|
||||
|
||||
const palylistEntries = playlistResponseData?.playlist_entries;
|
||||
const videoArchivedCount = Number(palylistEntries?.filter(video => video.downloaded).length);
|
||||
const videoInPlaylistCount = pagination?.total_hits;
|
||||
const videoInPlaylistCount = Number(palylistEntries?.length);
|
||||
|
||||
const view = userConfig.view_style_home;
|
||||
const gridItems = userConfig.grid_items;
|
||||
@ -304,7 +304,7 @@ const Playlist = () => {
|
||||
<div className={`boxed-content ${gridView}`}>
|
||||
<Filterbar
|
||||
hideToggleText="Hide watched videos:"
|
||||
viewStyleName={ViewStyleNames.playlist}
|
||||
viewStyleName={ViewStyleNames.home}
|
||||
showSort={false}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import updateUserConfig, {
|
||||
ColourVariants,
|
||||
FileSizeUnits,
|
||||
UserConfigType,
|
||||
} from '../api/actions/updateUserConfig';
|
||||
import { ColourConstant } from '../configuration/colours/useColours';
|
||||
import SettingsNavigation from '../components/SettingsNavigation';
|
||||
import Notifications from '../components/Notifications';
|
||||
import Button from '../components/Button';
|
||||
@ -12,14 +10,13 @@ import useIsAdmin from '../functions/useIsAdmin';
|
||||
import { useUserConfigStore } from '../stores/UserConfigStore';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ToggleConfig from '../components/ToggleConfig';
|
||||
import { ColourConstant } from '../configuration/colours/colourConstant';
|
||||
|
||||
const SettingsUser = () => {
|
||||
const { userConfig, setUserConfig } = useUserConfigStore();
|
||||
const isAdmin = useIsAdmin();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [styleSheet, setStyleSheet] = useState<ColourVariants>(userConfig.stylesheet);
|
||||
const [styleSheetRefresh, setStyleSheetRefresh] = useState(false);
|
||||
const [pageSize, setPageSize] = useState<number>(userConfig.page_size);
|
||||
const [showHelpText, setShowHelpText] = useState(userConfig.show_help_text);
|
||||
const [selectedFileSizeUnit, setSelectedFileSizeUnit] = useState(FileSizeUnits.Binary);
|
||||
@ -41,7 +38,6 @@ const SettingsUser = () => {
|
||||
const handleStyleSheetChange = async (selectedStyleSheet: ColourVariants) => {
|
||||
handleUserConfigUpdate({ stylesheet: selectedStyleSheet });
|
||||
setStyleSheet(selectedStyleSheet);
|
||||
setStyleSheetRefresh(true);
|
||||
};
|
||||
|
||||
const handlePageSizeChange = async () => {
|
||||
@ -65,11 +61,6 @@ const SettingsUser = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageRefresh = () => {
|
||||
navigate(0);
|
||||
setStyleSheetRefresh(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>TA | User Settings</title>
|
||||
@ -104,7 +95,6 @@ const SettingsUser = () => {
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
{styleSheetRefresh && <button onClick={handlePageRefresh}>Refresh</button>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user