File storage rewrite (#2676)

* Restructure data layer part 2 (#2599)
* Refactor and separate image model
* Refactor image query builder
* Handle relationships in image query builder
* Remove relationship management methods
* Refactor gallery model/query builder
* Add scenes to gallery model
* Convert scene model
* Refactor scene models
* Remove unused methods
* Add unit tests for gallery
* Add image tests
* Add scene tests
* Convert unnecessary scene value pointers to values
* Convert unnecessary pointer values to values
* Refactor scene partial
* Add scene partial tests
* Refactor ImagePartial
* Add image partial tests
* Refactor gallery partial update
* Add partial gallery update tests
* Use zero/null package for null values
* Add files and scan system
* Add sqlite implementation for files/folders
* Add unit tests for files/folders
* Image refactors
* Update image data layer
* Refactor gallery model and creation
* Refactor scene model
* Refactor scenes
* Don't set title from filename
* Allow galleries to freely add/remove images
* Add multiple scene file support to graphql and UI
* Add multiple file support for images in graphql/UI
* Add multiple file for galleries in graphql/UI
* Remove use of some deprecated fields
* Remove scene path usage
* Remove gallery path usage
* Remove path from image
* Move funscript to video file
* Refactor caption detection
* Migrate existing data
* Add post commit/rollback hook system
* Lint. Comment out import/export tests
* Add WithDatabase read only wrapper
* Prepend tasks to list
* Add 32 pre-migration
* Add warnings in release and migration notes
This commit is contained in:
WithoutPants
2022-07-13 16:30:54 +10:00
parent 30877c75fb
commit 5495d72849
359 changed files with 43690 additions and 16000 deletions

View File

@@ -134,10 +134,8 @@ export const SceneDuplicateChecker: React.FC = () => {
setEditingScenes(true);
}
const renderFilesize = (filesize: string | null | undefined) => {
const { size: parsedSize, unit } = TextUtils.fileSize(
Number.parseInt(filesize ?? "0", 10)
);
const renderFilesize = (filesize: number | null | undefined) => {
const { size: parsedSize, unit } = TextUtils.fileSize(filesize ?? 0);
return (
<FormattedNumber
value={parsedSize}
@@ -477,78 +475,84 @@ export const SceneDuplicateChecker: React.FC = () => {
</thead>
<tbody>
{filteredScenes.map((group, groupIndex) =>
group.map((scene, i) => (
<>
{i === 0 && groupIndex !== 0 ? (
<tr className="separator" />
) : undefined}
<tr
className={i === 0 ? "duplicate-group" : ""}
key={scene.id}
>
<td>
<Form.Check
onChange={(e) =>
handleCheck(e.currentTarget.checked, scene.id)
}
/>
</td>
<td>
<HoverPopover
content={
group.map((scene, i) => {
const file =
scene.files.length > 0 ? scene.files[0] : undefined;
return (
<>
{i === 0 && groupIndex !== 0 ? (
<tr className="separator" />
) : undefined}
<tr
className={i === 0 ? "duplicate-group" : ""}
key={scene.id}
>
<td>
<Form.Check
onChange={(e) =>
handleCheck(e.currentTarget.checked, scene.id)
}
/>
</td>
<td>
<HoverPopover
content={
<img
src={scene.paths.sprite ?? ""}
alt=""
width={600}
/>
}
placement="right"
>
<img
src={scene.paths.sprite ?? ""}
alt=""
width={600}
width={100}
/>
}
placement="right"
>
<img
src={scene.paths.sprite ?? ""}
alt=""
width={100}
</HoverPopover>
</td>
<td className="text-left">
<p>
<Link to={`/scenes/${scene.id}`}>
{scene.title
? scene.title
: TextUtils.fileNameFromPath(file?.path ?? "")}
</Link>
</p>
<p className="scene-path">{file?.path ?? ""}</p>
</td>
<td className="scene-details">
{maybeRenderPopoverButtonGroup(scene)}
</td>
<td>
{file?.duration &&
TextUtils.secondsToTimestamp(file.duration)}
</td>
<td>{renderFilesize(file?.size ?? 0)}</td>
<td>{`${file?.width ?? 0}x${file?.height ?? 0}`}</td>
<td>
<FormattedNumber
value={(file?.bit_rate ?? 0) / 1000000}
maximumFractionDigits={2}
/>
</HoverPopover>
</td>
<td className="text-left">
<p>
<Link to={`/scenes/${scene.id}`}>
{scene.title ??
TextUtils.fileNameFromPath(scene.path)}
</Link>
</p>
<p className="scene-path">{scene.path}</p>
</td>
<td className="scene-details">
{maybeRenderPopoverButtonGroup(scene)}
</td>
<td>
{scene.file.duration &&
TextUtils.secondsToTimestamp(scene.file.duration)}
</td>
<td>{renderFilesize(scene.file.size)}</td>
<td>{`${scene.file.width}x${scene.file.height}`}</td>
<td>
<FormattedNumber
value={(scene.file.bitrate ?? 0) / 1000000}
maximumFractionDigits={2}
/>
&nbsp;mbps
</td>
<td>{scene.file.video_codec}</td>
<td>
<Button
className="edit-button"
variant="danger"
onClick={() => handleDeleteScene(scene)}
>
<FormattedMessage id="actions.delete" />
</Button>
</td>
</tr>
</>
))
&nbsp;mbps
</td>
<td>{file?.video_codec ?? ""}</td>
<td>
<Button
className="edit-button"
variant="danger"
onClick={() => handleDeleteScene(scene)}
>
<FormattedMessage id="actions.delete" />
</Button>
</td>
</tr>
</>
);
})
)}
</tbody>
</Table>