Initial commit — YT Hub
Self-hosted personal YouTube management app. FastAPI + SQLite backend, React + Vite + Tailwind frontend. Dockerfiles and compose included for Portainer deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
50
frontend/src/hooks/useAuth.jsx
Normal file
50
frontend/src/hooks/useAuth.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useState, useEffect, createContext, useContext } from "react";
|
||||
import { getMe, login as apiLogin, register as apiRegister } from "../api";
|
||||
|
||||
const AuthContext = createContext(null);
|
||||
|
||||
export function AuthProvider({ children }) {
|
||||
const [user, setUser] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
getMe()
|
||||
.then((res) => setUser(res.data))
|
||||
.catch(() => localStorage.removeItem("token"))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const login = async (username, password) => {
|
||||
const res = await apiLogin(username, password);
|
||||
localStorage.setItem("token", res.data.access_token);
|
||||
const me = await getMe();
|
||||
setUser(me.data);
|
||||
};
|
||||
|
||||
const register = async (username, email, password) => {
|
||||
const res = await apiRegister({ username, email, password });
|
||||
localStorage.setItem("token", res.data.access_token);
|
||||
const me = await getMe();
|
||||
setUser(me.data);
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("token");
|
||||
setUser(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, loading, login, register, logout }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
return useContext(AuthContext);
|
||||
}
|
||||
25
frontend/src/hooks/usePlayer.js
Normal file
25
frontend/src/hooks/usePlayer.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
export function usePlayer() {
|
||||
const [params, setParams] = useSearchParams();
|
||||
|
||||
const play = (youtubeVideoId, meta = {}) => {
|
||||
setParams((p) => {
|
||||
p.set("play", youtubeVideoId);
|
||||
if (meta.title) p.set("pt", meta.title);
|
||||
if (meta.channel_name) p.set("pc", meta.channel_name);
|
||||
return p;
|
||||
});
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
setParams((p) => {
|
||||
p.delete("play");
|
||||
p.delete("pt");
|
||||
p.delete("pc");
|
||||
return p;
|
||||
});
|
||||
};
|
||||
|
||||
return { play, close, currentId: params.get("play") };
|
||||
}
|
||||
Reference in New Issue
Block a user