0.10.2-25 Fixes
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"primeicons": "^7.0.0",
|
"primeicons": "^7.0.0",
|
||||||
"primereact": "^10.9.2",
|
"primereact": "^10.9.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -774,42 +774,43 @@ export default function JobDetailDialog({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="job-meta-block job-meta-block-full">
|
<section className="job-meta-block job-meta-block-full">
|
||||||
<h4>Job-Infos</h4>
|
<div className="job-infos-header">
|
||||||
<div className="job-meta-grid job-meta-grid-compact">
|
<h4>Job-Infos</h4>
|
||||||
<div>
|
<div className="job-infos-badges">
|
||||||
<strong>Status:</strong>{' '}
|
<span>
|
||||||
<span
|
<strong>Status:</strong>{' '}
|
||||||
className={`job-status-icon tone-${statusMeta.tone}`}
|
<span
|
||||||
title={statusMeta.label}
|
className={`job-status-icon tone-${statusMeta.tone}`}
|
||||||
aria-label={statusMeta.label}
|
title={statusMeta.label}
|
||||||
>
|
aria-label={statusMeta.label}
|
||||||
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
>
|
||||||
|
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{' '}<span className="job-meta-subtle">{statusMeta.label}</span>
|
<span className="job-infos-sep">|</span>
|
||||||
|
{isCd ? (
|
||||||
|
<>
|
||||||
|
<span><strong>Rip:</strong> <BoolState value={job?.ripSuccessful} /></span>
|
||||||
|
<span className="job-infos-sep">|</span>
|
||||||
|
<span><strong>Backup:</strong> <BoolState value={job?.backupSuccess} /></span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span><strong>{isAudiobook ? 'Import:' : 'Backup:'}</strong> <BoolState value={job?.backupSuccess} /></span>
|
||||||
|
<span className="job-infos-sep">|</span>
|
||||||
|
<span><strong>Encode:</strong> <BoolState value={job?.encodeSuccess} /></span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<strong>Start:</strong> {job.start_time || '-'}
|
<div className="job-infos-layout">
|
||||||
</div>
|
{/* Zeile 1: Start | Ende */}
|
||||||
<div>
|
<div><strong>Start:</strong> {job.start_time || '-'}</div>
|
||||||
<strong>Ende:</strong> {job.end_time || '-'}
|
<div><strong>Ende:</strong> {job.end_time || '-'}</div>
|
||||||
</div>
|
{/* Zeile 3+4: Pfade */}
|
||||||
{isCd ? (
|
|
||||||
<div>
|
|
||||||
<strong>Rip:</strong> <BoolState value={job?.ripSuccessful} />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<strong>{isAudiobook ? 'Import:' : 'Backup:'}</strong> <BoolState value={job?.backupSuccess} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<strong>Encode:</strong> <BoolState value={job?.encodeSuccess} />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<PathField
|
<PathField
|
||||||
label={isCd ? 'WAV:' : 'RAW:'}
|
label={isCd ? 'WAV:' : 'RAW:'}
|
||||||
value={job.raw_path}
|
value={isCd ? (job.raw_path || job.output_path) : job.raw_path}
|
||||||
onDownload={canDownloadRaw ? () => onDownloadArchive?.(job, 'raw') : null}
|
onDownload={canDownloadRaw ? () => onDownloadArchive?.(job, 'raw') : null}
|
||||||
downloadDisabled={!canDownloadRaw}
|
downloadDisabled={!canDownloadRaw}
|
||||||
downloadLoading={downloadBusyTarget === 'raw'}
|
downloadLoading={downloadBusyTarget === 'raw'}
|
||||||
@@ -822,12 +823,10 @@ export default function JobDetailDialog({
|
|||||||
downloadLoading={downloadBusyTarget === 'output'}
|
downloadLoading={downloadBusyTarget === 'output'}
|
||||||
/>
|
/>
|
||||||
{job.error_message ? (
|
{job.error_message ? (
|
||||||
<div className="job-meta-col-span-2">
|
<div><strong>Fehler:</strong> {job.error_message}</div>
|
||||||
<strong>Fehler:</strong> {job.error_message}
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
{expertMode ? (
|
{expertMode ? (
|
||||||
<div className="job-meta-col-span-2">
|
<div>
|
||||||
<Link to={`/database?table=jobs&id=${job.id}`} className="job-db-link" onClick={onHide}>
|
<Link to={`/database?table=jobs&id=${job.id}`} className="job-db-link" onClick={onHide}>
|
||||||
<i className="pi pi-database" /> DB-Eintrag ansehen
|
<i className="pi pi-database" /> DB-Eintrag ansehen
|
||||||
</Link>
|
</Link>
|
||||||
@@ -885,50 +884,51 @@ export default function JobDetailDialog({
|
|||||||
return (
|
return (
|
||||||
<div key={title.id} className="track-title-block">
|
<div key={title.id} className="track-title-block">
|
||||||
<div className="track-title-row">
|
<div className="track-title-row">
|
||||||
<span>#{title.id} | {title.fileName} | {title.durationMinutes != null ? `${Number(title.durationMinutes).toFixed(2)} min` : '-'} | {trackSizeFormat(title.sizeBytes)}</span>
|
<span>#{title.id} | {title.fileName} | {title.durationMinutes != null ? `${Number(title.durationMinutes).toFixed(2)} min` : '-'}</span>
|
||||||
{title.encodeInput ? <span className="track-input-badge">Encode-Input</span> : null}
|
</div>
|
||||||
|
<div className="track-groups-row">
|
||||||
|
{audioTracks.length > 0 ? (
|
||||||
|
<div className="track-group">
|
||||||
|
<div className="track-group-label">Tonspuren (Titel #{title.id})</div>
|
||||||
|
{audioTracks.map((track) => {
|
||||||
|
const lang = trackLang(track.language || track.languageLabel);
|
||||||
|
const codec = trackCodec('audio', track.format, track.description || track.title);
|
||||||
|
const chLayout = trackChLayout(track.channels);
|
||||||
|
let displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||||
|
if (chLayout) displayText += ` | ${chLayout}`;
|
||||||
|
const actionInfo = track.selectedForEncode
|
||||||
|
? (String(track.encodePreviewSummary || track.encodeActionSummary || '').trim() || 'Copy')
|
||||||
|
: 'Nicht übernommen';
|
||||||
|
return (
|
||||||
|
<div key={track.id} className="track-item">
|
||||||
|
<span>{displayText}</span>
|
||||||
|
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{subtitleTracks.length > 0 ? (
|
||||||
|
<div className="track-group">
|
||||||
|
<div className="track-group-label">Subtitles (Titel #{title.id})</div>
|
||||||
|
{subtitleTracks.map((track) => {
|
||||||
|
const lang = trackLang(track.language || track.languageLabel);
|
||||||
|
const codec = trackCodec('subtitle', track.format);
|
||||||
|
const displayText = `#${track.id} | ${lang} | ${codec}`;
|
||||||
|
const rawAction = String(track.subtitlePreviewSummary || track.subtitleActionSummary || '').trim();
|
||||||
|
const actionInfo = track.selectedForEncode
|
||||||
|
? (/^nicht übernommen$/i.test(rawAction) ? 'Übernehmen' : (rawAction || 'Übernehmen'))
|
||||||
|
: 'Nicht übernommen';
|
||||||
|
return (
|
||||||
|
<div key={track.id} className="track-item">
|
||||||
|
<span>{displayText}</span>
|
||||||
|
<small className="track-action-note">Encode: {actionInfo}</small>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{audioTracks.length > 0 ? (
|
|
||||||
<div className="track-group">
|
|
||||||
<div className="track-group-label">Tonspuren (Titel #{title.id})</div>
|
|
||||||
{audioTracks.map((track) => {
|
|
||||||
const lang = trackLang(track.language || track.languageLabel);
|
|
||||||
const codec = trackCodec('audio', track.format, track.description || track.title);
|
|
||||||
const chLayout = trackChLayout(track.channels);
|
|
||||||
let displayText = `#${track.id} | ${lang} | ${codec}`;
|
|
||||||
if (chLayout) displayText += ` | ${chLayout}`;
|
|
||||||
const actionInfo = track.selectedForEncode
|
|
||||||
? (String(track.encodePreviewSummary || track.encodeActionSummary || '').trim() || 'Copy')
|
|
||||||
: 'Nicht übernommen';
|
|
||||||
return (
|
|
||||||
<div key={track.id} className="track-item">
|
|
||||||
<span>{displayText}</span>
|
|
||||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{subtitleTracks.length > 0 ? (
|
|
||||||
<div className="track-group">
|
|
||||||
<div className="track-group-label">Subtitles (Titel #{title.id})</div>
|
|
||||||
{subtitleTracks.map((track) => {
|
|
||||||
const lang = trackLang(track.language || track.languageLabel);
|
|
||||||
const codec = trackCodec('subtitle', track.format);
|
|
||||||
const displayText = `#${track.id} | ${lang} | ${codec}`;
|
|
||||||
const rawAction = String(track.subtitlePreviewSummary || track.subtitleActionSummary || '').trim();
|
|
||||||
const actionInfo = track.selectedForEncode
|
|
||||||
? (/^nicht übernommen$/i.test(rawAction) ? 'Übernehmen' : (rawAction || 'Übernehmen'))
|
|
||||||
: 'Nicht übernommen';
|
|
||||||
return (
|
|
||||||
<div key={track.id} className="track-item">
|
|
||||||
<span>{displayText}</span>
|
|
||||||
<small className="track-action-note">Encode: {actionInfo}</small>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -938,14 +938,99 @@ export default function JobDetailDialog({
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
{(isCd || isAudiobook) && job.encodePlan ? (
|
||||||
|
<section className="job-meta-block job-meta-block-full">
|
||||||
|
<h4>{isCd ? 'Titelauswahl' : 'Kapitelauswahl'}</h4>
|
||||||
|
{isCd ? (() => {
|
||||||
|
const tracksRaw = Array.isArray(job.makemkvInfo?.tracks) && job.makemkvInfo.tracks.length > 0
|
||||||
|
? job.makemkvInfo.tracks
|
||||||
|
: (Array.isArray(job.encodePlan?.tracks) ? job.encodePlan.tracks : []);
|
||||||
|
const selectedSet = Array.isArray(job.encodePlan?.selectedTracks) && job.encodePlan.selectedTracks.length > 0
|
||||||
|
? new Set(job.encodePlan.selectedTracks.map(Number))
|
||||||
|
: null;
|
||||||
|
if (tracksRaw.length === 0) return <p className="job-meta-subtle">Keine Tracks vorhanden.</p>;
|
||||||
|
return (
|
||||||
|
<div className="track-group">
|
||||||
|
{tracksRaw.map((track, i) => {
|
||||||
|
const pos = Number(track.position ?? (i + 1));
|
||||||
|
const label = String(track.title || track.name || `Track ${pos}`).trim();
|
||||||
|
const artist = String(track.artist || '').trim();
|
||||||
|
const durationSec = Number(track.durationMs || 0) > 0
|
||||||
|
? Number(track.durationMs) / 1000
|
||||||
|
: Number(track.durationSec || 0);
|
||||||
|
const durLabel = durationSec > 0
|
||||||
|
? `${Math.floor(durationSec / 60)}:${String(Math.floor(durationSec % 60)).padStart(2, '0')} min`
|
||||||
|
: '-';
|
||||||
|
const selected = selectedSet ? selectedSet.has(pos) : track.selected !== false;
|
||||||
|
const ripDone = job?.ripSuccessful != null;
|
||||||
|
const encodeLabel = !selected ? 'Nicht übernommen'
|
||||||
|
: ripDone ? (job.ripSuccessful ? 'Erfolgreich' : 'Fehler')
|
||||||
|
: 'Übernommen';
|
||||||
|
const encodeClass = !selected ? '' : ripDone ? (job.ripSuccessful ? 'tone-ok' : 'tone-no') : '';
|
||||||
|
return (
|
||||||
|
<div key={pos} className="track-item">
|
||||||
|
<span>#{pos} | {label}{artist ? ` | ${artist}` : ''} | {durLabel}</span>
|
||||||
|
<small className={`track-action-note ${encodeClass}`}>Encode: {encodeLabel}</small>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})() : (() => {
|
||||||
|
const chapters = Array.isArray(job.handbrakeInfo?.metadata?.chapters) && job.handbrakeInfo.metadata.chapters.length > 0
|
||||||
|
? job.handbrakeInfo.metadata.chapters
|
||||||
|
: (Array.isArray(job.makemkvInfo?.chapters) && job.makemkvInfo.chapters.length > 0
|
||||||
|
? job.makemkvInfo.chapters
|
||||||
|
: (Array.isArray(job.encodePlan?.metadata?.chapters) ? job.encodePlan.metadata.chapters : []));
|
||||||
|
const stepsByIndex = new Map(
|
||||||
|
(Array.isArray(job.handbrakeInfo?.steps) ? job.handbrakeInfo.steps : [])
|
||||||
|
.map((s) => [Number(s.chapterIndex), s])
|
||||||
|
);
|
||||||
|
if (chapters.length === 0) return <p className="job-meta-subtle">Keine Kapitelinformationen vorhanden.</p>;
|
||||||
|
return (
|
||||||
|
<div className="track-group">
|
||||||
|
{chapters.map((chapter, i) => {
|
||||||
|
const id = Number(chapter.id ?? chapter.index ?? chapter.position ?? (i + 1));
|
||||||
|
const label = String(chapter.title || chapter.name || `Kapitel ${id}`).trim();
|
||||||
|
const durationSec = Number(chapter.durationMs || 0) > 0
|
||||||
|
? Number(chapter.durationMs) / 1000
|
||||||
|
: Number(chapter.durationSec || 0);
|
||||||
|
const durLabel = durationSec > 0
|
||||||
|
? `${Math.floor(durationSec / 60)}:${String(Math.floor(durationSec % 60)).padStart(2, '0')} min`
|
||||||
|
: '-';
|
||||||
|
const step = stepsByIndex.get(id);
|
||||||
|
const stepStatus = step ? String(step.status || '').toUpperCase() : null;
|
||||||
|
const encodeLabel = stepStatus === 'SUCCESS' ? 'Erfolgreich'
|
||||||
|
: stepStatus === 'ERROR' ? 'Fehler'
|
||||||
|
: stepStatus === 'CANCELLED' ? 'Abgebrochen'
|
||||||
|
: stepStatus ? stepStatus
|
||||||
|
: 'Übernommen';
|
||||||
|
const encodeClass = stepStatus === 'SUCCESS' ? 'tone-ok'
|
||||||
|
: stepStatus === 'ERROR' ? 'tone-no'
|
||||||
|
: '';
|
||||||
|
return (
|
||||||
|
<div key={id} className="track-item">
|
||||||
|
<span>#{id} | {label} | {durLabel}</span>
|
||||||
|
<small className={`track-action-note ${encodeClass}`}>Encode: {encodeLabel}</small>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</section>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<section className="job-meta-block job-meta-block-full">
|
<section className="job-meta-block job-meta-block-full">
|
||||||
<h4>Rohdaten</h4>
|
<h4>Logs</h4>
|
||||||
<div className="job-json-grid">
|
<div className="job-json-grid">
|
||||||
{!isCd && !isAudiobook ? <JsonView title="OMDb Info" value={job.omdbInfo} /> : null}
|
{!isCd && !isAudiobook ? <JsonView title="OMDb Info" value={job.omdbInfo} /> : null}
|
||||||
|
{isCd ? <JsonView title="MusicBrainz" value={job.makemkvInfo?.selectedMetadata ?? null} /> : null}
|
||||||
|
{isAudiobook ? <JsonView title="Metadaten" value={job.handbrakeInfo?.metadata ?? job.makemkvInfo?.selectedMetadata ?? null} /> : null}
|
||||||
<JsonView title={isCd ? 'cdparanoia Info' : (isAudiobook ? 'Audiobook Info' : 'MakeMKV Info')} value={job.makemkvInfo} />
|
<JsonView title={isCd ? 'cdparanoia Info' : (isAudiobook ? 'Audiobook Info' : 'MakeMKV Info')} value={job.makemkvInfo} />
|
||||||
{!isCd && !isAudiobook ? <JsonView title="Mediainfo Info" value={job.mediainfoInfo} /> : null}
|
{!isCd && !isAudiobook ? <JsonView title="Mediainfo Info" value={job.mediainfoInfo} /> : null}
|
||||||
<JsonView title={isCd ? 'Rip-Plan' : 'Encode Plan'} value={job.encodePlan} />
|
<JsonView title={isCd ? 'Rip-Plan' : 'Encode Plan'} value={job.encodePlan} />
|
||||||
{!isCd ? <JsonView title={isAudiobook ? 'FFmpeg Info' : 'HandBrake Info'} value={job.handbrakeInfo} /> : null}
|
<JsonView title={isCd ? 'Rip-Info' : (isAudiobook ? 'FFmpeg Info' : 'HandBrake Info')} value={job.handbrakeInfo} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -867,9 +867,8 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
|||||||
const renderPoster = (row, className = 'history-dv-poster') => {
|
const renderPoster = (row, className = 'history-dv-poster') => {
|
||||||
const mediaMeta = resolveMediaTypeMeta(row);
|
const mediaMeta = resolveMediaTypeMeta(row);
|
||||||
const isAudioSquare = ['cd', 'audiobook'].includes(mediaMeta.mediaType);
|
const isAudioSquare = ['cd', 'audiobook'].includes(mediaMeta.mediaType);
|
||||||
const imgClass = className === 'history-dv-poster-grid' && isAudioSquare
|
const audioClass = className === 'history-dv-poster-grid' ? 'history-dv-poster-grid-audio' : 'history-dv-poster-audio';
|
||||||
? 'history-dv-poster-grid-audio'
|
const imgClass = isAudioSquare ? audioClass : className;
|
||||||
: className;
|
|
||||||
const title = row?.title || row?.detected_title || 'Poster';
|
const title = row?.title || row?.detected_title || 'Poster';
|
||||||
if (row?.poster_url && row.poster_url !== 'N/A') {
|
if (row?.poster_url && row.poster_url !== 'N/A') {
|
||||||
return <img src={row.poster_url} alt={title} className={imgClass} loading="lazy" />;
|
return <img src={row.poster_url} alt={title} className={imgClass} loading="lazy" />;
|
||||||
@@ -903,9 +902,6 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
|||||||
if (cdDetails.totalDurationLabel) {
|
if (cdDetails.totalDurationLabel) {
|
||||||
infoItems.push({ key: 'duration', label: 'Dauer', value: cdDetails.totalDurationLabel });
|
infoItems.push({ key: 'duration', label: 'Dauer', value: cdDetails.totalDurationLabel });
|
||||||
}
|
}
|
||||||
if (cdDetails.mbId) {
|
|
||||||
infoItems.push({ key: 'mb', label: 'MusicBrainz', value: 'gesetzt' });
|
|
||||||
}
|
|
||||||
if (infoItems.length === 0) {
|
if (infoItems.length === 0) {
|
||||||
return <span className="history-dv-subtle">Keine CD-Details</span>;
|
return <span className="history-dv-subtle">Keine CD-Details</span>;
|
||||||
}
|
}
|
||||||
@@ -1013,35 +1009,15 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-flags-row">
|
<div className="history-dv-flags-row">
|
||||||
{isCdJob ? (
|
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||||
<>
|
{renderPresenceChip(isCdJob || mediaMeta.mediaType === 'audiobook' ? 'Audio' : 'Movie', Boolean(row?.outputStatus?.exists))}
|
||||||
{renderPresenceChip('Audio', Boolean(row?.outputStatus?.exists))}
|
{renderPresenceChip('Encode', isCdJob || mediaMeta.mediaType === 'audiobook' ? Boolean(row?.ripSuccessful) : Boolean(row?.encodeSuccess))}
|
||||||
{renderPresenceChip('Rip', Boolean(row?.ripSuccessful))}
|
|
||||||
{renderPresenceChip('Metadaten', Boolean(cdDetails?.artist || cdDetails?.mbId))}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
|
||||||
{renderPresenceChip('Movie', Boolean(row?.outputStatus?.exists))}
|
|
||||||
{renderPresenceChip('Encode', Boolean(row?.encodeSuccess))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-actions">
|
|
||||||
<Button
|
|
||||||
label="Details"
|
|
||||||
icon="pi pi-search"
|
|
||||||
size="small"
|
|
||||||
onClick={(event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
void openDetail(row);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1096,35 +1072,13 @@ export default function HistoryPage({ refreshToken = 0 }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-flags-row">
|
<div className="history-dv-flags-row">
|
||||||
{isCdJob ? (
|
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
||||||
<>
|
{renderPresenceChip(isCdJob || mediaMeta.mediaType === 'audiobook' ? 'Audio' : 'Movie', Boolean(row?.outputStatus?.exists))}
|
||||||
{renderPresenceChip('Audio', Boolean(row?.outputStatus?.exists))}
|
{renderPresenceChip('Encode', isCdJob || mediaMeta.mediaType === 'audiobook' ? Boolean(row?.ripSuccessful) : Boolean(row?.encodeSuccess))}
|
||||||
{renderPresenceChip('Rip', Boolean(row?.ripSuccessful))}
|
|
||||||
{renderPresenceChip('Metadaten', Boolean(cdDetails?.artist || cdDetails?.mbId))}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{renderPresenceChip('RAW', Boolean(row?.rawStatus?.exists))}
|
|
||||||
{renderPresenceChip('Movie', Boolean(row?.outputStatus?.exists))}
|
|
||||||
{renderPresenceChip('Encode', Boolean(row?.encodeSuccess))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
<div className="history-dv-ratings-row">{renderSupplementalInfo(row)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="history-dv-actions history-dv-actions-grid">
|
|
||||||
<Button
|
|
||||||
label="Details"
|
|
||||||
icon="pi pi-search"
|
|
||||||
size="small"
|
|
||||||
onClick={(event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
void openDetail(row);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+69
-14
@@ -2334,6 +2334,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.history-dv-poster,
|
.history-dv-poster,
|
||||||
|
.history-dv-poster-audio,
|
||||||
.history-dv-poster-grid,
|
.history-dv-poster-grid,
|
||||||
.history-dv-poster-grid-audio {
|
.history-dv-poster-grid-audio {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -2348,9 +2349,13 @@ body {
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-dv-poster-audio {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
.history-dv-poster-grid {
|
.history-dv-poster-grid {
|
||||||
height: 164px;
|
height: 180px;
|
||||||
object-fit: contain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-dv-poster-grid-audio {
|
.history-dv-poster-grid-audio {
|
||||||
@@ -2360,7 +2365,7 @@ body {
|
|||||||
|
|
||||||
.history-dv-grid-poster-wrap {
|
.history-dv-grid-poster-wrap {
|
||||||
width: min(120px, 100%);
|
width: min(120px, 100%);
|
||||||
height: 164px;
|
height: 180px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -2517,6 +2522,7 @@ body {
|
|||||||
|
|
||||||
.job-film-info-grid {
|
.job-film-info-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
gap: 0.55rem;
|
gap: 0.55rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2572,16 +2578,18 @@ body {
|
|||||||
|
|
||||||
.job-path-field {
|
.job-path-field {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 0.2rem;
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.15rem 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-path-field-value {
|
.job-path-field-value {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: grid;
|
flex: 1 1 auto;
|
||||||
grid-template-columns: minmax(0, 1fr) auto;
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
align-items: start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-path-field-value > span {
|
.job-path-field-value > span {
|
||||||
@@ -2598,6 +2606,47 @@ body {
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.job-infos-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.75rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-badges {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.4rem;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-sep {
|
||||||
|
color: var(--rip-border);
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-layout {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.4rem;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-layout strong {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-infos-row-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-downloads-row {
|
.dashboard-downloads-row {
|
||||||
border-top: 1px solid var(--surface-border);
|
border-top: 1px solid var(--surface-border);
|
||||||
padding-top: 0.75rem;
|
padding-top: 0.75rem;
|
||||||
@@ -2762,7 +2811,7 @@ body {
|
|||||||
color: #f8e2b8;
|
color: #f8e2b8;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
max-height: 16rem;
|
height: 16rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-family: 'JetBrains Mono', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -2847,7 +2896,7 @@ body {
|
|||||||
color: #f6ddb2;
|
color: #f6ddb2;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
max-height: 25rem;
|
height: 25rem;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -3050,10 +3099,6 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.track-title-block {
|
.track-title-block {
|
||||||
border: 1px solid var(--rip-border);
|
|
||||||
border-radius: 0.45rem;
|
|
||||||
padding: 0.55rem 0.65rem;
|
|
||||||
background: var(--rip-panel-soft);
|
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -3077,6 +3122,16 @@ body {
|
|||||||
border: 1px solid var(--rip-success, #2d7a3a);
|
border: 1px solid var(--rip-success, #2d7a3a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.track-groups-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: start;
|
||||||
|
border-top: 1px solid var(--rip-border);
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.track-group {
|
.track-group {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.1.2"
|
"concurrently": "^9.1.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.10.2-24",
|
"version": "0.10.2-25",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
|
"dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
|
||||||
"dev:backend": "npm run dev --prefix backend",
|
"dev:backend": "npm run dev --prefix backend",
|
||||||
|
|||||||
Reference in New Issue
Block a user