generated at
✅VTuber Scrapboxを一般解放する

~2024-05-05 GitHubにログが貯まる仕組みを稼働できるか確認するest: 🍅x1 actual: 🍅x2
🍅22:21-22:46 GitHubにログが貯まる仕組みを稼働できるか確認する

まとめ
/R は関係なかったので削除した
GitHub Actionsでcronで定期実行していた
index.tsがScrapboxのAPIを利用してページ情報を取得する
scrapbox.io/api/pages/userName/?limit=1&skip=1 でページ情報をバルク取得うる
差分がある場合だけ、このデータをgithubにcommitする
コミットするだけでなく、Google Driveにもアップロードしていた


どっちがどういう機能を持っているの?

https://github.com/meganii/sandbox-github-actions-scheduler が現役で動いているのでこれを参考にするか

どうやって動かすんだろう?
cronが18時に設定されていた
Google Driveにもアップロードしているようだ

2024-05-06 23:09 プロジェクト名を変更した


基素github actionsで workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}; のようなものがあったときにsecretsはどう設定すればいいの
GPT-4
GitHub Actionsでsecretsを使用してWORKLOAD_IDENTITY_PROVIDERのような値を設定する方法は以下の通りです:
GitHubリポジトリページにアクセスします。
リポジトリのメニューから「Settings」(設定)を選択します。
左側のメニューから「Secrets & Policies」(シークレットとポリシー)を選びます。
「Actions」セクションの下で「New repository secret」(新しいリポジトリシークレット)をクリックします。
「Name」フィールドにWORKLOAD_IDENTITY_PROVIDERと入力します。
「Value」フィールドにWorkload Identity Providerの値を入力します。この値は、使用しているクラウドサービス(例:Google Cloud Platform)で設定したものです。
「Add secret」(シークレットを追加)ボタンをクリックして保存します。
これで、GitHub Actionsのワークフロー定義ファイル内で${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}を使用して、設定したシークレット値を参照できるようになります。このシークレットは、ワークフローが実行される際に環境変数として読み込まれます。

https://scrapbox.io/api/pages/motoso/?limit=1&skip=1 これでとっていけるのか。なるほど
2024-05-06 23:19 🍅2つ目を消費してしまった

設定をして一般開放する est: 🍅x3
🍅🍅🍅🍅

Google Driveはなしでもいいかも
基素内容的にはcommitされるものと同じものがgoogle driveにアップされますよね?
Claude 3 Opus
そうですね。ワークフローの内容を見ると、コミットされるファイルと同じデータがZIP化されてGoogle Driveにアップロードされています。この場合、データの冗長性は確保されていますが、同じデータが二重に管理されているため、非効率的である可能性があります。
以下の点を考慮すると、Google Driveへのアップロードが不要である可能性が高いです:
バージョン管理:GitHubリポジトリでは、コミットの履歴からデータの変更を追跡し、必要に応じて以前のバージョンにアクセスできます。
データのサイズ:コミットされるデータのサイズが大きくない場合、GitHubリポジトリのみで十分に管理できます。
アクセス制御:GitHubリポジトリでは、アクセス権限を細かく設定できるため、データへのアクセスを適切に制御できます。
シンプルさ:Google Driveへのアップロードを削除することで、ワークフローがシンプルになり、管理が容易になります。
ただし、プロジェクトの要件や、開発チームの方針によっては、Google Driveへのバックアップが必要とされる場合もあります。その場合は、アップロードの目的を明確にし、必要に応じてワークフローを最適化することをお勧めします。


index.ts
基素差分がある場合、差分だけが保存される?それとも全てのページの情報がコミットされるのかな?
Claude 3 Opus
このコードを見ると、毎回全てのページの情報を取得し、JSONファイルとして保存していることがわかります。具体的には以下のような処理が行われています。
Scrapbox APIを使用して、指定されたプロジェクト(villagepump)の全ページ情報を取得します。
取得したページ情報から、必要なデータ(id, title, created, updated, image, descriptions)を抽出し、titles配列に格納します。
titles配列をページ作成日時(created)で昇順にソートします。
ソートされたtitles配列をpages.jsonファイルに書き込みます。
再度Scrapbox APIを使用して、各ページの詳細情報(id, title, created, updated, lines)を取得します。
取得した詳細情報をdetailPages配列に格納します。
detailPages配列をJSON Lines形式でdata.jsonファイルに書き込みます。
この処理では、差分の有無に関係なく、常に全ページの情報が取得され、JSONファイルとして保存されます。
したがって、GitHubにコミットされるのは、毎回全ページの情報が含まれたpages.jsonとdata.jsonファイルになります。差分だけがコミットされるわけではありません。
ただし、Git自体は差分を効率的に管理するため、実際にGitHub上で保存されるデータは、前回のコミットからの差分のみになります。これにより、リポジトリのサイズが肥大化することを防ぐことができます。
もし差分のみをコミットしたい場合は、コードを修正して、前回の保存内容と比較し、変更があったページの情報だけを抽出する必要があります。ただし、その場合は、全ページの情報を取得する必要がないため、APIへのリクエスト数を減らすことができるという利点があります。
基素pipeThrough使う意味ありますかね?detailPagesに全てのページ情報が載ってるから逐次処理になるんじゃ?
Claude 3 Opus
ご指摘の通り、この部分のコードを見直してみると、pipeThroughを使用する必要性は低いと思われます。detailPages配列には全ページの詳細情報が格納されているため、JSON.stringifyを使用して直接JSONに変換し、ファイルに書き込むことができます。
以下のように修正することができます。
tsx
// JSON形式でpagesを出力 const file = await Deno.open(dist_data, { create: true, write: true }); await Deno.write(file, new TextEncoder().encode(JSON.stringify(detailPages))); console.log("write success");
ただし、元のコードでストリーム処理を使用していた理由は、大量のデータを処理する際にメモリ使用量を抑えるためだと考えられます。detailPages配列に大量のデータが格納されている場合は、ストリーム処理を使用することで、メモリ使用量を抑えることができます。
じゃあこのままのほうがいい基素

>ストリーミングでは、ネットワーク経由で受信するリソースを小さなチャンク(塊)に分割し、少しずつ処理します。
>ブラウザーはメディア資産を受信する際にすでにこのような動作を行っています。動画はコンテンツのダウンロードが進むにつれてバッファーされ再生されますし、画像も読み込みが進むにつれて徐々に表示されることがあります。
> しかし、この機能はこれまで JavaScript では利用できませんでした。
>以前は、ある種のリソース(動画やテキストファイルなど)を処理したい場合、ファイル全体をダウンロードして、適切な形式にデシリアライズされるのを待ち、それからすべてのデータを処理しなければなりませんでした。
> ストリーム API を使えば、バッファーや文字列、blob などを生成する必要なく、利用できるようになったらすぐに、JavaScript で生のデータを少しずつ処理し始めることができます。

Scheduled buildを有効にするにはUIでenableをクリックしなければいけなかった
3時の実行を逃したので、手動で回した
どれぐらいでタイムアウトするのだろうか?無料枠足りるかな。井戸端で足りているのなら余裕だろうけど
rmでjsonがないので失敗したので修正した
split pagesで失敗
sh
Run deno run --allow-read --allow-write --no-check split.ts error: Module not found "file:///home/runner/work/backup-vtuber-scrapbox/backup-vtuber-scrapbox/index". at file:///home/runner/work/backup-vtuber-scrapbox/backup-vtuber-scrapbox/split.ts:1:23 Error: Process completed with exit code 1.
importに .ts が必要だった

sh
Run deno run --allow-read --allow-write --no-check split.ts error: Uncaught (in promise) PermissionDenied: Requires net access to "scrapbox.io", run again with the --allow-net flag const pagesResponse = await fetch( ^ at mainFetch (ext:deno_fetch/26_fetch.js:152:43) at ext:deno_fetch/26_fetch.js:352:9 at new Promise (<anonymous>) at fetch (ext:deno_fetch/26_fetch.js:315:18) at file:///home/runner/work/backup-vtuber-scrapbox/backup-vtuber-scrapbox/index.ts:15:29 Error: Process completed with exit code 1.
Claude 3 Opus
Denoはモジュールをインポートする際に、インポートされたモジュールが必要とする権限も考慮します。つまり、split.tsがindex.tsをインポートしており、index.tsがネットワークアクセスを必要とするため、split.tsを実行する際にも--allow-netフラグが必要になります。
え〜基素
これは、インポートされたモジュールが実行される可能性があるためです。Denoはこの動作によって、予期しないセキュリティ上の問題を防いでいます。
したがって、split.ts自体にはネットワークアクセスのコードがなくても、index.tsの依存関係によって--allow-netフラグが必要になります。
ただし、split.tsを実行する前にindex.tsを別々に実行し、data.jsonファイルを生成している場合は、split.tsの実行時に--allow-netフラグは不要です。
基素もしかして定数は別のコードに切り出すほうがdeno way?
Claude 3 Opus
はい、その通りです。Denoでは、コードの再利用性と、必要な権限の範囲を最小限に抑えるために、関心事の分離(Separation of Concerns)の原則に従うことが推奨されています。
この原則に従って、定数や設定値を別のファイルに切り出すことは良い習慣だと言えます。これにより、それぞれのファイルが独立した責務を持ち、必要な権限のみを要求することができます。
例えば、config.tsという名前の新しいファイルを作成し、project定数をそこに移動することができます。
ts
//config.ts export const project = "vtuber"; そして、index.tsとsplit.tsの両方でconfig.tsからprojectをインポートします。 typescriptCopy // index.ts import { project } from "./config.ts"; // ... // split.ts import { project } from "./config.ts"; // ...
この方法では、config.tsはネットワークアクセスを必要としないため、split.tsを実行する際に--allow-netフラグは不要になります。
さらに、この方法は将来的にプロジェクト名を変更する必要がある場合など、設定を管理するのにも役立ちます。一箇所の変更ですべての参照箇所に反映されるので、コードのメンテナンス性が向上します。
これは、Denoの哲学である明示的な権限の付与とコードの明確性に合致しています。


sh
Run deno run --allow-read --allow-write --no-check split.ts error: Uncaught (in promise) NotFound: No such file or directory (os error 2): writefile './vtuber/pages/5aafe7726f0c300014f76c97.json' Deno.writeTextFile( ^ at writeFile (ext:deno_fs/30_fs.js:935:13) at Object.writeTextFile (ext:deno_fs/30_fs.js:977:12) at file:///home/runner/work/backup-vtuber-scrapbox/backup-vtuber-scrapbox/split.ts:10:8
Claude 3 Opus
このエラーは、 split.ts ./vtuber/pages/ ディレクトリ内にJSONファイルを書き込もうとしたが、そのディレクトリが存在しないために発生しています。
エラーメッセージ No such file or directory (os error 2): writefile './vtuber/pages/5aafe7726f0c300014f76c97.json' は、指定されたパスにディレクトリが存在しないことを示しています。
この問題を解決するには、 split.ts を実行する前に、 ./vtuber/pages/ ディレクトリを作成する必要があります。
split.ts の中で、ファイルを書き込む前にディレクトリが存在するかどうかを確認し、存在しない場合は作成するようにコードを修正することができます。
ts
import { project } from "./config.ts"; const filepath = "./data.json"; const distpath = `./${project}/pages/`; // ディレクトリが存在しない場合は作成する if (!Deno.existsSync(distpath)) { Deno.mkdirSync(distpath, { recursive: true }); } const text = Deno.readTextFileSync(filepath); const content = JSON.parse(text); for (const page of content['pages']) { Deno.writeTextFile(distpath + page.id + '.json', JSON.stringify(page, null, 2)); }
ここでは、 Deno.existsSync を使用してディレクトリの存在を確認し、存在しない場合は Deno.mkdirSync を使用して再帰的にディレクトリを作成しています。 { recursive: true } オプションにより、必要に応じて中間のディレクトリも作成されます。
この修正により、 ./vtuber/pages/ ディレクトリが存在しない場合は自動的に作成され、ファイルの書き込みが成功するはずです。
ただし、 split.ts の実行時に --allow-write フラグを指定して、ディレクトリの作成とファイルの書き込みを許可する必要があることに注意してください。
基素エラーになった
sh
Run deno run --allow-read --allow-write --no-check split.ts error: Uncaught (in promise) TypeError: Deno.existsSync is not a function if (!Deno.existsSync(distpath)) { ^ at file:///home/runner/work/backup-vtuber-scrapbox/backup-vtuber-scrapbox/split.ts:7:11 Error: Process completed with exit code 1.
Claude 3 Opus
申し訳ありません。Deno.existsSyncは非推奨となり、Deno.statに置き換えられました。Deno.statは非同期関数であるため、使い方を少し変更する必要があります。
(略)


基素github actionsのworkflowのre-runってコードプッシュしても反映されない?(最新のコードではなくその時のコードが使われる?)
Claude 3 Opus
はい、その通りです。GitHub Actionsのワークフローをre-run(再実行)した場合、その時点でのコードが使用されます。最新のコードではなく、そのワークフローの実行が最初にトリガーされた時点のコードが使われます。
再実行するワークフローは、元の実行と同じコードとコンテキストを使用します。これは、ワークフローの実行結果の再現性を確保するためです。再実行は、同じコードと同じ環境で実行されるため、元の実行と同じ結果が得られるはずです。

Actionsで嘘を教えられて修正したが、バックアップ取れた
すぐ試して間違いに気づけるプログラミングとの相性は良い

diffがなければ作られないことも確認した


基素pagesとstatsに入るファイルはどのようなものになりますか?
Claude 3 Opus
index.ts split.ts のコードを見ると、 vtuber/pages vtuber/stats ディレクトリには以下のようなファイルが生成されることがわかります。

1. vtuber/pages ディレクトリ:
このディレクトリには、各Scrapboxページの詳細情報を含むJSONファイルが格納されます。
各ファイルは、ページのIDを使って <page_id>.json という形式で命名されます。
例: 5aafe7726f0c300014f76c97.json , 5aafe7726f0c300014f76c98.json , など
各JSONファイルには、以下のような構造のデータが含まれます:
json
{ "id": "5aafe7726f0c300014f76c97", "title": "Example Page", "created": 1620000000000, "updated": 1620000000000, "lines": [ { "id": "5aafe7726f0c300014f76c97", "text": "This is an example page." }, { "id": "5aafe7726f0c300014f76c98", "text": "It has two lines." } ] }
2. vtuber/stats ディレクトリ:
このディレクトリには、 pages.json という名前の単一のファイルが格納されます。
すべてのページの概要情報を単一のJSONファイル(pages.json)にまとめて格納します。
pages.json の構造は以下のようになります:
json
{ "projectName": "vtuber", "count": 100, "pages": [ { "id": "5aafe7726f0c300014f76c97", "title": "Example Page", "created": 1620000000000, "updated": 1620000000000, "image": "https://example.com/image.jpg", "descriptions": [ "This is an example page." ] }, { "id": "5aafe7726f0c300014f76c98", "title": "Another Page", "created": 1620000000001, "updated": 1620000000001, "image": null, "descriptions": [] } ] }
この pages.json ファイルは、すべてのページの基本情報(id、title、created、updated、image、descriptionsなど)を含む配列を提供します。
これらのファイルは、Scrapboxプロジェクトのバックアップとして機能し、必要に応じて情報を取得したり復元したりするために使用できます。 pages ディレクトリには各ページの詳細が、 stats ディレクトリにはすべてのページの概要情報が格納されます。
つくらんとScrapboxを復元できない基素
自分の理解と同じ基素

更新されていたら差分が定期実行でバックアップされることも確認済

動作確認
$ deno run --allow-read --allow-write --allow-net index.ts
$ deno run --allow-read --allow-write split.ts