@tienne/gestalt 0.101.1 → 0.103.0
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/README.ko.md +2 -1
- package/README.md +2 -1
- package/dist/package.json +1 -1
- package/dist/plugin/role-agents/video-summarizer/AGENT.md +177 -113
- package/dist/plugin/skills/_shared/agent-delegation.md +1 -1
- package/dist/plugin/skills/_shared/proactive-routing.md +3 -2
- package/dist/plugin/skills/_shared/research-humanize.md +160 -0
- package/dist/plugin/skills/research/SKILL.md +20 -2
- package/dist/plugin/skills/research/references/design.md +14 -2
- package/dist/plugin/skills/reverse-plan/SKILL.md +3 -1
- package/dist/plugin/skills/ux-research/SKILL.md +3 -1
- package/dist/plugin/skills/video-digest/SKILL.md +408 -0
- package/dist/plugin/skills/video-digest/templates/background.md +15 -0
- package/dist/plugin/skills/video-digest/templates/blog.md +16 -0
- package/dist/plugin/skills/video-digest/templates/comments.md +19 -0
- package/dist/plugin/skills/video-digest/templates/counterpoints.md +15 -0
- package/dist/plugin/skills/video-digest/templates/flashcards.md +15 -0
- package/dist/plugin/skills/video-digest/templates/interview.md +15 -0
- package/dist/plugin/skills/video-digest/templates/meeting.md +15 -0
- package/dist/plugin/skills/video-digest/templates/mindmap.md +16 -0
- package/dist/plugin/skills/video-digest/templates/quiz.md +16 -0
- package/dist/plugin/skills/video-digest/templates/quotes.md +16 -0
- package/dist/plugin/skills/video-digest/templates/resources.md +14 -0
- package/dist/plugin/skills/video-digest/templates/timestamps.md +14 -0
- package/dist/src/cli/commands/digest.d.ts +57 -0
- package/dist/src/cli/commands/digest.d.ts.map +1 -0
- package/dist/src/cli/commands/digest.js +368 -0
- package/dist/src/cli/commands/digest.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +77 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/digest/blocks.d.ts +1853 -0
- package/dist/src/digest/blocks.d.ts.map +1 -0
- package/dist/src/digest/blocks.js +148 -0
- package/dist/src/digest/blocks.js.map +1 -0
- package/dist/src/digest/captions.d.ts +37 -0
- package/dist/src/digest/captions.d.ts.map +1 -0
- package/dist/src/digest/captions.js +138 -0
- package/dist/src/digest/captions.js.map +1 -0
- package/dist/src/digest/comments.d.ts +113 -0
- package/dist/src/digest/comments.d.ts.map +1 -0
- package/dist/src/digest/comments.js +153 -0
- package/dist/src/digest/comments.js.map +1 -0
- package/dist/src/digest/format.d.ts +9 -0
- package/dist/src/digest/format.d.ts.map +1 -0
- package/dist/src/digest/format.js +26 -0
- package/dist/src/digest/format.js.map +1 -0
- package/dist/src/digest/frames.d.ts +26 -0
- package/dist/src/digest/frames.d.ts.map +1 -0
- package/dist/src/digest/frames.js +109 -0
- package/dist/src/digest/frames.js.map +1 -0
- package/dist/src/digest/index.d.ts +25 -0
- package/dist/src/digest/index.d.ts.map +1 -0
- package/dist/src/digest/index.js +25 -0
- package/dist/src/digest/index.js.map +1 -0
- package/dist/src/digest/ingest.d.ts +65 -0
- package/dist/src/digest/ingest.d.ts.map +1 -0
- package/dist/src/digest/ingest.js +303 -0
- package/dist/src/digest/ingest.js.map +1 -0
- package/dist/src/digest/lint-extension.d.ts +57 -0
- package/dist/src/digest/lint-extension.d.ts.map +1 -0
- package/dist/src/digest/lint-extension.js +395 -0
- package/dist/src/digest/lint-extension.js.map +1 -0
- package/dist/src/digest/lint.d.ts +40 -0
- package/dist/src/digest/lint.d.ts.map +1 -0
- package/dist/src/digest/lint.js +517 -0
- package/dist/src/digest/lint.js.map +1 -0
- package/dist/src/digest/merge.d.ts +40 -0
- package/dist/src/digest/merge.d.ts.map +1 -0
- package/dist/src/digest/merge.js +104 -0
- package/dist/src/digest/merge.js.map +1 -0
- package/dist/src/digest/ocr.d.ts +96 -0
- package/dist/src/digest/ocr.d.ts.map +1 -0
- package/dist/src/digest/ocr.js +168 -0
- package/dist/src/digest/ocr.js.map +1 -0
- package/dist/src/digest/prose.d.ts +43 -0
- package/dist/src/digest/prose.d.ts.map +1 -0
- package/dist/src/digest/prose.js +112 -0
- package/dist/src/digest/prose.js.map +1 -0
- package/dist/src/digest/render-blocks.d.ts +32 -0
- package/dist/src/digest/render-blocks.d.ts.map +1 -0
- package/dist/src/digest/render-blocks.js +292 -0
- package/dist/src/digest/render-blocks.js.map +1 -0
- package/dist/src/digest/render-html.d.ts +22 -0
- package/dist/src/digest/render-html.d.ts.map +1 -0
- package/dist/src/digest/render-html.js +466 -0
- package/dist/src/digest/render-html.js.map +1 -0
- package/dist/src/digest/render-md.d.ts +18 -0
- package/dist/src/digest/render-md.d.ts.map +1 -0
- package/dist/src/digest/render-md.js +113 -0
- package/dist/src/digest/render-md.js.map +1 -0
- package/dist/src/digest/render.d.ts +47 -0
- package/dist/src/digest/render.d.ts.map +1 -0
- package/dist/src/digest/render.js +123 -0
- package/dist/src/digest/render.js.map +1 -0
- package/dist/src/digest/reports.d.ts +26 -0
- package/dist/src/digest/reports.d.ts.map +1 -0
- package/dist/src/digest/reports.js +70 -0
- package/dist/src/digest/reports.js.map +1 -0
- package/dist/src/digest/schema-base.d.ts +31 -0
- package/dist/src/digest/schema-base.d.ts.map +1 -0
- package/dist/src/digest/schema-base.js +19 -0
- package/dist/src/digest/schema-base.js.map +1 -0
- package/dist/src/digest/schema.d.ts +5713 -0
- package/dist/src/digest/schema.d.ts.map +1 -0
- package/dist/src/digest/schema.js +229 -0
- package/dist/src/digest/schema.js.map +1 -0
- package/dist/src/digest/server.d.ts +36 -0
- package/dist/src/digest/server.d.ts.map +1 -0
- package/dist/src/digest/server.js +278 -0
- package/dist/src/digest/server.js.map +1 -0
- package/dist/src/digest/slice.d.ts +20 -0
- package/dist/src/digest/slice.d.ts.map +1 -0
- package/dist/src/digest/slice.js +48 -0
- package/dist/src/digest/slice.js.map +1 -0
- package/dist/src/digest/store.d.ts +67 -0
- package/dist/src/digest/store.d.ts.map +1 -0
- package/dist/src/digest/store.js +152 -0
- package/dist/src/digest/store.js.map +1 -0
- package/dist/src/digest/svg.d.ts +44 -0
- package/dist/src/digest/svg.d.ts.map +1 -0
- package/dist/src/digest/svg.js +264 -0
- package/dist/src/digest/svg.js.map +1 -0
- package/dist/src/digest/templates.d.ts +38 -0
- package/dist/src/digest/templates.d.ts.map +1 -0
- package/dist/src/digest/templates.js +125 -0
- package/dist/src/digest/templates.js.map +1 -0
- package/dist/src/digest/translate.d.ts +46 -0
- package/dist/src/digest/translate.d.ts.map +1 -0
- package/dist/src/digest/translate.js +50 -0
- package/dist/src/digest/translate.js.map +1 -0
- package/dist/src/digest/viewer-js.d.ts +4 -0
- package/dist/src/digest/viewer-js.d.ts.map +1 -0
- package/dist/src/digest/viewer-js.js +710 -0
- package/dist/src/digest/viewer-js.js.map +1 -0
- package/dist/src/digest/viewer-logic.d.ts +46 -0
- package/dist/src/digest/viewer-logic.d.ts.map +1 -0
- package/dist/src/digest/viewer-logic.js +89 -0
- package/dist/src/digest/viewer-logic.js.map +1 -0
- package/dist/src/digest/ytdlp.d.ts +34 -0
- package/dist/src/digest/ytdlp.d.ts.map +1 -0
- package/dist/src/digest/ytdlp.js +64 -0
- package/dist/src/digest/ytdlp.js.map +1 -0
- package/dist/src/humanize/detectors.js +2 -2
- package/dist/src/humanize/detectors.js.map +1 -1
- package/dist/src/mcp/schemas.d.ts +78 -4
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +40 -2
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +8 -2
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/digest-passthrough.d.ts +3 -0
- package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -0
- package/dist/src/mcp/tools/digest-passthrough.js +148 -0
- package/dist/src/mcp/tools/digest-passthrough.js.map +1 -0
- package/dist/src/mcp/tools/research-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/research-passthrough.js +56 -0
- package/dist/src/mcp/tools/research-passthrough.js.map +1 -1
- package/dist/src/research/index.d.ts +1 -0
- package/dist/src/research/index.d.ts.map +1 -1
- package/dist/src/research/index.js +1 -0
- package/dist/src/research/index.js.map +1 -1
- package/dist/src/research/prose.d.ts +60 -0
- package/dist/src/research/prose.d.ts.map +1 -0
- package/dist/src/research/prose.js +200 -0
- package/dist/src/research/prose.js.map +1 -0
- package/package.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/role-agents/video-summarizer/AGENT.md +177 -113
- package/plugin/skills/_shared/agent-delegation.md +1 -1
- package/plugin/skills/_shared/proactive-routing.md +3 -2
- package/plugin/skills/_shared/research-humanize.md +160 -0
- package/plugin/skills/research/SKILL.md +20 -2
- package/plugin/skills/research/references/design.md +14 -2
- package/plugin/skills/reverse-plan/SKILL.md +3 -1
- package/plugin/skills/ux-research/SKILL.md +3 -1
- package/plugin/skills/video-digest/SKILL.md +408 -0
- package/plugin/skills/video-digest/templates/background.md +15 -0
- package/plugin/skills/video-digest/templates/blog.md +16 -0
- package/plugin/skills/video-digest/templates/comments.md +19 -0
- package/plugin/skills/video-digest/templates/counterpoints.md +15 -0
- package/plugin/skills/video-digest/templates/flashcards.md +15 -0
- package/plugin/skills/video-digest/templates/interview.md +15 -0
- package/plugin/skills/video-digest/templates/meeting.md +15 -0
- package/plugin/skills/video-digest/templates/mindmap.md +16 -0
- package/plugin/skills/video-digest/templates/quiz.md +16 -0
- package/plugin/skills/video-digest/templates/quotes.md +16 -0
- package/plugin/skills/video-digest/templates/resources.md +14 -0
- package/plugin/skills/video-digest/templates/timestamps.md +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/digest/schema.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BnC,CAAC;AAEH,QAAA,MAAM,kBAAkB;;;;;;;;YA5BtB,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiCnC,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ValidationError } from '../core/errors.js';
|
|
3
|
+
import { err, ok } from '../core/result.js';
|
|
4
|
+
import { citeSchema, idSchema, LANG_TAG_PATTERN, sentenceIndex, SLUG_PATTERN, textSchema, } from './schema-base.js';
|
|
5
|
+
import { extensionSchema, mindmapNodeSchema } from './blocks.js';
|
|
6
|
+
export { citeSchema, LANG_TAG_PATTERN };
|
|
7
|
+
export const DIGEST_SCHEMA_VERSION = '1.3.0';
|
|
8
|
+
export const TRANSCRIPT_SCHEMA_VERSION = '1.0.0';
|
|
9
|
+
export const CAPTION_SOURCES = ['manual', 'auto', 'whisper'];
|
|
10
|
+
export const VIDEO_SOURCES = ['youtube', 'file'];
|
|
11
|
+
/**
|
|
12
|
+
* 본문 문장 안에서 렌더러가 해석하는 마커는 이 둘뿐이다.
|
|
13
|
+
* lint, 렌더, 윤문이 같은 정규식을 써야 서로 다른 걸 마커로 보지 않는다.
|
|
14
|
+
* 전역 플래그라 lastIndex가 남으니 쓸 때마다 새로 만든다.
|
|
15
|
+
*/
|
|
16
|
+
export const boldPattern = () => /\*\*(.+?)\*\*/g;
|
|
17
|
+
export const keywordPattern = () => /\{\{kw:([A-Za-z0-9][A-Za-z0-9_-]*)\|([^}]+)\}\}/g;
|
|
18
|
+
export const segmentSchema = z.object({
|
|
19
|
+
i: sentenceIndex,
|
|
20
|
+
startSec: z.number().nonnegative(),
|
|
21
|
+
text: textSchema,
|
|
22
|
+
speaker: z.string().optional(),
|
|
23
|
+
translation: z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
export const youtubeWatchUrl = (videoId) => `https://www.youtube.com/watch?v=${videoId}`;
|
|
26
|
+
/**
|
|
27
|
+
* url은 yt-dlp 인자와 뷰어 링크로 그대로 나간다. transcript.json을 손으로 고쳐도
|
|
28
|
+
* 옵션이나 javascript: 링크가 끼지 않게 ingest가 쓰는 꼴만 받는다
|
|
29
|
+
*/
|
|
30
|
+
export const videoMetaSchema = z
|
|
31
|
+
.object({
|
|
32
|
+
source: z.enum(VIDEO_SOURCES),
|
|
33
|
+
videoId: z
|
|
34
|
+
.string()
|
|
35
|
+
.regex(/^[A-Za-z0-9_-]{11}$/)
|
|
36
|
+
.optional(),
|
|
37
|
+
url: z.string().optional(),
|
|
38
|
+
title: textSchema,
|
|
39
|
+
channel: z.string().optional(),
|
|
40
|
+
durationSec: z.number().nonnegative(),
|
|
41
|
+
publishedAt: z.string().optional(),
|
|
42
|
+
lang: z.string().min(1),
|
|
43
|
+
/** segments[].translation의 언어. 뷰어 lang 속성으로 나간다 */
|
|
44
|
+
translationLang: z.string().regex(LANG_TAG_PATTERN).optional(),
|
|
45
|
+
captionSource: z.enum(CAPTION_SOURCES),
|
|
46
|
+
})
|
|
47
|
+
.superRefine((m, ctx) => {
|
|
48
|
+
if (m.source === 'youtube') {
|
|
49
|
+
if (!m.videoId) {
|
|
50
|
+
ctx.addIssue({
|
|
51
|
+
code: z.ZodIssueCode.custom,
|
|
52
|
+
path: ['videoId'],
|
|
53
|
+
message: '유튜브 영상은 videoId가 있어야 한다',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else if (m.url !== undefined && m.url !== youtubeWatchUrl(m.videoId)) {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: z.ZodIssueCode.custom,
|
|
59
|
+
path: ['url'],
|
|
60
|
+
message: `url은 ${youtubeWatchUrl(m.videoId)}여야 한다`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (!m.url?.startsWith('file:')) {
|
|
65
|
+
ctx.addIssue({
|
|
66
|
+
code: z.ZodIssueCode.custom,
|
|
67
|
+
path: ['url'],
|
|
68
|
+
message: '로컬 영상은 url이 file: 주소여야 한다',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
export const transcriptSchema = z
|
|
73
|
+
.object({
|
|
74
|
+
schemaVersion: z.string().default(TRANSCRIPT_SCHEMA_VERSION),
|
|
75
|
+
slug: z.string().regex(SLUG_PATTERN, 'slug는 영문 소문자, 숫자, -만 쓴다'),
|
|
76
|
+
meta: videoMetaSchema,
|
|
77
|
+
segments: z.array(segmentSchema).min(1),
|
|
78
|
+
})
|
|
79
|
+
.superRefine((t, ctx) => {
|
|
80
|
+
// Cite가 문장 번호로 배열을 바로 찾아가서 i가 자리 번호와 어긋나면 출처가 엇나간다
|
|
81
|
+
t.segments.forEach((s, idx) => {
|
|
82
|
+
if (s.i !== idx) {
|
|
83
|
+
ctx.addIssue({
|
|
84
|
+
code: z.ZodIssueCode.custom,
|
|
85
|
+
path: ['segments', idx, 'i'],
|
|
86
|
+
message: `i는 ${idx}여야 한다`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const prev = t.segments[idx - 1];
|
|
90
|
+
if (prev && s.startSec < prev.startSec) {
|
|
91
|
+
ctx.addIssue({
|
|
92
|
+
code: z.ZodIssueCode.custom,
|
|
93
|
+
path: ['segments', idx, 'startSec'],
|
|
94
|
+
message: '시작 시각이 앞 문장보다 이르다',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
// 3단 이상은 스키마가 아니라 lint가 잡는다. 어느 불릿이 깊은지 경로로 알려주려고
|
|
100
|
+
export const bulletSchema = z.lazy(() => z.object({
|
|
101
|
+
text: textSchema,
|
|
102
|
+
cite: citeSchema,
|
|
103
|
+
children: z.array(bulletSchema).optional(),
|
|
104
|
+
}));
|
|
105
|
+
export const subsectionSchema = z.object({
|
|
106
|
+
id: idSchema,
|
|
107
|
+
title: textSchema,
|
|
108
|
+
cite: citeSchema,
|
|
109
|
+
frameSec: z.number().nonnegative(),
|
|
110
|
+
bullets: z.array(bulletSchema).min(1),
|
|
111
|
+
});
|
|
112
|
+
const diagramNodeSchema = z.object({ label: textSchema, cite: citeSchema.optional() });
|
|
113
|
+
const diagramCaption = textSchema.optional();
|
|
114
|
+
export const DIAGRAM_KINDS = ['flow', 'cycle', 'compare', 'tree'];
|
|
115
|
+
/**
|
|
116
|
+
* 대섹션 도식. 단계, 순환, 비교, 트리 중 하나의 구조만 받고 그림은 svg.ts가 그린다.
|
|
117
|
+
* 모델이 쓴 SVG를 그대로 실으면 스크립트나 외부 링크가 섞일 수 있어서 원문은 받지 않는다
|
|
118
|
+
*/
|
|
119
|
+
export const diagramSchema = z.discriminatedUnion('kind', [
|
|
120
|
+
z.object({
|
|
121
|
+
kind: z.literal('flow'),
|
|
122
|
+
caption: diagramCaption,
|
|
123
|
+
steps: z.array(diagramNodeSchema).min(2).max(8),
|
|
124
|
+
}),
|
|
125
|
+
z.object({
|
|
126
|
+
kind: z.literal('cycle'),
|
|
127
|
+
caption: diagramCaption,
|
|
128
|
+
steps: z.array(diagramNodeSchema).min(3).max(8),
|
|
129
|
+
}),
|
|
130
|
+
z.object({
|
|
131
|
+
kind: z.literal('compare'),
|
|
132
|
+
caption: diagramCaption,
|
|
133
|
+
columns: z
|
|
134
|
+
.array(z.object({ title: textSchema, items: z.array(diagramNodeSchema).min(1).max(6) }))
|
|
135
|
+
.min(2)
|
|
136
|
+
.max(4),
|
|
137
|
+
}),
|
|
138
|
+
z.object({ kind: z.literal('tree'), caption: diagramCaption, root: mindmapNodeSchema }),
|
|
139
|
+
]);
|
|
140
|
+
export const sectionSchema = z.object({
|
|
141
|
+
id: idSchema,
|
|
142
|
+
title: textSchema,
|
|
143
|
+
conclusion: textSchema,
|
|
144
|
+
cite: citeSchema,
|
|
145
|
+
subsections: z.array(subsectionSchema).min(1),
|
|
146
|
+
diagram: diagramSchema.optional(),
|
|
147
|
+
});
|
|
148
|
+
export const keywordSchema = z.object({
|
|
149
|
+
id: idSchema,
|
|
150
|
+
term: textSchema,
|
|
151
|
+
explanation: textSchema,
|
|
152
|
+
firstCite: citeSchema,
|
|
153
|
+
});
|
|
154
|
+
export const skippedSchema = z
|
|
155
|
+
.object({
|
|
156
|
+
from: sentenceIndex,
|
|
157
|
+
to: sentenceIndex,
|
|
158
|
+
reason: textSchema,
|
|
159
|
+
})
|
|
160
|
+
.refine((s) => s.from <= s.to, 'from이 to보다 크다');
|
|
161
|
+
export const REPORT_LENGTHS = ['short', 'default', 'long'];
|
|
162
|
+
export const REPORT_DIFFICULTIES = ['normal', 'easy'];
|
|
163
|
+
export const reportOptionsSchema = z.object({
|
|
164
|
+
length: z.enum(REPORT_LENGTHS).default('default'),
|
|
165
|
+
difficulty: z.enum(REPORT_DIFFICULTIES).default('normal'),
|
|
166
|
+
/** 요약한 구간. 영상 시각(초)으로 [시작, 끝)이다 */
|
|
167
|
+
// 리포트 키와 slice 파일 이름에 그대로 실려서 초 단위 정수만 받는다
|
|
168
|
+
range: z
|
|
169
|
+
.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()])
|
|
170
|
+
.refine(([from, to]) => from < to, '구간 시작이 끝보다 앞이어야 한다')
|
|
171
|
+
.optional(),
|
|
172
|
+
lang: z
|
|
173
|
+
.string()
|
|
174
|
+
.regex(LANG_TAG_PATTERN, '언어 태그(ko, en, pt-BR) 꼴이어야 한다')
|
|
175
|
+
// 리포트 키가 -로 이어 붙여서 끝이 구간(-r시작-끝)처럼 생긴 태그는 키 경계를 흐린다.
|
|
176
|
+
// 요청문 해시(p+8자)는 하위 태그 8자 상한에서 이미 막혀서 es-PA 같은 지역 태그까지 거절하지 않는다
|
|
177
|
+
.refine((v) => !/-r\d+-\d+$/i.test(v), '언어 태그 끝이 구간(-r숫자-숫자)처럼 생기면 안 된다')
|
|
178
|
+
.default('ko'),
|
|
179
|
+
prompt: z.string().trim().min(1).max(2000).optional(),
|
|
180
|
+
});
|
|
181
|
+
export const reportSchema = z.object({
|
|
182
|
+
options: reportOptionsSchema.default({}),
|
|
183
|
+
lead: z.object({
|
|
184
|
+
question: textSchema,
|
|
185
|
+
answer: textSchema,
|
|
186
|
+
takeaway: textSchema,
|
|
187
|
+
}),
|
|
188
|
+
sections: z.array(sectionSchema).min(1),
|
|
189
|
+
skipped: z.array(skippedSchema).default([]),
|
|
190
|
+
keywords: z.array(keywordSchema).default([]),
|
|
191
|
+
});
|
|
192
|
+
const digestObjectSchema = z.object({
|
|
193
|
+
schemaVersion: z.string().default(DIGEST_SCHEMA_VERSION),
|
|
194
|
+
slug: z.string().regex(SLUG_PATTERN, 'slug는 영문 소문자, 숫자, -만 쓴다'),
|
|
195
|
+
generatedAt: z.string().optional(),
|
|
196
|
+
reports: z.array(reportSchema).min(1),
|
|
197
|
+
/** 템플릿으로 만든 확장 리포트. 1.1.0 이하에는 없다 */
|
|
198
|
+
extensions: z.array(extensionSchema).default([]),
|
|
199
|
+
});
|
|
200
|
+
/**
|
|
201
|
+
* 1.0.0은 리포트 한 벌을 `report`에 뒀다. 읽을 때 `reports` 한 칸으로 옮겨서
|
|
202
|
+
* lint와 렌더가 한 꼴만 보게 한다. 저장할 때는 늘 `reports`로 쓴다
|
|
203
|
+
*/
|
|
204
|
+
export const digestSchema = z.preprocess((input) => {
|
|
205
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
206
|
+
return input;
|
|
207
|
+
const { report, ...rest } = input;
|
|
208
|
+
if (report === undefined || 'reports' in rest)
|
|
209
|
+
return input;
|
|
210
|
+
return { ...rest, reports: [report] };
|
|
211
|
+
}, digestObjectSchema);
|
|
212
|
+
function issuesOf(error) {
|
|
213
|
+
return error.issues.map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`);
|
|
214
|
+
}
|
|
215
|
+
export function parseTranscript(input) {
|
|
216
|
+
const parsed = transcriptSchema.safeParse(input);
|
|
217
|
+
if (parsed.success)
|
|
218
|
+
return ok(parsed.data);
|
|
219
|
+
const issues = issuesOf(parsed.error);
|
|
220
|
+
return err(new ValidationError(`transcript.json 형식 오류: ${issues.join('; ')}`, issues));
|
|
221
|
+
}
|
|
222
|
+
export function parseDigest(input) {
|
|
223
|
+
const parsed = digestSchema.safeParse(input);
|
|
224
|
+
if (parsed.success)
|
|
225
|
+
return ok(parsed.data);
|
|
226
|
+
const issues = issuesOf(parsed.error);
|
|
227
|
+
return err(new ValidationError(`digest.json 형식 오류: ${issues.join('; ')}`, issues));
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/digest/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const DEFAULT_DIGEST_PORT = 7893;
|
|
2
|
+
export type ByteRange = {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
} | 'none' | 'unsatisfiable';
|
|
6
|
+
/**
|
|
7
|
+
* Range 헤더에서 단일 바이트 구간만 받는다. 꼴이 틀렸거나 여러 구간이면 무시하고 전체를 내준다(RFC 9110 14.2)
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseByteRange(header: string | undefined, size: number): ByteRange;
|
|
10
|
+
export declare const DIGEST_CSP: string;
|
|
11
|
+
/** graph-viz는 7891, pr serve는 7892를 쓴다. 겹치지 않게 7893부터 찾는다 */
|
|
12
|
+
export declare function findDigestPort(start?: number, attempts?: number): Promise<number>;
|
|
13
|
+
/**
|
|
14
|
+
* `.gestalt/digest/` 아래 렌더 결과만 내주는 읽기 전용 서버.
|
|
15
|
+
* 뷰어가 유튜브 IFrame API를 쓰려면 file://이 아니라 http 출처가 있어야 해서 둔다.
|
|
16
|
+
*/
|
|
17
|
+
export declare class DigestServer {
|
|
18
|
+
private server;
|
|
19
|
+
private readonly root;
|
|
20
|
+
private readonly videoPaths;
|
|
21
|
+
constructor(root: string);
|
|
22
|
+
start(port: number): Promise<void>;
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
get port(): number | undefined;
|
|
25
|
+
private deny;
|
|
26
|
+
private handle;
|
|
27
|
+
/**
|
|
28
|
+
* 루트 밖에서 내주는 파일은 이것 하나다. transcript.json에 ingest가 적은 로컬 영상 경로만 따르고
|
|
29
|
+
* 요청 URL에서 경로를 받지 않는다. 영상 확장자가 아니면 그 경로도 내주지 않는다
|
|
30
|
+
*/
|
|
31
|
+
private serveVideo;
|
|
32
|
+
private videoPath;
|
|
33
|
+
private stream;
|
|
34
|
+
}
|
|
35
|
+
export declare function openInBrowser(url: string): Promise<void>;
|
|
36
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/digest/server.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAkBxC,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,eAAe,CAAC;AAElF;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAclF;AAID,eAAO,MAAM,UAAU,QAYX,CAAC;AAkBb,6DAA6D;AAC7D,wBAAsB,cAAc,CAAC,KAAK,SAAsB,EAAE,QAAQ,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhG;AAUD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+D;gBAE9E,IAAI,EAAE,MAAM;IAIxB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrB,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAG7B;IAED,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,MAAM;IAoCd;;;OAGG;IACH,OAAO,CAAC,UAAU;IAmClB,OAAO,CAAC,SAAS;IA2BjB,OAAO,CAAC,MAAM;CAWf;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9D"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { createReadStream, existsSync, realpathSync, statSync } from 'node:fs';
|
|
2
|
+
import { createServer as createNetServer } from 'node:net';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { extname, join, sep } from 'node:path';
|
|
5
|
+
import { pipeline } from 'node:stream';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { parseTranscript } from './schema.js';
|
|
8
|
+
import { isValidSlug, readRaw } from './store.js';
|
|
9
|
+
import { VIEWER_JS_SHA256 } from './viewer-js.js';
|
|
10
|
+
export const DEFAULT_DIGEST_PORT = 7893;
|
|
11
|
+
const MIME = {
|
|
12
|
+
'.html': 'text/html; charset=utf-8',
|
|
13
|
+
'.md': 'text/markdown; charset=utf-8',
|
|
14
|
+
'.jpg': 'image/jpeg',
|
|
15
|
+
'.jpeg': 'image/jpeg',
|
|
16
|
+
'.png': 'image/png',
|
|
17
|
+
};
|
|
18
|
+
const VIDEO_MIME = {
|
|
19
|
+
'.mp4': 'video/mp4',
|
|
20
|
+
'.m4v': 'video/mp4',
|
|
21
|
+
'.mov': 'video/quicktime',
|
|
22
|
+
'.webm': 'video/webm',
|
|
23
|
+
'.mkv': 'video/x-matroska',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Range 헤더에서 단일 바이트 구간만 받는다. 꼴이 틀렸거나 여러 구간이면 무시하고 전체를 내준다(RFC 9110 14.2)
|
|
27
|
+
*/
|
|
28
|
+
export function parseByteRange(header, size) {
|
|
29
|
+
const m = header ? /^bytes=(\d*)-(\d*)$/.exec(header.trim()) : null;
|
|
30
|
+
if (!m || (m[1] === '' && m[2] === ''))
|
|
31
|
+
return 'none';
|
|
32
|
+
if (m[1] === '') {
|
|
33
|
+
const suffix = Number(m[2]);
|
|
34
|
+
if (suffix === 0 || size === 0)
|
|
35
|
+
return 'unsatisfiable';
|
|
36
|
+
return { start: Math.max(0, size - suffix), end: size - 1 };
|
|
37
|
+
}
|
|
38
|
+
const start = Number(m[1]);
|
|
39
|
+
// 끝이 시작보다 앞이면 문법 오류라 무시한다. 끝을 size에 맞춰 자르기 전에 봐야 bytes=5-999 같은 정상 요청이 안 빠진다
|
|
40
|
+
if (m[2] !== '' && Number(m[2]) < start)
|
|
41
|
+
return 'none';
|
|
42
|
+
if (start >= size)
|
|
43
|
+
return 'unsatisfiable';
|
|
44
|
+
const end = m[2] === '' ? size - 1 : Math.min(Number(m[2]), size - 1);
|
|
45
|
+
return { start, end };
|
|
46
|
+
}
|
|
47
|
+
// 유튜브 IFrame API가 스크립트와 iframe을 함께 끌어와서 그 둘만 밖으로 연다.
|
|
48
|
+
// 렌더가 싣는 실행 스크립트는 VIEWER_JS 하나뿐이라 해시로 고정한다. 데이터 블록은 type이 JSON이라 실행되지 않는다
|
|
49
|
+
export const DIGEST_CSP = [
|
|
50
|
+
"default-src 'self'",
|
|
51
|
+
`script-src 'self' 'sha256-${VIEWER_JS_SHA256}' https://www.youtube.com https://s.ytimg.com`,
|
|
52
|
+
'frame-src https://www.youtube.com https://www.youtube-nocookie.com',
|
|
53
|
+
"img-src 'self' data: https://i.ytimg.com",
|
|
54
|
+
"media-src 'self'",
|
|
55
|
+
"style-src 'self' 'unsafe-inline'",
|
|
56
|
+
"connect-src 'self'",
|
|
57
|
+
"base-uri 'none'",
|
|
58
|
+
"form-action 'none'",
|
|
59
|
+
"object-src 'none'",
|
|
60
|
+
"frame-ancestors 'none'",
|
|
61
|
+
].join('; ');
|
|
62
|
+
const BASE_HEADERS = {
|
|
63
|
+
'X-Content-Type-Options': 'nosniff',
|
|
64
|
+
// referrer를 아예 안 보내면 유튜브 임베드가 153 오류로 막힌다
|
|
65
|
+
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
|
66
|
+
'Cache-Control': 'no-store',
|
|
67
|
+
};
|
|
68
|
+
function isPortAvailable(port) {
|
|
69
|
+
return new Promise((done) => {
|
|
70
|
+
const probe = createNetServer();
|
|
71
|
+
probe.once('error', () => done(false));
|
|
72
|
+
probe.once('listening', () => probe.close(() => done(true)));
|
|
73
|
+
probe.listen(port, '127.0.0.1');
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** graph-viz는 7891, pr serve는 7892를 쓴다. 겹치지 않게 7893부터 찾는다 */
|
|
77
|
+
export async function findDigestPort(start = DEFAULT_DIGEST_PORT, attempts = 20) {
|
|
78
|
+
for (let i = 0; i < attempts; i++) {
|
|
79
|
+
if (await isPortAvailable(start + i))
|
|
80
|
+
return start + i;
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`${start}부터 ${start + attempts - 1}까지 빈 포트가 없어요.`);
|
|
83
|
+
}
|
|
84
|
+
function safeDecode(raw) {
|
|
85
|
+
try {
|
|
86
|
+
return decodeURIComponent(raw);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `.gestalt/digest/` 아래 렌더 결과만 내주는 읽기 전용 서버.
|
|
94
|
+
* 뷰어가 유튜브 IFrame API를 쓰려면 file://이 아니라 http 출처가 있어야 해서 둔다.
|
|
95
|
+
*/
|
|
96
|
+
export class DigestServer {
|
|
97
|
+
server = null;
|
|
98
|
+
root;
|
|
99
|
+
// 영상은 Range 요청이 연달아 와서 transcript.json을 매번 파싱하지 않는다. 파일이 바뀌면 mtime으로 다시 읽는다
|
|
100
|
+
videoPaths = new Map();
|
|
101
|
+
constructor(root) {
|
|
102
|
+
this.root = realpathSync(root);
|
|
103
|
+
}
|
|
104
|
+
start(port) {
|
|
105
|
+
return new Promise((resolveStart, reject) => {
|
|
106
|
+
this.server = createServer((req, res) => {
|
|
107
|
+
try {
|
|
108
|
+
this.handle(req, res);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
process.stderr.write(`[digest] request failed: ${err.message}\n`);
|
|
112
|
+
if (!res.headersSent)
|
|
113
|
+
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
114
|
+
res.end('Internal Server Error');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
this.server.once('error', reject);
|
|
118
|
+
this.server.listen(port, '127.0.0.1', () => {
|
|
119
|
+
this.server.off('error', reject);
|
|
120
|
+
resolveStart();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
stop() {
|
|
125
|
+
return new Promise((done, reject) => {
|
|
126
|
+
if (!this.server)
|
|
127
|
+
return done();
|
|
128
|
+
this.server.close((err) => {
|
|
129
|
+
this.server = null;
|
|
130
|
+
if (err)
|
|
131
|
+
reject(err);
|
|
132
|
+
else
|
|
133
|
+
done();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
get port() {
|
|
138
|
+
const addr = this.server?.address();
|
|
139
|
+
return addr && typeof addr === 'object' ? addr.port : undefined;
|
|
140
|
+
}
|
|
141
|
+
deny(res, status, text, extra = {}) {
|
|
142
|
+
res.writeHead(status, {
|
|
143
|
+
...BASE_HEADERS,
|
|
144
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
145
|
+
...extra,
|
|
146
|
+
});
|
|
147
|
+
res.end(text);
|
|
148
|
+
}
|
|
149
|
+
handle(req, res) {
|
|
150
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
151
|
+
return this.deny(res, 405, 'Method Not Allowed', { Allow: 'GET, HEAD' });
|
|
152
|
+
}
|
|
153
|
+
// 127.0.0.1에만 바인딩해도 DNS 리바인딩이면 남의 이름으로 여기 닿는다
|
|
154
|
+
const host = (req.headers.host ?? '').split(':')[0];
|
|
155
|
+
if (host !== '127.0.0.1' && host !== 'localhost')
|
|
156
|
+
return this.deny(res, 403, 'Forbidden');
|
|
157
|
+
const decoded = safeDecode((req.url ?? '/').split('?')[0]);
|
|
158
|
+
if (decoded === null || decoded.includes('\0'))
|
|
159
|
+
return this.deny(res, 400, 'Bad Request');
|
|
160
|
+
const rel = decoded.endsWith('/') ? `${decoded}digest.html` : decoded;
|
|
161
|
+
const parts = rel.split('/');
|
|
162
|
+
if (parts.length === 3 && parts[0] === '' && parts[2] === 'video' && isValidSlug(parts[1])) {
|
|
163
|
+
return this.serveVideo(req, res, parts[1]);
|
|
164
|
+
}
|
|
165
|
+
const ext = extname(rel).toLowerCase();
|
|
166
|
+
// 받아 둔 영상(cache/)과 원본 JSON은 뷰어가 쓰지 않으니 내주지 않는다
|
|
167
|
+
if (!MIME[ext] || rel.split('/').includes('cache'))
|
|
168
|
+
return this.deny(res, 404, 'Not Found');
|
|
169
|
+
const target = join(this.root, rel);
|
|
170
|
+
if (!existsSync(target))
|
|
171
|
+
return this.deny(res, 404, 'Not Found');
|
|
172
|
+
// 심링크로 루트 밖을 가리키는 경우까지 막으려고 실제 경로로 비교한다
|
|
173
|
+
const real = realpathSync(target);
|
|
174
|
+
if (!real.startsWith(this.root + sep) || !statSync(real).isFile()) {
|
|
175
|
+
return this.deny(res, 404, 'Not Found');
|
|
176
|
+
}
|
|
177
|
+
res.writeHead(200, {
|
|
178
|
+
...BASE_HEADERS,
|
|
179
|
+
'Content-Type': MIME[ext],
|
|
180
|
+
...(ext === '.html' ? { 'Content-Security-Policy': DIGEST_CSP } : {}),
|
|
181
|
+
});
|
|
182
|
+
if (req.method === 'HEAD')
|
|
183
|
+
return void res.end();
|
|
184
|
+
this.stream(res, real);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 루트 밖에서 내주는 파일은 이것 하나다. transcript.json에 ingest가 적은 로컬 영상 경로만 따르고
|
|
188
|
+
* 요청 URL에서 경로를 받지 않는다. 영상 확장자가 아니면 그 경로도 내주지 않는다
|
|
189
|
+
*/
|
|
190
|
+
serveVideo(req, res, slug) {
|
|
191
|
+
const file = this.videoPath(slug);
|
|
192
|
+
if (!file)
|
|
193
|
+
return this.deny(res, 404, 'Not Found');
|
|
194
|
+
// 경로는 캐시해도 실제 파일 검사는 요청마다 한다. 그사이 심링크가 바뀌거나 파일이 지워질 수 있다
|
|
195
|
+
let real;
|
|
196
|
+
let stat;
|
|
197
|
+
try {
|
|
198
|
+
real = realpathSync(file);
|
|
199
|
+
stat = statSync(real);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return this.deny(res, 404, 'Not Found');
|
|
203
|
+
}
|
|
204
|
+
const type = VIDEO_MIME[extname(real).toLowerCase()];
|
|
205
|
+
if (!type || !stat.isFile())
|
|
206
|
+
return this.deny(res, 404, 'Not Found');
|
|
207
|
+
const range = parseByteRange(req.headers.range, stat.size);
|
|
208
|
+
if (range === 'unsatisfiable') {
|
|
209
|
+
return this.deny(res, 416, 'Range Not Satisfiable', {
|
|
210
|
+
'Content-Range': `bytes */${stat.size}`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const headers = { ...BASE_HEADERS, 'Content-Type': type, 'Accept-Ranges': 'bytes' };
|
|
214
|
+
if (range === 'none') {
|
|
215
|
+
res.writeHead(200, { ...headers, 'Content-Length': String(stat.size) });
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
res.writeHead(206, {
|
|
219
|
+
...headers,
|
|
220
|
+
'Content-Range': `bytes ${range.start}-${range.end}/${stat.size}`,
|
|
221
|
+
'Content-Length': String(range.end - range.start + 1),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (req.method === 'HEAD')
|
|
225
|
+
return void res.end();
|
|
226
|
+
this.stream(res, real, range === 'none' ? undefined : range);
|
|
227
|
+
}
|
|
228
|
+
videoPath(slug) {
|
|
229
|
+
const transcriptPath = join(this.root, slug, 'transcript.json');
|
|
230
|
+
let mtimeMs;
|
|
231
|
+
try {
|
|
232
|
+
mtimeMs = statSync(transcriptPath).mtimeMs;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
this.videoPaths.delete(slug);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
const hit = this.videoPaths.get(slug);
|
|
239
|
+
if (hit && hit.mtimeMs === mtimeMs)
|
|
240
|
+
return hit.file;
|
|
241
|
+
const raw = readRaw(transcriptPath);
|
|
242
|
+
const parsed = raw.kind === 'ok' ? parseTranscript(raw.value) : null;
|
|
243
|
+
const meta = parsed?.ok ? parsed.value.meta : null;
|
|
244
|
+
let file = null;
|
|
245
|
+
if (meta && meta.source === 'file' && meta.url) {
|
|
246
|
+
try {
|
|
247
|
+
file = fileURLToPath(meta.url);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
file = null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
this.videoPaths.set(slug, { mtimeMs, file });
|
|
254
|
+
return file;
|
|
255
|
+
}
|
|
256
|
+
stream(res, path, range) {
|
|
257
|
+
// 바깥 try/catch는 동기 구간만 잡는다. open 실패나 클라이언트 중단을 여기서 받지 않으면 serve 프로세스가 죽는다
|
|
258
|
+
pipeline(createReadStream(path, range), res, (err) => {
|
|
259
|
+
if (!err)
|
|
260
|
+
return;
|
|
261
|
+
// 클라이언트가 먼저 끊은 건 정상 흐름이라 로그를 남기지 않는다
|
|
262
|
+
if (err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
|
|
263
|
+
process.stderr.write(`[digest] stream failed: ${err.message}\n`);
|
|
264
|
+
}
|
|
265
|
+
res.destroy();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
export async function openInBrowser(url) {
|
|
270
|
+
try {
|
|
271
|
+
const { default: open } = await import('open');
|
|
272
|
+
await open(url);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
process.stderr.write(`[digest] 브라우저를 열지 못했어요: ${err.message}\n`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/digest/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Segment, Transcript } from './schema.js';
|
|
2
|
+
/** `90`, `1:30`, `1:02:03`을 초로 바꾼다. 꼴이 틀리면 null이다 */
|
|
3
|
+
export declare function parseTimeArg(value: string): number | null;
|
|
4
|
+
/** `1:30-5:00` 꼴 구간을 [시작, 끝) 초로 바꾼다 */
|
|
5
|
+
export declare function parseRangeArg(value: string): [number, number];
|
|
6
|
+
export interface TranscriptSlice {
|
|
7
|
+
slug: string;
|
|
8
|
+
range: [number, number];
|
|
9
|
+
/** 구간이 덮는 첫 문장과 끝 문장 번호 */
|
|
10
|
+
from: number;
|
|
11
|
+
to: number;
|
|
12
|
+
segments: Segment[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 구간 리포트가 읽을 문장만 잘라 낸다. 출처는 원래 스크립트의 문장 번호를 가리켜야 해서
|
|
16
|
+
* i를 다시 매기지 않는다. 그래서 transcript.json 꼴이 아니라 따로 저장한다
|
|
17
|
+
*/
|
|
18
|
+
export declare function sliceTranscript(transcript: Transcript, range: readonly [number, number]): TranscriptSlice;
|
|
19
|
+
export declare const sliceFileName: (range: readonly [number, number]) => string;
|
|
20
|
+
//# sourceMappingURL=slice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../../src/digest/slice.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQzD;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAY7D;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,eAAe,CAcjB;AAED,eAAO,MAAM,aAAa,GAAI,OAAO,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MACQ,CAAC"}
|