批次下載 YouTube 縮圖並調整尺寸
前言
今天在更新網站上「Tiny Desk Concerts」的欄位,突然想到沒有把下載步驟記下來,在這邊補一下。
第一步:用 yt-dlp 抓整個播放清單的縮圖
yt-dlp ^
--skip-download ^
--write-thumbnail ^
--convert-thumbnails jpg ^
-o "%(title)s.%(ext)s" ^
"{播放清單/影片網址}"
第二步:用 ImageMagick 統一縮放
magick mogrify -resize 480x270! *.jpg
mogrify 會直接覆寫原檔,省下另開資料夾的功夫。
尺寸後面的 ! 代表忽略原始長寬比,強制拉伸到指定尺寸。
沒加的話,ImageMagick 會把 480x270 當成最大邊界框,在框內保持原始比例縮放。
筆記
大小寫問題讓網站連結失效
發現問題
今天偶然發現之前寫的多益資源整理,這篇文章連結點下去會直接跳回首頁。
奇怪,網址明明還停在 /blog/toeic-resources-2026/,內容卻是首頁。
但我在本地跑沒有問題啊!?
想說是不是 Cloudflare Pages 的問題,但往回前翻好幾版都有這個問題。
找出問題
我先去看了 sitemap、RSS、文章列表頁,所有指向這篇的連結都是小寫 /toeic-resources-2026/,沒有問題。
也跑去看了 public/blog/ 底下的資料夾,確實有 toeic-resources-2026/index.html,檔案在啊。
那為什麼 Cloudflare 找不到?
我請 AI 幫我比對 git 跟磁碟上的檔名,這時候真相浮出水面:
GIT: public/blog/TOEIC-resources-2026/index.html
DISK: public/blog/toeic-resources-2026/index.html
兩邊的大小寫不一樣。
為什麼
雖然我想不起來了,不過最有可能的情況應該是,我手動把資料夾從大寫的 TOEIC-resources-2026 改成小寫的 toeic-resources-2026,因為其他文章 slug 都是小寫,看起來比較一致。
當時改完,本機看一切正常,就 commit、push 上去了,根本沒注意到 git 其實沒抓到這次改名。
事後才知道,這是三個東西交織的結果:
- Windows 檔案系統大小寫不敏感,
Foo跟foo是同一個資料夾。 - Git on Windows 預設
core.ignorecase=true,會配合 Windows 的行為,這次的重新命名根本沒被當成一次 diff。 - Cloudflare Pages 跑在 Linux 上,大小寫嚴格區分,
/toeic-resources-2026/跟/TOEIC-resources-2026/對它來說是兩個完全不同的網址。
於是,本機看起來沒事,repo 裡其實還是大寫,部署上去就只認大寫,小寫的 URL 全部 404。
解決問題
要讓 git「真的」承認這次改名,得從索引裡先把舊的拿掉,再加回新的:
git rm -r --cached public/blog/TOEIC-resources-2026
git add public/blog/toeic-resources-2026
git commit -m "Fix case: TOEIC-resources-2026 → toeic-resources-2026"
git push
--cached 只動 git 索引,不會碰到磁碟上的實體檔案。
未來怎麼防範
可以考慮把 git 設成大小寫敏感:
git config core.ignorecase false
之後任何資料夾或檔名只要改了大小寫,git status 就會老老實實顯示「舊名稱被刪除 + 新名稱新增」,不會再無聲無息地漏掉。
再順手跑了一下 git status 全域掃描,確認其他歷史檔案沒有同樣的漏網之魚。
中島美雪《時代》
《時代》
中島美雪的代表作《時代》,是在 1975 年那一年,她連續闖過兩個比賽的一首歌。
1975 年 10 月:Popcon
10 月 12 日,第 10 屆 Popcon(ポピュラーソングコンテスト)在靜岡縣つま恋舉辦。
那一屆收到了 12,000 首 應募曲,中島美雪的〈時代〉拿下了最高獎 グランプリ。也因為這個獎,她得到了代表日本參加 11 月世界歌謠祭的資格。
1975 年 11 月:世界歌謠祭
11 月 16 日,「第 6 屆世界歌謠祭」在日本武道館舉辦。〈時代〉再次拿下了最大獎 Grand Prix(グランプリ)。
那一屆的主持人,是日本傳奇歌手坂本九,以及當時已經紅遍亞洲的翁倩玉。
下面這段珍貴的影片中,約 1 分 56 秒處,收錄了當年在世界歌謠祭的影像,你可以清楚地聽到坂本九與翁倩玉主持的聲音。
坂本九:「Entry number 30, 日本, 中島みゆき, "時代".」
翁倩玉:「Entry number 30, Japan, "Time Goes Around".」
伴奏的故事
〈時代〉在舞台上原本是有管弦樂團伴奏的版本。但拿下 Grand Prix 之後的 得獎者加演(安可),中島美雪走上台前,對著指揮耳語了幾句。接著,整個樂團安靜下來,她抱著吉他,只用一把吉他自彈自唱了一遍〈時代〉。
這個決定來自於她的伯樂、YAMAHA 音樂振興會的理事長 川上源一 對她說過的一段話:
「あなたはすごい詞を書く。将来、詞で勝負するようなアーティストに育って欲しい。できれば大音量をバックにするよりも、ギター一本で歌った方が、あなたの詞が人々に伝わる」
「妳寫的詞非常出色。希望將來你能成長為一位以歌詞實力取勝的藝術家。如果可以的話,與其背負著巨大的音量(伴奏),不如只用一把吉他自彈自唱,你的歌詞反而更能傳達進人們的心裡。」(AI 翻譯)
從那之後,中島美雪在每一張專輯的工作人員名單裡,都會寫上一行 「DAD 川上源一」,以此致敬這位恩人。
關於父親
中島美雪在出道單曲〈薊花姑娘的搖籃曲〉發行前一週(1975 年 9 月 16 日),父親就因腦溢血倒下、昏迷不醒。
10 月的 Popcon、11 月的世界歌謠祭,她其實都是從父親昏迷的病房趕到會場上台的。父親後來於 1976 年 1 月離世,始終沒能聽到女兒奪冠的消息。
世界歌謠祭頒給她的 5,000 美元獎金,後來拿去當作父親的葬儀費用。
1993 年的彩蛋
中島美雪在 1993 年重新錄製了《時代》,歌曲的開頭,她取樣了在世界歌謠祭裡面,主持人坂本九與翁倩玉的介紹詞,以及歌曲開頭的一小段演唱。
翁倩玉:「Entry number 30, Japan, compose and sung by Miyuki Nakajima, the title of the song: Time Goes Around.」
(這聲音也太美了吧!!)
備註
我在「這篇貼文」中提到我前陣子跑去看了《陽光女子合唱團》,才發現其實我以前經常聽到這位國民阿嬤翁倩玉的聲音。
至於坂本九的話,我最喜歡的歌曲是《見上げてごらん夜の星を》。
參考資料
- ヤマハ音楽振興会:第 6 回世界歌謠祭 (1975)(主持人、得獎者、會場等基本資料)
- Tap the POP:中島みゆき「時代」③〜亡くなった父の言葉(父親病倒、昏迷、葬儀費的細節)
- 集英社オンライン:23 歳の中島みゆきがオーケストラ演奏を断り、ギター 1 本で『時代』を歌った理由
收集部落格 RSS 網址列表
最近「部落格問題挑戰」這個問答挑戰突然很多人響應。
想說可以收集一下大家的答案,就像 Ava 的「bear blog question challenge」一樣!
這樣的話,我就需要收集一下大家的 RSS Feed 了,在這邊記錄一下做法。
雖然都是 AI 在做。
目標
將 BlogBlog 同樂會 頁面上的所有部落格整理成一份可匯入閱讀器的 OPML 清單。
1. 取得部落格網址列表
- 在 BlogBlog 同樂會 頁面爬取所有連結。
- 去除重複網址,整理並輸出成 txt 檔案。
2. 將網址列表轉成 RSS Feed
- 先比對既有的 OPML(原本就訂閱過的就不用找了)
- 用平台規則猜 RSS 位置,用 cURL 去試試看,平台型部落格通常都會直接成功。
- 抓首頁 HTML,找
link rel="alternate",有的話通常就直接是 RSS 網址了。 - 測試常見路徑(
/feed、/rss、/index.xml、/atom.xml等等) - 輸出成
rss_feeds.csv:每個站的 RSS、來源、狀態
這時候大概能收集到九成的 RSS Feed 了,剩下的就手動稍微找一下,很快就處理完了!
最後輸出成 url.opml.xml,然後在我的 FreshRSS 閱讀器開一個帳號,把這份清單匯入進去。
之後只要上去搜尋關鍵字「部落格問題挑戰」就可以了!
e89295
TIL,《我的部落格》的網站名稱「e89295」,是用三個十六進位的 UTF-8 位元組來表示的:0xE8、0x92、0x95。
new TextDecoder().decode(new Uint8Array([0xE8, 0x92, 0x95]))
如何用 Telegram 傳送通知給自己
前言
前幾天看到 Eddie 在這篇文章中提到,戒了 IG 後「會想一直開自己網站刷留言,看看有沒有新留言!」。
其實我的這套「留言系統」有接「通知功能」耶!只要有人留言,就會觸發 Telegram 的機器人通知我,這樣我就能快快審核,不用定時一直上去檢查。
不過,更簡單的方法應該是:Google Apps Script 內建直接用 Gmail 發信,這樣還能順便備份留言,一舉兩得,簡單又好用!(但我還沒試過,講得我自己都想用了)
正文
有時候會希望程式跑完某件事之後,自動發個通知給自己,像是排程結束、伺服器異常、或是有人填了表單之類的。
這件事其實用 Telegram 來做超簡單,只要申請一個 BOT、拿到 Chat ID,然後用 POST 打一下 Telegram 的 API 就搞定了!
BTW,其實我早期一直都是用 Line Notify 來做通知,但是 Line 又複雜又難用,而且 2025 年 Notify 功能就收掉了,於是就改成用 Telegram 來做通知了。
筆記
I'm Marcus 的閱讀軌跡(推薦系統)
今天看到 I'm Marcus 的文章:「来玩玩新开发的小游戏吧」。
Marcus 在自己的部落格實作了一套基於「閱讀軌跡」的文章推薦系統,這個設計還滿有意思的。
我觀察到的一些東西:
- 文章向量壓縮到 64 維,整份資料不到 200KB,載入和計算速度都很快。
- 使用者記錄存在瀏覽器的 Local Storage,完全不需要後端,隱私性高又即時。
- 文章不僅能標記「喜歡」,還能標記「不喜歡」,系統會同時考慮兩種訊號。
- 根據「已反饋文章」計算出使用者向量,並對「未反饋文章」計算相似度,決定推薦哪篇文章,也不會重複推薦。
- 每次根據當下的狀態計算推薦,並且記錄下來,形成一條固定的閱讀軌跡。
我推測他的運作原理大概是:
- 使用者向量 =
AVG(喜歡文章向量) - AVG(不喜歡文章向量) - 計算所有的
Cosine Similarity(使用者向量, 未反饋文章) - 取 Top 1 作為推薦
幾個吹毛求疵的小缺點:
- 只有推薦一篇文章的話,我自己會覺得有點「被牽著走」的感覺,選擇有點太少了。(不過這樣才是「軌跡」,所以也不是缺點,只是一種取捨)
- 按「換點口味」會被視為負反饋,但這不一定代表我對該主題不感興趣,可能只是對該文章不感興趣而已。
- 要讓使用者評分實在是有點難度,但這確實是比較尊重使用者的做法。(通常會用隱性一點的特徵)
用 FFMPEG 製作 Nightcore 風格音樂
今天跟 GPT 學到了用 FFMPEG 製作 Nightcore 風格音樂的方法。
Nightcore 的核心特徵是「音調變高、速度變快」,聽起來像花栗鼠在唱歌的那種感覺。
指令
ffmpeg -i input.mp3 -af "asetrate=44100*1.35,aresample=44100" output.mp3
-
asetrate=44100*1.35:改變音訊的播放速率,將採樣率強制改為原來的 1.35 倍,音調與速度都會同步提高。 -
aresample=44100:將採樣率重採樣回標準的 44100Hz,確保檔案在所有設備上都能正常播放。
微調速度
atempo=1.05:純速度濾波器,不影響音調,用來微調最終節奏。
例如可以這樣搭配:
ffmpeg -i input.mp3 -af "asetrate=44100*1.3,aresample=44100,atempo=1.05" output.mp3
用 Embedding 做「相關文章」推薦
最近幫部落格做了一個「相關文章」功能,用 AI 的語義向量(Embedding)來計算文章之間的相似度。
原文:《DIY 系列:來做個「相關文章」功能》
原理
三個步驟:
-
把文章餵給 Embedding 模型,得到一組向量(一串浮點數)。這組向量代表文章的「語意」,語意越接近的文章,向量在空間中的距離也越近。
-
計算餘弦相似度,也就是兩個向量之間的夾角,越接近 1 代表越相似。
-
排序取前 K 名,就是「相關文章」了。
兩種 Embedding 方案
方案一:Gemini API(免費)
到 Google AI Studio 申請 API Key,呼叫 gemini-embedding-001 模型。
免費方案有速率限制,我的做法是每篇截取前 2000 字,每隔兩秒呼叫一次。
方案二:BGE-M3 本地端(也免費)
用 Ollama 在本機跑 BGE-M3,CPU 就能跑,完全離線。
ollama pull bge-m3
pip install ollama
import ollama
res = ollama.embeddings(model="bge-m3", prompt="文章內容...")
vector = res["embedding"]
快取機制
每次重新計算 Embedding 很耗時,所以用 Hash(標題 + 內文) 來判斷文章是否有改變,沒變就直接讀快取。
相似度計算目前是全部重跑(讓新舊文章可以互相連結),一百多篇大概三秒,還可以接受。
完整流程
- 載入快取,用 Hash 比對找出需要更新的文章。
- 清除已刪除文章的舊快取。
- 對需要更新的文章重新 Embedding,存入快取。
- 計算所有文章兩兩之間的相似度,排序取前 K 名。
- 輸出
related.json或直接生成靜態 HTML。