import React, {useContext} from "react"; import FileBrowser from 'react-keyed-file-browser'; import { Button as SButton, CardContent, CardDescription, CardHeader, CardMeta, Confirm, Container, Divider, Dropdown, Header as SHeader, Image, Modal, PlaceholderLine, TableCell, TableHeaderCell, } from "semantic-ui-react"; import 'react-keyed-file-browser/dist/react-keyed-file-browser.css'; import {deleteFile, refreshDirectoryFiles, refreshFiles} from "../api"; import { CardGroupCentered, CardPosterLink, cardTitleWrapper, isoDatetimeToString, ExternalCardLink, FileIcon, humanFileSize, isEmpty, mimetypeColor, PageContainer, Paginator, textEllipsis, useTitle, CardLink } from "./Common"; import {useBrowseFiles, useQuery, useSearchFiles} from "../hooks/customHooks"; import {Route, Routes} from "react-router-dom"; import {CardPlacholder} from "./Placeholder"; import {ArchiveCard, ArchiveRowCells} from "./Archive"; import Grid from "semantic-ui-react/dist/commonjs/collections/Grid"; import {ThemeContext} from "../contexts/contexts"; import {Button, Card, CardIcon, Header, Icon, Placeholder, Segment} from "./Theme"; import {SelectableTable} from "./Tables"; import {VideoCard, VideoRowCells} from "./Videos"; import _ from 'lodash'; const icons = { File: , Folder: , FolderOpen: , Image: , PDF: , }; export function Files() { useTitle('Files'); const {t} = useContext(ThemeContext); const {browseFiles, setOpenFolders, fetchFiles} = useBrowseFiles(); const [deleteOpen, setDeleteOpen] = React.useState(false); const [selectedFile, setSelectedFile] = React.useState(null); const [selectedDirectory, setSelectedDirectory] = React.useState(null); const handleFolderChange = async (file, browserProps) => { let openFolders = Object.keys(browserProps.openFolders); setOpenFolders(openFolders); } const onSelect = async (file) => { // A user can only select one file or one directory. if (file.key.endsWith('/')) { setSelectedFile(null); setSelectedDirectory(file); } else { setSelectedDirectory(null); setSelectedFile(file); } } const onDeleteFile = async () => { await deleteFile(selectedFile.key); await fetchFiles(); } const openDelete = () => { setDeleteOpen(true); } const closeDelete = () => { setDeleteOpen(false); } const clearSelection = async (e) => { e.preventDefault(); setOpenFolders(null); setSelectedDirectory(null); setSelectedFile(null); await fetchFiles(); } let clearButton = Clear ; let buttons; if (selectedFile) { buttons = <> Open Delete >; } else if (selectedDirectory) { buttons = <> >; } else { buttons = ; } return <> {clearButton} {buttons} <>>} // Hide the preview that the 3rd party provided. /> > } function EbookCard({file}) { const {s} = useContext(ThemeContext); let {ebook, suffix} = file; const downloadUrl = `/download/${encodeURIComponent(file.path)}`; const isEpub = file['mimetype'].startsWith('application/epub'); const viewerUrl = isEpub ? `/epub.html?url=${downloadUrl}` : null; let cover = ; if (ebook && ebook.cover_path) { const coverSrc = `/media/${encodeURIComponent(ebook.cover_path)}`; cover = ; } suffix = suffix ? _.trimStart(suffix, '.').toUpperCase() : null; const downloadButton = ; const detailsButton = setDetailsOpen(true)} />; const [detailsOpen, setDetailsOpen] = React.useState(false); const detailsModal = setDetailsOpen(false)} trigger={detailsButton} > {ebook.title || file.title} Author: {ebook.creator} {humanFileSize(ebook.size)} eBook Path {ebook ? ebook.ebook_path : file.path} Cover Path {ebook && ebook.cover_path ? ebook.cover_path : 'N/A'} {downloadButton} ; const color = mimetypeColor(file.mimetype); return {cover} {ebook ? ebook.title : file.title} {suffix} {detailsModal} } function ImageCard({file}) { const {s} = useContext(ThemeContext); const url = `/media/${encodeURIComponent(file.path)}`; let poster = ; if (file.size && file.size < 50000000) { // Image is less than 5mb, use it. poster = ; } return {poster} {textEllipsis(file.title || file.stem || file.path)} {isoDatetimeToString(file.modified / 1000)} {humanFileSize(file.size)} } function FileCard({file}) { const {s} = useContext(ThemeContext); const isEbookType = file.mimetype && ( file.mimetype.startsWith('application/epub') || file.mimetype.startsWith('application/x-mobipocket-ebook') ); if (file.model === 'video' && file['video']) { return ; } else if (file.model === 'archive' && file['archive']) { return ; } else if (file.mimetype && file.mimetype.startsWith('image/')) { return ; } else if (isEbookType) { return ; } const url = `/download/${encodeURIComponent(file.path)}`; const color = mimetypeColor(file.mimetype); const size = file.size !== null && file.size !== undefined ? humanFileSize(file.size) : null; return {cardTitleWrapper(file.title || file.stem || file.path)} {isoDatetimeToString(file.modified / 1000)} {size} } export function FileCards({files}) { if (!isEmpty(files)) { return {files.map(i => )} } else if (files && files.length === 0) { return No files found. } else { return } } function ImageRowCells({file}) { const url = `/media/${encodeURIComponent(file.path)}`; let poster = ; if (file.size && file.size < 50000000) { // Image is less than 5mb, use it. poster = ; } // Fragment for SelectableRow return ( {poster} {textEllipsis(file.title || file.stem || file.path)} ) } export function EbookRowCells({file}) { const {ebook} = file; const downloadUrl = `/download/${encodeURIComponent(file.path)}`; const viewerUrl = file['mimetype'].startsWith('application/epub') ? `/epub.html?url=${downloadUrl}` : null; let cover = ; if (ebook && ebook.cover_path) { const coverSrc = `/media/${encodeURIComponent(ebook.cover_path)}`; cover = ; } // Fragment for SelectableRow return ( {cover} {textEllipsis(ebook.title || file.title)} ) } function FileRow({file}) { const isEbookType = file.mimetype && ( file.mimetype.startsWith('application/epub') || file.mimetype.startsWith('application/x-mobipocket-ebook') ); if (file.model === 'video' && 'video' in file) { return ; } else if (file.model === 'archive' && 'archive' in file) { return ; } else if (file.mimetype && file.mimetype.startsWith('image/')) { return ; } else if (isEbookType) { return ; } const onDownloadFile = async () => window.open(`/media/${file.key}`); // Fragment for SelectableRow return onDownloadFile()}> {textEllipsis(file.title)} } export function FileTable({files, selectOn, onSelect, footer, selectedKeys}) { if (!isEmpty(files)) { const headerContents = ['Poster', 'Title']; const rows = files.map(i => ); return ; } else if (isEmpty(files)) { return No results! } else { return } } export function FilesView({ files, limit, setLimit, showLimit = false, activePage, totalPages, view, setView, showView = true, showSelect = false, selectElem, selectedKeys, onSelect, setPage, menuColumnsCount, menuColumns, filterOptions, activeFilters, setFilters, multipleFilters, filterPlaceholder, }) { let selectButton; const [selectOn, setSelectOn] = React.useState(false); const toggleSelectOn = () => setSelectOn(!selectOn); const selectButtonDisabled = view !== 'list'; if (showSelect && selectOn) { selectButton = ; } else if (showSelect) { selectButton = ; } let viewButton; if (showView) { if (view === 'list') { viewButton = setView('cards')}/>; } else { viewButton = setView('list')}/>; } } let limitDropdown; const limitOptions = [ {key: 12, value: 12, text: '12'}, {key: 24, value: 24, text: '24'}, {key: 48, value: 48, text: '48'}, {key: 96, value: 96, text: '96'}, ]; if (showLimit) { limitDropdown = setLimit(value)} /> } const paginator = ; let body; if (view === 'list') { const footer = selectOn && selectElem ? <> {selectElem} > : null; body = ; } else { body = ; } const filtersDropdown = setFilters(value)} style={{marginLeft: '0.3em'}} value={activeFilters} />; return <> {selectButton} {viewButton} {limitDropdown} {filterOptions && filtersDropdown} {menuColumns} {body} {paginator} > } export function FilesSearchView({ showView = true, showLimit = false, showSelect = false, emptySearch = false, filterOptions, model, onSelect, setFilters, }) { filterOptions = filterOptions || [ {key: 'video', text: 'Video', value: 'video'}, {key: 'archive', text: 'Archive', value: 'archive'}, {key: 'pdf', text: 'PDF', value: 'pdf'}, {key: 'ebook', text: 'eBook', value: 'ebook'}, {key: 'image', text: 'Image', value: 'image'}, {key: 'zip', text: 'ZIP', value: 'zip'}, ]; const {searchFiles, limit, setLimit, totalPages, activePage, setPage, filter} = useSearchFiles(24, emptySearch, model); const {searchParams, updateQuery} = useQuery(); const setView = (value) => updateQuery({view: value}); const view = searchParams.get('view'); const setFilter = (value) => updateQuery({'filter': value}); return } function FilesRefreshButton() { const {t} = useContext(ThemeContext); const [loading, setLoading] = React.useState(false); const [name, setName] = React.useState('refresh'); const handleClick = async () => { setLoading(true); await refreshFiles(); setLoading(false); setName('check'); } return <> Refresh Files Find and index all files in the media directory. >; } function DirectoryFilesRefreshButton({directory}) { const {t} = useContext(ThemeContext); const [loading, setLoading] = React.useState(false); const [name, setName] = React.useState('refresh'); const handleClick = async () => { setLoading(true); await refreshDirectoryFiles(directory); setLoading(false); setName('check'); } return <> Refresh Directory Find and index all files in the directory. >; } export function FilesRoute() { return ( }/> ); }
{humanFileSize(ebook.size)}
{ebook ? ebook.ebook_path : file.path}
{ebook && ebook.cover_path ? ebook.cover_path : 'N/A'}
{suffix}
{textEllipsis(file.title || file.stem || file.path)}
{isoDatetimeToString(file.modified / 1000)}
{humanFileSize(file.size)}
{size}
No results!