diff --git a/CHANGELOG.md b/CHANGELOG.md index 961039be..9de9b9b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,13 @@ All notable changes to this project will be documented in this file. ## v2.2.1 +- ⚡️ New getting started page - ⚡️ Auto Downloader: Added 'additional terms' filter option -- 🦺 Torrent streaming: Fixed auto-select regression -- 🦺 Fixed auto-scanning regression +- 🦺 Torrent streaming: Fixed auto-select runtime error +- 🦺 Fixed auto-scanning runtime error - 🦺 Fixed issue with inexistant log directory +- 🦺 Torrent streaming: Fixed runtime error caused by missing settings +- 🦺 Fixed scan summaries of unresolved files not showing up ## v2.2.0 diff --git a/codegen/generated/handlers.json b/codegen/generated/handlers.json index e555d758..edca609c 100644 --- a/codegen/generated/handlers.json +++ b/codegen/generated/handlers.json @@ -1365,6 +1365,15 @@ "required": true, "descriptions": [] }, + { + "name": "AdditionalTerms", + "jsonName": "additionalTerms", + "goType": "[]string", + "usedStructType": "", + "typescriptType": "Array\u003cstring\u003e", + "required": true, + "descriptions": [] + }, { "name": "ComparisonTitle", "jsonName": "comparisonTitle", @@ -6469,6 +6478,24 @@ "typescriptType": "boolean", "required": true, "descriptions": [] + }, + { + "name": "DebridProvider", + "jsonName": "debridProvider", + "goType": "string", + "usedStructType": "", + "typescriptType": "string", + "required": true, + "descriptions": [] + }, + { + "name": "DebridApiKey", + "jsonName": "debridApiKey", + "goType": "string", + "usedStructType": "", + "typescriptType": "string", + "required": true, + "descriptions": [] } ], "returns": "handlers.Status", diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 88eb2e24..8a6c5c85 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -3,7 +3,7 @@ package constants import "time" const ( - Version = "2.2.0" + Version = "2.2.1" VersionName = "Sangatsu" GcTime = time.Minute * 30 ConfigFileName = "config.toml" diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index d98e9db2..195e932f 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/goccy/go-json" "seanime/internal/database/models" + "seanime/internal/util" "time" ) @@ -72,6 +73,13 @@ func HandleLogin(c *RouteCtx) error { c.App.InitOrRefreshModules() + go func() { + defer util.HandlePanicThen(func() {}) + c.App.InitOrRefreshTorrentstreamSettings() + c.App.InitOrRefreshMediastreamSettings() + c.App.InitOrRefreshDebridSettings() + }() + // Return new status return c.RespondWithData(status) diff --git a/internal/handlers/settings.go b/internal/handlers/settings.go index 2ecf35f4..aa3249fd 100644 --- a/internal/handlers/settings.go +++ b/internal/handlers/settings.go @@ -49,6 +49,8 @@ func HandleGettingStarted(c *RouteCtx) error { Notifications models.NotificationSettings `json:"notifications"` EnableTranscode bool `json:"enableTranscode"` EnableTorrentStreaming bool `json:"enableTorrentStreaming"` + DebridProvider string `json:"debridProvider"` + DebridApiKey string `json:"debridApiKey"` } var b body @@ -93,6 +95,7 @@ func HandleGettingStarted(c *RouteCtx) error { prev, found := c.App.Database.GetTorrentstreamSettings() if found { prev.Enabled = true + //prev.IncludeInLibrary = true _, _ = c.App.Database.UpsertTorrentstreamSettings(prev) } }() @@ -109,6 +112,20 @@ func HandleGettingStarted(c *RouteCtx) error { }() } + if b.DebridProvider != "" && b.DebridProvider != "none" { + go func() { + defer util.HandlePanicThen(func() {}) + prev, found := c.App.Database.GetDebridSettings() + if found { + prev.Enabled = true + prev.Provider = b.DebridProvider + prev.ApiKey = b.DebridApiKey + //prev.IncludeDebridStreamInLibrary = true + _, _ = c.App.Database.UpsertDebridSettings(prev) + } + }() + } + c.App.WSEventManager.SendEvent("settings", settings) status := NewStatus(c) diff --git a/internal/library/autoscanner/autoscanner.go b/internal/library/autoscanner/autoscanner.go index 7f74f070..a1f7a4ea 100644 --- a/internal/library/autoscanner/autoscanner.go +++ b/internal/library/autoscanner/autoscanner.go @@ -245,11 +245,12 @@ func (as *AutoScanner) scan() { return } - // Save the scan summary - err = db_bridge.InsertScanSummary(as.db, scanSummaryLogger.GenerateSummary()) - if err != nil { - as.logger.Error().Err(err).Msg("failed to insert scan summary") - } + } + + // Save the scan summary + err = db_bridge.InsertScanSummary(as.db, scanSummaryLogger.GenerateSummary()) + if err != nil { + as.logger.Error().Err(err).Msg("failed to insert scan summary") } // Refresh the queue diff --git a/seanime-web/src/api/generated/endpoint.types.ts b/seanime-web/src/api/generated/endpoint.types.ts index 3b49f323..b95ca311 100644 --- a/seanime-web/src/api/generated/endpoint.types.ts +++ b/seanime-web/src/api/generated/endpoint.types.ts @@ -311,6 +311,7 @@ export type CreateAutoDownloaderRule_Variables = { mediaId: number releaseGroups: Array resolutions: Array + additionalTerms: Array comparisonTitle: string titleComparisonType: Anime_AutoDownloaderRuleTitleComparisonType episodeType: Anime_AutoDownloaderRuleEpisodeType @@ -1324,6 +1325,8 @@ export type GettingStarted_Variables = { notifications: Models_NotificationSettings enableTranscode: boolean enableTorrentStreaming: boolean + debridProvider: string + debridApiKey: string } /** diff --git a/seanime-web/src/app/(main)/_features/getting-started/getting-started-page.tsx b/seanime-web/src/app/(main)/_features/getting-started/getting-started-page.tsx index 057f2b65..29dda143 100644 --- a/seanime-web/src/app/(main)/_features/getting-started/getting-started-page.tsx +++ b/seanime-web/src/app/(main)/_features/getting-started/getting-started-page.tsx @@ -5,6 +5,8 @@ import { LoadingOverlayWithLogo } from "@/components/shared/loading-overlay-with import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion" import { AppLayoutStack } from "@/components/ui/app-layout" import { Card } from "@/components/ui/card" +import { CheckboxProps } from "@/components/ui/checkbox" +import { cn } from "@/components/ui/core/styling" import { Field, Form } from "@/components/ui/form" import { DEFAULT_DOH_PROVIDER, @@ -18,6 +20,7 @@ import { useRouter } from "next/navigation" import React from "react" import { FcClapperboard, FcFolder, FcVideoCall, FcVlc } from "react-icons/fc" import { HiPlay } from "react-icons/hi" +import { HiOutlineServerStack } from "react-icons/hi2" import { ImDownload } from "react-icons/im" import { RiFolderDownloadFill } from "react-icons/ri" @@ -54,7 +57,7 @@ export function GettingStartedPage({ status }: { status: Status }) {
logo
- +
@@ -133,6 +136,8 @@ export function GettingStartedPage({ status }: { status: Status }) { disableAutoDownloaderNotifications: false, disableAutoScannerNotifications: false, }, + debridProvider: data.debridProvider, + debridApiKey: data.debridApiKey, }) }} defaultValues={{ @@ -157,300 +162,367 @@ export function GettingStartedPage({ status }: { status: Status }) { enableAdultContent: true, enableTorrentStreaming: false, enableTranscode: false, + debridProvider: "none", + debridApiKey: "", }} - stackClass="space-y-4" + stackClass="space-y-8" > - } - shouldExist - /> - -
-

Desktop Media Player

- -

- Used to play media files and track your progress automatically. -

-
- - } - options={[ - { label: "MPV", value: "mpv" }, - { label: "VLC", value: "vlc" }, - { label: "MPC-HC", value: "mpc-hc" }, - ]} - /> - - - - -

MPV

-
- -
- -
-
-
- - -

VLC

-
- -

- Leave these fields if you don't want to use VLC. + {(f) => (<> + + +

+

Anime library

+
+ + } + shouldExist + required + help="Create an empty folder if you don't have one yet. You can add more folders later." + /> + + + + +
+

Desktop Media Player

+ +

+ Used to play media files on your host computer and track your progress automatically.

-
- - -
-
- - -
- + +
+ } + options={[ + { label: "MPV", value: "mpv" }, + { label: "VLC", value: "vlc" }, + { label: "MPC-HC", value: "mpc-hc" }, + ]} /> - - - - -

MPC-HC

-
- -

- Leave these fields if you don't want to use MPC-HC. + + + + +

MPV

+ + +
+ +
+
+
+ + +

VLC

+
+ +

+ Leave these fields if you don't want to use VLC. +

+
+ + +
+
+ + +
+ +
+
+ + +

MPC-HC

+
+ +

+ Leave these fields if you don't want to use MPC-HC. +

+
+ + +
+
+ +
+
+
+ +
+ + + + +
+

Torrent Provider Extension

+ +

+ Built-in torrent provider extension used by the search engine and Auto Downloader.

-
- - -
-
- -
- - - - -
-

Torrent Provider Extension

- -

- Built-in torrent provider extension used by the search engine and auto downloader. AnimeTosho is recommended for - more accurate results. -

-
- - } - options={[ - { label: "AnimeTosho (recommended)", value: TORRENT_PROVIDER.ANIMETOSHO }, - { label: "Nyaa", value: TORRENT_PROVIDER.NYAA }, - ]} - /> - -
-

Torrent Client

- -

- Torrent client used to download media. -

-
- - } - options={[ - { label: "qBittorrent", value: "qbittorrent" }, - { label: "Transmission", value: "transmission" }, - ]} - /> - - - - -

qBittorrent

-
- - + + + } + options={[ + { label: "AnimeTosho (recommended)", value: TORRENT_PROVIDER.ANIMETOSHO }, + { label: "Nyaa", value: TORRENT_PROVIDER.NYAA }, + ]} + /> + + + + +
+

Torrent Client

+ +

+ Torrent client used to download media. +

+
+ +
+ } + options={[ + { label: "qBittorrent", value: "qbittorrent" }, + { label: "Transmission", value: "transmission" }, + ]} /> -
- + + + + +

qBittorrent

+
+ + +
+ + + +
+ +
+
+ + +

Transmission

+
+ + +
+ + + +
+ +
+
+
+
+ + + +
+

Debrid Service

+ +

+ Debrid service used to download or stream anime. +

+
+ +
+ } + options={[ + { label: "None", value: "none" }, + { label: "TorBox", value: "torbox" }, + ]} + /> + + {f.watch("debridProvider") !== "none" && f.watch("debridProvider") !== "" && ( - -
- +
+ + +
+

Features

+ +

+ Select additional features you want to use. +

+
+ +
+ Manga} + help="Read and download manga chapters." + size="lg" + {...cardCheckboxStyles} /> - - - - -

Transmission

-
- - Media streaming / Transcoding} + help="Stream downloaded episodes to other devices using transcoding or direct play. FFmpeg is required." + size="lg" + {...cardCheckboxStyles} /> -
- - - -
- Torrent streaming} + help="Stream torrents directly to your media player without having to wait for the download to complete." + size="lg" + {...cardCheckboxStyles} + /> + + Online streaming} + help="Watch anime episodes from online sources." + size="lg" + {...cardCheckboxStyles} + /> + + Discord Rich Presence} + help="Show what you're watching/reading on Discord." + size="lg" + {...cardCheckboxStyles} /> -
-
- - -
-

More features

- -

- Select additional features you want to use. -

-
- - Manga} - help="Read and download manga chapters." - size="lg" - /> - - Media streaming / Transcoding} - help="Stream downloaded episodes to other devices using transcoding or direct play. FFmpeg is required." - size="lg" - /> - - - Torrent streaming} - help="Stream torrents directly to your media player without having to wait for the download to complete." - size="lg" - /> - - Online streaming} - help="Watch anime episodes from online sources." - size="lg" - /> - - Discord Rich Presence} - help="Show what you're watching/reading on Discord." - size="lg" - /> - - - NSFW} - help={
-

Show adult content in your library and search results.

-
} - size="lg" - /> - - - Continue + + + NSFW} + help={
+

Show adult content in your library and search results.

+
} + size="lg" + {...cardCheckboxStyles} + /> +
+
+ + + Continue + )}
@@ -459,3 +531,28 @@ export function GettingStartedPage({ status }: { status: Status }) {
) } + +const cardCheckboxStyles: CheckboxProps = { + labelClass: cn( + "block cursor-pointer transition overflow-hidden w-full py-1 px-2 rounded-md", + "bg-gray-50 hover:bg-[--subtle] dark:bg-gray-950 border-dashed", + "data-[checked=false]:text-[--muted] hover:data-[checked=false]:opacity-50", + "data-[checked=true]:bg-white dark:data-[checked=true]:bg-gray-950", + "focus:ring-2 ring-brand-100 dark:ring-brand-900 ring-offset-1 ring-offset-[--background] focus-within:ring-2 transition", + "data-[checked=true]:ring-offset-0", + "data-[checked=true]:text-[--brand]", + ), + containerClass: "flex items-center justify-between", + className: cn( + "absolute top-0 right-0 z-10 rounded-tl-none rounded-br-none", + ), + fieldClass: "border p-2 rounded-md relative", + fieldHelpTextClass: "text-pretty", + // labelClass: cn( + // "border-transparent border data-[checked=true]:border-brand dark:bg-transparent dark:data-[state=unchecked]:bg-transparent", + // "data-[state=unchecked]:bg-transparent data-[state=unchecked]:hover:bg-transparent dark:data-[state=unchecked]:hover:bg-transparent", + // "focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:ring-offset-transparent", + // ), + // itemLabelClass: "font-medium flex flex-col items-center data-[state=checked]:text-[--brand] cursor-pointer", + // stackClass: "flex md:flex-row flex-col space-y-0 gap-4", +} diff --git a/seanime-web/src/app/(main)/scan-summaries/page.tsx b/seanime-web/src/app/(main)/scan-summaries/page.tsx index c2a742fa..695b7896 100644 --- a/seanime-web/src/app/(main)/scan-summaries/page.tsx +++ b/seanime-web/src/app/(main)/scan-summaries/page.tsx @@ -33,7 +33,7 @@ export default function Page() { const selectedSummary = React.useMemo(() => { const summary = data?.find(summary => summary.scanSummary?.id === selectedSummaryId) - if (!summary || !summary?.createdAt || !summary?.scanSummary?.id || !summary.scanSummary?.groups?.length) return undefined + if (!summary || !summary?.createdAt || !summary?.scanSummary?.id) return undefined return { createdAt: summary?.createdAt, ...summary.scanSummary, diff --git a/seanime-web/src/lib/server/settings.ts b/seanime-web/src/lib/server/settings.ts index 0a759602..4a1ae7e6 100644 --- a/seanime-web/src/lib/server/settings.ts +++ b/seanime-web/src/lib/server/settings.ts @@ -17,6 +17,8 @@ export const enum TORRENT_PROVIDER { export const _gettingStartedSchema = z.object({ enableTranscode: z.boolean().optional().default(false), enableTorrentStreaming: z.boolean().optional().default(false), + debridProvider: z.string().optional().default("none"), + debridApiKey: z.string().optional().default(""), }) export const settingsSchema = z.object({