プロトタイプver1.0 の作成
- 超シンプルなモデルの作成から始める。
- 完全に自分用からつくること、サーバーとか、アプリ化とかまだ難しい。
- 自分の過去の投稿をまずはリスト化して、それを時系列ランダムで表示するモデルを考える。
- 過去の投稿はXアカウントの設定から、アーカイブをダウンロードできる。
- Xのアーカイブは過去のある時点までしか保存されていなかった。
- 第二のバックアップとしては、かつて使っていたTwilogに、最近の投稿が欠けているはずだが、Xのアーカイブに保存されていない過去の投稿まで記録されていた。
-
全ツイートとポストをリスト化する。
- どこでどのようにリスト化するのか。現時点では、google spreadseatを使って、GASにjava scriptでリスト作成を自動化するコードを書くくらいしか思いつかないので、一旦、そのように実行する。
- Xアーカイブと、Twilogのcsvデータをダウンロード。
- スプレッドシートを作成し、拡張機能からGASと連携、今日はGeminiにコードを書いてもらう。
- Xアーカイブに含まれているtweets.jsという投稿本文のファイルはWindowsで直接開こうとすると、セキュリティ上しっかりブロックされるので、Googledriveにtweets.jsをアップロードして、それを参照して日時、本文、投稿IDを取得して、リスト化
- 次に、アーカイブでは足りていない過去の部分を、Twilogのcsvファイルから読み込む。こちらも一度Googledriveにアップロードして、スクリプト内で参照し、日時、本文、IDを同順でリスト化
- Geminiが出力したコードは、同様にcsvファイルをリスト化するものだが、これをそのまま実行すると、ほとんどの投稿が重複してしまうので、IDをキーとして重複のないものだけを追加するように修正指示。
-
-
function importTwilogOnly() { const fileName = 'twilog-p2357111317-260123.csv'; const files = DriveApp.getFilesByName(fileName); if (!files.hasNext()) { Browser.msgBox('CSVファイルが見つかりません。マイドライブ直下にあるか再確認。'); return; } const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); const lastRow = sheet.getLastRow(); const existingIds = new Set(); // 1. 既存シートのID(3列目)を取得 if (lastRow > 1) { const idData = sheet.getRange(2, 3, lastRow - 1, 1).getValues(); for (let i = 0; i < idData.length; i++) { existingIds.add(String(idData[i][0])); } } // 2. CSVを解析 const csvText = files.next().getBlob().getDataAsString('UTF-8'); const csvData = Utilities.parseCsv(csvText); const newRows = []; // 1行目はヘッダーなので i=1 から開始 for (let i = 1; i < csvData.length; i++) { const tweetId = String(csvData[i][0]); // A列: ID const createdAt = csvData[i][2]; // C列: 日時 const text = csvData[i][3]; // D列: 本文 // 重複チェック if (tweetId && !existingIds.has(tweetId)) { // 現在のシート形式 [日時, 本文, ID] に合わせて格納 newRows.push([createdAt, text, tweetId]); } } // 3. 高速書き込み if (newRows.length > 0) { const startRow = sheet.getLastRow() + 1; sheet.insertRowsAfter(sheet.getLastRow(), newRows.length); sheet.getRange(startRow, 1, newRows.length, 3).setValues(newRows); Browser.msgBox(newRows.length + ' 件の新規投稿を追加しました!'); } else { Browser.msgBox('重複のない新規投稿は見つかりませんでした。'); } }
-TwilogのとXアーカイブの日時の形式が異なるので統一。
function unifyDateFormat() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
const lastRow = sheet.getLastRow();
if (lastRow < 2) return;
// A列(日時)のデータをすべて取得
const range = sheet.getRange(2, 1, lastRow - 1, 1);
const values = range.getValues();
const unifiedValues = values.map(row => {
let dateStr = row[0];
if (!dateStr) return [""];
// すでに YYYY-MM-DD 形式ならそのまま
if (/^\d{4}-\d{2}-\d{2}/.test(dateStr)) {
return [dateStr];
}
try {
// Xアーカイブ形式 (Fri Jun 07...) を日付オブジェクトに変換
const date = new Date(dateStr);
// 有効な日付であれば YYYY-MM-DD HH:mm:ss に整形
if (!isNaN(date.getTime())) {
return [Utilities.formatDate(date, "JST", "yyyy-MM-dd HH:mm:ss")];
}
} catch (e) {
// 変換失敗時は元の値を残す
}
return [dateStr];
});
// まとめてシートに書き戻す
range.setValues(unifiedValues);
Browser.msgBox("日時の書式を統一しました!");
}
-
リストが完成したので、これをデプロイしてウェブアプリURLを参照するコードを書けば、これをひとまずデータベースとして使えるようになる。
-
次に、このリストからtwitterライクなUIで時系列ランダムに表示したい。
-
よいところ
- 時系列ランダム、新規投稿とそれをリストに追加する操作は〇
- リンクも開ける。
- リプライと画像の投稿もアイコンの未実装できている。(機能未実装)
- 要件通り、アイコンもフリー素材を用いて、ランダムに表示できており、自分の中の他者というコンセプトに合う。
-
修正点
- 下に向かってスクロールする仕様になっているが、上から降ってくるほうが良い。
- 上から降ってくるのだとすれば、一番上に書き込み欄があるのは邪魔
- ページ下部までいかないと新しく投稿を読み込めない。
- 新規投稿が画面の一番下に追加されてしまい、投稿できたのかわかりづらい。
- 引用リツイートや画像などのサムネイルを表示できたらうれしい。
いくつかの点について修正
- 背景に雨のアニメーションを追加。
- 新しい投稿が真ん中に入るように修正。
- 修正点
- リンクのあとの文字がリンクみたいな青色で表示されている。
- おそらくスレッドになっていたツイートが切り離されてしまっている。(リスト作成時にツイート同士のリンク・つながりまでは読み込んでいない)
- フリー素材の画像が少なすぎて、よく被る。
- なにかへの返信は、Xのように縦につながって表示されるほうが良い
さらにいくつかの点を修正
-
アイコンを作成し、別にあった「さらに読み込む」ボタンをアイコンに統合。
-
書き込みタブを、メインラインのサイドに移動。
-
要修正点
- なんか少し表示がすくない。
学習メモ
- .pngファイルは背景透過できるが、.jpgでは背景透過できず一緒くたの1レイヤーになってしまうので、このようなアイコンをつくるときは、.png。また、LINE上でやりとりされた画像は自動的に.jpgに圧縮されている。
- いままで、違うプログラミング言語は、同じファイル内で実行できないと思い込んでいたが、GeminiがHTMLとjavascriptが混ざったコードを出力してきて、これでも行けますと言っていたので驚いた。
- リツイートの本文情報がRT+引用という形式なら、普段のリツイートとは、埋め込みによる表示形式だったのだろうか。
- 機能をひとつずつ追加していく方式だと、新しいコードを差し替える範囲を間違えやすく、エラーも起きやすい
- Vscodeに標準搭載のAIチャット欄の生成するコードは割とめちゃくちゃ
- guthubの使い方がまだよくわからないが、一度に大量の不具合が出たり、徐々に追加実装する開発方針では、バージョン管理の重要性はよくわかった。
- .mdの表記法を少しだけ覚えた。
- 別のプログラミング言語の特性や利便性とそれぞれの機能はどんなものなのか。
- あるプロダクトの開発を目指すときの言語選定はどのように行われるのか。
- Qiitaの記事作成を含めた本日の作業時間:約11時間。
- 今日はGeminiにコードを生成してもらい、vscodeに張り付けてその都度デバッグしていたが、もっとやりやすい方法がある気がする。


