mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 10:51:36 -04:00
Unifying Files tab appearance for model pages.
This commit is contained in:
parent
2943b2a9c8
commit
bf5b787fb3
5 changed files with 153 additions and 88 deletions
|
|
@ -23,6 +23,7 @@ import {
|
|||
APIButton,
|
||||
BackButton,
|
||||
CardLink,
|
||||
DirectoryLink,
|
||||
encodeMediaPath,
|
||||
ErrorMessage,
|
||||
ExternalCardLink,
|
||||
|
|
@ -89,19 +90,6 @@ import {CollectionEditForm} from "./collections/CollectionEditForm";
|
|||
import {RecurringDownloadsTable} from "./admin/Downloads";
|
||||
import {DestinationForm} from "./Download";
|
||||
|
||||
function archiveFileLink(path, directory = false) {
|
||||
if (path) {
|
||||
const href = directory ?
|
||||
`/media/${encodeMediaPath(path)}/`
|
||||
: `/media/${encodeMediaPath(path)}`;
|
||||
return <a href={href} target='_blank' rel='noopener noreferrer'>
|
||||
<pre>{path}</pre>
|
||||
</a>
|
||||
} else {
|
||||
return <p>Unknown</p>
|
||||
}
|
||||
}
|
||||
|
||||
function ArchivePage() {
|
||||
const navigate = useNavigate();
|
||||
const {fileGroupId} = useParams();
|
||||
|
|
@ -258,37 +246,63 @@ function ArchivePage() {
|
|||
</Tab.Pane>
|
||||
};
|
||||
|
||||
// Helper to find file size from the files array by resolved path
|
||||
const findFileSize = (resolvedPath) => {
|
||||
if (!resolvedPath || !archiveFile.files) return null;
|
||||
const file = archiveFile.files.find(i => String(i.path) === String(resolvedPath));
|
||||
return file && file.size
|
||||
? <span style={{marginLeft: '1em', color: 'grey'}}>({humanFileSize(file.size)})</span>
|
||||
: null;
|
||||
};
|
||||
|
||||
// Helper to resolve and preview a data path
|
||||
const localPreviewPath = (dataPath, mimetype) => {
|
||||
const resolvedPath = resolveDataPath(dataPath, directory);
|
||||
if (resolvedPath) {
|
||||
return <PreviewPath path={resolvedPath} mimetype={mimetype} taggable={false}>{resolvedPath}</PreviewPath>
|
||||
return <><PreviewPath path={resolvedPath} mimetype={mimetype}
|
||||
taggable={false}>{resolvedPath}</PreviewPath>{findFileSize(resolvedPath)}</>
|
||||
} else {
|
||||
return 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
const tableStyle = {width: '100%', borderCollapse: 'separate', borderSpacing: '0 0.7em'};
|
||||
const labelStyle = {whiteSpace: 'nowrap', paddingRight: '1.5em', verticalAlign: 'top'};
|
||||
const filesPane = {
|
||||
menuItem: 'Files', render: () => <Tab.Pane>
|
||||
<Header as={'h3'}>Singlefile File</Header>
|
||||
{localPreviewPath(data.singlefile_path, 'text/html')}
|
||||
|
||||
<Header as={'h3'}>Readability File</Header>
|
||||
{localPreviewPath(data.readability_path, 'text/html')}
|
||||
|
||||
<Header as={'h3'}>Readability Text File</Header>
|
||||
{localPreviewPath(data.readability_txt_path, 'text/plain')}
|
||||
|
||||
<Header as={'h3'}>Readability JSON File</Header>
|
||||
{localPreviewPath(data.readability_json_path, 'application/json')}
|
||||
|
||||
<Header as={'h3'}>Screenshot File</Header>
|
||||
{screenshotPath ?
|
||||
archiveFileLink(screenshotPath)
|
||||
: 'Unknown'}
|
||||
|
||||
<Header as={'h3'}>Directory</Header>
|
||||
{archiveFileLink(archiveFile.directory, true)}
|
||||
<table style={tableStyle}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Singlefile File</strong></td>
|
||||
<td>{localPreviewPath(data.singlefile_path, 'text/html')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Readability File</strong></td>
|
||||
<td>{localPreviewPath(data.readability_path, 'text/html')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Readability Text File</strong></td>
|
||||
<td>{localPreviewPath(data.readability_txt_path, 'text/plain')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Readability JSON File</strong></td>
|
||||
<td>{localPreviewPath(data.readability_json_path, 'application/json')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Screenshot File</strong></td>
|
||||
<td>
|
||||
{screenshotPath
|
||||
? <><PreviewPath path={screenshotPath} mimetype='image/*'
|
||||
taggable={false}>{screenshotPath}</PreviewPath>{findFileSize(screenshotPath)}</>
|
||||
: 'Unknown'}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Directory</strong></td>
|
||||
<td><DirectoryLink path={archiveFile.directory}/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Tab.Pane>
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -246,6 +246,15 @@ export function PreviewPath({path, mimetype, taggable = true, ...props}) {
|
|||
return <PreviewLink file={{path, mimetype, taggable}} {...props}/>
|
||||
}
|
||||
|
||||
export function DirectoryLink({path}) {
|
||||
if (!path) return <span>Unknown</span>;
|
||||
const href = `/media/${encodeMediaPath(path)}/`;
|
||||
return <a href={href} target='_blank' rel='noopener noreferrer'
|
||||
style={{color: 'inherit', textDecoration: 'none'}}>
|
||||
{path}
|
||||
</a>
|
||||
}
|
||||
|
||||
export function RequiredAsterisk() {
|
||||
return <span style={{color: '#db2828'}}> *</span>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {Media, ThemeContext} from "../contexts/contexts";
|
|||
import {
|
||||
APIButton,
|
||||
BackButton,
|
||||
DirectoryLink,
|
||||
encodeMediaPath,
|
||||
ErrorMessage,
|
||||
humanFileSize,
|
||||
|
|
@ -288,21 +289,33 @@ function DocPage() {
|
|||
};
|
||||
|
||||
// Files pane.
|
||||
const tableStyle = {width: '100%', borderCollapse: 'separate', borderSpacing: '0 0.7em'};
|
||||
const labelStyle = {whiteSpace: 'nowrap', paddingRight: '1.5em', verticalAlign: 'top'};
|
||||
const filesPane = {
|
||||
menuItem: 'Files', render: () => <Tab.Pane>
|
||||
{docFile.files && docFile.files.map((file, idx) =>
|
||||
<div key={idx} style={{marginBottom: '0.5em'}}>
|
||||
<PreviewPath path={file.path} mimetype={file.mimetype} taggable={false}>
|
||||
{file.path}
|
||||
</PreviewPath>
|
||||
{file.size && <span style={{marginLeft: '1em', color: 'grey'}}>
|
||||
({humanFileSize(file.size)})
|
||||
</span>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Header as='h3'>Directory</Header>
|
||||
<p>{directory || 'Unknown'}</p>
|
||||
<table style={tableStyle}>
|
||||
<tbody>
|
||||
{docFile.files && docFile.files.map((file, idx) =>
|
||||
<tr key={idx}>
|
||||
<td style={labelStyle}>
|
||||
<strong>{file.path.split('.').pop().toUpperCase()}</strong>
|
||||
</td>
|
||||
<td>
|
||||
<PreviewPath path={file.path} mimetype={file.mimetype} taggable={false}>
|
||||
{file.path}
|
||||
</PreviewPath>
|
||||
{file.size && <span style={{marginLeft: '1em', color: 'grey'}}>
|
||||
({humanFileSize(file.size)})
|
||||
</span>}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Directory</strong></td>
|
||||
<td><DirectoryLink path={directory}/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Tab.Pane>
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import _ from "lodash";
|
|||
import {
|
||||
APIButton,
|
||||
BackButton,
|
||||
DirectoryLink,
|
||||
encodeMediaPath,
|
||||
humanFileSize,
|
||||
humanNumber,
|
||||
|
|
@ -29,19 +30,6 @@ import {Comment, CommentGroup, Input, Label} from "semantic-ui-react";
|
|||
const MEDIA_PATH = '/media';
|
||||
|
||||
|
||||
function videoFileLink(path, directory = false) {
|
||||
if (path) {
|
||||
const href = directory ?
|
||||
// Add / to end of directory.
|
||||
`${MEDIA_PATH}/${encodeMediaPath(path)}/` :
|
||||
`${MEDIA_PATH}/${encodeMediaPath(path)}`;
|
||||
return <a href={href} target='_blank' rel='noopener noreferrer'>
|
||||
<pre>{path}</pre>
|
||||
</a>
|
||||
} else {
|
||||
return 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
export function CaptionTrack({src, ...props}) {
|
||||
if (src.endsWith('.de.vtt')) {
|
||||
|
|
@ -311,44 +299,84 @@ function VideoPage({videoFile, prevFile, nextFile, fetchVideo, ...props}) {
|
|||
};
|
||||
|
||||
const getFile = (suffix) => videoFile.files.find(i => i.path.toLowerCase().endsWith(suffix));
|
||||
const fileSize = (file) => file && file.size
|
||||
? <span style={{marginLeft: '1em', color: 'grey'}}>({humanFileSize(file.size)})</span>
|
||||
: null;
|
||||
|
||||
const {poster_file, info_json_file} = video;
|
||||
const videoPathFile = videoFile.files.find(i => i.path === video['video_path']);
|
||||
const ffprobeJsonFile = getFile('.ffprobe.json');
|
||||
const tableStyle = {width: '100%', borderCollapse: 'separate', borderSpacing: '0 0.7em'};
|
||||
const labelStyle = {whiteSpace: 'nowrap', paddingRight: '1.5em', verticalAlign: 'top'};
|
||||
const filesPane = {
|
||||
menuItem: 'Files', render: () => <Tab.Pane>
|
||||
<h3>Video File</h3>
|
||||
{videoFileLink(video['video_path'])}
|
||||
<table style={tableStyle}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Video File</strong></td>
|
||||
<td>
|
||||
{video['video_path']
|
||||
? <><PreviewPath path={video['video_path']} mimetype='video/*' taggable={false}>
|
||||
{video['video_path']}
|
||||
</PreviewPath>{fileSize(videoPathFile)}</>
|
||||
: 'Unknown'}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<h4>Caption Files</h4>
|
||||
{caption_files ?
|
||||
caption_files.map(i => <p key={i['path']}><PreviewPath {...i} taggable={false}>
|
||||
{i['path']}
|
||||
</PreviewPath></p>) : 'No caption files'
|
||||
}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Caption Files</strong></td>
|
||||
<td>
|
||||
{caption_files
|
||||
? caption_files.map(i => <div key={i['path']} style={{marginBottom: '0.3em'}}>
|
||||
<PreviewPath {...i} taggable={false}>{i['path']}</PreviewPath>
|
||||
{fileSize(i)}
|
||||
</div>)
|
||||
: 'No caption files'}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<h4>Poster File</h4>
|
||||
{poster_file ?
|
||||
<PreviewPath path={poster_file['path']} mimetype={poster_file['mimetype']} taggable={false}>
|
||||
{poster_file['path']}
|
||||
</PreviewPath> : 'No poster file'
|
||||
}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Poster File</strong></td>
|
||||
<td>
|
||||
{poster_file
|
||||
? <><PreviewPath path={poster_file['path']} mimetype={poster_file['mimetype']}
|
||||
taggable={false}>
|
||||
{poster_file['path']}
|
||||
</PreviewPath>{fileSize(poster_file)}</>
|
||||
: 'No poster file'}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<h4>Info JSON File</h4>
|
||||
{info_json_file ?
|
||||
<PreviewPath path={info_json_file['path']} mimetype={info_json_file['mimetype']} taggable={false}>
|
||||
{info_json_file['path']}
|
||||
</PreviewPath> : 'No yt-dlp info json file'
|
||||
}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Info JSON File</strong></td>
|
||||
<td>
|
||||
{info_json_file
|
||||
? <><PreviewPath path={info_json_file['path']} mimetype={info_json_file['mimetype']}
|
||||
taggable={false}>
|
||||
{info_json_file['path']}
|
||||
</PreviewPath>{fileSize(info_json_file)}</>
|
||||
: 'No yt-dlp info json file'}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<h4>ffprobe JSON File</h4>
|
||||
{ffprobeJsonFile ?
|
||||
<PreviewPath path={ffprobeJsonFile['path']} mimetype={ffprobeJsonFile['mimetype']} taggable={false}>
|
||||
{ffprobeJsonFile['path']}
|
||||
</PreviewPath> : 'No ffprobe json file'
|
||||
}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>ffprobe JSON File</strong></td>
|
||||
<td>
|
||||
{ffprobeJsonFile
|
||||
? <><PreviewPath path={ffprobeJsonFile['path']} mimetype={ffprobeJsonFile['mimetype']}
|
||||
taggable={false}>
|
||||
{ffprobeJsonFile['path']}
|
||||
</PreviewPath>{fileSize(ffprobeJsonFile)}</>
|
||||
: 'No ffprobe json file'}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<h4>Directory</h4>
|
||||
{videoFileLink(videoFile['directory'], true)}
|
||||
<tr>
|
||||
<td style={labelStyle}><strong>Directory</strong></td>
|
||||
<td><DirectoryLink path={videoFile['directory']}/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Tab.Pane>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -272,7 +272,8 @@ class FileGroup(ModelHelper, Base):
|
|||
new_files = list(self.files) if self.files else list()
|
||||
for path in paths:
|
||||
# Store just the filename, not the full path
|
||||
new_files.append(dict(path=path.name, mimetype=get_mimetype(path)))
|
||||
size = path.stat().st_size if path.exists() else None
|
||||
new_files.append(dict(path=path.name, mimetype=get_mimetype(path), size=size))
|
||||
self.files = unique_by_predicate(new_files, lambda i: i['path'])
|
||||
# Update modification_datetime to include the new files' mtimes
|
||||
if paths:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue