@gobing-ai/knowledge-kit 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +137 -59
- package/package.json +4 -4
- package/plugins/generations/content-gen/dist/index.js +97 -45
- package/plugins/generations/core-facts-gen/dist/index.js +106 -57
- package/plugins/generations/daily-article-gen/dist/index.js +105 -56
- package/plugins/generations/dailynews-gen/dist/index.js +235 -57
- package/plugins/generations/dailynews-gen/src/index.ts +67 -2
- package/plugins/generations/dailynews-gen/src/script-builder.ts +36 -15
- package/plugins/generations/dailynews-gen/src/script-plan.ts +142 -0
- package/plugins/generations/episode-plan-gen/dist/index.js +115 -66
- package/plugins/generations/gemini-tts/README.md +125 -0
- package/plugins/generations/gemini-tts/dist/index.js +23348 -0
- package/plugins/generations/gemini-tts/package.json +16 -0
- package/plugins/generations/gemini-tts/plugin.json +6 -0
- package/plugins/generations/gemini-tts/profiles.json +3 -0
- package/plugins/generations/gemini-tts/src/gemini-client.ts +220 -0
- package/plugins/generations/gemini-tts/src/index.ts +33 -0
- package/plugins/generations/gemini-tts/src/voice-create.ts +180 -0
- package/plugins/generations/gemini-tts/tsconfig.json +8 -0
- package/plugins/generations/image-gen/dist/index.js +338 -117
- package/plugins/generations/image-gen/presets/formats/daily-news-cover.yaml +19 -0
- package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +55 -0
- package/plugins/generations/image-gen/presets/styles/daily-news.yaml +9 -0
- package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +7 -0
- package/plugins/generations/image-gen/src/index.ts +148 -14
- package/plugins/generations/image-gen/src/job.ts +30 -0
- package/plugins/generations/image-gen/src/providers/errors.ts +91 -0
- package/plugins/generations/image-gen/src/providers/types.ts +79 -0
- package/plugins/generations/news-report-gen/dist/index.js +136 -55
- package/plugins/generations/news-report-gen/src/index.ts +57 -1
- package/plugins/generations/voice-gen/dist/index.js +121 -69
- package/plugins/generations/voice-gen/package.json +3 -0
- package/plugins/generations/voice-gen/src/index.ts +2 -1
- package/plugins/generations/voice-gen/src/voicebox-client.ts +2 -1
- package/plugins/ingestions/aihot-ingest/dist/index.js +103 -53
- package/plugins/ingestions/horizon-ingest/dist/index.js +102 -53
- package/plugins/ingestions/karakeep-local/dist/index.js +273 -224
- package/plugins/ingestions/last30days-ingest/dist/index.js +97 -48
- package/plugins/ingestions/web-search/dist/index.js +121 -72
- package/plugins/kk/config.example.yaml +13 -0
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/daily-voice-style.zh.md +52 -0
- package/plugins/kk/scripts/kk-workflow-stages.ts +438 -17
- package/plugins/kk/skills/publish/SKILL.md +24 -1
- package/plugins/kk/skills/xhs-images/SKILL.md +89 -0
- package/plugins/kk/skills/xhs-images/references/card-layouts.md +35 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +164 -13
- package/plugins/publishings/emdash-pub/dist/index.js +94 -45
- package/plugins/publishings/infoq-pub/dist/index.js +94 -45
- package/plugins/publishings/juejin-pub/dist/index.js +94 -45
- package/plugins/publishings/medium-pub/dist/index.js +94 -45
- package/plugins/publishings/podcast-pub/dist/index.js +115 -55
- package/plugins/publishings/podcast-pub/src/map.ts +30 -10
- package/plugins/publishings/podcast-pub/src/show-notes.ts +6 -1
- package/plugins/publishings/qiita-pub/dist/index.js +94 -45
- package/plugins/publishings/substack-pub/dist/index.js +94 -45
- package/plugins/publishings/surfdash-pub/dist/index.js +99 -63
- package/plugins/publishings/surfdash-pub/src/index.ts +10 -1
- package/plugins/publishings/wechatmp-pub/dist/index.js +94 -45
- package/plugins/publishings/x-pub/dist/index.js +94 -45
- package/plugins/publishings/xhs-pub/dist/index.js +8908 -229
- package/plugins/publishings/xhs-pub/package.json +1 -0
- package/plugins/publishings/xhs-pub/plugin.json +1 -1
- package/plugins/publishings/xhs-pub/src/automation-guard.ts +128 -0
- package/plugins/publishings/xhs-pub/src/index.ts +753 -24
- package/plugins/publishings/xhs-pub/src/profile-check.ts +133 -0
- package/plugins/publishings/zenn-pub/dist/index.js +94 -45
- package/plugins/sp/lib/env.ts +46 -0
- package/plugins/sp/lib/inline-run.generated.mjs +1489 -0
- package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
- package/plugins/sp/scripts/inline-run-setup.ts +571 -47
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +190 -0
- package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +77 -6
- package/plugins/sp/scripts/wrapup-steps.ts +91 -5
|
@@ -14642,6 +14642,72 @@ var init_zod = __esm(() => {
|
|
|
14642
14642
|
init_external();
|
|
14643
14643
|
});
|
|
14644
14644
|
|
|
14645
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/errors.js
|
|
14646
|
+
var ErrorCode;
|
|
14647
|
+
var init_errors3 = __esm(() => {
|
|
14648
|
+
ErrorCode = {
|
|
14649
|
+
NotFound: "NOT_FOUND",
|
|
14650
|
+
Validation: "VALIDATION",
|
|
14651
|
+
Conflict: "CONFLICT",
|
|
14652
|
+
Internal: "INTERNAL"
|
|
14653
|
+
};
|
|
14654
|
+
});
|
|
14655
|
+
|
|
14656
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/api-response.js
|
|
14657
|
+
var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
|
|
14658
|
+
var init_api_response = __esm(() => {
|
|
14659
|
+
init_errors3();
|
|
14660
|
+
API_ERROR_CODES = {
|
|
14661
|
+
SUCCESS: 0,
|
|
14662
|
+
NOT_FOUND: 404,
|
|
14663
|
+
VALIDATION_ERROR: 422,
|
|
14664
|
+
BAD_REQUEST: 400,
|
|
14665
|
+
UNAUTHORIZED: 401,
|
|
14666
|
+
FORBIDDEN: 403,
|
|
14667
|
+
CONFLICT: 409,
|
|
14668
|
+
INTERNAL_ERROR: 500
|
|
14669
|
+
};
|
|
14670
|
+
ERROR_CODE_TO_HTTP = {
|
|
14671
|
+
[ErrorCode.NotFound]: API_ERROR_CODES.NOT_FOUND,
|
|
14672
|
+
[ErrorCode.Validation]: API_ERROR_CODES.VALIDATION_ERROR,
|
|
14673
|
+
[ErrorCode.Conflict]: API_ERROR_CODES.CONFLICT,
|
|
14674
|
+
[ErrorCode.Internal]: API_ERROR_CODES.INTERNAL_ERROR
|
|
14675
|
+
};
|
|
14676
|
+
CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
|
|
14677
|
+
});
|
|
14678
|
+
|
|
14679
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/cursor.js
|
|
14680
|
+
var init_cursor = () => {};
|
|
14681
|
+
|
|
14682
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
|
|
14683
|
+
var init_event_severity = () => {};
|
|
14684
|
+
|
|
14685
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
14686
|
+
function processStream(name) {
|
|
14687
|
+
const proc = globalThis.process;
|
|
14688
|
+
const stream = proc?.[name];
|
|
14689
|
+
if (stream === undefined) {
|
|
14690
|
+
throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
|
|
14691
|
+
}
|
|
14692
|
+
return stream;
|
|
14693
|
+
}
|
|
14694
|
+
function writeLine(message, target) {
|
|
14695
|
+
target.write(`${message}
|
|
14696
|
+
`);
|
|
14697
|
+
}
|
|
14698
|
+
function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
|
|
14699
|
+
writeLine(message, target);
|
|
14700
|
+
}
|
|
14701
|
+
var defaultStderrTarget;
|
|
14702
|
+
|
|
14703
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/index.js
|
|
14704
|
+
var init_dist = __esm(() => {
|
|
14705
|
+
init_api_response();
|
|
14706
|
+
init_cursor();
|
|
14707
|
+
init_errors3();
|
|
14708
|
+
init_event_severity();
|
|
14709
|
+
});
|
|
14710
|
+
|
|
14645
14711
|
// ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
|
|
14646
14712
|
var require_identity = __commonJS((exports) => {
|
|
14647
14713
|
var ALIAS = Symbol.for("yaml.alias");
|
|
@@ -17546,15 +17612,15 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
17546
17612
|
throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
17547
17613
|
const [, year, month, day, hour, minute, second] = match.map(Number);
|
|
17548
17614
|
const millisec = match[7] ? Number((match[7] + "00").substr(1, 3)) : 0;
|
|
17549
|
-
let
|
|
17615
|
+
let date6 = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
|
|
17550
17616
|
const tz = match[8];
|
|
17551
17617
|
if (tz && tz !== "Z") {
|
|
17552
17618
|
let d = parseSexagesimal(tz, false);
|
|
17553
17619
|
if (Math.abs(d) < 30)
|
|
17554
17620
|
d *= 60;
|
|
17555
|
-
|
|
17621
|
+
date6 -= 60000 * d;
|
|
17556
17622
|
}
|
|
17557
|
-
return new Date(
|
|
17623
|
+
return new Date(date6);
|
|
17558
17624
|
},
|
|
17559
17625
|
stringify: ({ value }) => value?.toISOString().replace(/(T00:00:00)?\.000Z$/, "") ?? ""
|
|
17560
17626
|
};
|
|
@@ -19414,7 +19480,7 @@ var require_composer = __commonJS((exports) => {
|
|
|
19414
19480
|
var node_process = __require("process");
|
|
19415
19481
|
var directives = require_directives();
|
|
19416
19482
|
var Document = require_Document();
|
|
19417
|
-
var
|
|
19483
|
+
var errors4 = require_errors();
|
|
19418
19484
|
var identity = require_identity();
|
|
19419
19485
|
var composeDoc = require_compose_doc();
|
|
19420
19486
|
var resolveEnd = require_resolve_end();
|
|
@@ -19465,9 +19531,9 @@ var require_composer = __commonJS((exports) => {
|
|
|
19465
19531
|
this.onError = (source, code, message, warning) => {
|
|
19466
19532
|
const pos = getErrorPos(source);
|
|
19467
19533
|
if (warning)
|
|
19468
|
-
this.warnings.push(new
|
|
19534
|
+
this.warnings.push(new errors4.YAMLWarning(pos, code, message));
|
|
19469
19535
|
else
|
|
19470
|
-
this.errors.push(new
|
|
19536
|
+
this.errors.push(new errors4.YAMLParseError(pos, code, message));
|
|
19471
19537
|
};
|
|
19472
19538
|
this.directives = new directives.Directives({ version: options.version || "1.2" });
|
|
19473
19539
|
this.options = options;
|
|
@@ -19553,7 +19619,7 @@ ${cb}` : comment;
|
|
|
19553
19619
|
break;
|
|
19554
19620
|
case "error": {
|
|
19555
19621
|
const msg = token.source ? `${token.message}: ${JSON.stringify(token.source)}` : token.message;
|
|
19556
|
-
const error51 = new
|
|
19622
|
+
const error51 = new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg);
|
|
19557
19623
|
if (this.atDirectives || !this.doc)
|
|
19558
19624
|
this.errors.push(error51);
|
|
19559
19625
|
else
|
|
@@ -19563,7 +19629,7 @@ ${cb}` : comment;
|
|
|
19563
19629
|
case "doc-end": {
|
|
19564
19630
|
if (!this.doc) {
|
|
19565
19631
|
const msg = "Unexpected doc-end without preceding document";
|
|
19566
|
-
this.errors.push(new
|
|
19632
|
+
this.errors.push(new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg));
|
|
19567
19633
|
break;
|
|
19568
19634
|
}
|
|
19569
19635
|
this.doc.directives.docEnd = true;
|
|
@@ -19578,7 +19644,7 @@ ${end.comment}` : end.comment;
|
|
|
19578
19644
|
break;
|
|
19579
19645
|
}
|
|
19580
19646
|
default:
|
|
19581
|
-
this.errors.push(new
|
|
19647
|
+
this.errors.push(new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", `Unsupported token ${token.type}`));
|
|
19582
19648
|
}
|
|
19583
19649
|
}
|
|
19584
19650
|
*end(forceDoc = false, endOffset = -1) {
|
|
@@ -19604,7 +19670,7 @@ ${end.comment}` : end.comment;
|
|
|
19604
19670
|
var require_cst_scalar = __commonJS((exports) => {
|
|
19605
19671
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
19606
19672
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
19607
|
-
var
|
|
19673
|
+
var errors4 = require_errors();
|
|
19608
19674
|
var stringifyString = require_stringifyString();
|
|
19609
19675
|
function resolveAsScalar(token, strict = true, onError) {
|
|
19610
19676
|
if (token) {
|
|
@@ -19613,7 +19679,7 @@ var require_cst_scalar = __commonJS((exports) => {
|
|
|
19613
19679
|
if (onError)
|
|
19614
19680
|
onError(offset, code, message);
|
|
19615
19681
|
else
|
|
19616
|
-
throw new
|
|
19682
|
+
throw new errors4.YAMLParseError([offset, offset + 1], code, message);
|
|
19617
19683
|
};
|
|
19618
19684
|
switch (token.type) {
|
|
19619
19685
|
case "scalar":
|
|
@@ -21493,7 +21559,7 @@ var require_parser = __commonJS((exports) => {
|
|
|
21493
21559
|
var require_public_api = __commonJS((exports) => {
|
|
21494
21560
|
var composer = require_composer();
|
|
21495
21561
|
var Document = require_Document();
|
|
21496
|
-
var
|
|
21562
|
+
var errors4 = require_errors();
|
|
21497
21563
|
var log = require_log();
|
|
21498
21564
|
var identity = require_identity();
|
|
21499
21565
|
var lineCounter = require_line_counter();
|
|
@@ -21510,8 +21576,8 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21510
21576
|
const docs = Array.from(composer$1.compose(parser$1.parse(source)));
|
|
21511
21577
|
if (prettyErrors && lineCounter2)
|
|
21512
21578
|
for (const doc2 of docs) {
|
|
21513
|
-
doc2.errors.forEach(
|
|
21514
|
-
doc2.warnings.forEach(
|
|
21579
|
+
doc2.errors.forEach(errors4.prettifyError(source, lineCounter2));
|
|
21580
|
+
doc2.warnings.forEach(errors4.prettifyError(source, lineCounter2));
|
|
21515
21581
|
}
|
|
21516
21582
|
if (docs.length > 0)
|
|
21517
21583
|
return docs;
|
|
@@ -21526,13 +21592,13 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21526
21592
|
if (!doc2)
|
|
21527
21593
|
doc2 = _doc;
|
|
21528
21594
|
else if (doc2.options.logLevel !== "silent") {
|
|
21529
|
-
doc2.errors.push(new
|
|
21595
|
+
doc2.errors.push(new errors4.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
|
|
21530
21596
|
break;
|
|
21531
21597
|
}
|
|
21532
21598
|
}
|
|
21533
21599
|
if (prettyErrors && lineCounter2) {
|
|
21534
|
-
doc2.errors.forEach(
|
|
21535
|
-
doc2.warnings.forEach(
|
|
21600
|
+
doc2.errors.forEach(errors4.prettifyError(source, lineCounter2));
|
|
21601
|
+
doc2.warnings.forEach(errors4.prettifyError(source, lineCounter2));
|
|
21536
21602
|
}
|
|
21537
21603
|
return doc2;
|
|
21538
21604
|
}
|
|
@@ -21584,12 +21650,12 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21584
21650
|
});
|
|
21585
21651
|
|
|
21586
21652
|
// ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/index.js
|
|
21587
|
-
var composer, Document, Schema,
|
|
21588
|
-
var
|
|
21653
|
+
var composer, Document, Schema, errors4, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
|
|
21654
|
+
var init_dist2 = __esm(() => {
|
|
21589
21655
|
composer = require_composer();
|
|
21590
21656
|
Document = require_Document();
|
|
21591
21657
|
Schema = require_Schema();
|
|
21592
|
-
|
|
21658
|
+
errors4 = require_errors();
|
|
21593
21659
|
Alias = require_Alias();
|
|
21594
21660
|
identity = require_identity();
|
|
21595
21661
|
Pair = require_Pair();
|
|
@@ -21605,9 +21671,9 @@ var init_dist = __esm(() => {
|
|
|
21605
21671
|
$Composer = composer.Composer;
|
|
21606
21672
|
$Document = Document.Document;
|
|
21607
21673
|
$Schema = Schema.Schema;
|
|
21608
|
-
$YAMLError =
|
|
21609
|
-
$YAMLParseError =
|
|
21610
|
-
$YAMLWarning =
|
|
21674
|
+
$YAMLError = errors4.YAMLError;
|
|
21675
|
+
$YAMLParseError = errors4.YAMLParseError;
|
|
21676
|
+
$YAMLWarning = errors4.YAMLWarning;
|
|
21611
21677
|
$Alias = Alias.Alias;
|
|
21612
21678
|
$isAlias = identity.isAlias;
|
|
21613
21679
|
$isCollection = identity.isCollection;
|
|
@@ -21632,10 +21698,10 @@ var init_dist = __esm(() => {
|
|
|
21632
21698
|
$visitAsync = visit.visitAsync;
|
|
21633
21699
|
});
|
|
21634
21700
|
|
|
21635
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.
|
|
21701
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
21636
21702
|
var configSchema;
|
|
21637
21703
|
var init_config = __esm(() => {
|
|
21638
|
-
|
|
21704
|
+
init_dist2();
|
|
21639
21705
|
init_zod();
|
|
21640
21706
|
configSchema = exports_external.object({
|
|
21641
21707
|
app: exports_external.object({
|
|
@@ -21656,7 +21722,7 @@ var init_config = __esm(() => {
|
|
|
21656
21722
|
});
|
|
21657
21723
|
});
|
|
21658
21724
|
|
|
21659
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.
|
|
21725
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
|
|
21660
21726
|
import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
|
|
21661
21727
|
import { dirname, resolve as resolvePath } from "path";
|
|
21662
21728
|
function createNodeFileSystem(root, paths) {
|
|
@@ -21836,28 +21902,10 @@ var PluginManifestSchema = exports_external.looseObject({
|
|
|
21836
21902
|
description: exports_external.string().optional(),
|
|
21837
21903
|
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21838
21904
|
});
|
|
21839
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.
|
|
21905
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21840
21906
|
init_file_system_node();
|
|
21841
21907
|
init_config();
|
|
21842
21908
|
|
|
21843
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.67/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
21844
|
-
var defaultStderrTarget;
|
|
21845
|
-
function processStream(name) {
|
|
21846
|
-
const proc = globalThis.process;
|
|
21847
|
-
const stream = proc?.[name];
|
|
21848
|
-
if (stream === undefined) {
|
|
21849
|
-
throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
|
|
21850
|
-
}
|
|
21851
|
-
return stream;
|
|
21852
|
-
}
|
|
21853
|
-
function writeLine(message, target) {
|
|
21854
|
-
target.write(`${message}
|
|
21855
|
-
`);
|
|
21856
|
-
}
|
|
21857
|
-
function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
|
|
21858
|
-
writeLine(message, target);
|
|
21859
|
-
}
|
|
21860
|
-
|
|
21861
21909
|
// ../../packages/kk-core/src/render-md.ts
|
|
21862
21910
|
if (false) {}
|
|
21863
21911
|
// ../../packages/publish-harness/src/index.ts
|
|
@@ -21934,6 +21982,9 @@ class FakeBrowserTransport {
|
|
|
21934
21982
|
}
|
|
21935
21983
|
}
|
|
21936
21984
|
|
|
21985
|
+
// ../../plugins/publishings/podcast-pub/src/index.ts
|
|
21986
|
+
init_dist();
|
|
21987
|
+
|
|
21937
21988
|
// ../../plugins/publishings/podcast-pub/src/map.ts
|
|
21938
21989
|
import { extname } from "path";
|
|
21939
21990
|
|
|
@@ -21984,14 +22035,14 @@ function computeAudioOffsets(docs, segments) {
|
|
|
21984
22035
|
elapsed += s.duration ?? 0;
|
|
21985
22036
|
return { at, text: normalizeForMatch(s.transcription ?? "") };
|
|
21986
22037
|
});
|
|
21987
|
-
let
|
|
22038
|
+
let cursor2 = 1;
|
|
21988
22039
|
for (const d of docs) {
|
|
21989
22040
|
const title = normalizeForMatch(d.title ?? "");
|
|
21990
22041
|
const needle = title.slice(0, 12);
|
|
21991
|
-
const hit = needle.length >= 4 ? marks.findIndex((m, i) => i >=
|
|
22042
|
+
const hit = needle.length >= 4 ? marks.findIndex((m, i) => i >= cursor2 && m.text.includes(needle)) : -1;
|
|
21992
22043
|
if (hit >= 0) {
|
|
21993
22044
|
starts.push(marks[hit]?.at ?? 0);
|
|
21994
|
-
|
|
22045
|
+
cursor2 = hit + 1;
|
|
21995
22046
|
} else {
|
|
21996
22047
|
starts.push(Number.NaN);
|
|
21997
22048
|
}
|
|
@@ -22114,7 +22165,8 @@ function renderShowNotesMarkdown(docs, opts) {
|
|
|
22114
22165
|
const segments = opts.articlePostPath?.split(/[\\/]/).filter((s) => s.length > 0) ?? [];
|
|
22115
22166
|
const postSlug = segments.length >= 2 ? segments[segments.length - 2] ?? "" : "";
|
|
22116
22167
|
const postLocale = segments.find((s) => ["zh", "en", "ja"].includes(s)) ?? "zh";
|
|
22117
|
-
const
|
|
22168
|
+
const localePrefix = postLocale === "en" ? "" : `/${postLocale}`;
|
|
22169
|
+
const articleUrl = postSlug.length > 0 ? `${baseUrl}${localePrefix}/posts/${postSlug}` : `${baseUrl}/zh/posts/${opts.runDate}-${slugify2(opts.title)}`;
|
|
22118
22170
|
const briefMode = opts.briefMode === true && postSlug.length > 0;
|
|
22119
22171
|
const sourceLabel = (d) => {
|
|
22120
22172
|
const m = d.metadata ?? {};
|
|
@@ -22147,13 +22199,21 @@ var COVER_EXTS = new Set([".png", ".jpg", ".jpeg", ".webp", ".gif"]);
|
|
|
22147
22199
|
var AUDIO_MIME_BY_EXTENSION = {
|
|
22148
22200
|
".mp3": "audio/mpeg",
|
|
22149
22201
|
".wav": "audio/wav",
|
|
22150
|
-
".m4a": "audio/
|
|
22202
|
+
".m4a": "audio/x-m4a",
|
|
22151
22203
|
".aac": "audio/aac",
|
|
22152
22204
|
".ogg": "audio/ogg",
|
|
22153
22205
|
".oga": "audio/ogg",
|
|
22154
22206
|
".flac": "audio/flac",
|
|
22155
22207
|
".opus": "audio/opus"
|
|
22156
22208
|
};
|
|
22209
|
+
var APPLE_AUDIO_MIME = new Set([
|
|
22210
|
+
"audio/mpeg",
|
|
22211
|
+
"audio/x-m4a",
|
|
22212
|
+
"audio/mp4",
|
|
22213
|
+
"video/mp4",
|
|
22214
|
+
"video/quicktime",
|
|
22215
|
+
"video/x-m4v"
|
|
22216
|
+
]);
|
|
22157
22217
|
function resolveAudioMimeType(reference, mimeType) {
|
|
22158
22218
|
if (typeof mimeType === "string" && mimeType.trim().length > 0) {
|
|
22159
22219
|
return mimeType.trim();
|
|
@@ -22225,15 +22285,15 @@ function mapContentToEpisode(content) {
|
|
|
22225
22285
|
...typeof rec.block === "boolean" ? { block: rec.block } : {}
|
|
22226
22286
|
};
|
|
22227
22287
|
}
|
|
22288
|
+
const audioMimeType = resolveAudioMimeType(audioFile ?? audioUrl, metadata.mimeType);
|
|
22289
|
+
if (!APPLE_AUDIO_MIME.has(audioMimeType)) {
|
|
22290
|
+
throw new Error(`unsupported audio MIME type "${audioMimeType}" for Apple Podcasts: expected one of ${[...APPLE_AUDIO_MIME].join(", ")}`);
|
|
22291
|
+
}
|
|
22228
22292
|
return {
|
|
22229
22293
|
title,
|
|
22230
22294
|
contentHtml: showNotes && showNotes.length > 0 ? renderShowNotesHtml(showNotes) : content.format === "html" ? content.body : renderShowNotesHtml(content.body),
|
|
22231
22295
|
status,
|
|
22232
|
-
audio: audioFile ? { kind: "file", path: audioFile, mimeType:
|
|
22233
|
-
kind: "url",
|
|
22234
|
-
url: audioUrl,
|
|
22235
|
-
mimeType: resolveAudioMimeType(audioUrl, metadata.mimeType)
|
|
22236
|
-
},
|
|
22296
|
+
audio: audioFile ? { kind: "file", path: audioFile, mimeType: audioMimeType } : { kind: "url", url: audioUrl, mimeType: audioMimeType },
|
|
22237
22297
|
durationSeconds: duration3,
|
|
22238
22298
|
...imageUrl ? { imageUrl } : {},
|
|
22239
22299
|
...imagePath ? { imagePath } : {},
|
|
@@ -40,7 +40,7 @@ export interface EpisodeMapping {
|
|
|
40
40
|
const AUDIO_MIME_BY_EXTENSION: Record<string, string> = {
|
|
41
41
|
'.mp3': 'audio/mpeg',
|
|
42
42
|
'.wav': 'audio/wav',
|
|
43
|
-
'.m4a': 'audio/
|
|
43
|
+
'.m4a': 'audio/x-m4a',
|
|
44
44
|
'.aac': 'audio/aac',
|
|
45
45
|
'.ogg': 'audio/ogg',
|
|
46
46
|
'.oga': 'audio/ogg',
|
|
@@ -48,6 +48,20 @@ const AUDIO_MIME_BY_EXTENSION: Record<string, string> = {
|
|
|
48
48
|
'.opus': 'audio/opus',
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Audio MIME types Apple Podcasts accepts for an enclosure. microfeed stores and serves
|
|
53
|
+
* whatever MIME it is given, so anything outside this set must be refused here — before
|
|
54
|
+
* any network call — rather than shipping an enclosure Apple cannot ingest.
|
|
55
|
+
*/
|
|
56
|
+
const APPLE_AUDIO_MIME: ReadonlySet<string> = new Set([
|
|
57
|
+
'audio/mpeg',
|
|
58
|
+
'audio/x-m4a',
|
|
59
|
+
'audio/mp4',
|
|
60
|
+
'video/mp4',
|
|
61
|
+
'video/quicktime',
|
|
62
|
+
'video/x-m4v',
|
|
63
|
+
]);
|
|
64
|
+
|
|
51
65
|
/**
|
|
52
66
|
* Resolves the audio MIME type from `metadata.mimeType` or the file extension
|
|
53
67
|
* (`.wav` → `audio/wav`); unknown extensions fall back to `application/octet-stream`.
|
|
@@ -65,9 +79,9 @@ export function resolveAudioMimeType(reference: string, mimeType?: unknown): str
|
|
|
65
79
|
|
|
66
80
|
/**
|
|
67
81
|
* Maps Content + episode metadata into microfeed item fields (design D6).
|
|
68
|
-
* Validates only the plugin's own requirements — title resolvable
|
|
69
|
-
* audio
|
|
70
|
-
* and server 400s surface everything else (R4 error path).
|
|
82
|
+
* Validates only the plugin's own requirements — title resolvable, exactly one audio
|
|
83
|
+
* reference, and an Apple-compatible audio MIME — before any network call (R5);
|
|
84
|
+
* microfeed's `validate` endpoint and server 400s surface everything else (R4 error path).
|
|
71
85
|
* Throws with a diagnostic when the Content is not publishable.
|
|
72
86
|
*/
|
|
73
87
|
export function mapContentToEpisode(content: Content): EpisodeMapping {
|
|
@@ -150,6 +164,16 @@ export function mapContentToEpisode(content: Content): EpisodeMapping {
|
|
|
150
164
|
};
|
|
151
165
|
}
|
|
152
166
|
|
|
167
|
+
// Resolved once so the Apple-compatibility guard also covers a `metadata.mimeType`
|
|
168
|
+
// override; `AUDIO_MIME_BY_EXTENSION` still says what a file is, the allowlist decides
|
|
169
|
+
// what is publishable.
|
|
170
|
+
const audioMimeType = resolveAudioMimeType(audioFile ?? (audioUrl as string), metadata.mimeType);
|
|
171
|
+
if (!APPLE_AUDIO_MIME.has(audioMimeType)) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`unsupported audio MIME type "${audioMimeType}" for Apple Podcasts: expected one of ${[...APPLE_AUDIO_MIME].join(', ')}`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
153
177
|
return {
|
|
154
178
|
title,
|
|
155
179
|
contentHtml:
|
|
@@ -160,12 +184,8 @@ export function mapContentToEpisode(content: Content): EpisodeMapping {
|
|
|
160
184
|
: renderShowNotesHtml(content.body),
|
|
161
185
|
status,
|
|
162
186
|
audio: audioFile
|
|
163
|
-
? { kind: 'file', path: audioFile, mimeType:
|
|
164
|
-
: {
|
|
165
|
-
kind: 'url',
|
|
166
|
-
url: audioUrl as string,
|
|
167
|
-
mimeType: resolveAudioMimeType(audioUrl as string, metadata.mimeType),
|
|
168
|
-
},
|
|
187
|
+
? { kind: 'file', path: audioFile, mimeType: audioMimeType }
|
|
188
|
+
: { kind: 'url', url: audioUrl as string, mimeType: audioMimeType },
|
|
169
189
|
durationSeconds: duration as number | undefined,
|
|
170
190
|
...(imageUrl ? { imageUrl } : {}),
|
|
171
191
|
...(imagePath ? { imagePath } : {}),
|
|
@@ -309,9 +309,14 @@ export function renderShowNotesMarkdown(docs: Doc[], opts: ShowNotesRenderOption
|
|
|
309
309
|
const segments = opts.articlePostPath?.split(/[\\/]/).filter((s) => s.length > 0) ?? [];
|
|
310
310
|
const postSlug = segments.length >= 2 ? (segments[segments.length - 2] ?? '') : '';
|
|
311
311
|
const postLocale = segments.find((s) => ['zh', 'en', 'ja'].includes(s)) ?? 'zh';
|
|
312
|
+
// URL shape mirrors surfdash's localePathPrefix (surfdash/src/lib/seo.ts):
|
|
313
|
+
// en is served at the site root, zh/ja carry a /<locale> prefix. A bare
|
|
314
|
+
// /<locale>/posts/<slug> 404s en posts. Fallback stays zh — the podcast
|
|
315
|
+
// is zh-only today.
|
|
316
|
+
const localePrefix = postLocale === 'en' ? '' : `/${postLocale}`;
|
|
312
317
|
const articleUrl =
|
|
313
318
|
postSlug.length > 0
|
|
314
|
-
? `${baseUrl}
|
|
319
|
+
? `${baseUrl}${localePrefix}/posts/${postSlug}`
|
|
315
320
|
: `${baseUrl}/zh/posts/${opts.runDate}-${slugify(opts.title)}`;
|
|
316
321
|
const briefMode = opts.briefMode === true && postSlug.length > 0;
|
|
317
322
|
const sourceLabel = (d: Doc): string => {
|