fix: fix tasks

This commit is contained in:
master 2025-06-14 22:30:58 +08:00
parent 882b29d7a1
commit 1b5bdadf10
15 changed files with 91 additions and 49 deletions

9
Cargo.lock generated
View File

@ -5388,9 +5388,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.19" version = "0.12.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
@ -5407,13 +5407,11 @@ dependencies = [
"hyper-rustls", "hyper-rustls",
"hyper-tls", "hyper-tls",
"hyper-util", "hyper-util",
"ipnet",
"js-sys", "js-sys",
"log", "log",
"mime", "mime",
"mime_guess", "mime_guess",
"native-tls", "native-tls",
"once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"quinn", "quinn",
@ -5426,7 +5424,6 @@ dependencies = [
"tokio", "tokio",
"tokio-native-tls", "tokio-native-tls",
"tokio-rustls", "tokio-rustls",
"tokio-socks",
"tokio-util", "tokio-util",
"tower", "tower",
"tower-http", "tower-http",
@ -5995,7 +5992,7 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]] [[package]]
name = "seaography" name = "seaography"
version = "1.1.4" version = "1.1.4"
source = "git+https://github.com/dumtruck/seaography.git?rev=01d3f99#01d3f99aebd476860b9c061676b2b22083188b03" source = "git+https://github.com/dumtruck/seaography.git?rev=a787c3a#a787c3ab83cf1f8275894e1bc1ca3c766b54674b"
dependencies = [ dependencies = [
"async-graphql", "async-graphql",
"fnv", "fnv",

View File

@ -28,7 +28,7 @@ downloader = { path = "./packages/downloader" }
recorder = { path = "./apps/recorder" } recorder = { path = "./apps/recorder" }
proxy = { path = "./apps/proxy" } proxy = { path = "./apps/proxy" }
reqwest = { version = "0.12", features = [ reqwest = { version = "0.12.20", features = [
"charset", "charset",
"http2", "http2",
"json", "json",
@ -69,4 +69,4 @@ color-eyre = "0.6.5"
inquire = "0.7.5" inquire = "0.7.5"
[patch.crates-io] [patch.crates-io]
seaography = { git = "https://github.com/dumtruck/seaography.git", rev = "01d3f99" } seaography = { git = "https://github.com/dumtruck/seaography.git", rev = "a787c3a" }

View File

@ -1 +1 @@
^https://mikanani.me/*** http://127.0.0.1:5010/$1 ^https://mikanani.me/*** http://127.0.0.1:5005/$1

View File

@ -10,7 +10,7 @@ async fn main() -> RecorderResult<()> {
.with_max_level(Level::DEBUG) .with_max_level(Level::DEBUG)
.init(); .init();
let mut mikan_server = MikanMockServer::new_with_port(5010).await.unwrap(); let mut mikan_server = MikanMockServer::new_with_port(5005).await.unwrap();
let resources_mock = mikan_server.mock_resources_with_doppel(); let resources_mock = mikan_server.mock_resources_with_doppel();

View File

@ -14,3 +14,4 @@ BASIC_PASSWORD = "konobangu"
# MIKAN_PROXY = "" # MIKAN_PROXY = ""
# MIKAN_PROXY_AUTH_HEADER = "" # MIKAN_PROXY_AUTH_HEADER = ""
# MIKAN_NO_PROXY = "" # MIKAN_NO_PROXY = ""
# MIKAN_PROXY_ACCEPT_INVALID_CERTS = "true"

17
apps/recorder/.env.dev Normal file
View File

@ -0,0 +1,17 @@
HOST="konobangu.com"
DATABASE_URL = "postgres://konobangu:konobangu@localhost:5432/konobangu"
STORAGE_DATA_DIR = "./data"
AUTH_TYPE = "basic" # or oidc
BASIC_USER = "konobangu"
BASIC_PASSWORD = "konobangu"
# OIDC_ISSUER="https://auth.logto.io/oidc"
# OIDC_AUDIENCE = "https://konobangu.com/api"
# OIDC_CLIENT_ID = "client_id"
# OIDC_CLIENT_SECRET = "client_secret" # optional
# OIDC_EXTRA_SCOPES = "read:konobangu write:konobangu"
# OIDC_EXTRA_CLAIM_KEY = ""
# OIDC_EXTRA_CLAIM_VALUE = ""
MIKAN_PROXY = "http://127.0.0.1:8899"
# MIKAN_PROXY_AUTH_HEADER = ""
# MIKAN_NO_PROXY = ""
MIKAN_PROXY_ACCEPT_INVALID_CERTS = true

View File

@ -111,7 +111,12 @@ tracing-appender = "0.2.3"
clap = "4.5.31" clap = "4.5.31"
ipnetwork = "0.21.1" ipnetwork = "0.21.1"
typed-builder = "0.21.0" typed-builder = "0.21.0"
apalis = { version = "0.7", features = ["limit", "tracing", "catch-panic"] } apalis = { version = "0.7", features = [
"limit",
"tracing",
"catch-panic",
"retry",
] }
apalis-sql = { version = "0.7", features = ["postgres"] } apalis-sql = { version = "0.7", features = ["postgres"] }
cocoon = { version = "0.4.3", features = ["getrandom", "thiserror"] } cocoon = { version = "0.4.3", features = ["getrandom", "thiserror"] }
rand = "0.9.1" rand = "0.9.1"

View File

@ -710,6 +710,7 @@ pub async fn scrape_mikan_bangumi_meta_from_bangumi_homepage_url(
) )
} }
#[allow(dead_code)]
#[instrument(err, skip_all, fields(mikan_bangumi_homepage_url = mikan_bangumi_homepage_url.as_str()))] #[instrument(err, skip_all, fields(mikan_bangumi_homepage_url = mikan_bangumi_homepage_url.as_str()))]
pub async fn scrape_mikan_bangumi_index_meta_from_bangumi_homepage_url( pub async fn scrape_mikan_bangumi_index_meta_from_bangumi_homepage_url(
mikan_client: &MikanClient, mikan_client: &MikanClient,

View File

@ -3,6 +3,7 @@ use std::{ops::Deref, sync::Arc};
use apalis::prelude::*; use apalis::prelude::*;
use apalis_sql::{ use apalis_sql::{
Config, Config,
context::SqlContext,
postgres::{PgListen, PostgresStorage}, postgres::{PgListen, PostgresStorage},
}; };
use tokio::sync::RwLock; use tokio::sync::RwLock;
@ -51,7 +52,13 @@ impl TaskService {
) -> RecorderResult<TaskId> { ) -> RecorderResult<TaskId> {
let task_id = { let task_id = {
let mut storage = self.subscriber_task_storage.write().await; let mut storage = self.subscriber_task_storage.write().await;
storage.push(subscriber_task).await?.task_id let sql_context = {
let mut c = SqlContext::default();
c.set_max_attempts(1);
c
};
let request = Request::new_with_ctx(subscriber_task, sql_context);
storage.push_request(request).await?.task_id
}; };
Ok(task_id) Ok(task_id)

View File

@ -13,3 +13,4 @@ dist/
.idea .idea
.env.local .env.local
.env.*.lcoal .env.*.lcoal
.tanstack

View File

@ -1,18 +1,30 @@
import { memo } from "react"; import { cn } from "@/presentation/utils";
import { DetailedHTMLProps, HTMLAttributes, memo } from "react";
import { Card, CardContent } from "./card"; import { Card, CardContent } from "./card";
export interface DetailEmptyViewProps { export interface DetailEmptyViewProps
extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
message: string; message: string;
fullWidth?: boolean;
} }
export const DetailEmptyView = memo(({ message }: DetailEmptyViewProps) => { export const DetailEmptyView = memo(
return ( ({ message, fullWidth, ...props }: DetailEmptyViewProps) => {
<div className="container mx-auto py-6 max-w-4xl"> return (
<Card> <div
<CardContent className="flex items-center justify-center h-32"> {...props}
<p className="text-muted-foreground">{message ?? "No data"}</p> className={cn(
</CardContent> "container mx-auto py-6",
</Card> fullWidth ? "w-full" : "max-w-4xl",
</div> props.className
); )}
}); >
<Card>
<CardContent className="flex items-center justify-center h-32">
<p className="text-muted-foreground">{message ?? "No data"}</p>
</CardContent>
</Card>
</div>
);
}
);

View File

@ -133,7 +133,7 @@ export type BangumiInsertInput = {
savePath?: InputMaybe<Scalars['String']['input']>; savePath?: InputMaybe<Scalars['String']['input']>;
season: Scalars['Int']['input']; season: Scalars['Int']['input'];
seasonRaw?: InputMaybe<Scalars['String']['input']>; seasonRaw?: InputMaybe<Scalars['String']['input']>;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
}; };
@ -267,7 +267,7 @@ export type Credential3rdInsertInput = {
credentialType: Credential3rdTypeEnum; credentialType: Credential3rdTypeEnum;
id?: InputMaybe<Scalars['Int']['input']>; id?: InputMaybe<Scalars['Int']['input']>;
password?: InputMaybe<Scalars['String']['input']>; password?: InputMaybe<Scalars['String']['input']>;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
userAgent?: InputMaybe<Scalars['String']['input']>; userAgent?: InputMaybe<Scalars['String']['input']>;
username?: InputMaybe<Scalars['String']['input']>; username?: InputMaybe<Scalars['String']['input']>;
@ -450,7 +450,7 @@ export type DownloadersInsertInput = {
id?: InputMaybe<Scalars['Int']['input']>; id?: InputMaybe<Scalars['Int']['input']>;
password: Scalars['String']['input']; password: Scalars['String']['input'];
savePath: Scalars['String']['input']; savePath: Scalars['String']['input'];
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
username: Scalars['String']['input']; username: Scalars['String']['input'];
}; };
@ -566,7 +566,7 @@ export type DownloadsInsertInput = {
rawName: Scalars['String']['input']; rawName: Scalars['String']['input'];
savePath?: InputMaybe<Scalars['String']['input']>; savePath?: InputMaybe<Scalars['String']['input']>;
status: DownloadStatusEnum; status: DownloadStatusEnum;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
url: Scalars['String']['input']; url: Scalars['String']['input'];
}; };
@ -729,7 +729,7 @@ export type EpisodesInsertInput = {
season: Scalars['Int']['input']; season: Scalars['Int']['input'];
seasonRaw?: InputMaybe<Scalars['String']['input']>; seasonRaw?: InputMaybe<Scalars['String']['input']>;
source?: InputMaybe<Scalars['String']['input']>; source?: InputMaybe<Scalars['String']['input']>;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
subtitle?: InputMaybe<Scalars['String']['input']>; subtitle?: InputMaybe<Scalars['String']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
}; };
@ -1292,7 +1292,7 @@ export type SubscriberTasksInsertInput = {
priority: Scalars['Int']['input']; priority: Scalars['Int']['input'];
runAt: Scalars['String']['input']; runAt: Scalars['String']['input'];
status: SubscriberTaskStatusEnum; status: SubscriberTaskStatusEnum;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
taskType: SubscriberTaskTypeEnum; taskType: SubscriberTaskTypeEnum;
}; };
@ -1449,7 +1449,7 @@ export type SubscriptionBangumiFilterInput = {
export type SubscriptionBangumiInsertInput = { export type SubscriptionBangumiInsertInput = {
bangumiId: Scalars['Int']['input']; bangumiId: Scalars['Int']['input'];
id?: InputMaybe<Scalars['Int']['input']>; id?: InputMaybe<Scalars['Int']['input']>;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
subscriptionId: Scalars['Int']['input']; subscriptionId: Scalars['Int']['input'];
}; };
@ -1532,7 +1532,7 @@ export type SubscriptionEpisodeFilterInput = {
export type SubscriptionEpisodeInsertInput = { export type SubscriptionEpisodeInsertInput = {
episodeId: Scalars['Int']['input']; episodeId: Scalars['Int']['input'];
id?: InputMaybe<Scalars['Int']['input']>; id?: InputMaybe<Scalars['Int']['input']>;
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
subscriptionId: Scalars['Int']['input']; subscriptionId: Scalars['Int']['input'];
}; };
@ -1645,7 +1645,7 @@ export type SubscriptionsInsertInput = {
enabled: Scalars['Boolean']['input']; enabled: Scalars['Boolean']['input'];
id?: InputMaybe<Scalars['Int']['input']>; id?: InputMaybe<Scalars['Int']['input']>;
sourceUrl: Scalars['String']['input']; sourceUrl: Scalars['String']['input'];
subscriberId: Scalars['Int']['input']; subscriberId?: InputMaybe<Scalars['Int']['input']>;
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
}; };

View File

@ -231,7 +231,7 @@ function TaskManageRouteComponent() {
); );
}) })
) : ( ) : (
<DetailEmptyView message="No tasks found" /> <DetailEmptyView message="No tasks found" fullWidth />
)} )}
</div> </div>

View File

@ -2,8 +2,9 @@ set windows-shell := ["pwsh.exe", "-c"]
set dotenv-load := true set dotenv-load := true
prepare-dev: prepare-dev:
cargo install sea-orm-cli cargo-llvm-cov cargo-nextest cargo install cargo-binstall
# install watchexec cargo binstall sea-orm-cli cargo-llvm-cov cargo-nextest
# <package-manager> install watchexec just zellij
prepare-dev-testcontainers: prepare-dev-testcontainers:
docker pull linuxserver/qbittorrent:latest docker pull linuxserver/qbittorrent:latest
@ -14,7 +15,7 @@ dev-webui:
pnpm run --filter=webui dev pnpm run --filter=webui dev
dev-proxy: dev-proxy:
npx --yes kill-port --port 8899,5010 npx --yes kill-port --port 8899,5005
pnpm run --parallel --filter=proxy dev pnpm run --parallel --filter=proxy dev
dev-recorder: dev-recorder:

View File

@ -1,13 +1,13 @@
packages: packages:
- packages/* - packages/*
- apps/* - apps/*
- '!packages/testing-torrents' - "!packages/testing-torrents"
onlyBuiltDependencies: onlyBuiltDependencies:
- '@biomejs/biome' - "@biomejs/biome"
- '@parcel/watcher' - "@parcel/watcher"
- '@tailwindcss/oxide' - "@tailwindcss/oxide"
- bufferutil - bufferutil
- core-js - core-js
- esbuild - esbuild
- sharp - sharp
- utf-8-validate - utf-8-validate