@s-hirano-ist/s-scripts 1.26.7 → 4.0.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.md +2 -0
- package/dist/chunk-5OXUZW2Q.js +590 -0
- package/dist/chunk-7PVU2Z32.js +71 -0
- package/dist/chunk-AJMTRCPJ.js +15 -0
- package/dist/chunk-AZF2R2BF.js +85 -0
- package/dist/chunk-F4J6JBR4.js +115 -0
- package/dist/chunk-HDYQV2Y2.js +58 -0
- package/dist/chunk-HIK7SX34.js +85 -0
- package/dist/chunk-IWNZQXDG.js +7660 -0
- package/dist/chunk-J4VLH4VA.js +267 -0
- package/dist/chunk-JZOR5GA2.js +42 -0
- package/dist/chunk-KKZP7ZF3.js +77 -0
- package/dist/chunk-N6TZF755.js +102 -0
- package/dist/chunk-S5WJ5VXW.js +85 -0
- package/dist/chunk-UXGLXHQ6.js +40 -0
- package/dist/cleanup-minio-images.js +115 -92
- package/dist/enrich-books.js +87 -78
- package/dist/fetch-articles.js +101 -90
- package/dist/fetch-books.js +147 -128
- package/dist/fetch-images.js +88 -72
- package/dist/fetch-notes.js +66 -54
- package/dist/find-duplicate-json-articles.js +100 -97
- package/dist/fix-book-frontmatter.js +111 -99
- package/dist/fix-image-formats.js +81 -65
- package/dist/ingest-articles.js +30 -249
- package/dist/ingest-books.js +61 -318
- package/dist/ingest-images.js +33 -184
- package/dist/ingest-notes.js +41 -171
- package/dist/rag/delete-collection.js +32 -22
- package/dist/rag/ingest.js +371 -92
- package/dist/rag/search.js +80 -76
- package/dist/reset-articles.js +57 -60
- package/dist/reset-books.js +57 -59
- package/dist/reset-images.js +57 -59
- package/dist/reset-notes.js +57 -59
- package/dist/revert-articles.js +53 -55
- package/dist/revert-books.js +53 -53
- package/dist/revert-images.js +53 -53
- package/dist/revert-notes.js +53 -53
- package/dist/s-content-format.js +103 -13
- package/dist/update-json-articles.js +101 -97
- package/dist/update-raw-articles.js +130 -130
- package/dist/validate-json-articles.js +129 -130
- package/package.json +14 -51
- package/dist/cleanup-minio-images.d.ts +0 -3
- package/dist/cleanup-minio-images.d.ts.map +0 -1
- package/dist/cleanup-minio-images.js.map +0 -1
- package/dist/enrich-books.d.ts +0 -3
- package/dist/enrich-books.d.ts.map +0 -1
- package/dist/enrich-books.js.map +0 -1
- package/dist/fetch-articles.d.ts +0 -3
- package/dist/fetch-articles.d.ts.map +0 -1
- package/dist/fetch-articles.js.map +0 -1
- package/dist/fetch-books.d.ts +0 -3
- package/dist/fetch-books.d.ts.map +0 -1
- package/dist/fetch-books.js.map +0 -1
- package/dist/fetch-images.d.ts +0 -3
- package/dist/fetch-images.d.ts.map +0 -1
- package/dist/fetch-images.js.map +0 -1
- package/dist/fetch-notes.d.ts +0 -3
- package/dist/fetch-notes.d.ts.map +0 -1
- package/dist/fetch-notes.js.map +0 -1
- package/dist/find-duplicate-json-articles.d.ts +0 -3
- package/dist/find-duplicate-json-articles.d.ts.map +0 -1
- package/dist/find-duplicate-json-articles.js.map +0 -1
- package/dist/fix-book-frontmatter.d.ts +0 -3
- package/dist/fix-book-frontmatter.d.ts.map +0 -1
- package/dist/fix-book-frontmatter.js.map +0 -1
- package/dist/fix-image-formats.d.ts +0 -3
- package/dist/fix-image-formats.d.ts.map +0 -1
- package/dist/fix-image-formats.js.map +0 -1
- package/dist/infrastructures/articles-command-repository.d.ts +0 -57
- package/dist/infrastructures/articles-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/articles-command-repository.js +0 -68
- package/dist/infrastructures/articles-command-repository.js.map +0 -1
- package/dist/infrastructures/books-command-repository.d.ts +0 -34
- package/dist/infrastructures/books-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/books-command-repository.js +0 -53
- package/dist/infrastructures/books-command-repository.js.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.d.ts +0 -9
- package/dist/infrastructures/cache-invalidation-client.d.ts.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.js +0 -21
- package/dist/infrastructures/cache-invalidation-client.js.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.test.d.ts +0 -2
- package/dist/infrastructures/cache-invalidation-client.test.d.ts.map +0 -1
- package/dist/infrastructures/cache-invalidation-client.test.js +0 -25
- package/dist/infrastructures/cache-invalidation-client.test.js.map +0 -1
- package/dist/infrastructures/images-command-repository.d.ts +0 -34
- package/dist/infrastructures/images-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/images-command-repository.js +0 -53
- package/dist/infrastructures/images-command-repository.js.map +0 -1
- package/dist/infrastructures/notes-command-repository.d.ts +0 -34
- package/dist/infrastructures/notes-command-repository.d.ts.map +0 -1
- package/dist/infrastructures/notes-command-repository.js +0 -53
- package/dist/infrastructures/notes-command-repository.js.map +0 -1
- package/dist/ingest-articles.d.ts +0 -3
- package/dist/ingest-articles.d.ts.map +0 -1
- package/dist/ingest-articles.js.map +0 -1
- package/dist/ingest-books.d.ts +0 -3
- package/dist/ingest-books.d.ts.map +0 -1
- package/dist/ingest-books.js.map +0 -1
- package/dist/ingest-images.d.ts +0 -3
- package/dist/ingest-images.d.ts.map +0 -1
- package/dist/ingest-images.js.map +0 -1
- package/dist/ingest-notes.d.ts +0 -3
- package/dist/ingest-notes.d.ts.map +0 -1
- package/dist/ingest-notes.js.map +0 -1
- package/dist/lib/glob-paths.d.ts +0 -6
- package/dist/lib/glob-paths.d.ts.map +0 -1
- package/dist/lib/glob-paths.js +0 -9
- package/dist/lib/glob-paths.js.map +0 -1
- package/dist/lib/glob-paths.test.d.ts +0 -2
- package/dist/lib/glob-paths.test.d.ts.map +0 -1
- package/dist/lib/glob-paths.test.js +0 -30
- package/dist/lib/glob-paths.test.js.map +0 -1
- package/dist/lib/html-charset.d.ts +0 -4
- package/dist/lib/html-charset.d.ts.map +0 -1
- package/dist/lib/html-charset.js +0 -33
- package/dist/lib/html-charset.js.map +0 -1
- package/dist/lib/html-charset.test.d.ts +0 -2
- package/dist/lib/html-charset.test.d.ts.map +0 -1
- package/dist/lib/html-charset.test.js +0 -27
- package/dist/lib/html-charset.test.js.map +0 -1
- package/dist/rag/delete-collection.d.ts +0 -3
- package/dist/rag/delete-collection.d.ts.map +0 -1
- package/dist/rag/delete-collection.js.map +0 -1
- package/dist/rag/ingest-config.d.ts +0 -8
- package/dist/rag/ingest-config.d.ts.map +0 -1
- package/dist/rag/ingest-config.js +0 -8
- package/dist/rag/ingest-config.js.map +0 -1
- package/dist/rag/ingest.d.ts +0 -3
- package/dist/rag/ingest.d.ts.map +0 -1
- package/dist/rag/ingest.js.map +0 -1
- package/dist/rag/search.d.ts +0 -3
- package/dist/rag/search.d.ts.map +0 -1
- package/dist/rag/search.js.map +0 -1
- package/dist/reset-articles.d.ts +0 -3
- package/dist/reset-articles.d.ts.map +0 -1
- package/dist/reset-articles.js.map +0 -1
- package/dist/reset-books.d.ts +0 -3
- package/dist/reset-books.d.ts.map +0 -1
- package/dist/reset-books.js.map +0 -1
- package/dist/reset-images.d.ts +0 -3
- package/dist/reset-images.d.ts.map +0 -1
- package/dist/reset-images.js.map +0 -1
- package/dist/reset-notes.d.ts +0 -3
- package/dist/reset-notes.d.ts.map +0 -1
- package/dist/reset-notes.js.map +0 -1
- package/dist/revert-articles.d.ts +0 -3
- package/dist/revert-articles.d.ts.map +0 -1
- package/dist/revert-articles.js.map +0 -1
- package/dist/revert-books.d.ts +0 -3
- package/dist/revert-books.d.ts.map +0 -1
- package/dist/revert-books.js.map +0 -1
- package/dist/revert-images.d.ts +0 -3
- package/dist/revert-images.d.ts.map +0 -1
- package/dist/revert-images.js.map +0 -1
- package/dist/revert-notes.d.ts +0 -3
- package/dist/revert-notes.d.ts.map +0 -1
- package/dist/revert-notes.js.map +0 -1
- package/dist/s-content-format-runner.d.ts +0 -10
- package/dist/s-content-format-runner.d.ts.map +0 -1
- package/dist/s-content-format-runner.js +0 -76
- package/dist/s-content-format-runner.js.map +0 -1
- package/dist/s-content-format.d.ts +0 -3
- package/dist/s-content-format.d.ts.map +0 -1
- package/dist/s-content-format.js.map +0 -1
- package/dist/s-content-format.test.d.ts +0 -2
- package/dist/s-content-format.test.d.ts.map +0 -1
- package/dist/s-content-format.test.js +0 -99
- package/dist/s-content-format.test.js.map +0 -1
- package/dist/update-json-articles.d.ts +0 -3
- package/dist/update-json-articles.d.ts.map +0 -1
- package/dist/update-json-articles.js.map +0 -1
- package/dist/update-raw-articles.d.ts +0 -3
- package/dist/update-raw-articles.d.ts.map +0 -1
- package/dist/update-raw-articles.js.map +0 -1
- package/dist/validate-json-articles.d.ts +0 -3
- package/dist/validate-json-articles.d.ts.map +0 -1
- package/dist/validate-json-articles.js.map +0 -1
|
@@ -1,117 +1,120 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/find-duplicate-json-articles.ts
|
|
2
5
|
import fs from "node:fs";
|
|
3
6
|
import { join } from "node:path";
|
|
4
7
|
function getAllJsonFiles(directory) {
|
|
5
|
-
|
|
6
|
-
.readdirSync(directory)
|
|
7
|
-
.filter((file) => file.endsWith(".json") && file !== ".DS_Store");
|
|
8
|
+
return fs.readdirSync(directory).filter((file) => file.endsWith(".json") && file !== ".DS_Store");
|
|
8
9
|
}
|
|
9
10
|
function readArticleFile(filePath) {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const fileContents = fs.readFileSync(filePath, "utf8");
|
|
12
|
+
return JSON.parse(fileContents);
|
|
12
13
|
}
|
|
13
14
|
function findDuplicateUrls() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
urlMap.set(item.url, [occurrence]);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
console.error(`エラー: ${fileName} の読み込みに失敗しました:`, error);
|
|
15
|
+
const articleDirectory = join(process.cwd(), "json", "article");
|
|
16
|
+
const jsonFiles = getAllJsonFiles(articleDirectory);
|
|
17
|
+
console.log(`\u691C\u7D22\u5BFE\u8C61\u306EJSON\u30D5\u30A1\u30A4\u30EB\u6570: ${jsonFiles.length}`);
|
|
18
|
+
console.log(`\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7: ${jsonFiles.join(", ")}
|
|
19
|
+
`);
|
|
20
|
+
const urlMap = /* @__PURE__ */ new Map();
|
|
21
|
+
let totalUrls = 0;
|
|
22
|
+
for (const fileName of jsonFiles) {
|
|
23
|
+
const filePath = join(articleDirectory, fileName);
|
|
24
|
+
try {
|
|
25
|
+
const articleFile = readArticleFile(filePath);
|
|
26
|
+
const category = articleFile.heading;
|
|
27
|
+
console.log(
|
|
28
|
+
`\u51E6\u7406\u4E2D: ${fileName} (\u30AB\u30C6\u30B4\u30EA: ${category}, \u8A18\u4E8B\u6570: ${articleFile.body.length})`
|
|
29
|
+
);
|
|
30
|
+
for (const item of articleFile.body) {
|
|
31
|
+
totalUrls++;
|
|
32
|
+
const occurrence = {
|
|
33
|
+
url: item.url,
|
|
34
|
+
title: item.title,
|
|
35
|
+
fileName,
|
|
36
|
+
category
|
|
37
|
+
};
|
|
38
|
+
if (urlMap.has(item.url)) {
|
|
39
|
+
urlMap.get(item.url)?.push(occurrence);
|
|
40
|
+
} else {
|
|
41
|
+
urlMap.set(item.url, [occurrence]);
|
|
47
42
|
}
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`\u30A8\u30E9\u30FC: ${fileName} \u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F:`, error);
|
|
48
46
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
}
|
|
48
|
+
console.log(`
|
|
49
|
+
\u5408\u8A08URL\u6570: ${totalUrls}`);
|
|
50
|
+
console.log(`\u30E6\u30CB\u30FC\u30AFURL\u6570: ${urlMap.size}`);
|
|
51
|
+
const duplicates = [];
|
|
52
|
+
for (const [url, occurrences] of urlMap.entries()) {
|
|
53
|
+
if (occurrences.length > 1) {
|
|
54
|
+
duplicates.push({
|
|
55
|
+
url,
|
|
56
|
+
occurrences
|
|
57
|
+
});
|
|
60
58
|
}
|
|
61
|
-
|
|
59
|
+
}
|
|
60
|
+
return duplicates;
|
|
62
61
|
}
|
|
63
62
|
function displayResults(duplicates) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
// サマリー統計
|
|
82
|
-
const totalDuplicateOccurrences = duplicates.reduce((sum, dup) => sum + dup.occurrences.length, 0);
|
|
83
|
-
const wastedEntries = totalDuplicateOccurrences - duplicates.length;
|
|
84
|
-
console.log("=== サマリー ===");
|
|
85
|
-
console.log(`重複により無駄になっているエントリ数: ${wastedEntries}`);
|
|
86
|
-
console.log(`最も多く重複しているURL: ${duplicates[0]?.occurrences.length || 0}回重複`);
|
|
87
|
-
// カテゴリ別の重複統計
|
|
88
|
-
const categoryStats = new Map();
|
|
89
|
-
duplicates.forEach((dup) => {
|
|
90
|
-
dup.occurrences.forEach((occ) => {
|
|
91
|
-
categoryStats.set(occ.category, (categoryStats.get(occ.category) || 0) + 1);
|
|
92
|
-
});
|
|
63
|
+
console.log("\n=== \u91CD\u8907URL\u691C\u51FA\u7D50\u679C ===");
|
|
64
|
+
console.log(`\u91CD\u8907URL\u6570: ${duplicates.length}
|
|
65
|
+
`);
|
|
66
|
+
if (duplicates.length === 0) {
|
|
67
|
+
console.log("\u91CD\u8907URL\u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF01");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
duplicates.sort((a, b) => b.occurrences.length - a.occurrences.length);
|
|
71
|
+
duplicates.forEach((duplicate, index) => {
|
|
72
|
+
console.log(`${index + 1}. URL: ${duplicate.url}`);
|
|
73
|
+
console.log(` \u91CD\u8907\u6570: ${duplicate.occurrences.length}\u56DE`);
|
|
74
|
+
duplicate.occurrences.forEach((occurrence, occIndex) => {
|
|
75
|
+
console.log(
|
|
76
|
+
` ${occIndex + 1}) [${occurrence.category}] ${occurrence.fileName}`
|
|
77
|
+
);
|
|
78
|
+
console.log(` \u30BF\u30A4\u30C8\u30EB: ${occurrence.title}`);
|
|
93
79
|
});
|
|
94
|
-
console.log("
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
80
|
+
console.log("");
|
|
81
|
+
});
|
|
82
|
+
const totalDuplicateOccurrences = duplicates.reduce(
|
|
83
|
+
(sum, dup) => sum + dup.occurrences.length,
|
|
84
|
+
0
|
|
85
|
+
);
|
|
86
|
+
const wastedEntries = totalDuplicateOccurrences - duplicates.length;
|
|
87
|
+
console.log("=== \u30B5\u30DE\u30EA\u30FC ===");
|
|
88
|
+
console.log(`\u91CD\u8907\u306B\u3088\u308A\u7121\u99C4\u306B\u306A\u3063\u3066\u3044\u308B\u30A8\u30F3\u30C8\u30EA\u6570: ${wastedEntries}`);
|
|
89
|
+
console.log(
|
|
90
|
+
`\u6700\u3082\u591A\u304F\u91CD\u8907\u3057\u3066\u3044\u308BURL: ${duplicates[0]?.occurrences.length || 0}\u56DE\u91CD\u8907`
|
|
91
|
+
);
|
|
92
|
+
const categoryStats = /* @__PURE__ */ new Map();
|
|
93
|
+
duplicates.forEach((dup) => {
|
|
94
|
+
dup.occurrences.forEach((occ) => {
|
|
95
|
+
categoryStats.set(
|
|
96
|
+
occ.category,
|
|
97
|
+
(categoryStats.get(occ.category) || 0) + 1
|
|
98
|
+
);
|
|
99
99
|
});
|
|
100
|
+
});
|
|
101
|
+
console.log("\n\u30AB\u30C6\u30B4\u30EA\u5225\u91CD\u8907\u7D71\u8A08:");
|
|
102
|
+
Array.from(categoryStats.entries()).toSorted((a, b) => b[1] - a[1]).forEach(([category, count]) => {
|
|
103
|
+
console.log(` ${category}: ${count}\u500B\u306E\u91CD\u8907\u30A8\u30F3\u30C8\u30EA`);
|
|
104
|
+
});
|
|
100
105
|
}
|
|
101
106
|
async function main() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
107
|
+
try {
|
|
108
|
+
console.log("json/article\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u5185\u306EURL\u91CD\u8907\u3092\u691C\u7D22\u4E2D...\n");
|
|
109
|
+
const duplicates = findDuplicateUrls();
|
|
110
|
+
displayResults(duplicates);
|
|
111
|
+
console.log("\n\u691C\u7D22\u5B8C\u4E86");
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
112
116
|
}
|
|
113
117
|
main().catch((error) => {
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
console.error(error);
|
|
119
|
+
process.exit(1);
|
|
116
120
|
});
|
|
117
|
-
//# sourceMappingURL=find-duplicate-json-articles.js.map
|
|
@@ -1,121 +1,133 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
parseMarkdownFrontmatter
|
|
5
|
+
} from "./chunk-HDYQV2Y2.js";
|
|
6
|
+
import {
|
|
7
|
+
globPaths
|
|
8
|
+
} from "./chunk-AJMTRCPJ.js";
|
|
9
|
+
import "./chunk-JZOR5GA2.js";
|
|
10
|
+
|
|
11
|
+
// src/fix-book-frontmatter.ts
|
|
3
12
|
import { dump } from "js-yaml";
|
|
4
13
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
14
|
import { basename, join } from "node:path";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"googleHref",
|
|
15
|
+
var REQUIRED_KEYS = [
|
|
16
|
+
"heading",
|
|
17
|
+
"title",
|
|
18
|
+
"draft",
|
|
19
|
+
"rating",
|
|
20
|
+
"tags",
|
|
21
|
+
"googleSubtitle",
|
|
22
|
+
"googleAuthors",
|
|
23
|
+
"googleDescription",
|
|
24
|
+
"googleImgSrc",
|
|
25
|
+
"googleHref"
|
|
18
26
|
];
|
|
19
|
-
|
|
27
|
+
var LEGACY_KEYS = ["googleTitle"];
|
|
20
28
|
function dumpFrontmatter(data) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
return dump(data, {
|
|
30
|
+
lineWidth: -1,
|
|
31
|
+
forceQuotes: false,
|
|
32
|
+
noRefs: true
|
|
33
|
+
});
|
|
26
34
|
}
|
|
27
35
|
function extractTitleFromContent(content) {
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
const match = /^# (.+)$/mu.exec(content);
|
|
37
|
+
return match ? match[1].trim() : null;
|
|
30
38
|
}
|
|
31
39
|
function buildFrontmatter(existing, isbn, title) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
googleHref: "googleHref" in existing ? existing.googleHref : null,
|
|
45
|
-
};
|
|
40
|
+
return {
|
|
41
|
+
heading: existing.heading ?? isbn,
|
|
42
|
+
title,
|
|
43
|
+
draft: existing.draft ?? false,
|
|
44
|
+
rating: "rating" in existing ? existing.rating : null,
|
|
45
|
+
tags: Array.isArray(existing.tags) ? existing.tags : [],
|
|
46
|
+
googleSubtitle: "googleSubtitle" in existing ? existing.googleSubtitle : null,
|
|
47
|
+
googleAuthors: Array.isArray(existing.googleAuthors) ? existing.googleAuthors : [],
|
|
48
|
+
googleDescription: "googleDescription" in existing ? existing.googleDescription : null,
|
|
49
|
+
googleImgSrc: "googleImgSrc" in existing ? existing.googleImgSrc : null,
|
|
50
|
+
googleHref: "googleHref" in existing ? existing.googleHref : null
|
|
51
|
+
};
|
|
46
52
|
}
|
|
47
53
|
function resolveTitle(existing, content, fileName) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return
|
|
54
|
+
const title = typeof existing.title === "string" ? existing.title : "";
|
|
55
|
+
if (title) {
|
|
56
|
+
return title;
|
|
57
|
+
}
|
|
58
|
+
const h1 = extractTitleFromContent(content);
|
|
59
|
+
if (!h1) {
|
|
60
|
+
console.error(
|
|
61
|
+
`\u26A0\uFE0F ${fileName}: title \u3082 H1 \u3082\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059\u3002`
|
|
62
|
+
);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return h1;
|
|
58
66
|
}
|
|
59
67
|
async function processFile(filePath, dryRun) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return "error";
|
|
75
|
-
}
|
|
76
|
-
const next = buildFrontmatter(existing, isbn, title);
|
|
77
|
-
const body = parsed.content.replace(/^\n+/u, "");
|
|
78
|
-
const newContent = `---\n${dumpFrontmatter(next)}---\n\n${body}`;
|
|
79
|
-
if (dryRun) {
|
|
80
|
-
console.log(`🔍 [dry-run] 修正予定: ${fileName}`);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
await writeFile(filePath, newContent, "utf8");
|
|
84
|
-
console.log(`✅ 修正完了: ${fileName} (${title})`);
|
|
85
|
-
}
|
|
86
|
-
return "fixed";
|
|
68
|
+
const fileName = basename(filePath);
|
|
69
|
+
const isbn = basename(filePath, ".md");
|
|
70
|
+
try {
|
|
71
|
+
const raw = await readFile(filePath, "utf8");
|
|
72
|
+
const parsed = parseMarkdownFrontmatter(raw);
|
|
73
|
+
const existing = parsed.data;
|
|
74
|
+
const hasAllKeys = REQUIRED_KEYS.every((k) => Object.hasOwn(existing, k));
|
|
75
|
+
const hasLegacyKeys = LEGACY_KEYS.some((k) => Object.hasOwn(existing, k));
|
|
76
|
+
if (hasAllKeys && !hasLegacyKeys) {
|
|
77
|
+
return "skipped";
|
|
78
|
+
}
|
|
79
|
+
const title = resolveTitle(existing, parsed.content, fileName);
|
|
80
|
+
if (title === null) {
|
|
81
|
+
return "error";
|
|
87
82
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
const next = buildFrontmatter(existing, isbn, title);
|
|
84
|
+
const body = parsed.content.replace(/^\n+/u, "");
|
|
85
|
+
const newContent = `---
|
|
86
|
+
${dumpFrontmatter(next)}---
|
|
87
|
+
|
|
88
|
+
${body}`;
|
|
89
|
+
if (dryRun) {
|
|
90
|
+
console.log(`\u{1F50D} [dry-run] \u4FEE\u6B63\u4E88\u5B9A: ${fileName}`);
|
|
91
|
+
} else {
|
|
92
|
+
await writeFile(filePath, newContent, "utf8");
|
|
93
|
+
console.log(`\u2705 \u4FEE\u6B63\u5B8C\u4E86: ${fileName} (${title})`);
|
|
91
94
|
}
|
|
95
|
+
return "fixed";
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`\u274C ${fileName}: ${String(error)}`);
|
|
98
|
+
return "error";
|
|
99
|
+
}
|
|
92
100
|
}
|
|
93
101
|
async function main() {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
103
|
+
const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
|
|
104
|
+
const bookDir = join(contentsPath, "markdown", "book");
|
|
105
|
+
console.log(
|
|
106
|
+
`markdown/book \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Efrontmatter\u3092\u691C\u8A3C\u4E2D...${dryRun ? " (dry-run)" : ""}
|
|
107
|
+
`
|
|
108
|
+
);
|
|
109
|
+
const files = await globPaths(`${bookDir}/*.md`);
|
|
110
|
+
console.log(`\u691C\u51FA\u30D5\u30A1\u30A4\u30EB\u6570: ${files.length}
|
|
111
|
+
`);
|
|
112
|
+
let fixedCount = 0;
|
|
113
|
+
let skippedCount = 0;
|
|
114
|
+
let errorCount = 0;
|
|
115
|
+
for (const filePath of files) {
|
|
116
|
+
const result = await processFile(filePath, dryRun);
|
|
117
|
+
if (result === "fixed") {
|
|
118
|
+
fixedCount++;
|
|
119
|
+
} else if (result === "skipped") {
|
|
120
|
+
skippedCount++;
|
|
121
|
+
} else {
|
|
122
|
+
errorCount++;
|
|
114
123
|
}
|
|
115
|
-
|
|
124
|
+
}
|
|
125
|
+
console.log(
|
|
126
|
+
`
|
|
127
|
+
\u{1F4CA} \u7D50\u679C: \u4FEE\u6B63 ${fixedCount} \u4EF6, \u30B9\u30AD\u30C3\u30D7 ${skippedCount} \u4EF6, \u30A8\u30E9\u30FC ${errorCount} \u4EF6${dryRun ? " (dry-run)" : ""}`
|
|
128
|
+
);
|
|
116
129
|
}
|
|
117
130
|
main().catch((error) => {
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
|
|
132
|
+
process.exit(1);
|
|
120
133
|
});
|
|
121
|
-
//# sourceMappingURL=fix-book-frontmatter.js.map
|
|
@@ -1,80 +1,96 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
convertToWebp
|
|
5
|
+
} from "./chunk-KKZP7ZF3.js";
|
|
6
|
+
import {
|
|
7
|
+
globPaths
|
|
8
|
+
} from "./chunk-AJMTRCPJ.js";
|
|
9
|
+
import "./chunk-JZOR5GA2.js";
|
|
10
|
+
|
|
11
|
+
// src/fix-image-formats.ts
|
|
3
12
|
import { readFile, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
13
|
import { basename, extname, join } from "node:path";
|
|
5
|
-
|
|
6
|
-
const WEBP_QUALITY = 80;
|
|
14
|
+
var WEBP_QUALITY = 80;
|
|
7
15
|
function isConvertibleImage(filePath) {
|
|
8
|
-
|
|
9
|
-
|
|
16
|
+
const ext = extname(filePath).toLowerCase();
|
|
17
|
+
return [".jpg", ".jpeg", ".png"].includes(ext);
|
|
10
18
|
}
|
|
11
19
|
function getWebpOutputPath(filePath) {
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
const ext = extname(filePath);
|
|
21
|
+
return `${filePath.slice(0, -ext.length)}.webp`;
|
|
14
22
|
}
|
|
15
|
-
async function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
async function convertToWebp2(inputPath, outputPath) {
|
|
24
|
+
const inputBytes = await readFile(inputPath);
|
|
25
|
+
const outputBytes = await convertToWebp(inputBytes, {
|
|
26
|
+
quality: WEBP_QUALITY
|
|
27
|
+
});
|
|
28
|
+
await writeFile(outputPath, outputBytes);
|
|
21
29
|
}
|
|
22
30
|
async function processDirectory(directory, label, dryRun) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
31
|
+
const files = await globPaths(`${directory}/*`);
|
|
32
|
+
const convertible = files.filter((filePath) => isConvertibleImage(filePath));
|
|
33
|
+
console.log(
|
|
34
|
+
`
|
|
35
|
+
\u{1F4C1} ${label}: ${convertible.length} \u4EF6\u306E\u5909\u63DB\u5BFE\u8C61\u3092\u691C\u51FA\uFF08\u5168 ${files.length} \u30D5\u30A1\u30A4\u30EB\u4E2D\uFF09`
|
|
36
|
+
);
|
|
37
|
+
let converted = 0;
|
|
38
|
+
let skipped = 0;
|
|
39
|
+
let errors = 0;
|
|
40
|
+
for (const filePath of convertible) {
|
|
41
|
+
const fileName = basename(filePath);
|
|
42
|
+
const outputPath = getWebpOutputPath(filePath);
|
|
43
|
+
try {
|
|
44
|
+
try {
|
|
45
|
+
await stat(outputPath);
|
|
46
|
+
console.log(`\u23ED\uFE0F \u30B9\u30AD\u30C3\u30D7\uFF08WebP\u65E2\u5B58\uFF09: ${fileName}`);
|
|
47
|
+
skipped++;
|
|
48
|
+
continue;
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
if (dryRun) {
|
|
52
|
+
console.log(
|
|
53
|
+
`\u{1F50D} [dry-run] \u5909\u63DB\u4E88\u5B9A: ${fileName} \u2192 ${basename(outputPath)}`
|
|
54
|
+
);
|
|
55
|
+
converted++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
await convertToWebp2(filePath, outputPath);
|
|
59
|
+
const outputStat = await stat(outputPath);
|
|
60
|
+
if (outputStat.size === 0) {
|
|
61
|
+
throw new Error("\u5909\u63DB\u5F8C\u306E\u30D5\u30A1\u30A4\u30EB\u30B5\u30A4\u30BA\u304C0\u3067\u3059");
|
|
62
|
+
}
|
|
63
|
+
await unlink(filePath);
|
|
64
|
+
console.log(`\u2705 \u5909\u63DB\u5B8C\u4E86: ${fileName} \u2192 ${basename(outputPath)}`);
|
|
65
|
+
converted++;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`\u274C ${fileName}: ${String(error)}`);
|
|
68
|
+
errors++;
|
|
62
69
|
}
|
|
63
|
-
|
|
70
|
+
}
|
|
71
|
+
return { converted, skipped, errors };
|
|
64
72
|
}
|
|
65
73
|
async function main() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
const dryRun = process.argv.includes("--dry-run");
|
|
75
|
+
const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
|
|
76
|
+
console.log(
|
|
77
|
+
`\u66F8\u7C4D\u753B\u50CF\u3092WebP\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u306B\u5909\u63DB\u4E2D...${dryRun ? " (dry-run)" : ""}`
|
|
78
|
+
);
|
|
79
|
+
const bookDir = join(contentsPath, "image", "book");
|
|
80
|
+
const { converted, skipped, errors } = await processDirectory(
|
|
81
|
+
bookDir,
|
|
82
|
+
"image/book",
|
|
83
|
+
dryRun
|
|
84
|
+
);
|
|
85
|
+
console.log(
|
|
86
|
+
`
|
|
87
|
+
\u{1F4CA} \u5408\u8A08: \u5909\u63DB ${converted} \u4EF6, \u30B9\u30AD\u30C3\u30D7 ${skipped} \u4EF6, \u30A8\u30E9\u30FC ${errors} \u4EF6${dryRun ? " (dry-run)" : ""}`
|
|
88
|
+
);
|
|
89
|
+
if (errors > 0) {
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
75
92
|
}
|
|
76
93
|
main().catch((error) => {
|
|
77
|
-
|
|
78
|
-
|
|
94
|
+
console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
|
|
95
|
+
process.exit(1);
|
|
79
96
|
});
|
|
80
|
-
//# sourceMappingURL=fix-image-formats.js.map
|