import axios from "axios"; const api = axios.create({ baseURL: "/api" }); api.interceptors.request.use((config) => { const token = localStorage.getItem("token"); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); api.interceptors.response.use( (res) => res, (err) => { if (err.response?.status === 401 && !err.config?.url?.includes("/auth/login")) { localStorage.removeItem("token"); window.location.href = "/login"; } return Promise.reject(err); } ); export default api; // Auth export const login = (username, password) => { const form = new FormData(); form.append("username", username); form.append("password", password); return api.post("/auth/login", form); }; export const register = (data) => api.post("/auth/register", data); export const getMe = () => api.get("/auth/me"); // Search export const search = (q, live = false) => api.get("/search", { params: { q, live } }); export const getSearchHistory = () => api.get("/search/history"); // Channels export const getChannels = () => api.get("/channels"); export const getChannelFeed = (offset = 0) => api.get("/channels/feed", { params: { offset, limit: 24 } }); export const getChannel = (id) => api.get(`/channels/${id}`); export const syncAllChannels = () => api.post("/channels/sync-all"); export const getChannelVideos = (id, sort = "newest", offset = 0, limit = 60, q = "") => api.get(`/channels/${id}/videos`, { params: { sort, offset, limit, ...(q ? { q } : {}) } }); export const searchChannelYoutube = (id, q) => api.post(`/channels/${id}/search`, null, { params: { q } }); export const followChannel = (id) => api.post(`/channels/${id}/follow`); export const unfollowChannel = (id) => api.delete(`/channels/${id}/follow`); export const indexChannel = (id) => api.post(`/channels/${id}/index`); export const indexChannelFull = (id) => api.post(`/channels/${id}/index-full`); export const exploreChannelOlder = (id, page) => api.post(`/channels/${id}/explore`, null, { params: { page } }); export const fetchPopularVideos = (id) => api.post(`/channels/${id}/fetch-popular`); export const followChannelByUrl = (data) => api.post("/channels/follow-by-url", data); export const setChannelAutoDownload = (id, value) => api.patch(`/channels/${id}/auto-download`, { auto_download: value }); export const markChannelsSeen = () => api.post("/channels/mark-seen"); export const followBulk = (handles) => api.post("/channels/follow-bulk", { handles }); export const updateChannelNotes = (id, notes) => api.patch(`/channels/${id}/notes`, { notes }); export const muteChannel = (id) => api.post(`/channels/${id}/mute`); export const unmuteChannel = (id) => api.delete(`/channels/${id}/mute`); export const getChannelGroups = () => api.get("/channels/groups"); export const createChannelGroup = (name) => api.post("/channels/groups", { name }); export const deleteChannelGroup = (id) => api.delete(`/channels/groups/${id}`); export const renameChannelGroup = (id, name) => api.patch(`/channels/groups/${id}`, { name }); export const addChannelToGroup = (groupId, channelId) => api.post(`/channels/groups/${groupId}/channels/${channelId}`); export const removeChannelFromGroup = (groupId, channelId) => api.delete(`/channels/groups/${groupId}/channels/${channelId}`); export const bulkChannelAction = (channel_ids, action) => api.post("/channels/bulk-action", { channel_ids, action }); export const getActiveTasks = () => api.get("/channels/tasks"); export const getRssFeedUrl = () => `/api/channels/rss`; export const getRandomChannelVideo = (id, unwatchedOnly = true) => api.get(`/channels/${id}/random`, { params: { unwatched_only: unwatchedOnly } }); export const getChannelInProgress = (id) => api.get(`/channels/${id}/in-progress`); // Videos export const homeFeed = (page = 0, limit = 25, mode = "ranked", duration = "") => api.get("/videos/home-feed", { params: { offset: page * limit, limit, mode, ...(duration ? { duration } : {}) } }); export const continueWatching = () => api.get("/videos/continue-watching"); export const longVideos = () => api.get("/videos/long"); export const surpriseMe = () => api.get("/videos/surprise"); export const getVideo = (id) => api.get(`/videos/${id}`); export const getVideoByYtId = (ytId) => api.get(`/videos/by-yt/${ytId}`); export const getVideoComments = (ytId) => api.get(`/videos/by-yt/${ytId}/comments`); export const refreshVideoComments = (ytId) => api.post(`/videos/by-yt/${ytId}/comments/refresh`); export const updateProgress = (id, data) => api.patch(`/videos/${id}/progress`, data); export const toggleQueue = (id) => api.post(`/videos/${id}/queue`); export const getQueue = () => api.get("/videos/queue"); export const toggleLike = (id) => api.post(`/videos/${id}/like`); export const getLikedVideos = () => api.get("/videos/liked"); export const rateVideo = (id, rating) => api.post(`/videos/${id}/rate`, { rating }); export const getRelatedVideos = (videoId, mode = "weighted") => api.get(`/videos/${videoId}/related`, { params: { mode } }); export const getHistory = (page = 0, limit = 25, channel_id = null) => api.get("/videos/history", { params: { offset: page * limit, limit, ...(channel_id ? { channel_id } : {}) } }); export const getBookmarks = (videoId) => api.get(`/videos/${videoId}/bookmarks`); export const createBookmark = (videoId, data) => api.post(`/videos/${videoId}/bookmarks`, data); export const updateBookmark = (videoId, bookmarkId, data) => api.patch(`/videos/${videoId}/bookmarks/${bookmarkId}`, data); export const deleteBookmark = (videoId, bookmarkId) => api.delete(`/videos/${videoId}/bookmarks/${bookmarkId}`); export const importChapters = (videoId) => api.post(`/videos/${videoId}/bookmarks/import-chapters`); export const clearChapters = (videoId) => api.delete(`/videos/${videoId}/bookmarks/clear-chapters`); // Downloads export const createDownload = (youtube_video_id, quality, subtitle_langs) => api.post("/downloads", { youtube_video_id, ...(quality ? { quality } : {}), ...(subtitle_langs ? { subtitle_langs } : {}) }); export const getDownloads = () => api.get("/downloads"); export const getAvailableSubs = (ytId) => api.get(`/videos/by-yt/${ytId}/subs`); export const getSubtitleFiles = (ytId) => api.get(`/videos/by-yt/${ytId}/subtitle-files`); export const downloadSubs = (ytId, subtitle_langs) => api.post(`/videos/by-yt/${ytId}/download-subs`, { subtitle_langs }); export const getDownload = (id) => api.get(`/downloads/${id}`); export const deleteDownload = (id) => api.delete(`/downloads/${id}`); export const deleteAllDownloads = () => api.delete("/downloads/all"); export const restoreDownload = (id) => api.post(`/downloads/${id}/restore`); export const downloadChannel = (channelId) => api.post(`/downloads/channel/${channelId}`); export const downloadFollowing = () => api.post("/downloads/following"); // Export export const exportData = () => api.get("/export", { responseType: "blob" }); // Settings export const getSettings = () => api.get("/settings"); export const updateSettings = (data) => api.patch("/settings", data); export const uploadCookiesFile = (file) => { const form = new FormData(); form.append("file", file); return api.post("/settings/cookies-file", form); }; export const deleteCookiesFile = () => api.delete("/settings/cookies-file"); export const initOAuth2 = () => api.post("/settings/oauth2-init"); export const getOAuth2Status = () => api.get("/settings/oauth2-status"); export const enableOAuth2 = () => api.post("/settings/oauth2-enable"); export const disableOAuth2 = () => api.post("/settings/oauth2-disable"); export const testYtdlp = () => api.get("/settings/ytdlp-test"); // Discovery export const getDiscovery = (offset = 0, limit = 50) => api.get("/discovery", { params: { offset, limit } }); export const dismissDiscoveryVideo = (youtubeVideoId) => api.post(`/discovery/videos/${youtubeVideoId}/dismiss`); export const getDiscoveryVideos = (offset = 0, limit = 50) => api.get("/discovery/videos", { params: { offset, limit } }); export const followDiscovery = (channelId) => api.post(`/discovery/${channelId}/follow`); export const dismissDiscovery = (channelId) => api.post(`/discovery/${channelId}/dismiss`); export const refreshDiscovery = () => api.post("/discovery/refresh"); export const getDiscoveryStatus = () => api.get("/discovery/status"); export const getCommunityShelf = () => api.get("/discovery/community"); // Stats export const getStats = () => api.get("/stats"); export const deleteTasteTag = (tag) => api.delete(`/stats/taste/${encodeURIComponent(tag)}`); // Admin export const getAdminUsers = () => api.get("/admin/users"); export const deleteAdminUser = (id) => api.delete(`/admin/users/${id}`); export const getAdminConfig = () => api.get("/admin/config"); export const updateAdminConfig = (data) => api.patch("/admin/config", data); // Collections export const getCollections = () => api.get("/collections"); export const createCollection = (name) => api.post("/collections", { name }); export const renameCollection = (id, name) => api.patch(`/collections/${id}`, { name }); export const deleteCollection = (id) => api.delete(`/collections/${id}`); export const getCollectionVideos = (id) => api.get(`/collections/${id}/videos`); export const addToCollection = (collectionId, videoId) => api.post(`/collections/${collectionId}/videos`, { video_id: videoId }); export const removeFromCollection = (collectionId, videoId) => api.delete(`/collections/${collectionId}/videos/${videoId}`); // Playlists export const getChannelPlaylists = (channelId) => api.get(`/playlists/channel/${channelId}`); export const fetchChannelPlaylists = (channelId) => api.post(`/playlists/channel/${channelId}/fetch`); export const getPlaylistVideos = (playlistId, offset = 0, limit = 60) => api.get(`/playlists/${playlistId}/videos`, { params: { offset, limit } }); export const indexPlaylist = (playlistId) => api.post(`/playlists/${playlistId}/index`); export const generateNfoFiles = () => api.post("/downloads/nfo/generate");