diff --git a/package.json b/package.json index 0d7a518..9184e7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ui", - "version": "6.4.150", + "version": "6.4.151", "license": "BUSL-1.1", "private": true, "packageManager": "pnpm@9.15.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0e21ccf..a5067b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,7 +185,7 @@ importers: version: 1.8.13(@gql.tada/svelte-support@1.0.1(svelte@4.2.19)(typescript@5.9.2))(graphql@16.10.0)(typescript@5.9.2) hayase-extensions: specifier: github:hayase-app/extensions - version: https://codeload.github.com/hayase-app/extensions/tar.gz/0fad214a4a0aacd826c0801255ced65bd1d49a13 + version: https://codeload.github.com/hayase-app/extensions/tar.gz/2c43ec0bf157733901be1ad9188b64933aac2e15 jassub: specifier: ^1.8.6 version: 1.8.6 @@ -197,7 +197,7 @@ importers: version: 2.1.3 native: specifier: github:hayase-app/native - version: https://codeload.github.com/hayase-app/native/tar.gz/b77747898ca7e4991fac752559ea159c8c0f5083 + version: https://codeload.github.com/hayase-app/native/tar.gz/e8045ec8878086117a9c3b52dcff069f4b9b48e8 rollup-plugin-license: specifier: ^3.6.0 version: 3.6.0(picomatch@4.0.3)(rollup@4.40.2) @@ -1711,8 +1711,8 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/0fad214a4a0aacd826c0801255ced65bd1d49a13: - resolution: {tarball: https://codeload.github.com/hayase-app/extensions/tar.gz/0fad214a4a0aacd826c0801255ced65bd1d49a13} + hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/2c43ec0bf157733901be1ad9188b64933aac2e15: + resolution: {tarball: https://codeload.github.com/hayase-app/extensions/tar.gz/2c43ec0bf157733901be1ad9188b64933aac2e15} version: 1.0.6 idb-keyval@6.2.2: @@ -2051,8 +2051,8 @@ packages: engines: {node: ^18 || >=20} hasBin: true - native@https://codeload.github.com/hayase-app/native/tar.gz/b77747898ca7e4991fac752559ea159c8c0f5083: - resolution: {tarball: https://codeload.github.com/hayase-app/native/tar.gz/b77747898ca7e4991fac752559ea159c8c0f5083} + native@https://codeload.github.com/hayase-app/native/tar.gz/e8045ec8878086117a9c3b52dcff069f4b9b48e8: + resolution: {tarball: https://codeload.github.com/hayase-app/native/tar.gz/e8045ec8878086117a9c3b52dcff069f4b9b48e8} version: 1.0.0 natural-compare@1.4.0: @@ -4560,7 +4560,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/0fad214a4a0aacd826c0801255ced65bd1d49a13: {} + hayase-extensions@https://codeload.github.com/hayase-app/extensions/tar.gz/2c43ec0bf157733901be1ad9188b64933aac2e15: {} idb-keyval@6.2.2: {} @@ -4865,7 +4865,7 @@ snapshots: nanoid@5.1.5: {} - native@https://codeload.github.com/hayase-app/native/tar.gz/b77747898ca7e4991fac752559ea159c8c0f5083: {} + native@https://codeload.github.com/hayase-app/native/tar.gz/e8045ec8878086117a9c3b52dcff069f4b9b48e8: {} natural-compare@1.4.0: {} diff --git a/src/app.html b/src/app.html index 1533c15..89ff183 100644 --- a/src/app.html +++ b/src/app.html @@ -4,6 +4,8 @@ Hayase + + %sveltekit.head% diff --git a/src/lib/components/ui/torrentclient/peers/cells/country.svelte b/src/lib/components/ui/torrentclient/peers/cells/country.svelte index bb48633..04f7784 100644 --- a/src/lib/components/ui/torrentclient/peers/cells/country.svelte +++ b/src/lib/components/ui/torrentclient/peers/cells/country.svelte @@ -13,5 +13,6 @@
{location.country}
+ {:catch} {/await} diff --git a/src/lib/modules/extensions/extensions.ts b/src/lib/modules/extensions/extensions.ts index 2126c8d..8d1e8de 100644 --- a/src/lib/modules/extensions/extensions.ts +++ b/src/lib/modules/extensions/extensions.ts @@ -1,6 +1,7 @@ import anitomyscript, { type AnitomyResult } from 'anitomyscript' import Debug from 'debug' import { get } from 'svelte/store' +import { toast } from 'svelte-sonner' import { dedupeAiring, episodes, isMovie, type Media, getParentForSpecial, isSingleEpisode } from '../anilist' import { episodes as _episodes } from '../anizip' @@ -203,13 +204,14 @@ export const extensions = new class Extensions { debug(`Checking ${Object.keys(workers).length} extensions for ${media.id}:${media.title?.userPreferred} ${episode} ${resolution} ${checkMovie ? 'movie' : ''} ${checkBatch ? 'batch' : ''}`) for (const [id, worker] of Object.entries(workers)) { - if (!extopts[id]!.enabled) continue + const thisExtOpts = extopts[id]! + if (!thisExtOpts.enabled) continue if (configs[id]!.type !== 'torrent') continue try { const promises: Array> = [] - promises.push(worker.single(options)) - if (checkMovie) promises.push(worker.movie(options)) - if (checkBatch) promises.push(worker.batch(options)) + promises.push(worker.single(options, thisExtOpts.options)) + if (checkMovie) promises.push(worker.movie(options, thisExtOpts.options)) + if (checkBatch) promises.push(worker.batch(options, thisExtOpts.options)) for (const result of await Promise.allSettled(promises)) { if (result.status === 'fulfilled') { @@ -246,6 +248,37 @@ export const extensions = new class Extensions { return { results: navigator.onLine ? await this.updatePeerCounts(deduped) : deduped, errors } } + async getNZBResultsFromExtensions (hash: string) { + await storage.modules + const workers = storage.workers + const results: Array<{ nzb: string, options: Record }> = [] + const errors: Array<{ error: Error, extension: string }> = [] + + const extopts = get(extensionOptions) + const configs = get(saved) + + for (const [id, worker] of Object.entries(workers)) { + const thisExtOpts = extopts[id]! + if (!thisExtOpts.enabled) continue + if (configs[id]!.type !== 'nzb') continue + try { + const nzb = await worker.query(hash, thisExtOpts.options) + if (!nzb) continue + results.push({ nzb, options: thisExtOpts.options }) + } catch (error) { + errors.push({ error: error as Error, extension: id }) + } + } + + if (errors.length) { + for (const { error, extension } of errors) { + toast.error(`Error fetching NZB from ${configs[extension]?.name ?? extension}`, { description: error.message }) + } + } + + return results + } + async updatePeerCounts (entries: T): Promise { debug(`Updating peer counts for ${entries.length} entries`) diff --git a/src/lib/modules/extensions/worker.ts b/src/lib/modules/extensions/worker.ts index 6fbaa19..c261f5a 100644 --- a/src/lib/modules/extensions/worker.ts +++ b/src/lib/modules/extensions/worker.ts @@ -1,15 +1,15 @@ import { finalizer } from 'abslink' import { expose } from 'abslink/w3c' -import type { SearchFunction, TorrentSource } from 'hayase-extensions' +import type { SearchFunction, TorrentSource, NZBorURLSource } from 'hayase-extensions' export default expose({ - mod: null as unknown as Promise, + mod: null as unknown as Promise, construct (code: string) { this.mod = this.load(code) }, - async load (code: string): Promise { + async load (code: string): Promise { // WARN: unsafe eval const url = URL.createObjectURL(new Blob([code], { type: 'application/javascript' })) const module = await import(/* @vite-ignore */url) @@ -22,15 +22,19 @@ export default expose({ }, async single (...args: Parameters): ReturnType { - return await ((await this.mod)).single(...args) + return await ((await this.mod) as TorrentSource).single(...args) }, async batch (...args: Parameters): ReturnType { - return await ((await this.mod)).batch(...args) + return await ((await this.mod) as TorrentSource).batch(...args) }, async movie (...args: Parameters): ReturnType { - return await ((await this.mod)).movie(...args) + return await ((await this.mod) as TorrentSource).movie(...args) + }, + + async query (...args: Parameters) { + return await ((await this.mod) as NZBorURLSource).query(...args) }, async test () { diff --git a/src/lib/modules/native.ts b/src/lib/modules/native.ts index b691237..aebc9e6 100644 --- a/src/lib/modules/native.ts +++ b/src/lib/modules/native.ts @@ -138,6 +138,7 @@ export default Object.assign>({ navigate: async () => undefined, downloadProgress: async () => undefined, updateProgress: async () => undefined, + createNZB: async () => undefined, torrentInfo: async (): Promise => ({ name: '', progress: 0, diff --git a/src/lib/modules/torrent/client.ts b/src/lib/modules/torrent/client.ts index 2e9d3d9..7f19fb0 100644 --- a/src/lib/modules/torrent/client.ts +++ b/src/lib/modules/torrent/client.ts @@ -2,8 +2,10 @@ import Debug from 'debug' import { writable } from 'simple-store-svelte' import { get } from 'svelte/store' import { persisted } from 'svelte-persisted-store' +import { toast } from 'svelte-sonner' import client from '../auth/client' +import { extensions } from '../extensions' import native from '../native' import { SUPPORTS } from '../settings' import { w2globby } from '../w2g/lobby' @@ -97,8 +99,21 @@ export const server = new class ServerClient { const result = { id, media, episode, files: await native.playTorrent(id, media.id, episode) } debug('torrent play result', result) this.downloaded.value = this.cachedSet() + this._addNZBs(result.files[0]!.hash) return result } + + async _addNZBs (hash: string) { + const nzbs = await extensions.getNZBResultsFromExtensions(hash) + + for (const { nzb, options } of nzbs) { + try { + await native.createNZB(hash, nzb, options.domain!, Number(options.port!), options.username!, options.password!, Number(options.poolSize!)) + } catch (e) { + toast.error('Failed to add NZB', { description: (e as Error).message }) + } + } + } }() requestIdleCallback(() => {