わいえむねっと

Contents
Categories
Calendar
2026/08
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Monthly Archives
~2000/01
Recent Entries
RSS1.0
Templates
Information
Processed: 0.073 sec
Chashed: -
2026/08/31 Mon
PCを再起動したらHyper-Vゲストで立ち上げていたサービスに繋がらなくなってたのでIPを固定化する。

ホスト(Windows 11)

ゲートウェイを作成する。

  • Hyper-Vマネージャー
  • 仮想スイッチマネージャー → 内部を選択して仮想スイッチの作成
  • 設定
  • ネットワークとインターネット → ネットワークの詳細設定 → (作成したスイッチ) → 追加のプロパティを表示
  • 手動を選択してIPアドレスとサブネットマスクを設定

ゲスト(Ubuntu 26.04)

netplan で設定する。
最初 YAML を手で編集していたけど、コマンドでもいけるようなのでそっちでメモ。

Ubuntu Manpage: netplan-set - write Netplan YAML configuration snippets to file
https://manpages.u​buntu.com/manpages/resolute/man8/netplan-set.8.html​

$ sudo netplan set --origin-hint 99-config ethernets.eth0.addresses="[(ゲストのIPアドレス)/24]"
$ sudo netplan set --origin-hint 99-config ethernets.eth0.routes="[{to: default, via: (ゲートウェイのIPアドレス)}]"
$ sudo netplan set --origin-hint 99-config ethernets.eth0.nameservers.addresses="[8.8.8.8, 8.8.4.4]"

でIPアドレス、ゲートウェイ、DNSを設定。

$ sudo cat /etc/netplan/99-config.yaml
network:
  version: 2
  ethernets:
    eth0:
      addresses:
      - "(ゲストのIPアドレス)/24"
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
      routes:
      - to: "default"
        via: "(ゲートウェイのIPアドレス)"

のようなファイルが生成される。

$ sudo netplan try

で反映。 いつもと違う梅干し買ってみたけどうまいな。
2026/08/30 Sun
日が落ちてからスーパーに行こうとアパートから出たら自転車が二台。
見たことのある形状。
これ、お巡りさんのやつだ。

アパートでなにか?
2026/08/29 Sat
お好み焼きでも焼くか。
2026/08/28 Fri


突発飲みで現場ビルの中華料理屋へ。
ハイボール4杯目で自動的にピッチャーになる。

店員さんには覚えられてるか聞いたら、「覚エテルヨ!前モタクサン飲ンデタネ!」って言われた。
2026/08/27 Thu
まほよの発売日なので秋葉原の書泉に寄って帰り購入。
久しぶりに利用したけど、レジが1階に集約かつセルフレジ導入とかされてたんだ。 ささみ焼きながらささみ食べてる。
2026/08/26 Wed
Teams 死んでるじゃん。
2026/08/25 Tue
高級キーボード「フィルコ」破綻、本業堅調も為替予約失敗引きずる - 日本経済新聞
https://www.nikkei​.com/article/DGXZQOUC17​6M80X10C26​A8000000/

FILCO死んだの?! なんか右耳が痛い。
2026/08/24 Mon
焼鳥重キャンセル。
2026/08/23 Sun

TweetVault④

前回

TweetVault①
TweetVault②
TweetVault③

絞り込み UI の改善

テキストボックスにタグを入力する形で複数条件の絞り込みに対応したけど、タグ一覧から選択するようにしたい。

  • Ctrl を押しながら選択した場合は複数選択にする。
  • 選択済みの場合は解除。
  • 後述の除外選択中のタグを Ctrl で選択した場合は状態を上書き。
  • Alt を押しながら選択した場合は除外するタグの選択として扱う
  • こちらも複数選択可。
  • 選択済みの場合は解除。
  • 通常選択中のタグを Alt で選択した場合は状態を上書き。
  • 通常選択のハイライトが青なのに対して、こちらは赤にする。
  • Ctrl も Alt も押下していない場合は従前の動作で排他選択。
  • 複数選択や除外選択されているタグがある場合は解除する。

frontend/src/app/page.tsx
@@ -17,3 +17,3 @@
   const [bookmarks, setBookmarks] = useState<Bookmark[]>([]);
-  const [selectedTag, setSelectedTag] = useState<string>();
+  const [selectedTag, setSelectedTag] = useState({inc:[], exc:[]});
   const [searchQuery, setSearchQuery] = useState('');
@@ -54,3 +54,3 @@
       const data = await api.getBookmarks({
-        tag: selectedTag,
+        tag: JSON.stringify(selectedTag),
         search: searchQuery,
@@ -117,4 +117,26 @@
 
-  function handleTagSelect(tag: string | undefined) {
-    setSelectedTag(tag);
+  function handleTagSelect(tag: string | undefined, e?: any) {
+    if (!tag) {
+      setSelectedTag({inc:[], exc:[]});
+      return;
+    }
+    setSelectedTag(prev => {
+      if (e && e.ctrlKey) {
+        return {
+          inc: prev.inc.includes(tag)
+             ? prev.inc.filter(item => item !== tag)
+             : [...prev.inc, tag],
+          exc: prev.exc.filter(item => item !== tag)
+        };
+      } else if (e && e.altKey) {
+        return {
+          exc: prev.exc.includes(tag)
+             ? prev.exc.filter(item => item !== tag)
+             : [...prev.exc, tag],
+          inc: prev.inc.filter(item => item !== tag)
+        };
+      } else {
+        return {inc:[tag], exc:[]};
+      }
+    });
     setCurrentPage(1);
選択中のタグを保持する selectedTag を、文字列から対象/対象外リストを保持するオブジェクトに変更。
Ctrl/Alt 押下時の処理を追加。

frontend/src/components/bookmarks/SearchAndFilter.tsx
@@ -8,3 +8,3 @@
   onTagSelect: (tag: string | undefined) => void;
-  selectedTag?: string;
+  selectedTag?: {};
   onDeleteTag?: (tagName: string) => void;
@@ -88,3 +88,3 @@
       // If the deleted tag was selected, reset to show all bookmarks
-      if (selectedTag === tagName) {
+      if (selectedTag.inc.includes(tagName) || selectedTag.exc.includes(tagName)) {
         onTagSelect(undefined);
@@ -122,3 +122,3 @@
             className={`rounded-full px-3 py-1 text-sm whitespace-nowrap ${
-              !selectedTag
+              selectedTag.inc.length == 0 && selectedTag.exc.length == 0
                 ? 'bg-blue-600 text-white'
@@ -132,6 +132,6 @@
               <div
-                onClick={() => onTagSelect(tag.name)}
+                onClick={(e) => onTagSelect(tag.name, e)}
                 className={`px-3 py-1 text-sm whitespace-nowrap flex items-center cursor-pointer ${
-                  selectedTag === tag.name
-                    ? 'bg-blue-600 text-white'
+                  selectedTag.inc.includes(tag.name) ? 'bg-blue-600 text-white' :
+                  selectedTag.exc.includes(tag.name) ? 'bg-red-600 text-white'
                     : 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600'
選択中タグに関する判定を修正。
キーボードイベントの引き渡しを追加。

frontend/src/components/bookmarks/TagMenu.tsx
@@ -8,3 +8,3 @@
   onSuccess: () => void;
-  selectedTag?: string;
+  selectedTag?: {};
   onDeleteTag?: (tagName: string) => void;
@@ -134,3 +134,4 @@
           className={`p-1 rounded-full cursor-pointer ${
-            selectedTag === tag.name ? 'hover:bg-blue-700' : 'text-gray-500 hover:bg-gray-200'
+            selectedTag.inc.includes(tag.name) ? 'hover:bg-blue-700' :
+            selectedTag.exc.includes(tag.name) ? 'hover:bg-red-700' : 'text-gray-500 hover:bg-gray-200'
           }`}
選択中タグに関する判定を修正。

backend/internal/services/bookmark_service.go(前回からの差分)
@@ -4,3 +4,2 @@
     "encoding/json"
-    "fmt"
     "log"
@@ -8,2 +7,3 @@
     "strings"
+    "slices"
 
@@ -197,6 +197,9 @@
 
-    type Tag struct {
+    type RequestTag struct {
+        Include []string `json:"inc"`
+        Exclude []string `json:"exc"`
+    }
+    type QueryTag struct {
         Name string `json:"name"`
     }
-    var tags []Tag
 
@@ -208,6 +211,24 @@
     // Apply tag filter if provided
-    if tag == "untagged" {
-        query = query.Where("tags_json::jsonb = ?", "[]")
-    } else if tag != "" {
-        tags = append(tags, Tag{Name: tag})
+    if tag != "" {
+        var req RequestTag
+        if err := json.Unmarshal([]byte(tag), &req); err != nil {
+            return nil, 0, err
+        }
+        if slices.Contains(req.Include, "untagged") {
+            query = query.Where("tags_json::jsonb = ?", "[]")
+        } else {
+            if len(req.Include) != 0 {
+                var tags []QueryTag
+                for _, v := range req.Include {
+                    tags = append(tags, QueryTag{Name: v})
+                }
+                tagsJson, _ := json.Marshal(tags)
+                query = query.Where("tags_json::jsonb @> ?", tagsJson)
+            }
+            for _, v := range req.Exclude {
+                tags := []QueryTag{{Name: v}}
+                tagsJson, _ := json.Marshal(tags)
+                query = query.Not("tags_json::jsonb @> ?", tagsJson)
+            }
+        }
     }
@@ -218,18 +239,5 @@
         for _, word := range words {
-            if strings.HasPrefix(word, "#") {
-                tags = append(tags, Tag{Name: strings.TrimPrefix(word, "#")})
-            } else if strings.HasPrefix(word, "-#") {
-                query = query.Not("tags_json::jsonb @> ?", fmt.Sprintf(`[{"name":"%s"}]`, strings.TrimPrefix(word, "-#")))
-            } else {
-                query = query.Where("full_text ILIKE ? OR name ILIKE ? OR screen_name ILIKE ?",
-                "%"+word+"%", "%"+word+"%", "%"+word+"%")
-            }
-        }
-    }
-    if len(tags) != 0 {
-        jsonData, err := json.Marshal(tags)
-        if err != nil {
-            return nil, 0, err
+            query = query.Where("full_text ILIKE ? OR name ILIKE ? OR screen_name ILIKE ?",
+            "%"+word+"%", "%"+word+"%", "%"+word+"%")
         }
-        query = query.Where("tags_json::jsonb @> ?", jsonData)
     }
フロントエンドから渡されたタグのリストから検索するよう改修。
テキストボックスの入力からタグ検索する処理は除去。複数キーワード対応は残す。
元の処理に合わせるためにいったんアンマーシャルしているのが微妙。
2026/08/22 Sat
胆のう摘出の手術をしてから二か月が経過。
術後の状態確認で MRI を撮ってくる。
結果は特に問題なし。

あと、今回の MRI でも膵臓には何も写りませんでした。
過去に診断された IPMN はなかったことになった。

先生「他に何か気になることはありますか」
なや「腎臓で石が見つかっていたのが気になってるくらいですかね」
先生「(写真をスクロール)あーこれですね。これが下に落ちると…」
なや「めちゃくちゃ痛いやつですね」
先生「そう、めちゃくちゃ痛いやつww」

不意に「痛いやつ」って差し込まれてツボに入ったのか、先生爆笑してた。 スーパーの弁当コーナーでなんにしよと眺めてたら、店員さんに案内されてきたお婆さんが鮭ハラス飯を買っていき、うまそうだなと思ったので自分も購入。

帰ってから気付いたけど、これ二人前だな? 今日はかよちゃん。

土砂降りだったけど、雨雲レーダーを見た感じ2時間もすれば通り過ぎそう。
飲んでいるうちに上がるだろ。
足元びしょ濡れになるだろうから、靴下は脱いでサンダルで出掛ける。


かよちゃん - 下総中山/居酒屋 | 食べログ
https://tabelog.co​m/chiba/A1202/A120202/12020652/





いつものように栄川を二合。
惣菜の盛り合わせ。




お次は木戸泉を二合。
今日は いかの丸干しがあったぞ。



女将さんが以前勤めていたスーパーの店長さんが今も昼営業に来てくれているって話は前に聞いていたけど、いつも定食と惣菜盛り合わせを食べながらビールに日本酒三合を飲んでいると聞いてびびる。
その量飲んで仕事戻ってるの。 雨はすっかり上がった。予定通り。
今日は雨上がりのにおいがしないなと思いつつ、江戸川沿いを歩く。



またサンダルで10km超歩いてる。


今日も元気。
2026/08/21 Fri
冷凍庫のロックアイスがでかいかたまりになってた。
一回溶けたなこれ。
開けっ放しになってたか?

前に買い替えたのが2009年なので、そろそろ故障してもおかしくはないんだよな。 歯医者20回目。
仮歯無限ループ。
2026/08/20 Thu
朝東京ばな奈。
2026/08/19 Wed
昨日と打って変わって忙しい。
2026/08/18 Tue
暇すぎて業務と関係ないコードずっと読んでる。
2026/08/17 Mon
朝自販機でお茶を買ったらSuicaの残額が15円。 LINE公式からメッセージがきててなんだろと思ったら、

いつもLINEをご利用いただき、誠にありがとうございます。

FacebookアカウントによるLINEログイン機能のサポートは、2024年1月に終了しました。それに伴い、現在ご利用中のログイン方法では、ご利用いただけなくなります。

現在のLINEアカウントを引き続き利用するには、2026年12月31日までに電話番号を登録してください。

期日までに電話番号を登録されない場合、お客様のFacebook連携IDは削除され、LINEアカウントがご利用いただけなくなります。アカウントに紐づく情報やアイテムを継続してご利用いただくためには、必ず2026年12月31日までに電話番号の登録を完了してください。

Facebook連携を使って電話番号登録を回避して複数アカウントつくっていたのがついに無効になった。
2026/08/16 Sun

TweetVault③

前回

TweetVault①
TweetVault②

絞り込み機能の拡張

標準だと「テキストボックスに入力した単一ワード」+「一覧から選択した単一タグ」の絞り込みにしか対応していないので、複数条件で絞り込めるようにしたい。

  • 複数ワードの絞り込みに対応
  • テキストボックスに「#xxx」の形式で入力した場合にタグとして絞り込む。複数指定可。一覧で選択したタグとAND。
  • テキストボックスに「-#xxx」の形式で入力した場合にタグを含まないものに絞り込む。複数指定可。

backend/internal/services/bookmark_service.go(前回からの差分)
@@ -7,2 +7,3 @@
     "strconv"
+    "strings"
 
@@ -196,2 +197,7 @@
 
+    type Tag struct {
+        Name string `json:"name"`
+    }
+    var tags []Tag
+
     query := s.db.Model(&models.BookmarkView{})
@@ -205,3 +211,3 @@
     } else if tag != "" {
-        query = query.Where("tags_json::jsonb @> ?", fmt.Sprintf(`[{"name":"%s"}]`, tag))
+        tags = append(tags, Tag{Name: tag})
     }
@@ -210,4 +216,20 @@
     if search != "" {
-        query = query.Where("full_text ILIKE ? OR name ILIKE ? OR screen_name ILIKE ?",
-            "%"+search+"%", "%"+search+"%", "%"+search+"%")
+        words := strings.Fields(search)
+        for _, word := range words {
+            if strings.HasPrefix(word, "#") {
+                tags = append(tags, Tag{Name: strings.TrimPrefix(word, "#")})
+            } else if strings.HasPrefix(word, "-#") {
+                query = query.Not("tags_json::jsonb @> ?", fmt.Sprintf(`[{"name":"%s"}]`, strings.TrimPrefix(word, "-#")))
+            } else {
+                query = query.Where("full_text ILIKE ? OR name ILIKE ? OR screen_name ILIKE ?",
+                "%"+word+"%", "%"+word+"%", "%"+word+"%")
+            }
+        }
+    }
+    if len(tags) != 0 {
+        jsonData, err := json.Marshal(tags)
+        if err != nil {
+            return nil, 0, err
+        }
+        query = query.Where("tags_json::jsonb @> ?", jsonData)
     }
冷凍揚げナスで味噌汁。
2026/08/15 Sat


手術してから走れていなかったけど久しぶりに。

前日の雨で路面は悪く、ところどころ水浸しの状態。
カニも道路に迷い込んでた。
迷いガニオーバーラン。




サンダルで10km歩き回ってるおじさん。
2026/08/14 Fri
ブックマーク2500件の整理完了。 整理していた中で「元十徳の店員さんがやっている店」というのが発掘されて、そういえばブックマークしてたっけと思い出す。



調べてみると、こちらの店のオープンは2012年。
自分が十徳に初めて行ったのは2014年なので自分が知っている店員さんではないか。
まぁせっかくなので行ってみようと一路中野坂上。



中野坂上に着いてみたところ既視感。
このときだ。

泥酔してスマホを紛失した翌朝、受け取りにいったのが中野坂上でした。。 お店は地上に出てすぐ。


居酒屋 じゃんだら - 中野坂上/居酒屋 | 食べログ
https://tabelog.co​m/tokyo/A1319/A131903/13149071/





ブックマークしていた記事だと日本酒をいろいろ扱っていそうだったけど見当たらず。
松竹梅 豪快を注文。

静岡おでん。
大根にすじぼこ。




松竹梅をもう一杯。
変わり種でモッツァレラ巾着。



立呑や じゃんだら(@janndara.nakanosakaue) • Instagram写真と動画
https://www.instag​ram.com/janndara.n​akanosakau​e/

居酒屋 じゃんだら(@izakaya_jandara) • Instagram写真と動画
https://www.instag​ram.com/izakaya_ja​ndara/

後で調べたら、インスタのアカウントが2つあり、下がリニューアル後のもの。
リニューアル前は日本酒をいろいろ扱っていたようだけど、変わってしまったのかな。 さくっと上がって次へ。
路地入ってすぐのところにL字カウンターのみの店があったのでネットで調べてみたけど情報が見つからず。
店名は福ちゃん。
新しい店というわけでもなさそうなんだけど。




店の外に貼ってあるメニューを見た感じ高いってわけでもないので入ってみる。





新宿 清酒。
アテに油揚げの納豆はさみ焼きを頼んだけどなかったので焼きさば。




福 純米吟醸。



入店時は自分一人だったけど、飲んでいるうちに一人二人とお姉さま方が。
ここも2杯でさくっと上がる。 移動して十徳へ。







壁のメニューから寿福絹子。
店員さんから「飲み方は?」と聞かれて一瞬「?」となったけど、これ焼酎か。日本酒じゃなかった。
まぁいいかとロックで注文。

アテにバクダン納豆。
さっき食べ損ねた納豆フラストレーションを解消。

続けて水鏡無私もロックで。




最後は日本酒で〆る。遊穂。
2026/08/13 Thu
コードブロックがある時にスマホからだと意図した表示になっていなかったのをずっと放置していたけどようやっと修正。

…したんだけど、手持ちのスマホで反映されず。
キャッシュのせいか。
仕方ないので、cssのリンクにクエリパラメータを付与。

これいい加減なんとかならんのかね。

TweetVault②

前回

TweetVault

アクセス改善

バックエンドへのアクセスが localhost になっていたのをポートフォワードで捻じ曲げていたけど、ポートフォワードなしで動くようにしたい。

frontend/src/lib/api.ts に下記コードがあり、.env に NEXT_PUBLIC_API_URL を定義してやればいいのねと思ったけどダメ。

const API_BASE_URL = (process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080') + '/api';

それならと、この定義を直接書き換えてみたけどダメ。は?

調べてみると、frontend/.next/server/app/page.js で API_BASE_URL が設定されていた。
で、そこの元はどこだと探すと docker-compose.yml。

  frontend:
    environment:
      - NEXT_PUBLIC_API_URL=http://localhost:8080

ここを仮想環境のアドレスに書き換えて解決。


データ反映の改善

タグを付与した後、しばらくしないと反映されないのをどうにかしたい。

調べた感じ、
  • DBには即時反映されている
  • APIを直接叩いてみると、単体取得では即時反映されているのに、ページ取得では即時反映されていない

なんでページ取得だと即時反映されないんだと思いながらDBの構造を眺めていたところ、マテリアライズドビューが目に入る。
マテリアライズドビュー経由かどうかの差異かこれ。
確認したら、5分おきの更新になっていた。

以下の対処で解決。
  • マテリアライズドビューと同じ内容のビューを別名で定義
  • 新規ビューから取得するよう向き先を変更

backend/internal/models/materialized_view.go
@@ -31,3 +31,3 @@
 func (BookmarkView) TableName() string {
-    return "bookmark_views"
+    return "bookmark_views_normal"
 }


未整理ブックマークの表示

タグを付与していないデータだけを表示したい。

ダミーのタグを作成し、絞り込み条件でそのタグを指定された場合はタグのないデータを抽出するよう対応。

backend/internal/services/bookmark_service.go
@@ -202,3 +202,5 @@
     // Apply tag filter if provided
-    if tag != "" {
+    if tag == "untagged" {
+        query = query.Where("tags_json::jsonb = ?", "[]")
+    } else if tag != "" {
         query = query.Where("tags_json::jsonb @> ?", fmt.Sprintf(`[{"name":"%s"}]`, tag))



これなんでマテリアライズドビュー使ってるんだろと思っていたけど、「1件の投稿に紐づくn件の情報(メディア、タグ)を JSON 変換、1カラムとして取得」とかしてるからか。
変換のオーバーヘッドを減らすためなんだな。

コードは簡潔になってるけど、トレードオフで犠牲してるものがでかすぎない?w 今、瞬断したな?
2026/08/12 Wed
Xのブックマークが2500件とかになっていて整理したかったのでアドオンなど見てみる。

Chrome 拡張機能

「X bookmark tag」で検索

XSaved — Bookmark Manager for X (Twitter)

  • ブックマークタブを独自表示と切り替える形式
  • 日本語でタグは付けられるけど、検索できないのが致命的
  • タグがマウスオーバー時しか表示されないというのもマイナス

X Bookmark Manager & Exporter (Twitter)

  • エクスポートして外部サイトに登録する形式
  • UIがカス

XBookmark - Twitter Bookmark Manager

  • 別画面を表示する形式
  • クソデカ広告が表示されてカス

Favourites.io Search X/Twitter Likes and Bookmarks

  • エクスポートして外部サイトに登録する形式
  • 有償

X Bookmark Tagging

  • サイドパネルを表示する形式
  • 国産
  • 無償だとタグが3つしか作成できないので実質有償
  • そもそも1投稿に対して1つのタグしか付けられないのが致命的

X (Twitter) Bookmark Exporter

  • 上の X Bookmark Manager & Exporter と同じ

X Vault - X スマートブックマーク管理

  • 別画面を表示する形式
  • 無償だとデフォルトのタグしか使用できないので実質有償

Noya — Read Your X Bookmarks

  • 「この拡張機能は、セーフブラウジング保護強化機能で信頼されていません」警告がでるので試さず

Xtash

  • フロート画面を表示する形式
  • タグが付与済みかどうかは視認できるが、クリックしないとなんのタグを付与しているか確認できないのがマイナス

XBookmark Tagger

  • 「この拡張機能は、セーフブラウジング保護強化機能で信頼されていません」警告がでるので試さず

TweetVault

  • 別画面を表示する形式
  • インポート時に投稿内のタグからタグ付けされるのが邪魔。そういうことじゃないんだよ。
  • 表示がリスト形式なのもマイナス

サービス

dewey

  • インポート時に投稿内容からAIでタグ付けされるのが邪魔。余計なことをするな。
  • 無償だとタグ付けできないので実質有償

GitHub

TweetVault

  • Chrome 拡張機能に同名のものがあったが別物
  • ローカルでWEBアプリを構築する形式



GitHub の方の TweetVault が面白そうだったので別途まとめ。

TweetVault


GitHub - helioLJ/TweetVault: A full-stack bookmark manager for Twitter/X posts with tagging, search, and archiving capabilities. Built with Next.js, Go, and PostgreSQL. · GitHub
https://github.com​/helioLJ/TweetVault​


インストール

Docker の利用が推奨されている。
手持ちの Linux 環境が古いものばかりだったので新規構築しようとしたけど、どうも最近の Ubuntu は Windows Server 2012 の Hyper-V だとカーネルパニックでこける。
仕方ないので、Windows 11 の Hyper-V で構築。
Ubuntu 26.04 Server install image を使用。


2026年版:UbuntuへのDocker & Docker Compose 推奨インストール手順 - TUKUMO工房
https://tukumolog.​com/ubuntu-docker-compose-install-2026/

を参考に Docker をインストール。
続けてコンテナをビルド。


実行

Access the application:
Frontend: http://localhost:3000
Backend API: http://localhost:8080
Database: localhost:5432

マニュアルに従い、仮想環境のポート3000にアクセス。
画面は表示されたが、

TypeError: Failed to fetch

というエラーがでている。
デバッガで見た感じ、バックエンドへのアクセスが仮想環境ではなく localhost になってしまっている。

設定でどうにかできそうな気がしたけど、いったんターミナルソフトのポートフォワードで localhost に対するアクセスを仮想環境に流す。
エラーは変わらず。

ログを見ると起動途中でバックエンドが

Failed to load configuration: error loading .env file: open .env: no such file or directory

を吐いている。
確かに .env ファイルはない。

Docker を利用しない場合のインストール手順に .env ファイルについて記載があったので、そちらに従い配置。
これでエラーは解消。


ブックマークのインポート

ブックマークは別ツールでエクスポートしたファイルをインポートする形式なので、そちらのツールの導入から。
Tampermonkey か Violentmonkey が必要ということなので、Violentmonkey をインストール。

GitHub - prinsss/twitter-web-exporter: Export tweets, bookmarks, lists and much more from Twitter(X) web app. (推文/书签/收藏/列表导出工具) · GitHub
https://github.com​/prinsss/twitter-web-exporter


WebExporter の「データをエクスポート」で JSON ファイルを出力。
続いて TweetVault の「Upload Bookmarks」からアップロードしようとしたところはじかれた。
メディアのエクスポートファイルとセットでアップロードする必要があるらしい。

WebExporter から「メディアをエクスポート」をするにあたり、ブックマーク数がアホみたいにあるのでお試しで数件だけ選択してエクスポート。
ブックマークの JSON ファイルとメディアの ZIP ファイルを両方指定することでアップロードは通った。
表示もOK。
ブックマークは全量あり、画像はメディアをエクスポートした対象だけ表示されている状態。


画像の補完

わざわざ画像をインポートさせているのだからその画像を表示しているのかと思いきや、画像は元のアドレスから表示されていた。
テーブルの構造を見た感じ、バイナリは保持しているようだけど、なくてもいけそうな?

列名 内容
id 連番
tweet_id JSON内の id
type JSON内の media->type
url JSON内の media->url
thumbnail JSON内の media->thumbnail
original JSON内の media->original
file_data ZIP内のファイル実体
file_name ZIP内のファイル名
created_at作成日時
updated_at更新日時


file_data と file_name を除外した状態でデータを補完してみたところ、問題なく表示された。

import json

with open('export.json', encoding='utf-8') as fp:
    obj = json.load(fp)
    i = 0
    for x in obj:
        for media in x['media']:
            i += 1
            sql = "insert into media (id,tweet_id,type,url,thumbnail,original,created_at,updated_at)" \
                  " values ({},'{}','{}','{}','{}','{}',current_timestamp,current_timestamp);".format( \
            i, \
            x['id'], \
            media['type'], \
            media['url'], \
            media['thumbnail'], \
            media['original'])
            print(sql)


画像表示のカスタマイズ

画像の縦横サイズが一律になっており、縦長の画像だと中央部分だけの表示になっている。
これをどうにかしたい。

高さを指定している場所が見つからず悩んだけど、幅と縦横比から決定されていて直接指定されてなかった。ああ。

BookmarkCard.tsx の下記を修正して解決。
  • img タグの親 div に指定されている aspect-video クラスが縦横比の指定なのでこれを外す
  • 親 div で高さが決定されなくなると fill で付与される position:absolute が原因で画像が表示されなくなるので fill を外す
  • fill を外すと幅と高さを求められるので別途指定

frontend/src/components/bookmarks/BookmarkCard.tsx
@@ -342,3 +342,3 @@
                   key={media.id} 
-                  className="relative aspect-video cursor-pointer overflow-hidden rounded-lg w-full"
+                  className="relative cursor-pointer overflow-hidden rounded-lg w-full"
                   onClick={() => setSelectedMedia({
@@ -351,3 +351,5 @@
                     alt=""
-                    fill
+                    width={0}
+                    height={0}
+                    style={{ width: "100%", height: "auto" }}
                     quality={100}



ブックマークの同期が手動なのは手間だけど、自前でカスタマイズできるってのはいいかなと。 ケンタッキーのウマ娘コラボメニューをアテに飲酒。
2026/08/11 Tue
賞味期限が8/2の飲むヨーグルトが発掘されたので飲む。 納豆の賞味期限も切れてたので食う。
2026/08/10 Mon

「永谷園監修 広東風かに玉風味まん」
永谷園「広東風かに玉」をイメージしたフィリングを包みました。



「永谷園監修 麻婆春雨まん」
永谷園「麻婆春雨」をイメージしたフィリングを包みました。
2026/08/09 Sun
ブラックニッカ4リットル補充。 ポテチとシソの葉をいっしょに食うやつやってみたけど別にうまくはない。
シソの葉20枚をもさもさ食う。 ワタサバが全話無料になってたのでまとめて読む。
高校教師編の評価が高いのが気になってたんですよね。

本田さん別人になってません?
2026/08/08 Sat
パスタの多いトルコライス。
16:50 組長 十徳応援いくか
16:51 なや ファイトだよ!(スタンプ
16:52 なや んじゃいくか
16:53 組長 あはっ(スタンプ

というわけで、別館営業中の十徳へ。


酒処十徳
http://www.juttok​u.com/
2026年8/1~8/31まで十徳本店はビルメンテナンスのため休業させていただきます。 この間は、十徳別館で営業を行います(8/4~8/28 定休:日曜・月曜)。





一杯目は写楽。
別館限定メニューの松坂牛肉すき焼き。




お次は栄光冨士。
栄光冨士の本醸造って初めて飲みましたね。
じゃがいもアンチョビソース。




自分が西條鶴、組長が酔鯨 Summer。
まぐろ脳天タタキ。




自分が鍋島ブルーラベル、組長が鳳凰美田。
白オクラ自家製ポンズかけ。




作の和悦。
福耳とうがらしと豚肉のみそ炒め。




すずしな。
カウンターに並んでいる桶はなんだろと思っていたらこれのため。
グラスでの提供もあるってことだったけど、せっかくなので桶でだしてもらう。
うなぎ蒲焼串と旬野菜串揚げ5種盛り合わせ。



  • 福島 写楽 純米酒
  • 山形 栄光冨士 辛口本醸造
  • 広島 西條鶴 無濾過純米酒
  • 高知 酔鯨 吟麗 Summer
  • 佐賀 鍋島 ブルーラベル 愛生
  • 栃木 鳳凰美田 限定酒 本吟醸 無濾過生酒
  • 三重 作 純米吟醸 和悦
  • 秋田 すずしな 生貯蔵酒
バーになだれ込む。


オールドバレー (OLD VALLEY) - 新宿/バー | 食べログ
https://tabelog.co​m/tokyo/A1304/A130401/13095497/





ここのところずっとスコッチだったのでたまにはバーボンをと、ノブクリーク。




ラフロイグ ホグスヘッド。
これは前回も飲んだやつですね。




ワットウイスキー インチガワー。




マスターオブモルト ダルユーイン。 さらにラーメン屋にもなだれ込む。




伍福軒に取って代わられた思ったらほどなくして復活した天一へ。




唐揚げ定食。
2026/08/07 Fri
明日から夏季休暇に入るので今日は日本酒でも飲もうかなと。
スーパーで刺身買って帰るかと思ったけど、近所の や台寿司が持ち帰りに対応していたなとモバイルオーダーしてみる。




刺し盛にガリ天、タコの唐揚げを注文。




刺し盛はマグロ、イカ、タイ、ハマチ、エビ、ツブ貝、ウニ、カズノコ、イクラと結構な品数。
2026/08/06 Thu
令和のダラさんのOPをずっと聞いてる。
2026/08/05 Wed
普段利用しない共用階のトイレの個室を利用したところ、腰を掛けた瞬間にせせらぎの音が。

「音姫?!やばい女子トイレだったか?!!」

慌てて出ようと扉を開けたら目の前に小便器。
男子トイレだ。

扉をそっと閉じる。
2026/08/04 Tue
十徳の古民家営業が今日からのはずなので行ってみる。




開いてる!




両関になめろう。




懐かしい店内。
お次は喜楽町のセカンド。




亀齢にちくわの磯辺揚げ。



会計時、店員さんに古民家久しぶりでしたって話をしたら、「こっちも久しぶりです」って返されて笑った。


古民家営業メモ

  • 本店で配布していた割引券は古民家用
  • 古民家でも割引券を配布しており、こちらは本店用
  • 古民家営業中はスタンプ押下なし



  • 秋田 両関 純米酒
  • 滋賀 喜楽町 純米酒 セカンド
  • 広島 亀齢 辛口純米 八拾
2026/08/03 Mon
イヤーピースが根元から千切れて、イヤーピースが耳の中に残ったままイヤホン本体がすっぽ抜けてった。
2026/08/02 Sun
しそをもそもそかじりながら死んだ目で飲酒。
2026/08/01 Sat
二日連続で一本ぐそがでた。
大腸の調子が良い。 うなぎの白焼きで日本酒 四合一本飲む。
うなぎが2k。日本酒も2k。