Compare commits

...
8 changed files with 89 additions and 11 deletions

No files matched your search

+12 -2
View File
@@ -22,10 +22,20 @@ export const downloadsRouter = createTRPCRouter({
},
})
.concat(createDownloadClientIntegrationMiddleware("query"))
.input(z.object({ limitPerIntegration: z.number().default(50) }))
.input(
z.object({
limitPerIntegration: z.number().default(50),
qbittorrentSort: z.string().optional(),
qbittorrentSortReverse: z.boolean().optional(),
}),
)
.query(async ({ ctx, input }) => {
return await settleIntegrationQueries(ctx.integrations, async (integration) => {
const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const innerHandler = downloadClientRequestHandler.handler(integration, {
limit: input.limitPerIntegration,
qbittorrentSort: input.qbittorrentSort,
qbittorrentSortReverse: input.qbittorrentSortReverse,
});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
@@ -27,10 +27,18 @@ export class QBitTorrentIntegration extends Integration implements IDownloadClie
};
}
public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
public async getClientJobsAndStatusAsync(input: {
limit: number;
qbittorrentSort?: string;
qbittorrentSortReverse?: boolean;
}): Promise<DownloadClientJobsAndStatus> {
const type = "torrent";
const client = await this.getClientAsync();
const torrents = await client.listTorrents({ limit: input.limit, sort: "progress", reverse: false });
const torrents = await client.listTorrents({
limit: input.limit,
sort: input.qbittorrentSort,
reverse: input.qbittorrentSortReverse,
});
const rates = torrents.reduce(
({ down, up }, { dlspeed, upspeed }) => ({ down: down + dlspeed, up: up + upspeed }),
{ down: 0, up: 0 },
@@ -3,7 +3,11 @@ import type { DownloadClientItem } from "./download-client-items";
export interface IDownloadClientIntegration {
/** Get download client's status and list of all of it's items */
getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus>;
getClientJobsAndStatusAsync(input: {
limit: number;
qbittorrentSort?: string;
qbittorrentSortReverse?: boolean;
}): Promise<DownloadClientJobsAndStatus>;
/** Pauses the client or all of it's items */
pauseQueueAsync(): Promise<void>;
/** Pause a single item using it's ID */
+1 -1
View File
@@ -7,7 +7,7 @@ import { createIntegrationRequestHandler } from "./lib/integration-request-handl
export const downloadClientRequestHandler = createIntegrationRequestHandler<
DownloadClientJobsAndStatus,
IntegrationKindByCategory<"downloadClient">,
{ limit: number }
{ limit: number; qbittorrentSort?: string; qbittorrentSortReverse?: boolean }
>({
async requestAsync(integration, input) {
const integrationInstance = await createIntegrationAsync(integration);
+22 -2
View File
@@ -3064,8 +3064,28 @@
"limitPerIntegration": {
"label": "Limit items per integration",
"description": "This will limit the number of items shown per integration, not globally"
}
},
},
"qbittorrentSort": {
"label": "qBittorrent sort order",
"option": {
"added_on": "Date Added",
"completion_on": "Completion Date",
"dlspeed": "Download Speed",
"eta": "ETA",
"name": "Name",
"priority": "Priority",
"progress": "Progress",
"ratio": "Ratio",
"size": "Size",
"state": "State",
"time_active": "Time Active",
"upspeed": "Upload Speed",
"uploaded": "Uploaded"
}
},
"qbittorrentSortReverse": {
"label": "Reverse qBittorrent sort order"
},
"errors": {
"noColumns": "Select Columns in Items",
"noCommunications": "Can't load data from integration"
@@ -91,6 +91,8 @@ export default function DownloadClientsWidget({
const { data: currentItems = [] } = clientApi.widget.downloads.getJobsAndStatuses.useQuery({
integrationIds,
limitPerIntegration: options.limitPerIntegration,
qbittorrentSort: options.qbittorrentSort,
qbittorrentSortReverse: options.qbittorrentSortReverse,
});
const t = useScopedI18n("widget.downloads");
+32
View File
@@ -88,6 +88,30 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
validate: z.number().min(1),
withDescription: true,
}),
qbittorrentSort: factory.select({
defaultValue: "added_on",
options: [
"added_on",
"completion_on",
"dlspeed",
"eta",
"name",
"priority",
"progress",
"ratio",
"size",
"state",
"time_active",
"upspeed",
"uploaded",
].map((value) => ({
value,
label: (t) => t(`widget.downloads.option.qbittorrentSort.option.${value}`),
})),
}),
qbittorrentSortReverse: factory.switch({
defaultValue: false,
}),
}),
{
defaultSort: {
@@ -116,6 +140,14 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
shouldHide: (_, integrationKinds) =>
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
},
qbittorrentSort: {
shouldHide: (_, integrationKinds) =>
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
},
qbittorrentSortReverse: {
shouldHide: (_, integrationKinds) =>
!getIntegrationKindsByCategory("torrent").some((kinds) => integrationKinds.includes(kinds)),
},
},
);
},
@@ -75,7 +75,9 @@ export default function MediaServerWidget({ options, integrationIds }: WidgetCom
? Math.min(100, Math.round((positionMs / durationMs) * 100))
: null;
const remainingMinutes =
positionMs !== null && durationMs !== null ? Math.max(0, Math.round((durationMs - positionMs) / 60_000)) : null;
positionMs !== null && durationMs !== null
? Math.max(0, Math.round((durationMs - positionMs) / 60_000))
: null;
return (
<Stack gap={4} style={{ minWidth: 0 }}>
@@ -122,8 +124,8 @@ export default function MediaServerWidget({ options, integrationIds }: WidgetCom
const isTranscoding = Boolean(
currentlyPlaying.metadata?.transcoding.target.videoCodec ??
currentlyPlaying.metadata?.transcoding.target.audioCodec ??
currentlyPlaying.metadata?.transcoding.container,
currentlyPlaying.metadata?.transcoding.target.audioCodec ??
currentlyPlaying.metadata?.transcoding.container,
);
return (