Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
064d1842de | ||
|
|
9ced0ab7d0 | ||
|
|
2000e1fff3 |
No files matched your search
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in new issue
Block a user