UI link to video files

This commit is contained in:
Igor Katson 2024-04-24 22:55:56 +01:00
parent f0788f2c4a
commit 94589a21fe
11 changed files with 64 additions and 19 deletions

View file

@ -1,4 +1,4 @@
import { useMemo, useState } from "react";
import { useContext, useMemo, useState } from "react";
import { TorrentDetails, TorrentStats } from "../api-types";
import { FormCheckbox } from "./forms/FormCheckbox";
import { CiSquarePlus, CiSquareMinus } from "react-icons/ci";
@ -6,6 +6,7 @@ import { IconButton } from "./buttons/IconButton";
import { formatBytes } from "../helper/formatBytes";
import { ProgressBar } from "./ProgressBar";
import sortBy from "lodash.sortby";
import { APIContext } from "../context";
type TorrentFileForCheckbox = {
id: number;
@ -86,6 +87,7 @@ const newFileTree = (
};
const FileTreeComponent: React.FC<{
torrentId?: number;
tree: FileTree;
torrentDetails: TorrentDetails;
torrentStats: TorrentStats | null;
@ -94,7 +96,9 @@ const FileTreeComponent: React.FC<{
initialExpanded: boolean;
showProgressBar?: boolean;
disabled?: boolean;
allowStream?: boolean;
}> = ({
torrentId,
tree,
selectedFiles,
setSelectedFiles,
@ -103,7 +107,9 @@ const FileTreeComponent: React.FC<{
torrentStats,
showProgressBar,
disabled,
allowStream,
}) => {
const API = useContext(APIContext);
let [expanded, setExpanded] = useState(initialExpanded);
let children = useMemo(() => {
let getAllChildren = (tree: FileTree): number[] => {
@ -149,6 +155,16 @@ const FileTreeComponent: React.FC<{
.reduce((a, b) => a + b, 0);
};
const fileLink = (file: TorrentFileForCheckbox) => {
if (
allowStream &&
torrentId != null &&
/\.(mp4|mkv|avi)$/.test(file.filename)
) {
return API.getTorrentStreamUrl(torrentId, file.id);
}
};
return (
<>
<div className="flex items-center">
@ -170,6 +186,7 @@ const FileTreeComponent: React.FC<{
<div className="pl-5" hidden={!expanded}>
{tree.dirs.map((dir) => (
<FileTreeComponent
torrentId={torrentId}
torrentDetails={torrentDetails}
torrentStats={torrentStats}
key={dir.name}
@ -179,6 +196,7 @@ const FileTreeComponent: React.FC<{
initialExpanded={false}
showProgressBar={showProgressBar}
disabled={disabled}
allowStream={allowStream}
/>
))}
<div className="pl-1">
@ -197,6 +215,7 @@ const FileTreeComponent: React.FC<{
name={`file-${file.id}`}
disabled={disabled}
onChange={() => handleToggleFile(file.id)}
labelLink={fileLink(file)}
></FormCheckbox>
{showProgressBar && (
<ProgressBar
@ -213,19 +232,23 @@ const FileTreeComponent: React.FC<{
};
export const FileListInput: React.FC<{
torrentId?: number;
torrentDetails: TorrentDetails;
torrentStats: TorrentStats | null;
selectedFiles: Set<number>;
setSelectedFiles: (_: Set<number>) => void;
showProgressBar?: boolean;
disabled?: boolean;
allowStream?: boolean;
}> = ({
torrentId,
torrentDetails,
selectedFiles,
setSelectedFiles,
torrentStats,
showProgressBar,
disabled,
allowStream,
}) => {
let fileTree = useMemo(
() => newFileTree(torrentDetails, torrentStats),
@ -234,6 +257,7 @@ export const FileListInput: React.FC<{
return (
<FileTreeComponent
torrentId={torrentId}
torrentDetails={torrentDetails}
torrentStats={torrentStats}
tree={fileTree}
@ -242,6 +266,7 @@ export const FileListInput: React.FC<{
initialExpanded={true}
showProgressBar={showProgressBar}
disabled={disabled}
allowStream={allowStream}
/>
);
};

View file

@ -170,11 +170,13 @@ export const TorrentRow: React.FC<{
{detailsResponse && extendedView && (
<div className="">
<FileListInput
torrentId={id}
torrentDetails={detailsResponse}
torrentStats={statsResponse}
selectedFiles={selectedFiles}
setSelectedFiles={updateSelectedFiles}
disabled={savingSelectedFiles}
allowStream
showProgressBar
/>
</div>

View file

@ -10,6 +10,7 @@ export const FormCheckbox: React.FC<{
onChange?: ChangeEventHandler<HTMLInputElement>;
children?: React.ReactNode;
classNames?: string;
labelLink?: string | null;
}> = ({
checked,
name,
@ -19,6 +20,7 @@ export const FormCheckbox: React.FC<{
help,
inputType,
children,
labelLink,
}) => {
return (
<div className={`flex gap-3 items-start`}>
@ -34,7 +36,17 @@ export const FormCheckbox: React.FC<{
/>
</div>
<div className="text-sm flex flex-col gap-1">
<label htmlFor={name}>{label}</label>
{labelLink ? (
<a
href={labelLink}
className="text-blue-600 dark:text-blue-500 hover:underline"
>
{label}
</a>
) : (
<label htmlFor={name}>{label}</label>
)}
{help && (
<div className="text-xs text-slate-500 dark:text-slate-300 mb-3">
{help}