@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.
Files changed (180) hide show
  1. package/README.md +2 -0
  2. package/dist/chunk-5OXUZW2Q.js +590 -0
  3. package/dist/chunk-7PVU2Z32.js +71 -0
  4. package/dist/chunk-AJMTRCPJ.js +15 -0
  5. package/dist/chunk-AZF2R2BF.js +85 -0
  6. package/dist/chunk-F4J6JBR4.js +115 -0
  7. package/dist/chunk-HDYQV2Y2.js +58 -0
  8. package/dist/chunk-HIK7SX34.js +85 -0
  9. package/dist/chunk-IWNZQXDG.js +7660 -0
  10. package/dist/chunk-J4VLH4VA.js +267 -0
  11. package/dist/chunk-JZOR5GA2.js +42 -0
  12. package/dist/chunk-KKZP7ZF3.js +77 -0
  13. package/dist/chunk-N6TZF755.js +102 -0
  14. package/dist/chunk-S5WJ5VXW.js +85 -0
  15. package/dist/chunk-UXGLXHQ6.js +40 -0
  16. package/dist/cleanup-minio-images.js +115 -92
  17. package/dist/enrich-books.js +87 -78
  18. package/dist/fetch-articles.js +101 -90
  19. package/dist/fetch-books.js +147 -128
  20. package/dist/fetch-images.js +88 -72
  21. package/dist/fetch-notes.js +66 -54
  22. package/dist/find-duplicate-json-articles.js +100 -97
  23. package/dist/fix-book-frontmatter.js +111 -99
  24. package/dist/fix-image-formats.js +81 -65
  25. package/dist/ingest-articles.js +30 -249
  26. package/dist/ingest-books.js +61 -318
  27. package/dist/ingest-images.js +33 -184
  28. package/dist/ingest-notes.js +41 -171
  29. package/dist/rag/delete-collection.js +32 -22
  30. package/dist/rag/ingest.js +371 -92
  31. package/dist/rag/search.js +80 -76
  32. package/dist/reset-articles.js +57 -60
  33. package/dist/reset-books.js +57 -59
  34. package/dist/reset-images.js +57 -59
  35. package/dist/reset-notes.js +57 -59
  36. package/dist/revert-articles.js +53 -55
  37. package/dist/revert-books.js +53 -53
  38. package/dist/revert-images.js +53 -53
  39. package/dist/revert-notes.js +53 -53
  40. package/dist/s-content-format.js +103 -13
  41. package/dist/update-json-articles.js +101 -97
  42. package/dist/update-raw-articles.js +130 -130
  43. package/dist/validate-json-articles.js +129 -130
  44. package/package.json +14 -51
  45. package/dist/cleanup-minio-images.d.ts +0 -3
  46. package/dist/cleanup-minio-images.d.ts.map +0 -1
  47. package/dist/cleanup-minio-images.js.map +0 -1
  48. package/dist/enrich-books.d.ts +0 -3
  49. package/dist/enrich-books.d.ts.map +0 -1
  50. package/dist/enrich-books.js.map +0 -1
  51. package/dist/fetch-articles.d.ts +0 -3
  52. package/dist/fetch-articles.d.ts.map +0 -1
  53. package/dist/fetch-articles.js.map +0 -1
  54. package/dist/fetch-books.d.ts +0 -3
  55. package/dist/fetch-books.d.ts.map +0 -1
  56. package/dist/fetch-books.js.map +0 -1
  57. package/dist/fetch-images.d.ts +0 -3
  58. package/dist/fetch-images.d.ts.map +0 -1
  59. package/dist/fetch-images.js.map +0 -1
  60. package/dist/fetch-notes.d.ts +0 -3
  61. package/dist/fetch-notes.d.ts.map +0 -1
  62. package/dist/fetch-notes.js.map +0 -1
  63. package/dist/find-duplicate-json-articles.d.ts +0 -3
  64. package/dist/find-duplicate-json-articles.d.ts.map +0 -1
  65. package/dist/find-duplicate-json-articles.js.map +0 -1
  66. package/dist/fix-book-frontmatter.d.ts +0 -3
  67. package/dist/fix-book-frontmatter.d.ts.map +0 -1
  68. package/dist/fix-book-frontmatter.js.map +0 -1
  69. package/dist/fix-image-formats.d.ts +0 -3
  70. package/dist/fix-image-formats.d.ts.map +0 -1
  71. package/dist/fix-image-formats.js.map +0 -1
  72. package/dist/infrastructures/articles-command-repository.d.ts +0 -57
  73. package/dist/infrastructures/articles-command-repository.d.ts.map +0 -1
  74. package/dist/infrastructures/articles-command-repository.js +0 -68
  75. package/dist/infrastructures/articles-command-repository.js.map +0 -1
  76. package/dist/infrastructures/books-command-repository.d.ts +0 -34
  77. package/dist/infrastructures/books-command-repository.d.ts.map +0 -1
  78. package/dist/infrastructures/books-command-repository.js +0 -53
  79. package/dist/infrastructures/books-command-repository.js.map +0 -1
  80. package/dist/infrastructures/cache-invalidation-client.d.ts +0 -9
  81. package/dist/infrastructures/cache-invalidation-client.d.ts.map +0 -1
  82. package/dist/infrastructures/cache-invalidation-client.js +0 -21
  83. package/dist/infrastructures/cache-invalidation-client.js.map +0 -1
  84. package/dist/infrastructures/cache-invalidation-client.test.d.ts +0 -2
  85. package/dist/infrastructures/cache-invalidation-client.test.d.ts.map +0 -1
  86. package/dist/infrastructures/cache-invalidation-client.test.js +0 -25
  87. package/dist/infrastructures/cache-invalidation-client.test.js.map +0 -1
  88. package/dist/infrastructures/images-command-repository.d.ts +0 -34
  89. package/dist/infrastructures/images-command-repository.d.ts.map +0 -1
  90. package/dist/infrastructures/images-command-repository.js +0 -53
  91. package/dist/infrastructures/images-command-repository.js.map +0 -1
  92. package/dist/infrastructures/notes-command-repository.d.ts +0 -34
  93. package/dist/infrastructures/notes-command-repository.d.ts.map +0 -1
  94. package/dist/infrastructures/notes-command-repository.js +0 -53
  95. package/dist/infrastructures/notes-command-repository.js.map +0 -1
  96. package/dist/ingest-articles.d.ts +0 -3
  97. package/dist/ingest-articles.d.ts.map +0 -1
  98. package/dist/ingest-articles.js.map +0 -1
  99. package/dist/ingest-books.d.ts +0 -3
  100. package/dist/ingest-books.d.ts.map +0 -1
  101. package/dist/ingest-books.js.map +0 -1
  102. package/dist/ingest-images.d.ts +0 -3
  103. package/dist/ingest-images.d.ts.map +0 -1
  104. package/dist/ingest-images.js.map +0 -1
  105. package/dist/ingest-notes.d.ts +0 -3
  106. package/dist/ingest-notes.d.ts.map +0 -1
  107. package/dist/ingest-notes.js.map +0 -1
  108. package/dist/lib/glob-paths.d.ts +0 -6
  109. package/dist/lib/glob-paths.d.ts.map +0 -1
  110. package/dist/lib/glob-paths.js +0 -9
  111. package/dist/lib/glob-paths.js.map +0 -1
  112. package/dist/lib/glob-paths.test.d.ts +0 -2
  113. package/dist/lib/glob-paths.test.d.ts.map +0 -1
  114. package/dist/lib/glob-paths.test.js +0 -30
  115. package/dist/lib/glob-paths.test.js.map +0 -1
  116. package/dist/lib/html-charset.d.ts +0 -4
  117. package/dist/lib/html-charset.d.ts.map +0 -1
  118. package/dist/lib/html-charset.js +0 -33
  119. package/dist/lib/html-charset.js.map +0 -1
  120. package/dist/lib/html-charset.test.d.ts +0 -2
  121. package/dist/lib/html-charset.test.d.ts.map +0 -1
  122. package/dist/lib/html-charset.test.js +0 -27
  123. package/dist/lib/html-charset.test.js.map +0 -1
  124. package/dist/rag/delete-collection.d.ts +0 -3
  125. package/dist/rag/delete-collection.d.ts.map +0 -1
  126. package/dist/rag/delete-collection.js.map +0 -1
  127. package/dist/rag/ingest-config.d.ts +0 -8
  128. package/dist/rag/ingest-config.d.ts.map +0 -1
  129. package/dist/rag/ingest-config.js +0 -8
  130. package/dist/rag/ingest-config.js.map +0 -1
  131. package/dist/rag/ingest.d.ts +0 -3
  132. package/dist/rag/ingest.d.ts.map +0 -1
  133. package/dist/rag/ingest.js.map +0 -1
  134. package/dist/rag/search.d.ts +0 -3
  135. package/dist/rag/search.d.ts.map +0 -1
  136. package/dist/rag/search.js.map +0 -1
  137. package/dist/reset-articles.d.ts +0 -3
  138. package/dist/reset-articles.d.ts.map +0 -1
  139. package/dist/reset-articles.js.map +0 -1
  140. package/dist/reset-books.d.ts +0 -3
  141. package/dist/reset-books.d.ts.map +0 -1
  142. package/dist/reset-books.js.map +0 -1
  143. package/dist/reset-images.d.ts +0 -3
  144. package/dist/reset-images.d.ts.map +0 -1
  145. package/dist/reset-images.js.map +0 -1
  146. package/dist/reset-notes.d.ts +0 -3
  147. package/dist/reset-notes.d.ts.map +0 -1
  148. package/dist/reset-notes.js.map +0 -1
  149. package/dist/revert-articles.d.ts +0 -3
  150. package/dist/revert-articles.d.ts.map +0 -1
  151. package/dist/revert-articles.js.map +0 -1
  152. package/dist/revert-books.d.ts +0 -3
  153. package/dist/revert-books.d.ts.map +0 -1
  154. package/dist/revert-books.js.map +0 -1
  155. package/dist/revert-images.d.ts +0 -3
  156. package/dist/revert-images.d.ts.map +0 -1
  157. package/dist/revert-images.js.map +0 -1
  158. package/dist/revert-notes.d.ts +0 -3
  159. package/dist/revert-notes.d.ts.map +0 -1
  160. package/dist/revert-notes.js.map +0 -1
  161. package/dist/s-content-format-runner.d.ts +0 -10
  162. package/dist/s-content-format-runner.d.ts.map +0 -1
  163. package/dist/s-content-format-runner.js +0 -76
  164. package/dist/s-content-format-runner.js.map +0 -1
  165. package/dist/s-content-format.d.ts +0 -3
  166. package/dist/s-content-format.d.ts.map +0 -1
  167. package/dist/s-content-format.js.map +0 -1
  168. package/dist/s-content-format.test.d.ts +0 -2
  169. package/dist/s-content-format.test.d.ts.map +0 -1
  170. package/dist/s-content-format.test.js +0 -99
  171. package/dist/s-content-format.test.js.map +0 -1
  172. package/dist/update-json-articles.d.ts +0 -3
  173. package/dist/update-json-articles.d.ts.map +0 -1
  174. package/dist/update-json-articles.js.map +0 -1
  175. package/dist/update-raw-articles.d.ts +0 -3
  176. package/dist/update-raw-articles.d.ts.map +0 -1
  177. package/dist/update-raw-articles.js.map +0 -1
  178. package/dist/validate-json-articles.d.ts +0 -3
  179. package/dist/validate-json-articles.d.ts.map +0 -1
  180. package/dist/validate-json-articles.js.map +0 -1
@@ -1,105 +1,128 @@
1
1
  #!/usr/bin/env node
2
- import { createPushoverService } from "@s-hirano-ist/s-notification";
3
- import { createMinioClient } from "@s-hirano-ist/s-storage";
2
+ import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
3
+ import {
4
+ createMinioClient
5
+ } from "./chunk-F4J6JBR4.js";
6
+ import {
7
+ createPushoverService
8
+ } from "./chunk-7PVU2Z32.js";
9
+ import {
10
+ globPaths
11
+ } from "./chunk-AJMTRCPJ.js";
12
+ import "./chunk-JZOR5GA2.js";
13
+
14
+ // src/cleanup-minio-images.ts
4
15
  import { basename, extname } from "node:path";
5
- import { globPaths } from "./lib/glob-paths.js";
6
- const SCRIPT_NAME = "cleanup-minio-images";
7
- const ORIGINAL_IMAGE_PATH = "images/original";
8
- const THUMBNAIL_IMAGE_PATH = "images/thumbnail";
16
+ var SCRIPT_NAME = "cleanup-minio-images";
17
+ var ORIGINAL_IMAGE_PATH = "images/original";
18
+ var THUMBNAIL_IMAGE_PATH = "images/thumbnail";
9
19
  function isImageFile(filePath) {
10
- const ext = extname(filePath).toLowerCase();
11
- return [".jpg", ".jpeg", ".png", ".webp"].includes(ext);
20
+ const ext = extname(filePath).toLowerCase();
21
+ return [".jpg", ".jpeg", ".png", ".webp"].includes(ext);
12
22
  }
13
23
  function listObjects(client, bucket, prefix) {
14
- const { promise, resolve, reject } = Promise.withResolvers();
15
- const keys = [];
16
- const stream = client.listObjectsV2(bucket, prefix, true);
17
- stream.on("data", (obj) => {
18
- if (obj.name)
19
- keys.push(obj.name);
20
- });
21
- stream.on("end", () => resolve(keys));
22
- stream.on("error", reject);
23
- return promise;
24
+ const { promise, resolve, reject } = Promise.withResolvers();
25
+ const keys = [];
26
+ const stream = client.listObjectsV2(bucket, prefix, true);
27
+ stream.on("data", (obj) => {
28
+ if (obj.name) keys.push(obj.name);
29
+ });
30
+ stream.on("end", () => resolve(keys));
31
+ stream.on("error", reject);
32
+ return promise;
24
33
  }
25
34
  async function main() {
26
- const dryRun = process.argv.includes("--dry-run");
27
- const env = {
28
- PUSHOVER_URL: process.env.PUSHOVER_URL,
29
- PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
30
- PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
31
- MINIO_BUCKET_NAME: process.env.MINIO_BUCKET_NAME,
32
- };
33
- if (Object.values(env).some((v) => !v)) {
34
- throw new Error("Required environment variables are not set.");
35
- }
36
- if (process.env.MINIO_USE_SSL === "true" &&
37
- (!process.env.CF_ACCESS_CLIENT_ID || !process.env.CF_ACCESS_CLIENT_SECRET)) {
38
- throw new Error("CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET are required when MINIO_USE_SSL is true.");
35
+ const dryRun = process.argv.includes("--dry-run");
36
+ const env = {
37
+ PUSHOVER_URL: process.env.PUSHOVER_URL,
38
+ PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
39
+ PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
40
+ MINIO_BUCKET_NAME: process.env.MINIO_BUCKET_NAME
41
+ };
42
+ if (Object.values(env).some((v) => !v)) {
43
+ throw new Error("Required environment variables are not set.");
44
+ }
45
+ if (process.env.MINIO_USE_SSL === "true" && (!process.env.CF_ACCESS_CLIENT_ID || !process.env.CF_ACCESS_CLIENT_SECRET)) {
46
+ throw new Error(
47
+ "CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET are required when MINIO_USE_SSL is true."
48
+ );
49
+ }
50
+ const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
51
+ const notificationService = createPushoverService({
52
+ url: env.PUSHOVER_URL ?? "",
53
+ userKey: env.PUSHOVER_USER_KEY ?? "",
54
+ appToken: env.PUSHOVER_APP_TOKEN ?? ""
55
+ });
56
+ const minioClient = createMinioClient();
57
+ const bucketName = env.MINIO_BUCKET_NAME ?? "";
58
+ try {
59
+ const localFiles = await globPaths(`${contentsPath}/image/dump/*`);
60
+ const localFileNames = new Set(
61
+ localFiles.filter((f) => isImageFile(f)).map((f) => basename(f))
62
+ );
63
+ console.log(
64
+ `\u{1F4C1} \u30ED\u30FC\u30AB\u30EB\u306B ${localFileNames.size} \u4EF6\u306E\u753B\u50CF\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002`
65
+ );
66
+ const [originalKeys, thumbnailKeys] = await Promise.all([
67
+ listObjects(minioClient, bucketName, `${ORIGINAL_IMAGE_PATH}/`),
68
+ listObjects(minioClient, bucketName, `${THUMBNAIL_IMAGE_PATH}/`)
69
+ ]);
70
+ console.log(
71
+ `\u{1F4E6} MinIO: original ${originalKeys.length} \u4EF6, thumbnail ${thumbnailKeys.length} \u4EF6`
72
+ );
73
+ const orphanedOriginals = originalKeys.filter(
74
+ (key) => !localFileNames.has(basename(key))
75
+ );
76
+ const orphanedThumbnails = thumbnailKeys.filter(
77
+ (key) => !localFileNames.has(basename(key))
78
+ );
79
+ const totalOrphaned = orphanedOriginals.length + orphanedThumbnails.length;
80
+ if (totalOrphaned === 0) {
81
+ console.log("\u2705 \u5B64\u7ACB\u30D5\u30A1\u30A4\u30EB\u306A\u3057");
82
+ await notificationService.notifyInfo(
83
+ `${SCRIPT_NAME} completed: no orphaned files`,
84
+ { caller: SCRIPT_NAME }
85
+ );
86
+ return;
39
87
  }
40
- const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
41
- const notificationService = createPushoverService({
42
- url: env.PUSHOVER_URL ?? "",
43
- userKey: env.PUSHOVER_USER_KEY ?? "",
44
- appToken: env.PUSHOVER_APP_TOKEN ?? "",
45
- });
46
- const minioClient = createMinioClient();
47
- const bucketName = env.MINIO_BUCKET_NAME ?? "";
48
- try {
49
- // 1. ใƒญใƒผใ‚ซใƒซใƒ•ใ‚กใ‚คใƒซไธ€่ฆงๅ–ๅพ—
50
- const localFiles = await globPaths(`${contentsPath}/image/dump/*`);
51
- const localFileNames = new Set(localFiles.filter((f) => isImageFile(f)).map((f) => basename(f)));
52
- console.log(`๐Ÿ“ ใƒญใƒผใ‚ซใƒซใซ ${localFileNames.size} ไปถใฎ็”ปๅƒใƒ•ใ‚กใ‚คใƒซใ‚’ๆคœๅ‡บใ—ใพใ—ใŸใ€‚`);
53
- // 2. MinIOใ‚ชใƒ–ใ‚ธใ‚งใ‚ฏใƒˆไธ€่ฆงๅ–ๅพ—
54
- const [originalKeys, thumbnailKeys] = await Promise.all([
55
- listObjects(minioClient, bucketName, `${ORIGINAL_IMAGE_PATH}/`),
56
- listObjects(minioClient, bucketName, `${THUMBNAIL_IMAGE_PATH}/`),
57
- ]);
58
- console.log(`๐Ÿ“ฆ MinIO: original ${originalKeys.length} ไปถ, thumbnail ${thumbnailKeys.length} ไปถ`);
59
- // 3. ๅทฎๅˆ†ๆคœๅ‡บ
60
- const orphanedOriginals = originalKeys.filter((key) => !localFileNames.has(basename(key)));
61
- const orphanedThumbnails = thumbnailKeys.filter((key) => !localFileNames.has(basename(key)));
62
- const totalOrphaned = orphanedOriginals.length + orphanedThumbnails.length;
63
- if (totalOrphaned === 0) {
64
- console.log("โœ… ๅญค็ซ‹ใƒ•ใ‚กใ‚คใƒซใชใ—");
65
- await notificationService.notifyInfo(`${SCRIPT_NAME} completed: no orphaned files`, { caller: SCRIPT_NAME });
66
- return;
67
- }
68
- console.log(`๐Ÿ—‘๏ธ ๅญค็ซ‹ใƒ•ใ‚กใ‚คใƒซๆคœๅ‡บ: original ${orphanedOriginals.length} ไปถ, thumbnail ${orphanedThumbnails.length} ไปถ`);
69
- // 4. ๅ‰Š้™คๅฎŸ่กŒ
70
- let deletedCount = 0;
71
- let errorCount = 0;
72
- for (const key of [...orphanedOriginals, ...orphanedThumbnails]) {
73
- try {
74
- if (dryRun) {
75
- console.log(`๐Ÿ” [dry-run] ๅ‰Š้™คไบˆๅฎš: ${key}`);
76
- }
77
- else {
78
- await minioClient.removeObject(bucketName, key);
79
- console.log(`๐Ÿ—‘๏ธ ๅ‰Š้™ค: ${key}`);
80
- }
81
- deletedCount++;
82
- }
83
- catch (error) {
84
- console.error(`โŒ ๅ‰Š้™คใ‚จใƒฉใƒผ๏ผˆ${key}๏ผ‰:`, error);
85
- errorCount++;
86
- }
88
+ console.log(
89
+ `\u{1F5D1}\uFE0F \u5B64\u7ACB\u30D5\u30A1\u30A4\u30EB\u691C\u51FA: original ${orphanedOriginals.length} \u4EF6, thumbnail ${orphanedThumbnails.length} \u4EF6`
90
+ );
91
+ let deletedCount = 0;
92
+ let errorCount = 0;
93
+ for (const key of [...orphanedOriginals, ...orphanedThumbnails]) {
94
+ try {
95
+ if (dryRun) {
96
+ console.log(`\u{1F50D} [dry-run] \u524A\u9664\u4E88\u5B9A: ${key}`);
97
+ } else {
98
+ await minioClient.removeObject(bucketName, key);
99
+ console.log(`\u{1F5D1}\uFE0F \u524A\u9664: ${key}`);
87
100
  }
88
- console.log(`\n๐Ÿ“Š ็ตๆžœ: ๅ‰Š้™ค ${deletedCount} ไปถ, ใ‚จใƒฉใƒผ ${errorCount} ไปถ${dryRun ? " (dry-run)" : ""}`);
89
- await notificationService.notifyInfo(`${SCRIPT_NAME} completed`, {
90
- caller: SCRIPT_NAME,
91
- });
92
- }
93
- catch (error) {
94
- console.error("โŒ ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ:", error);
95
- await notificationService.notifyError(`${SCRIPT_NAME} failed: ${String(error)}`, {
96
- caller: SCRIPT_NAME,
97
- });
98
- process.exit(1);
101
+ deletedCount++;
102
+ } catch (error) {
103
+ console.error(`\u274C \u524A\u9664\u30A8\u30E9\u30FC\uFF08${key}\uFF09:`, error);
104
+ errorCount++;
105
+ }
99
106
  }
107
+ console.log(
108
+ `
109
+ \u{1F4CA} \u7D50\u679C: \u524A\u9664 ${deletedCount} \u4EF6, \u30A8\u30E9\u30FC ${errorCount} \u4EF6${dryRun ? " (dry-run)" : ""}`
110
+ );
111
+ await notificationService.notifyInfo(`${SCRIPT_NAME} completed`, {
112
+ caller: SCRIPT_NAME
113
+ });
114
+ } catch (error) {
115
+ console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
116
+ await notificationService.notifyError(
117
+ `${SCRIPT_NAME} failed: ${String(error)}`,
118
+ {
119
+ caller: SCRIPT_NAME
120
+ }
121
+ );
122
+ process.exit(1);
123
+ }
100
124
  }
101
125
  main().catch((error) => {
102
- console.error(error);
103
- process.exit(1);
126
+ console.error(error);
127
+ process.exit(1);
104
128
  });
105
- //# sourceMappingURL=cleanup-minio-images.js.map
@@ -1,91 +1,100 @@
1
1
  #!/usr/bin/env node
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/enrich-books.ts
2
12
  import { books as googleBooksApis } from "@googleapis/books";
3
- import { parseMarkdownFrontmatter } from "@s-hirano-ist/s-search/frontmatter";
4
13
  import { dump } from "js-yaml";
5
- /**
6
- * markdown/book/*.md ใฎ frontmatter ใซใคใ„ใฆใ€ๆฏŽๅ›ž Google Books API ใ‚’ๅ‘ผใณๅ‡บใ—ใฆ
7
- * google* ใŠใ‚ˆใณ title ใ‚’ๆœ€ๆ–ฐ็Šถๆ…‹ใซๆ›ดๆ–ฐใ™ใ‚‹ใ‚นใ‚ฏใƒชใƒ—ใƒˆใ€‚
8
- *
9
- * API ใŒ title ใ‚’่ฟ”ใ—ใŸๅ ดๅˆใฏ frontmatter.title ใ‚’ไธŠๆ›ธใใ™ใ‚‹ใ€‚
10
- * notFound (API ใŒ volume ใ‚’่ฟ”ใ•ใชใ„) ใฎๅ ดๅˆใฏๆ‰‹ๅ‹•ๅ…ฅๅŠ› title ใ‚’ไฟๆŒใ™ใ‚‹ใ€‚
11
- * markdown ๆœฌๆ–‡ (h1 ๅซใ‚€) ใซใฏ่งฆใ‚Œใชใ„ใŸใ‚ใ€่‡ชๅทฑๅ…ฅๅŠ›ใฎ h1 ใฏใใฎใพใพ็ถญๆŒใ•ใ‚Œใ‚‹ใ€‚
12
- */
13
14
  import { readFile, writeFile } from "node:fs/promises";
14
15
  import { basename, join } from "node:path";
15
16
  import { setTimeout } from "node:timers/promises";
16
- import { globPaths } from "./lib/glob-paths.js";
17
- const NO_IMG_SRC = "https://s-hirano.com/notFound.png";
18
- const NOT_FOUND_HREF = "https://s-hirano.com/404";
19
- const API_INTERVAL_MS = 600;
17
+ var NO_IMG_SRC = "https://s-hirano.com/notFound.png";
18
+ var NOT_FOUND_HREF = "https://s-hirano.com/404";
19
+ var API_INTERVAL_MS = 600;
20
20
  function dumpFrontmatter(data) {
21
- return dump(data, {
22
- lineWidth: -1,
23
- forceQuotes: false,
24
- noRefs: true,
25
- });
21
+ return dump(data, {
22
+ lineWidth: -1,
23
+ forceQuotes: false,
24
+ noRefs: true
25
+ });
26
26
  }
27
27
  async function main() {
28
- const dryRun = process.argv.includes("--dry-run");
29
- const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
30
- const bookDir = join(contentsPath, "markdown", "book");
31
- const apiKey = process.env.GOOGLE_BOOKS_API_KEY;
32
- if (!apiKey) {
33
- throw new Error("GOOGLE_BOOKS_API_KEY is not set");
28
+ const dryRun = process.argv.includes("--dry-run");
29
+ const contentsPath = process.env.S_CONTENTS_PATH ?? process.cwd();
30
+ const bookDir = join(contentsPath, "markdown", "book");
31
+ const apiKey = process.env.GOOGLE_BOOKS_API_KEY;
32
+ if (!apiKey) {
33
+ throw new Error("GOOGLE_BOOKS_API_KEY is not set");
34
+ }
35
+ const api = googleBooksApis({ version: "v1", auth: apiKey });
36
+ const files = await globPaths(`${bookDir}/*.md`);
37
+ console.log(
38
+ `\u{1F4C1} ${files.length} \u4EF6\u306E markdown \u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002${dryRun ? " (dry-run)" : ""}`
39
+ );
40
+ let enrichedCount = 0;
41
+ let errorCount = 0;
42
+ for (const filePath of files.toSorted()) {
43
+ const fileName = basename(filePath);
44
+ const isbn = basename(filePath, ".md");
45
+ try {
46
+ const raw = await readFile(filePath, "utf8");
47
+ const parsed = parseMarkdownFrontmatter(raw);
48
+ const data = parsed.data;
49
+ console.log(`\u{1F50D} ${fileName}: Google Books API \u554F\u3044\u5408\u308F\u305B\u4E2D...`);
50
+ const book = await api.volumes.list({ q: `isbn:${isbn}` });
51
+ await setTimeout(API_INTERVAL_MS);
52
+ if (book.status !== 200) {
53
+ throw new Error(`Google Books API status ${book.status}`);
54
+ }
55
+ const volume = book.data.items?.[0]?.volumeInfo;
56
+ const httpsImgSrc = (volume?.imageLinks?.thumbnail ?? NO_IMG_SRC).replace(
57
+ "http://",
58
+ "https://"
59
+ );
60
+ const httpsHref = (volume?.infoLink ?? NOT_FOUND_HREF).replace(
61
+ "http://",
62
+ "https://"
63
+ );
64
+ const next = {
65
+ ...data,
66
+ googleSubtitle: volume?.subtitle ?? "",
67
+ googleAuthors: volume?.authors ?? [],
68
+ googleDescription: volume?.description ?? "No description",
69
+ googleImgSrc: httpsImgSrc,
70
+ googleHref: httpsHref
71
+ };
72
+ if (typeof volume?.title === "string" && volume.title !== "") {
73
+ next.title = volume.title;
74
+ }
75
+ const body = parsed.content.replace(/^\n+/u, "");
76
+ const newContent = `---
77
+ ${dumpFrontmatter(next)}---
78
+
79
+ ${body}`;
80
+ if (dryRun) {
81
+ console.log(" [dry-run] \u66F8\u304D\u8FBC\u307F\u30B9\u30AD\u30C3\u30D7");
82
+ } else {
83
+ await writeFile(filePath, newContent, "utf8");
84
+ console.log(` \u2705 ${volume?.title ?? "(title not found)"}`);
85
+ }
86
+ enrichedCount++;
87
+ } catch (error) {
88
+ console.error(`\u274C ${fileName}:`, error);
89
+ errorCount++;
34
90
  }
35
- const api = googleBooksApis({ version: "v1", auth: apiKey });
36
- const files = await globPaths(`${bookDir}/*.md`);
37
- console.log(`๐Ÿ“ ${files.length} ไปถใฎ markdown ใ‚’ๆคœๅ‡บใ—ใพใ—ใŸใ€‚${dryRun ? " (dry-run)" : ""}`);
38
- let enrichedCount = 0;
39
- let errorCount = 0;
40
- for (const filePath of files.toSorted()) {
41
- const fileName = basename(filePath);
42
- const isbn = basename(filePath, ".md");
43
- try {
44
- const raw = await readFile(filePath, "utf8");
45
- const parsed = parseMarkdownFrontmatter(raw);
46
- const data = parsed.data;
47
- console.log(`๐Ÿ” ${fileName}: Google Books API ๅ•ใ„ๅˆใ‚ใ›ไธญ...`);
48
- const book = await api.volumes.list({ q: `isbn:${isbn}` });
49
- await setTimeout(API_INTERVAL_MS);
50
- if (book.status !== 200) {
51
- throw new Error(`Google Books API status ${book.status}`);
52
- }
53
- const volume = book.data.items?.[0]?.volumeInfo;
54
- const httpsImgSrc = (volume?.imageLinks?.thumbnail ?? NO_IMG_SRC).replace("http://", "https://");
55
- const httpsHref = (volume?.infoLink ?? NOT_FOUND_HREF).replace("http://", "https://");
56
- const next = {
57
- ...data,
58
- googleSubtitle: volume?.subtitle ?? "",
59
- googleAuthors: volume?.authors ?? [],
60
- googleDescription: volume?.description ?? "No description",
61
- googleImgSrc: httpsImgSrc,
62
- googleHref: httpsHref,
63
- };
64
- // API ใŒ title ใ‚’่ฟ”ใ—ใŸๅ ดๅˆใฎใฟ frontmatter.title ใ‚’ไธŠๆ›ธใใ€‚
65
- // notFound ใฎๅ ดๅˆใฏๆ‰‹ๅ‹•ๅ…ฅๅŠ› title ใ‚’ไฟๆŒใ™ใ‚‹ใ€‚
66
- if (typeof volume?.title === "string" && volume.title !== "") {
67
- next.title = volume.title;
68
- }
69
- const body = parsed.content.replace(/^\n+/u, "");
70
- const newContent = `---\n${dumpFrontmatter(next)}---\n\n${body}`;
71
- if (dryRun) {
72
- console.log(" [dry-run] ๆ›ธใ่พผใฟใ‚นใ‚ญใƒƒใƒ—");
73
- }
74
- else {
75
- await writeFile(filePath, newContent, "utf8");
76
- console.log(` โœ… ${volume?.title ?? "(title not found)"}`);
77
- }
78
- enrichedCount++;
79
- }
80
- catch (error) {
81
- console.error(`โŒ ${fileName}:`, error);
82
- errorCount++;
83
- }
84
- }
85
- console.log(`\n๐Ÿ“Š ็ตๆžœ: ๆ›ดๆ–ฐ ${enrichedCount} ไปถ, ใ‚จใƒฉใƒผ ${errorCount} ไปถ${dryRun ? " (dry-run)" : ""}`);
91
+ }
92
+ console.log(
93
+ `
94
+ \u{1F4CA} \u7D50\u679C: \u66F4\u65B0 ${enrichedCount} \u4EF6, \u30A8\u30E9\u30FC ${errorCount} \u4EF6${dryRun ? " (dry-run)" : ""}`
95
+ );
86
96
  }
87
97
  main().catch((error) => {
88
- console.error("โŒ ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ:", error);
89
- process.exit(1);
98
+ console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
99
+ process.exit(1);
90
100
  });
91
- //# sourceMappingURL=enrich-books.js.map
@@ -1,104 +1,115 @@
1
1
  #!/usr/bin/env node
2
- import { makeUnexportedStatus, makeUserId, } from "@s-hirano-ist/s-core/shared-kernel/entities/common-entity";
3
- import { createPrismaClient } from "@s-hirano-ist/s-database";
4
- import { createPushoverService } from "@s-hirano-ist/s-notification";
2
+ import { createRequire as __cliCreateRequire } from "node:module"; const require = __cliCreateRequire(import.meta.url);
3
+ import {
4
+ createPrismaClient,
5
+ makeUnexportedStatus,
6
+ makeUserId
7
+ } from "./chunk-IWNZQXDG.js";
8
+ import {
9
+ createPushoverService
10
+ } from "./chunk-7PVU2Z32.js";
11
+ import "./chunk-JZOR5GA2.js";
12
+
13
+ // src/fetch-articles.ts
5
14
  import { mkdir, readFile, writeFile } from "node:fs/promises";
6
15
  import { dirname } from "node:path";
7
- const OUTPUT_PATH = "json/article";
16
+ var OUTPUT_PATH = "json/article";
8
17
  function categorizeArticles(articles) {
9
- return articles.reduce((acc, d) => {
10
- const { title, quote, url, categoryName } = d;
11
- // oxlint-disable-next-line typescript/no-unnecessary-condition -- Record index access is undefined at runtime for new keys; initializes the bucket
12
- if (!acc[categoryName])
13
- acc[categoryName] = [];
14
- acc[categoryName].push({ title, quote: quote ?? "", url });
15
- return acc;
16
- }, {});
18
+ return articles.reduce((acc, d) => {
19
+ const { title, quote, url, categoryName } = d;
20
+ if (!acc[categoryName]) acc[categoryName] = [];
21
+ acc[categoryName].push({ title, quote: quote ?? "", url });
22
+ return acc;
23
+ }, {});
17
24
  }
18
25
  async function readFileOrCreate(key) {
19
- const filePath = `${OUTPUT_PATH}/${key}.json`;
20
- try {
21
- const data = await readFile(filePath, "utf8");
22
- return JSON.parse(data);
23
- }
24
- catch {
25
- // File does not exist, create it
26
- await mkdir(dirname(filePath), { recursive: true });
27
- const data = { heading: key, description: "FIXME", body: [] };
28
- const jsonData = JSON.stringify(data, null, 2);
29
- await writeFile(filePath, jsonData);
30
- return data;
31
- }
26
+ const filePath = `${OUTPUT_PATH}/${key}.json`;
27
+ try {
28
+ const data = await readFile(filePath, "utf8");
29
+ return JSON.parse(data);
30
+ } catch {
31
+ await mkdir(dirname(filePath), { recursive: true });
32
+ const data = { heading: key, description: "FIXME", body: [] };
33
+ const jsonData = JSON.stringify(data, null, 2);
34
+ await writeFile(filePath, jsonData);
35
+ return data;
36
+ }
32
37
  }
33
38
  async function exportData(data) {
34
- for (const [key, value] of Object.entries(data)) {
35
- console.log(`Key: ${key}`);
36
- const originalData = await readFileOrCreate(key);
37
- originalData.body.push(...value);
38
- await writeFile(`${OUTPUT_PATH}/${key}.json`, `${JSON.stringify(originalData, null, 2)}\n`);
39
- }
39
+ for (const [key, value] of Object.entries(data)) {
40
+ console.log(`Key: ${key}`);
41
+ const originalData = await readFileOrCreate(key);
42
+ originalData.body.push(...value);
43
+ await writeFile(
44
+ `${OUTPUT_PATH}/${key}.json`,
45
+ `${JSON.stringify(originalData, null, 2)}
46
+ `
47
+ );
48
+ }
40
49
  }
41
50
  async function main() {
42
- const env = {
43
- DATABASE_URL: process.env.DATABASE_URL,
44
- PUSHOVER_URL: process.env.PUSHOVER_URL,
45
- PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
46
- PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
47
- USERNAME_TO_EXPORT: process.env.USERNAME_TO_EXPORT,
48
- };
49
- if (Object.values(env).some((v) => !v)) {
50
- throw new Error("Required environment variables are not set.");
51
- }
52
- const prisma = createPrismaClient(env.DATABASE_URL ?? "");
53
- const notificationService = createPushoverService({
54
- url: env.PUSHOVER_URL ?? "",
55
- userKey: env.PUSHOVER_USER_KEY ?? "",
56
- appToken: env.PUSHOVER_APP_TOKEN ?? "",
51
+ const env = {
52
+ DATABASE_URL: process.env.DATABASE_URL,
53
+ PUSHOVER_URL: process.env.PUSHOVER_URL,
54
+ PUSHOVER_USER_KEY: process.env.PUSHOVER_USER_KEY,
55
+ PUSHOVER_APP_TOKEN: process.env.PUSHOVER_APP_TOKEN,
56
+ USERNAME_TO_EXPORT: process.env.USERNAME_TO_EXPORT
57
+ };
58
+ if (Object.values(env).some((v) => !v)) {
59
+ throw new Error("Required environment variables are not set.");
60
+ }
61
+ const prisma = createPrismaClient(env.DATABASE_URL ?? "");
62
+ const notificationService = createPushoverService({
63
+ url: env.PUSHOVER_URL ?? "",
64
+ userKey: env.PUSHOVER_USER_KEY ?? "",
65
+ appToken: env.PUSHOVER_APP_TOKEN ?? ""
66
+ });
67
+ const userId = makeUserId(env.USERNAME_TO_EXPORT ?? "");
68
+ const UNEXPORTED = makeUnexportedStatus();
69
+ async function fetchArticles() {
70
+ const rawArticles = await prisma.article.findMany({
71
+ where: { userId, status: UNEXPORTED },
72
+ select: {
73
+ id: true,
74
+ title: true,
75
+ quote: true,
76
+ url: true,
77
+ Category: true
78
+ }
57
79
  });
58
- const userId = makeUserId(env.USERNAME_TO_EXPORT ?? "");
59
- const UNEXPORTED = makeUnexportedStatus();
60
- async function fetchArticles() {
61
- const rawArticles = await prisma.article.findMany({
62
- where: { userId, status: UNEXPORTED },
63
- select: {
64
- id: true,
65
- title: true,
66
- quote: true,
67
- url: true,
68
- Category: true,
69
- },
70
- });
71
- const articles = rawArticles.map((d) => ({
72
- id: d.id,
73
- title: d.title,
74
- url: d.url,
75
- quote: d.quote,
76
- // oxlint-disable-next-line typescript/no-unnecessary-condition -- Prisma row is an external runtime boundary; relation/name may differ from declared non-null type
77
- categoryName: d.Category?.name ?? "",
78
- }));
79
- console.log(`๐Ÿ“Š ${articles.length} ไปถใฎใƒ‡ใƒผใ‚ฟใ‚’ๅ–ๅพ—ใ—ใพใ—ใŸใ€‚`);
80
- await exportData(categorizeArticles(articles));
81
- console.log("๐Ÿ’พ ใƒ‡ใƒผใ‚ฟใŒJSONใƒ•ใ‚กใ‚คใƒซใซๆ›ธใๅ‡บใ•ใ‚Œใพใ—ใŸใ€‚");
82
- }
83
- try {
84
- await fetchArticles();
85
- await notificationService.notifyInfo("fetch-articles completed", {
86
- caller: "fetch-articles",
87
- });
88
- }
89
- catch (error) {
90
- console.error("โŒ ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸ:", error);
91
- await notificationService.notifyError(`fetch-articles failed: ${String(error)}`, {
92
- caller: "fetch-articles",
93
- });
94
- process.exit(1);
95
- }
96
- finally {
97
- await prisma.$disconnect();
98
- }
80
+ const articles = rawArticles.map(
81
+ (d) => ({
82
+ id: d.id,
83
+ title: d.title,
84
+ url: d.url,
85
+ quote: d.quote,
86
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- Prisma row is an external runtime boundary; relation/name may differ from declared non-null type
87
+ categoryName: d.Category?.name ?? ""
88
+ })
89
+ );
90
+ console.log(`\u{1F4CA} ${articles.length} \u4EF6\u306E\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002`);
91
+ await exportData(categorizeArticles(articles));
92
+ console.log("\u{1F4BE} \u30C7\u30FC\u30BF\u304CJSON\u30D5\u30A1\u30A4\u30EB\u306B\u66F8\u304D\u51FA\u3055\u308C\u307E\u3057\u305F\u3002");
93
+ }
94
+ try {
95
+ await fetchArticles();
96
+ await notificationService.notifyInfo("fetch-articles completed", {
97
+ caller: "fetch-articles"
98
+ });
99
+ } catch (error) {
100
+ console.error("\u274C \u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:", error);
101
+ await notificationService.notifyError(
102
+ `fetch-articles failed: ${String(error)}`,
103
+ {
104
+ caller: "fetch-articles"
105
+ }
106
+ );
107
+ process.exit(1);
108
+ } finally {
109
+ await prisma.$disconnect();
110
+ }
99
111
  }
100
112
  main().catch((error) => {
101
- console.error(error);
102
- process.exit(1);
113
+ console.error(error);
114
+ process.exit(1);
103
115
  });
104
- //# sourceMappingURL=fetch-articles.js.map