feat(subscriptions): private rule groups, MP quality presets, save path, reset and calendar API
- include/exclude sync to a per-subscription private rule group (rule_group.hard, migration 0036);
evaluation merges chain hard conditions; private groups hidden from GET /rules, soft-deleted with
the subscription and rebuilt on resubscribe
- MP resolution / quality / effect map to presets written onto the subscription's own slots
(default slot template on create); UHD / Atmos go to the private group include
- downloadSavePath mapped to the downloader path and passed as qB savepath; libraryRootId used
for the first organize when the work has no path binding; keywords appended to active search
- POST /subscriptions/{id}/reset releases stale in-flight plans, clears deferrals, re-evaluates
- GET /subscriptions/calendar from episode air dates; refreshMetadata writes TMDB season
episode air dates for tracked seasons
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
52402864d6
commit
70d56645fe
20 files changed
+1663
-44
No files matched your search
@@ -0,0 +1,50 @@
|
||||
import type { Kysely } from "kysely";
|
||||
import { execDdl } from "../src/migration-helpers.ts";
|
||||
|
||||
// C1-A 订阅遗留收尾(docs/design/subscriptions.md §3、§6.1):
|
||||
// - rule_group.hard:规则组的结构化硬条件(SlotHardConditions 子集,目前用 include / exclude 正则),
|
||||
// 评估时并入版本目标硬条件。订阅表单的"包含 / 排除"写成订阅私有规则组(scope.subscriptionId),
|
||||
// 不在规则页列表显示,随订阅删除(软删)。
|
||||
// - 存量:params 里已有 include / exclude 的未取消订阅各建一个私有组(params 原样保留,表单回显用)。
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await execDdl(
|
||||
db,
|
||||
`
|
||||
alter table rule_group add column hard jsonb not null default '{}'::jsonb check (jsonb_typeof(hard) = 'object');
|
||||
create index rule_group_private_idx on rule_group ((scope ->> 'subscriptionId'))
|
||||
where deleted_at is null and scope ? 'subscriptionId';
|
||||
|
||||
insert into rule_group (name, description, kind, scope, ladder_required, source, fingerprint, hard)
|
||||
select '订阅私有 ' || left(s.id::text, 8) || '-' || substr(s.id::text, 10, 4),
|
||||
'订阅表单的包含 / 排除,随订阅删除',
|
||||
'acquisition',
|
||||
jsonb_build_object('subscriptionId', s.id::text),
|
||||
false,
|
||||
'manual',
|
||||
'private:' || s.id::text || ':' || md5(coalesce(s.params -> 'include', '[]'::jsonb)::text || coalesce(s.params -> 'exclude', '[]'::jsonb)::text),
|
||||
jsonb_strip_nulls(jsonb_build_object(
|
||||
'include', case when jsonb_typeof(s.params -> 'include') = 'array' and jsonb_array_length(s.params -> 'include') > 0
|
||||
then s.params -> 'include' end,
|
||||
'exclude', case when jsonb_typeof(s.params -> 'exclude') = 'array' and jsonb_array_length(s.params -> 'exclude') > 0
|
||||
then s.params -> 'exclude' end))
|
||||
from subscription s
|
||||
where s.status <> 'cancelled'
|
||||
and ((jsonb_typeof(s.params -> 'include') = 'array' and jsonb_array_length(s.params -> 'include') > 0)
|
||||
or (jsonb_typeof(s.params -> 'exclude') = 'array' and jsonb_array_length(s.params -> 'exclude') > 0));
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 同上
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await execDdl(
|
||||
db,
|
||||
`
|
||||
delete from rule_group where scope ? 'subscriptionId' and fingerprint like 'private:%';
|
||||
drop index if exists rule_group_private_idx;
|
||||
alter table rule_group drop column if exists hard;
|
||||
`,
|
||||
);
|
||||
}
|
||||
@@ -1190,6 +1190,7 @@ export interface RuleGroupTable {
|
||||
deleted_at: Timestamptz | null;
|
||||
created_at: GeneratedTimestamptz;
|
||||
updated_at: GeneratedTimestamptz;
|
||||
hard: Generated<Json>;
|
||||
}
|
||||
|
||||
export interface ScheduledJobTable {
|
||||
|
||||
Reference in new issue
Block a user