← 一覧に戻る

youtube-downloader

GitHub ↗ HTML 最終push: 2026/6/17 10:51

WIP(現在進行中)

Work In Progress

このプロジェクトで現在進行中の作業と、過去のスナップショットを記録する。

現在の状況

多言語対応(バナー方式)+ URL 正規化まで完了。保存ファイルの拡張子なし問題はクライアント側ダウンロードを検討するも CORS 不可で見送り(現状維持)。次は獲得戦略 W1(検索意図ページ4本)。 英語版5ページ + 言語案内バナーで非日本語ユーザーを取りこぼさない構造。Cloudflare で全 URL バリエーションが https://yclip.org/ に 301 統一済み。

直近の未決事項:拡張子自動付与

  • ダサ方式の構造上「videoplayback / 拡張子なし」はサーバーを通さず解決不可(googlevideo が yclip.org に CORS を返さないと実測確定)
  • 唯一の解は VPS ストリーミングプロキシ(Content-Disposition)だが帯域ゼロ原則を崩すため見送り。ユーザー数が伸びたら再評価(DECISIONS.md 2026-06-17 / ROADMAP 今四半期)
  • CDN URL の ip= ロックは実質ゆるく、将来プロキシ化しても住宅プロキシ非消費で VPS 直取得可能なことは確認済み

インフラ:

  • VPS: AWS Lightsail Tokyo nano_3_0($5/月、512MB RAM + swap 1GB、IPv4 静的IP 13.158.151.98
  • Proxy: Webshare Rotating Residential($3.50/月、1GB帯域)
  • DNS/SSL: Cloudflare(Flexible、Proxied)
  • メール: Cloudflare Email Routing で support@yclip.org → gmail
  • ドメイン: yclip.org(お名前.com、初年無料)

SSH: ssh yclip-server~/.ssh/config に登録済み、鍵 ~/.ssh/lightsail-yclip

ページ:

  • / トップ(URL入力 + 結果表示)、/en/ 英語版
  • /save#... 保存ガイド(noindex、PC/Android/iPhone 別、視覚モックアップ + リネーム手順付き)、/en/save
  • /terms /privacy /faq 法的・案内ページ + 各 /en/<page> 英語版
  • /sitemap.xml /robots.txt SEO 用(hreflang 対応済)
  • /health 監視用、/health/deepHEALTH_DEEP_KEY 必須

URL正規化(Cloudflare):

  • http://* → 301 → https://*(Always Use HTTPS)
  • www.yclip.org/* → 301 → yclip.org/*(Redirect Rule、preserve query)
  • 結果:https://yclip.org/ が唯一の正規 URL

多言語対応:

  • 日本語デフォルト、英語版は /en/* に配置
  • 全 10 ページに言語案内バナー(ブラウザ言語が ja でなければ「View in English」、ja なら「日本語で見る」)
  • LocalStorage で「閉じた」状態を記憶

ブランド/UX:

  • カラー: ink(ネイビー)+ brand(ブルー)
  • タイポ: Inter + Noto Sans JP
  • favicon、OGP(言語ニュートラル)、Twitter card
  • iOS の自動拡大抑制、共有メニューの位置を視覚化
  • ヒーローコピーは「貼って、取得、保存。」のみ(広告関連の約束なし)
  • 保存ページにタイトルコピーボタン + リネーム手順を全プラットフォームで案内

SEO:

  • canonical / description / og:locale 各ページ
  • JSON-LD: トップは WebApplication、FAQ は FAQPage
  • Google Search Console にドメイン登録済み、サイトマップ送信済み
  • robots.txt に Cloudflare が自動で AI クローラー制御を prepend

セキュリティ・濫用対策:

  • backend で YouTube ホスト正規表現検証(/extract
  • CORS は https://yclip.org https://www.yclip.org のみ許可
  • asyncio.Semaphore(5) で同時抽出数を制限
  • Cloudflare Rate Limiting:/extract に IP 単位で 10秒5回超過 → 10秒ブロック
  • /health/deepHEALTH_DEEP_KEY 環境変数必須(未設定なら 404)

監視・解析:

  • CloudWatch Alarm(インスタンスステータス / CPU / バースト容量) → SNS → メール
  • FastAPI/nginx 死亡 → cron 5分間隔で /health 監視 → 状態遷移時 SNS publish
  • Cloudflare Web Analytics(全ページにビーコン埋め込み済み)

月額コスト: 約 ¥1,350(Lightsail $5 + Webshare $3.50、Cloudflare 無料、ドメインは来年から ¥2,000/年)

次にやること(優先順):

  1. 獲得戦略 W1:検索意図別ページ4本作成(/youtube-save-iphone, /youtube-save-android, /youtube-save-pc, /youtube-download-without-install) + Search Console インデックス送信
  2. 獲得戦略 W2:Zenn / note 技術記事1本(テーマ例「月額1,350円でYouTube保存ツールを運用するための設計判断」)
  3. 獲得戦略 W3〜W4:X 制作ログ毎日1投稿、補助ページ「クリーンなYouTube保存ツールを作った理由」
  4. ユーザー数が伸びてから:Adsterra マネタイズ、1080p 対応
  5. アクセス増加時に /health/deep(Webshare 死活)監視追加、E2E 失敗率計測

dev-timer 既登録:

  • 5/9:英語版の検索パフォーマンス・流入確認(# 11)
  • 5/18:Search Console の重複・代替ページ警告の解消状況確認(# 17)・E2E失敗率の計測(save.html の動画 error イベント送信)

未決事項:

  • Hetzner アカウントは未解約(最終請求待ち、5月に Close Account 予定)
  • マネタイズ後にスケール時のプロキシ運用(IPローテーション戦略、Static Residential 検討)
  • 多言語UI対応はまだ未実装(OGPは言語ニュートラル化済み)
  • レビュー指摘 P2(hash 経由 CDN URL)と P0(抽出IP/再生IP)は据え置き、ユーザー増加後に再評価

過去のWIPアーカイブ

2026-06-17 10:36 時点のスナップショット

多言語対応(バナー方式)+ URL 正規化(HTTPS / non-www 統一)まで完了。次は獲得戦略 W1 タスク(検索意図ページ4本)。 英語版5ページ + 言語案内バナーで非日本語ユーザーを取りこぼさない構造。Cloudflare で全 URL バリエーションが https://yclip.org/ に 301 統一済み。

2026-04-28 20:56 時点のスナップショット

レビュー指摘の P0/P1 全対応完了。セキュリティ・濫用対策が一段落(CORS制限・セマフォ・Cloudflare Rate Limiting・/health/deep認証・noindex・rel=noopener noreferrer)。次は公開・宣伝でユーザー獲得を狙うフェーズ。

次にやること(優先順):

  1. 公開・宣伝(Twitter/X、Reddit、はてブ、個人ブログで告知)
  2. 競合比較ページ
  3. Adsterra マネタイズ(ユーザー増加後)
  4. 1080p 対応(ユーザー増加後)
  5. /health/deep 監視追加

2026-04-28 20:10 時点のスナップショット

SEO 整備完了 + Search Console 連携済み。次は公開・宣伝でユーザー獲得を狙うフェーズ。 ファイル名「videoplayback」問題は技術的制約として、タイトルコピー+プラットフォーム別リネーム手順で UX 補完済み。1080p 対応はユーザー数が伸びるまで後回し。

次にやること(優先順):

  1. 公開・宣伝
  2. 競合比較ページ
  3. Adsterra マネタイズ(ユーザー増加後)
  4. 1080p 対応(ユーザー増加後)
  5. /health/deep 監視の追加

2026-04-28 19:27 時点のスナップショット

UX完成 + アクセス解析(Cloudflare Web Analytics)稼働開始。Adsterra マネタイズはユーザー増加まで延期、約束しないコピーで運用へ。

次にやること(優先順):

  1. SEO 整備(sitemap.xml、robots.txt、構造化データ、Google Search Console 登録)
  2. 公開・宣伝
  3. 1080p 以上の高画質対応
  4. 競合比較ページ
  5. ユーザー数が伸びてから:Adsterra マネタイズ
  6. /health/deep 監視の追加

2026-04-28 19:02 時点のスナップショット

UX/デザインフェーズ完了直後。マネタイズ準備フェーズへ移行する段階。 ダサ方式 + AWS Lightsail Tokyo + Webshare で稼働中。ブランド/法的整備/モバイル対応/エラーハンドリング/OGP まで完成。

次にやること(優先順):

  1. アクセス解析の導入(Plausible / Umami / GA4 のいずれか)
  2. Adsterra 広告の埋め込み
  3. 1080p 以上の高画質対応
  4. 公開・宣伝
  5. /health/deep 監視の追加

2026-04-28 15:05 時点のスナップショット

UX/デザインフェーズ着手の方針確定後、ブランド要素(ロゴ・カラー・タイポ)から手をつける段階。 インフラは完成(Lightsail Tokyo + Webshare、AWSネイティブ無料監視)、月額 ¥1,350。

次にやること(優先順):

  1. ① ブランド確定(ロゴ・カラーパレット・タイポ・favicon・OGP)← まずここから
  2. ② ランディング体験
  3. ③ コアフロー磨き
  4. ⑤ モバイル細部
  5. ④ エラー・エッジケース

その後 Adsterra マネタイズ → 1080p対応 など。


2026-04-28 12:50 時点のスナップショット

安定稼働中(クール方式)+ ダサ方式(直リン保存)を新規実装済み(動作未検証)。 ワーカー Mac 排除を Hetzner 単独で検証 → YouTube ボット検知で不可と確定、自宅 Mac ワーカー継続が現実解。

起動方法(ワーカーMac):

  • ターミナル①:cloudflared tunnel run yclip-worker
  • ターミナル②:
    source ~/yclip-worker/venv/bin/activate
    WORKER_TUNNEL_URL=https://worker.yclip.org python3 ~/yclip-worker/worker.py
    

次にやること(優先順):

  1. ダサ方式の動作検証(CDN URL がユーザーのブラウザIPで再生・保存できるか)
  2. Adsterra 広告の埋め込み(マネタイズ開始)
  3. 1080p 以上の高画質対応(ffmpeg マージ)
  4. モバイル対応・UX 改善

未決事項:

  • ダサ方式の URL が IP 制限で動かない場合の対応方針
  • ワーカー Mac がオフラインになるとサービス停止する問題(マネタイズ後に静的ISPプロキシ検証を再検討)
  • cloudflared / worker を起動時に自動立ち上げする仕組み(launchd など)

2026-04-25 18:43 時点のスナップショット

https://yclip.org でダウンロードが瞬時に完了し、player_client 指定により取得失敗動画も解消済み。 named tunnel(worker.yclip.org)+ range リクエスト + player_client=web,android で安定稼働。

起動方法(ワーカーMac):

  • ターミナル①:cloudflared tunnel run yclip-worker
  • ターミナル②:
    source ~/yclip-worker/venv/bin/activate
    WORKER_TUNNEL_URL=https://worker.yclip.org python3 ~/yclip-worker/worker.py
    

次にやること(優先順):

  1. Adsterra 広告の埋め込み(マネタイズ開始)
  2. 1080p 以上の高画質対応(ffmpeg マージ)
  3. モバイル対応・UX 改善

未決事項:

  • ワーカー Mac がオフラインになるとサービス停止する問題(スケール時に Residential Proxy 移行を検討)
  • cloudflared / worker を起動時に自動立ち上げする仕組み(launchd など)

2026-04-25 14:36 時点のスナップショット

https://yclip.org でダウンロードが瞬時に完了する状態。 named tunnel(worker.yclip.org)+ range リクエスト方式で YouTube CDN のスロットリングを回避済み。

起動方法(ワーカーMac):

  • ターミナル①:cloudflared tunnel run yclip-worker
  • ターミナル②:
    source ~/yclip-worker/venv/bin/activate
    WORKER_TUNNEL_URL=https://worker.yclip.org python3 ~/yclip-worker/worker.py
    

次にやること(優先順):

  1. Adsterra 広告の埋め込み(マネタイズ開始)
  2. 1080p 以上の高画質対応(ffmpeg マージ)
  3. モバイル対応・UX 改善

未決事項:

  • ワーカー Mac がオフラインになるとサービス停止する問題(スケール時に Residential Proxy 移行を検討)
  • cloudflared / worker を起動時に自動立ち上げする仕組み(launchd など)

2026-04-25 00:13 時点のスナップショット

https://yclip.org でダウンロードまで含めたエンドツーエンドが動作している。 自宅 Mac をワーカーとして動かし、yt-dlp 実行と CDN プロキシの両方を担わせる構成。

ワーカーの起動方法(別 Mac):

source ~/yclip-worker/venv/bin/activate
python3 ~/yclip-worker/worker.py

起動すると cloudflared Quick Tunnel が自動起動し、VPS にプロキシURLを登録する。

次にやること(優先順):

  1. Adsterra 広告の埋め込み(マネタイズ開始)
  2. named tunnel 設定(ワーカー再起動時のURL変動を恒久解決)
  3. 1080p 以上の高画質対応(ffmpeg マージ)

未決事項:

  • ワーカー Mac がオフラインになるとサービス停止する問題(スケール時に Residential Proxy 移行を検討)
  • Quick Tunnel はワーカー再起動ごとに URL が変わる(named tunnel で解決予定)

2026-04-24 20:00 時点のスナップショット

https://yclip.org でエンドツーエンドのダウンロードが動作している。 自宅 Mac をワーカーとして動かすことで YouTube の IP ブロックを回避。

ワーカーの起動方法(別 Mac):

source ~/yclip-worker/venv/bin/activate
python3 ~/yclip-worker/worker.py

次にやること(優先順):

  1. Adsterra 広告の埋め込み(マネタイズ開始)
  2. 1080p 以上の高画質対応(ffmpeg マージ)
  3. モバイル対応・UX 改善

未決事項:

  • ワーカー Mac がオフラインになるとサービス停止する問題(スケール時に Residential Proxy 移行を検討)
  • /download プロキシの帯域コスト(スケール時に Cloudflare Workers 移行を検討)

2026-04-24 17:00 時点のスナップショット

**https://yclip.org が外部公開済み。**ただし Hetzner のデータセンター IP を YouTube がブロックするため、実際のダウンロードが機能していない。

次にやること(優先順):

  1. YouTube IP ブロック対策(Residential Proxy または Cookie 認証)
  2. Adsterra 広告の埋め込み(マネタイズ開始)
  3. 1080p 以上の高画質対応(ffmpeg マージ)

2026-04-24 14:30 時点のスナップショット

Phase 1 MVP 完成・push 済み。DECISIONS/ROADMAP を含む4ファイル運用に移行完了。

次にやること(優先順):

  1. Railway デプロイ(railway up で外部公開)
  2. Adsterra 広告の埋め込み(マネタイズ開始)
  3. 1080p 以上の高画質対応(ffmpeg マージ)

未決事項:

  • yt-dlp がボット検知でブレイクした際の復旧フロー(Cookie 注入 or User-Agent ローテーション)
  • 高画質対応時のサーバー側 ffmpeg コスト試算

2026-04-24 14:00 時点のスナップショット

Phase 1 MVP が完成・GitHub push 済み(commit f7480fc)。ローカルで /extract API の動作確認まで完了。

次にやること:

  1. Railway デプロイ(railway up で公開)
  2. 1080p 以上の高画質対応(ffmpeg で映像+音声をマージ)
  3. Adsterra 広告の埋め込み(マネタイズ開始)

未決事項:

  • yt-dlp ボット検知でブレイクした際の復旧フロー(Cookie 注入 or User-Agent ローテーション)
  • 高画質対応時のサーバー側 ffmpeg コスト試算

ROADMAP(計画)

ロードマップ

今週

  • Hetzner VPS にデプロイして外部公開(yclip.org)
  • 独自ドメイン取得(yclip.org)
  • YouTube IP ブロック対策(自宅 Mac ワーカー構成で解決済み)
  • ダウンロードプロキシ修正(Cloudflare Tunnel 経由でワーカーMacが担う)
  • named tunnel 設定(worker.yclip.org で固定URL運用)
  • ダウンロード速度問題の解決(range リクエスト方式で YouTube スロットリング回避)
  • ダサ方式(直リン保存)の専用ページ実装(/save
  • ダサ方式の動作検証(Webshare 経由で抽出した URL が住宅IPなら任意IPで利用可と確認)
  • ダサ方式に完全移行(worker Mac / Cloudflare Tunnel 廃止、VPS で yt-dlp 直接実行)
  • AWS Lightsail Tokyo(nano_3_0)に移行(Hetzner 解約済み)
  • AWSネイティブ無料監視構成の構築(CloudWatch Alarm + SNS + cron self-check)
  • iPhone/Android/PC で別保存導線を提示する save.html 改修
  • UXフェーズ① ブランド確定(favicon・カラー・タイポ・ヘッダー/フッター・OGP)
  • UXフェーズ② ランディング体験(ヒーロー・信頼バッジ・利用規約・プライバシー・FAQ・support メール)
  • UXフェーズ③ コアフロー磨き(フォーマット動画/音声グループ化・推奨バッジ・段階的ローディング)
  • UXフェーズ⑤ モバイル細部(iPhone共有ボタン視覚化・iOS自動拡大抑制・ヒーロー整理・ロゴ拡大)
  • UXフェーズ④ エラー・エッジケース(状況別エラー・再試行・URL検証・タイムアウト)
  • OGP画像作成(言語ニュートラル)
  • アクセス解析の導入(Cloudflare Web Analytics)
  • 広告に関する約束コピーをサイトから削除(将来のマネタイズに備え)
  • SEO 整備(sitemap.xml、robots.txt、JSON-LD構造化データ、Search Console 登録、サイトマップ送信)
  • 保存ファイル名問題の UX 補完(タイトルコピーボタン + プラットフォーム別リネーム手順)
  • レビュー指摘 P0/P1 対応(YouTube URL検証・CORS制限・セマフォ・/health/deep認証・noindex・rel=noopener noreferrer・音声ラベル)
  • Cloudflare Rate Limiting 設定/extract に 10秒5回上限)
  • 多言語対応(基盤):英語版5ページ追加、/en/* ルート、sitemap.xml の hreflang 対応、/extract?lang=en のエラー文言英語化
  • 言語案内バナー:全10ページに navigator.language 判定バナーを追加(非日本語 → 英語版案内、日本語 → 日本語版案内、LocalStorage で閉じた状態を記憶)
  • URL 正規化:Cloudflare で HTTP → HTTPS(Always Use HTTPS)+ www → non-www(Redirect Rule)の 301 統一
  • アイコン PNG(512×512)を生成、.devnotes/icon.png に配置
  • 獲得戦略 W1:検索意図別ページ4本作成/youtube-save-iphone, /youtube-save-android, /youtube-save-pc, /youtube-download-without-install)+ Search Console インデックス送信
  • Hetzner アカウント Close(5月の最終請求後)

今月

  • 獲得戦略 W2:Zenn / note 技術記事1本(テーマ例「月額1,350円でYouTube保存ツールを運用するための設計判断」、yclip 宣伝より帯域コスト・保存UX・iPhone保存・法務グレーとの向き合い方を中心に)
  • 獲得戦略 W3:X で制作ログを毎日1投稿(リンクは3〜5投稿に1回。バズ投稿へのリプは1日3件まで・文脈先行・定型文連投NG)
  • 獲得戦略 W4:補助ページ「クリーンなYouTube保存ツールを作った理由」(競合名指しなしのカテゴリ比較)
  • 競合比較ページ(カテゴリ比較で:登録不要 / インストール不要 / 保存手順つき / 利用規約あり 等。名指しはしない)
  • ユーザー数が伸びてから:Adsterra 広告埋め込み(マネタイズ開始)
  • ユーザー数が伸びてから:1080p 以上の高画質対応(ffmpeg.wasm でブラウザ内結合)

今四半期

  • アクセス増加時に /health/deep(Webshare 死活)監視を追加
  • アクセス増加時に E2E 失敗率の計測(save.html の動画 error イベントを backend に送信)
  • 2か月目以降に Product Hunt 実験出稿(英語版ページ + OGP素材を整えてから)
  • HackerNews Show HN は技術記事ができたタイミングで検討(サービス投稿ではなく設計学び共有として)
  • スケール時の Webshare プラン昇格 / Static Residential 検討
  • ユーザー数が伸びてから:拡張子自動付与(VPS ストリーミングプロキシで Content-Disposition 付与)を帯域コストと引き換えに再評価(クライアント側 fetch は CORS で不可と確定済み)
  • プレイリスト対応
  • 音声のみ MP3 ダウンロード(ffmpeg で変換)

いつか

  • 字幕ダウンロード対応
  • 中国語など追加言語 UI(英語は対応済み)
  • 静的ISPプロキシ検証(マネタイズ後・自宅Mac排除候補)
  • GitHub 公開(する場合は設計メモ・UI のみに留め、プロキシ・抽出回避の具体設定はぼかす)

30日目標(参考指標)

  • 検索表示回数: 1,000
  • クリック: 30〜100
  • /extract 実行: 50〜200
  • 被リンクまたは言及: 3件
  • 技術記事: 1本
  • 検索意図別ページ: 4本

DECISIONS(意思決定)

意思決定記録

このプロジェクトで下した重要な意思決定を記録する。 最新が上に来る。


2026-06-17: クライアント側ダウンロード(fetch→blob / showSaveFilePicker)は不可と実測確定、帯域ゼロを優先して見送る

背景: 「保存ファイルに拡張子が付かない(手で .mp4 を足している)」問題の改善を再検討。サーバーを経由せずブラウザ側だけで正しいファイル名(タイトル+拡張子)を付ける方法として、JS で CDN URL を fetch() → 同一オリジン blob: 化(または Chrome の showSaveFilePicker でストリーミング保存)し <a download> で名前を強制する案を検証した。

決定: この方式は採用しない。save.html は現状のまま(タイトルコピー+プラットフォーム別リネーム手順)で運用を継続する([[2026-04-28: ファイル名「videoplayback」問題は UX で補完する]] を継続)。拡張子の自動付与を本当に実現するには VPS ストリーミングプロキシ(Content-Disposition 付与)しかないが、帯域ゼロ原則を崩すため見送る。ユーザー数が伸びてニーズが顕在化したら再評価する。

理由: 実 URL で googlevideo.com のレスポンスヘッダを実測した結果、CORS(Access-Control-Allow-Origin)を youtube.com 系オリジンにしか返さないことが判明(https://yclip.org には返さず、Vary: Origin で出し分けている。Cross-Origin-Resource-Policy: cross-origin は付くが CORP は fetch 読み取りを許可しない)。したがって yclip.org の JS から fetch() するとブラウザが CORS でブロックし、blob 化もストリーミング保存も成立しない。<a download> もクロスオリジンでは無視される。つまりブラウザ仕様上、サーバーを一切通さずにファイル名を強制する手段は存在しない。実装したボタンは毎回フォールバックに落ちるだけなので出荷せず破棄した。なお CDN URL は ip= でIPロックされているが現行サイトが別IP取得で動いている=ロックは実質ゆるく、将来プロキシ方式を採るなら住宅プロキシ(1GB/月)を消費せず VPS 直取得で済む点は確認済み。


2026-05-11: 多言語化は「URL を変えずブラウザ言語判定によるバナー案内」方式を採用

背景: 当初 Cloudflare Web Analytics で US ユーザーが多そうに見えたため「英語デフォルト化」や「Accept-Language で自動振り分け」を検討。実データを取得した結果、Japan 50% / US 31% / Korea 12.5% / Canada 6%、さらに ChromeHeadless 18.8% と Direct 81% で bot/VPN シグナルが強いことが判明。

決定: URL を変えるリダイレクト方式や英語デフォルト化は採用せず、ブラウザ言語が日本語以外のとき上部に細いバナーで英語版を案内する方式に統一する。逆方向(英語ページに日本語ユーザーが来た場合)も同様。LocalStorage で「閉じた」状態を記憶する。

理由: 実ユーザー比率では日本ユーザーがまだ最多であり、英語デフォルト化は日本ユーザーを冷遇する。一方で「URL を変える 302 リダイレクト」は SEO 上の同一 URL 複数言語問題を引き起こす可能性がある。バナー方式は GitHub / Stripe / Wikipedia 等の業界標準パターンで、SEO に影響せず・ユーザーに選択権を与え・実装も JS だけで完結する。


2026-05-11: URL 正規化は Cloudflare 側で HTTP → HTTPS + www → non-www の 301 統一を強制する

背景: Google Search Console で「重複しています、ユーザーにより正規ページとして選択されていません」(http://www.yclip.org/ が該当)と「代替ページ(適切な canonical タグあり)」(http://yclip.org/http://yclip.org/en/ が該当)の警告が出ていた。Cloudflare がいずれも 200 で返しており、https://yclip.org/ への正規化が効いていなかった。

決定: Cloudflare ダッシュボードで以下の 2 段構成を有効化:(1) SSL/TLS → Edge Certificates → Always Use HTTPS を ON(http://* を 301 で https:// に統一)、(2) Rules → Redirect Rules で www → non-www の 301 リダイレクトHostname equals www.yclip.orgconcat("https://yclip.org", http.request.uri.path)、preserve query string、status 301)。

理由: canonical タグだけでは Google の警告が消えず、複数の URL バリエーションがインデックス対象になりやすい。301 リダイレクトで正規化すれば、Google は明確に主たる URL を判定でき、再クロールに従って警告が自然解消する。Cloudflare で完結するため backend 改修不要。Free プランの Redirect Rules でも www サブドメイン限定の挙動は問題なく書ける。


2026-04-29: ユーザー獲得は短期バズより長期SEOの「検索意図別の受け皿ページ」作りを最優先する

背景: ユーザー獲得施策について別 LLM レビュー(gods-talk issue-001)を依頼。前提:オーナー側に既存チャンネル(フォロワー、ブログ、YouTube アカウント等)がゼロ。短期バズ狙い(Reddit / Product Hunt / Hacker News / X リプ営業)と長期 SEO のバランスを論点とした。

決定: 初月は「検索意図別の受け皿ページを増やして検索流入を拾う」を最優先する。短期バズの主戦場(Product Hunt / Hacker News / Reddit)は2か月目以降に回す。X リプ営業は「文脈先行・リンク後置・定型文連投なし」で限定運用。競合比較は名指しせずカテゴリ比較で実装。広告に関する約束コピーは引き続き使わない(既存方針継続)。

理由: ゼロチャンネルからのバズ狙いは現実的でなく、X 定型リプ連投はスパム認定リスクがある。YouTube ダウンロード需要は「今すぐ困っている人」が検索する性質のためロングテール SEO 勝負が向く。Google の helpful content 方針に合致する保存手順の実体験ページ(iPhone / Android / PC 別)が yclip の強みと噛み合う。Product Hunt は英語圏向け、HN は技術者向けで初手の主戦場としては相性が悪く、技術記事を先に書いてから出稿する方が通りやすい。GitHub 公開は YouTube ダウンローダーという性質上、悪用・クローン・規約面のリスクがあるため、公開する場合は設計メモ・UI に留めプロキシ詳細はぼかす。


2026-04-28: レビュー指摘の P0/P1 を全対応、P2 は実害低のため据え置く

背景: 別 LLM から受け取ったレビュー(tmp/指摘.md)で 6 件(P0×1、P1×3、P2×2)が指摘された。実コードと照合して妥当性を検証した。

決定: P1(backend URL 検証、/health/deep 認証、CORS制限と濫用対策)はすべて即対応。P0(抽出IPと再生IPのズレ)と P2(hash 経由 CDN URL の第三者JS露出、/save の noindex)のうち、/save noindex のみ即対応、残りは据え置く。

理由: P0 は実検証で住宅IPなら任意IPで動作する実績があり、サーバー結合に戻すコストの方が大きい。P2 の hash 経由URL は CDN URL が短命(6〜12h)かつIPバインドのため漏洩しても実害が低い。Tailwind CDN/Cloudflare Web Analytics は信頼できる第三者で、意図的な漏洩リスクは想定しない。ユーザー増加後に E2E 失敗率を計測して再評価する余地を残す。


2026-04-28: API 濫用対策は CORS制限 + 軽量セマフォ + Cloudflare Rate Limiting の3層構成にする

背景: /extract は Webshare プロキシ経由で yt-dlp を発火するため、悪用された場合のコスト・リスクが大きい。レビューでも CORS 全開放と rate limit 不足を指摘された。

決定: 3層で守る:(1) CORS を https://yclip.org に制限(ブラウザ経由 API 横利用を遮断)、(2) backend に asyncio.Semaphore(5) で同時抽出数制限(メモリ・プロキシ枯渇の暴発防止)、(3) Cloudflare Rate Limiting で IP 単位 10秒5回超過 → 10秒ブロック(Free プラン制約)。

理由: 単一の対策では不十分。CORS は legitimate ブラウザ濫用、セマフォはバックエンド負荷、Rate Limiting は IP 単位の連打に対応。それぞれ役割が異なるため積層が合理的。Cloudflare Free の 10秒固定制約は実用上 0.5 req/秒/IP に絞れるため許容範囲。


2026-04-28: 1080p以上の高画質対応は当面後回しにする(ダサ方式の帯域ゼロ原則を優先)

背景: YouTube は 1080p 以上を映像と音声に分離して配信しており、結合に ffmpeg が必要。実装案は3つ(A: ユーザーが手動結合、B: ブラウザで ffmpeg.wasm 結合、C: サーバーで結合・配信)。

決定: 高画質対応は当面後回し。ユーザー数が伸びた段階で B(ffmpeg.wasm)を再検討する。

理由: C はダサ方式の帯域ゼロ原則を破り、Webshare の $1.4/GB が動画 1 本ごとに課金される。A は UX が悪すぎる。B は妥当だが、ffmpeg.wasm が約 30MB あり、モバイル端末では結合処理に時間がかかる。当面は 720p までで十分(モバイル中心想定)と判断し、ユーザー数が伸びてニーズが顕在化してから対応する。


2026-04-28: ファイル名「videoplayback」問題は UX で補完する(サーバー結合に戻さない)

背景: ダサ方式では YouTube CDN URL を直接ブラウザに渡すため、保存時のデフォルトファイル名が「videoplayback」になる(Content-Disposition ヘッダを設定できないため)。

決定: サーバー結合(クール方式)に戻さず、save.html でタイトルコピーボタン + プラットフォーム別のリネーム手順を提供することで UX を補完する。

理由: ファイル名を制御するには Content-Disposition を付ける必要があり、それはサーバー中継(クール方式)でしかできない。クール方式は帯域コストが大きく、ダサ方式の前提を崩すため採用しない。タイトルコピー+リネーム導線は2ステップ追加されるが、各プラットフォーム(PC/iOS/Android)で具体的なリネーム手順を提示することで実用上問題ない。


2026-04-28: アクセス解析は Cloudflare Web Analytics を採用する

背景: マネタイズ前にユーザー行動を可視化する必要があった。候補は Cloudflare Web Analytics(無料)/ Plausible Cloud($9/月)/ Umami セルフホスト / Google Analytics 4 など。

決定: Cloudflare Web Analytics(無料・Cookie不使用・GDPR準拠)を採用し、全ページにビーコン JS スニペットを埋め込む。

理由: すでに Cloudflare 経由でサービスを公開しているため統合がスムーズ。Cookie 不使用なのでプライバシーポリシーの根本変更が不要(「Cookie なし」を維持できる)。ページビュー、参照元、国別、デバイス、Core Web Vitals まで取れて十分。物足りなくなったら後で Plausible や独自イベント追跡を追加可能。


2026-04-28: Adsterra マネタイズはユーザー数が一定規模になるまで延期する

背景: UX/デザインフェーズが完了しマネタイズ着手の段階に入ったが、当初は「ガッツリ広告化(C方針)」で進めようとしていた。

決定: マネタイズはユーザー数が一定規模に到達するまで延期する。それまでは広告ゼロを差別化要素として運用する(ただしコピーで「広告なし」を約束はしない)。

理由: 立ち上げ初期のユーザーは UX への印象が強く残るため、広告ゼロの体験を提供することで初期ユーザーのリテンション・口コミを最大化する。アクセスが伸びてから広告を入れた方が CPM も上がりやすく、トータル収益的にも合理的。


2026-04-28: 広告に関する約束コピーは将来の柔軟性のため使わない

背景: ヒーローコピーで「広告なし」「広告に邪魔されない」と明示すると、将来マネタイズ着手時にコピー変更が必要になり、ユーザー期待値も裏切ることになる。

決定: ヒーロー文言は「貼って、取得、保存。」のみ、メタタグも「シンプルで速い」表現に統一。広告の有無に関する明示的な主張はしない。

理由: マネタイズ時期や手法(広告 / 投げ銭 / 有料プラン等)の選択肢を保持できる。「広告なし」のような強い約束は、それを破棄する瞬間にブランド毀損を起こすため、最初から作らない方が堅実。


2026-04-28: ブランド方向性は「Trust First」を採用する

背景: UX/デザインフェーズの起点としてブランド方向性を3案(Trust First / Punchy Modern / Friendly Soft)から選定する必要があった。

決定: 方向A「Trust First」を採用。深いネイビーベース + 落ち着いたブルーアクセント、Inter + Noto Sans JP、Stripe / Linear 系の信頼感寄りのトーン。

理由: YouTube ダウンローダーは法的グレーが付きまとうため、信頼感の演出が広告クリック率と離脱率に直結する。Friendly 過ぎると「怪しい?」と思われるリスクがあり、Punchy だと尖りすぎて訴求対象を絞ってしまう。Trust First が最もバランス良く、Adsterra 等の広告審査も通りやすい。


2026-04-28: 法的グレーゾーンには「攻めない・予防線重視」スタンスで臨む

背景: 利用規約 / プライバシーポリシーを公開する際、法的グレーゾーンへのスタンスを決める必要があった(攻める / 中立 / 何もしない の3択)。

決定: 「私的利用範囲限定」「著作権者の権利尊重」を明示し、削除依頼窓口(support@yclip.org)を整備、利用規約に「YouTube ToS への準拠は利用者責任」と明記する。

理由: リスク最小化と Adsterra 等の広告審査通過の両立が必要。中立や無対応では万一トラブル時に弱い。攻めるとスケール時に攻撃対象になる。


2026-04-28: お問い合わせ窓口は Cloudflare Email Routing で support@yclip.org → gmail 転送

背景: 削除依頼・お問い合わせ用のメールアドレスが必要だが、個人 gmail を直接公開するのは抵抗がある。

決定: Cloudflare Email Routing(無料)で support@yclip.org → 個人 gmail に転送する構成にする。送信機能は不要(gmail から直接返信できるため)。

理由: 完全無料、設定5分、独自ドメインメールで信頼感あり、転送メール数の実質無制限(200エイリアスまで)。ドメインを Cloudflare 管理下にしているため設定が簡単。


2026-04-28: OGP画像はローカライズ対応のため言語ニュートラル化する

背景: OGP画像に「YouTube動画を、シンプルに保存。」と日本語タグラインを焼き込んだが、将来の多言語化時に英語ユーザーへ日本語が表示される問題があると指摘された。

決定: OGP画像はロゴ + yclip ワードマーク + yclip.org のみとし、テキストコピーを排除する。多言語化時には、HTMLは言語別に分けつつ OGP画像はこのまま使い回す。

理由: 1枚で全言語をカバーでき運用が単純。ローカライズ時に画像を作り直す手間がない。視覚的訴求はロゴで担保できる。多言語OGP(og:locale:alternate、言語別画像)は構造が複雑になりやすく、現段階ではオーバーエンジニアリング。


2026-04-28: ワーカーMac排除(Hetzner単独運用)は当面行わない

背景: 別 LLM から「静的 ISP プロキシ + Hetzner で yt-dlp を直接実行」する案が提案された(月額 ¥1,600〜¥4,000)。Hetzner 上で yt-dlp が動くか実際に検証した結果、最新版(2026.04.10.dev)でも player_client=web,android tv_embedded,ios tv,web_safari,mweb 全パターンで「Sign in to confirm you're not a bot」となり、Hetzner の AS(データセンター)IP が完全にブロックされていることを確認。

決定: 当面は自宅 Mac ワーカー構成を継続する。ISP プロキシ検証は Adsterra 等でマネタイズが立ってから実施する。

理由: Cookie 注入は運用負荷が高く、ISP プロキシは月額固定費が発生する上、YouTube が ISP IP を通すかは未検証で外れた場合は無駄になる。マネタイズ前に固定費を増やすのは得策でない。自宅 Mac ワーカーは無料で安定稼働している。


2026-04-28: ダウンロード方式の呼称を「クール方式」「ダサ方式」に統一

背景: yclip 現状の中継方式と、awakest.net 系の直リン方式を会話で頻繁に対比するため、口語的なラベルが必要だった。

決定: クール方式 = サーバー中継・1クリック、ダサ方式 = CDN URL 直リン・右クリック保存、として以後この呼称で統一する。

理由: 短く覚えやすく、UX の良し悪しが名前に込められているため対比が直感的になる。詳細は memory/project_terminology.md に記録済み。


2026-04-28: マネタイズ前にデザイン・UXを固めるフェーズを挟む

背景: 機能・インフラはほぼ整った(ダサ方式安定稼働、Lightsail Tokyo + Webshare、無料監視)。次の自然な流れは Adsterra でマネタイズだが、UX が未成熟のままユーザー獲得に走ると離脱率が高く、広告クリック率も低い。

決定: ユーザー獲得施策(Adsterra など)の前に、ブランド/ランディング/コアフロー/モバイル/エラーの順で UX 改善を行う。最初はブランド(ロゴ・カラー・タイポ)から固める。

理由: ブランド要素が決まれば、その後の画面設計・アニメーション・エラーUIの判断軸(トーン、色、フォント)が一貫する。逆順だと作り直しが発生する。マネタイズ前の UX 改善はリテンションと広告 CTR の両方に効く。


2026-04-28: 監視は AWS ネイティブ無料構成(CloudWatch + SNS + cron)で組む

背景: UptimeRobot 等の外部サービスは無料で楽だが、運用を AWS 内に閉じたい。だが AWS には HTTP エンドポイント監視を専用に行う完全無料サービスがない(Route 53 Health Check は最安 $0.50/月)。

決定: Lightsail インスタンス系メトリクス(StatusCheck/CPU/Burst)は CloudWatch アラーム → SNS、FastAPI/nginx の生死は cron + curl + SNS publish の自前構成で監視する。/health/deep(Webshare 死活)はスケール時に追加検討。

理由: 全て AWS 無料枠内で完結(CloudWatch Alarm 10個まで、SNS メール 1000通まで)。サーバー本体死亡は CloudWatch、アプリ死亡は cron で補完できるため二重カバー。アクセス数が増えて Webshare 死活も監視したくなったら Route 53 Health Check や UptimeRobot を後から足せばよい。


2026-04-28: インフラを Hetzner Nuremberg → AWS Lightsail Tokyo(nano_3_0)に移行する

背景: ダサ方式移行で動画データが VPS を通らなくなり、Hetzner の 20TB 込み帯域メリットが消失。既存の AWS アカウント・東京リージョンに統一したい意図もあった。

決定: AWS Lightsail Tokyo の nano_3_0($5/月、512MB RAM、IPv4、20GB SSD、1TB帯域)に移行。micro_ipv6_3_0($5、IPv6-only、1GB RAM)も検討したが、Webshare のプロキシエンドポイントが IPv4-only なため到達不可で却下。

理由: 抽出のみなら 512MB+swap 1GB で十分(multi-purpose-lightsail-server1 で同スペックが3サービス稼働中の実績あり)。東京リージョンでユーザーからのページ読み込みが速くなる。AWS で完結するため SNS / CloudWatch との統合がスムーズ。コスト差は Hetzner €4 → Lightsail $5 で +¥200 程度に収まる。


2026-04-28: ダサ方式に完全移行(Webshare Rotating Residential を採用)

背景: クール方式は worker Mac 依存(自宅電源・回線・手動起動)でサービス可用性が低かった。Webshare の Rotating Residential($3.50/月、1GB帯域)を $3.50 で検証したところ、抽出された CDN URL が住宅IPなら任意のIPから利用可能(YouTube CDN は redirect 時に ipbypass=yes を付与)と判明。

決定: クール方式を廃止。yt-dlp は VPS 上で Webshare proxy 経由で実行し、抽出した CDN URL は frontend/save.html 経由でブラウザに渡してユーザーが直接 YouTube CDN からダウンロードする構成に統一する。

理由: worker Mac が完全不要になり、サービス可用性が大幅向上。Webshare 1GB で約 2,000動画/月の抽出に耐える(実通信は抽出時のみ ~500KB)。動画データはユーザーのブラウザが YouTube CDN から直接取得するため VPS 帯域コストゼロ。月コストは worker Mac 廃止と Webshare 追加で実質変動なし。UX は1クリック → 7ステップ右クリック保存に劣化するが、PC/Android/iPhone それぞれで専用の保存ガイドを save.html に実装したため許容範囲内。


2026-04-25: yt-dlp の player_client は web,android を明示指定する

背景: 一部の動画でデフォルト挙動だと This video is not available が出て取得できない(ブラウザでは普通に再生可能)。yt-dlp のデフォルト client(ANDROID_VR)の制限が原因。

決定: extractor_args={"youtube": {"player_client": ["web", "android"]}}YDL_OPTS に追加して常に明示指定する。

理由: 動画ごとに利用可能な client が異なるため、フォールバックの効く web,android を指定するのが最も互換性が高い。yt-dlp のデフォルトは YouTube の制限変更に追従して変わるので、明示指定の方が安定運用に向く。


2026-04-25: ダウンロードプロキシは10MBの range リクエストで取得する

背景: 単一の HTTP GET で CDN URL を取得すると、YouTube が長時間接続をスロットリングし、7MB のダウンロードに5分以上かかる状態だった(ratebypass=yes パラメータがあっても効かず)。

決定: プロキシは Range ヘッダで 10MB ずつ分割取得する。yt-dlp と同じ手法。

理由: yt-dlp 直接ダウンロードでは一瞬で完了することから、スロットリングは長時間接続に対して掛かることが判明。短時間の range リクエストを連続で投げると掛からない。


2026-04-25: Cloudflare Tunnel は named tunnel(worker.yclip.org)を使う

背景: Quick Tunnel(trycloudflare.com)は無料で使えるが、Cloudflare 自身が「実験用」と明記しており速度が出ない。再起動ごとに URL も変わる。

決定: named tunnel を作成し worker.yclip.org で固定的に運用する。yclip.org 自体が Cloudflare 管理下にあるためサブドメイン追加のみで完結。

理由: 速度制限がほぼなく、URL も固定で運用が安定する。設定ファイル(~/.cloudflared/config.yml)と認証情報JSONをワーカー Mac に置くだけで済むため運用コストが小さい。


2026-04-25: ダウンロードプロキシをワーカーMac(Cloudflare Tunnel経由)に移す

背景: YouTube CDN URL には ip=<抽出時のIP> が署名として埋め込まれており、VPS 上のプロキシでは IP 不一致で 403 になることが判明した。

決定: ワーカーMac 上でダウンロードプロキシサーバー(port 8081)を起動し、Cloudflare Tunnel(Quick Tunnel)で公開する。VPS の /download はそのトンネルURLへリダイレクトするのみ。

理由: CDN URL はワーカーの IP にバインドされているため、ダウンロードもワーカーの IP から行う必要がある。Cloudflare Tunnel は無料で利用でき、インフラの追加が最小限で済む。


2026-04-24: YouTube IP ブロック対策として自宅 Mac ワーカー構成を採用する

背景: Hetzner のデータセンター IP を YouTube がボットとして弾く。Residential Proxy(月 $10〜50)や Cookie 注入が候補だった。

決定: 自宅 Mac を VPS のジョブワーカーとして使う。VPS はジョブをキューに積むだけで、yt-dlp は自宅の住宅用 IP から実行する。

理由: 無料かつ即座に実装可能。Residential Proxy のコストが不要。自宅ネットが安定していれば実用十分。スケール時は Residential Proxy への移行を検討。


2026-04-24: /download プロキシエンドポイントを追加する(帯域コスト増加を受け入れる)

背景: ブラウザの download 属性はクロスオリジン URL に効かないため、YouTube CDN の直リンクをそのまま渡してもダウンロードにならず再生されてしまう。

決定: FastAPI に /download プロキシエンドポイントを追加し、httpx でストリーミング中継する。「URL 抽出のみ」の設計原則を一部妥協する。

理由: ブラウザのセキュリティ制約上、クロスオリジン URL のダウンロードを強制する手段がない。競合サービスも全員プロキシしている。スケール時は Cloudflare Workers 移行で帯域コストを抑える方針。


2026-04-24: Cloudflare を DNS + SSL レイヤーとして採用する

背景: ドメインを取得後、HTTPS 化と DNS 管理が必要になった。

決定: Cloudflare Free プランを DNS + SSL に使う。SSL モードは「Flexible」(origin は HTTP のまま)。

理由: 無料で SSL・DDoS 対策・CDN が手に入る。Let's Encrypt を自前管理するより運用が楽。


2026-04-24: ドメインを yclip.org にする(お名前.com 初年無料)

背景: コスト優先でドメインを選定。yclip.com はプレミアムドメインで 774,312 円だった。

決定: yclip.org をお名前.com で取得(初年無料)。1年でサービスがうまくいかなければそのまま撤退する。

理由: 初年無料でリスクを最小化できる。サ終時のコストがゼロ。ただし自動更新に注意が必要。


2026-04-24: インフラを Railway → Hetzner Nuremberg に変更する

背景: Railway はデプロイが簡単だが帯域が従量課金で高い。コスト優先で再検討した。

決定: Hetzner の Nuremberg(Regular Performance)を使う。月 €4 程度で 20TB の帯域が付属。

理由: Hetzner Nuremberg は月 €4 + 20TB で、動画 100MB 換算で約 20 万 DL/月まで追加コストゼロ。Railway や Singapore リージョンと比べてコスパが圧倒的に高い。


2026-04-24: 広告ネットワークを AdSense ではなく Adsterra / PropellerAds にする

背景: マネタイズに広告収益を選定。メジャーな AdSense が第一候補だった。

決定: Adsterra または PropellerAds を使う。AdSense は使わない。

理由: YouTube ダウンローダーはグレーゾーンコンテンツとみなされ、AdSense の審査で落とされるリスクが高い。Adsterra / PropellerAds はこの種のサイト向けに実績があり審査も緩い。


2026-04-24: インフラを Railway(無料枠)でスタートする

背景: 初期の運用コストをゼロに近づけたい。

決定: Railway の無料枠でデプロイを開始し、トラフィックが増えたら $5 VPS(DigitalOcean / Vultr)に移行する。

理由: 無料枠で公開できれば PMF 前のコスト負担がない。URL 抽出のみのアーキテクチャなので帯域も食わず、小さいインスタンスで十分。


2026-04-24: バックエンドを Python (FastAPI) + yt-dlp にする

背景: バックエンド言語の選定。Node.js も候補だった。

決定: Python 3.12 + FastAPI + yt-dlp を使う。

理由: yt-dlp が Python ネイティブなので child process 経由より統合が簡潔。FastAPI は非同期対応で、run_in_executor で yt-dlp のブロッキング処理を逃がせる。


2026-04-24: サーバーは URL 抽出のみ(動画データを触らない)

背景: 運用コスト最小化が最優先。サーバーが動画を中継する構成も検討した。

決定: yt-dlp で YouTube CDN の直リンクを抽出してクライアントに返すだけ。動画バイナリはサーバーを通さない。

理由: サーバー中継だと 1000 ユーザー/日で月数万円以上の帯域コストになる。URL 抽出のみなら自サーバーの帯域はほぼゼロで、月 $5〜10 の VPS で十分に動く。

DEVLOG(作業ログ)

開発日誌

このプロジェクトでの作業を時系列で記録する。 最新のエントリが上に来る。


2026-06-17

10:36 - 保存ファイルの拡張子なし問題:クライアント側ダウンロードを検討するも CORS で不可と判明、見送り

やったこと:

  • ユーザー相談「ダウンロードすると拡張子が付かないことがある(手で .mp4 を足している)」の改善を検討
  • 原因整理:ダサ方式は video.src = cdnUrl(googlevideo 直リン)で右クリック/新タブ保存するため、ファイル名が CDN パス末尾 videoplayback になり、拡張子はブラウザが Content-Type から推測で付ける/付けないがまちまち
  • 改善案として「JS で CDN を fetch() → 同一オリジン blob 化 or showSaveFilePicker ストリーミング → <a download> で名前強制」を save.html(日本語・英語)に一度実装
  • CORS を実 URL で実測検証(yt-dlp -g で本物の CDN URL を取得 → curl で Origin 別にヘッダ確認):
    • googlevideo は Access-Control-Allow-Originyoutube.com 系オリジンにしか返さないVary: Origin で出し分け)。https://yclip.org には返さない
    • Cross-Origin-Resource-Policy: cross-origin は付くが CORP は fetch 読み取りを許可しない
    • OPTIONS プリフライトは 400
    • → yclip.org の JS から fetch() はブラウザが CORS でブロック。blob 化もストリーミング保存も成立しない。<a download> もクロスオリジンで無視
  • 実装したボタンは毎回フォールバックに落ちるだけなので git checkout で破棄(作業ツリーはクリーン)
  • 副次確認:CDN URL は ip= でIPロックされているが、現行サイトが別IP取得で稼働中=ロックは実質ゆるい(将来プロキシ方式を採るなら住宅プロキシを消費せず VPS 直取得で済む)

決めたこと:

  • クライアント側ダウンロード方式は採用せず、現状の UX 補完(タイトルコピー+リネーム手順)を継続。詳細は DECISIONS.md 2026-06-17 に記録

詰まったこと / 気づき:

  • 「帯域ゼロのままファイル名を強制する」方法はブラウザ仕様上存在しない。拡張子自動付与は VPS ストリーミングプロキシ(Content-Disposition 付与)しか手がなく、それは帯域ゼロ原則とのトレードオフ → ユーザー数が伸びてから再評価

次回やること:

  • 獲得戦略 W1(検索意図別ページ4本)が依然 next

2026-05-11

08:23 - 多言語化(バナー方式)+ URL正規化(www, HTTP 統一)+ アクセス傾向の実地調査

やったこと:

  • アイコン PNG 生成.devnotes/icon.png(512×512)を作成。SNS プロフィール等に使い回せるロゴ。最初 512px で直接レンダーしたら下端が切れていたため、1024px でレンダー → sips で 512 にダウンスケールに切替で解決
  • ローカライズ実装(コード):英語版 5 ページ(/en/index, /en/save, /en/faq, /en/terms, /en/privacy)を新規作成。backend/main.py/en/* ルートと /extract?lang=en のエラー文言英語化を追加。sitemap.xmlxhtml:link rel="alternate" hreflang" 対応に拡張
  • アクセス傾向調査(Codex Computer Use 経由):Cloudflare Web Analytics の 30日データを取得。Japan 50% / US 31% / Korea 12.5% / Canada 6%。ChromeHeadless 18.8%・Linux 31.3%・Direct 81% で bot or VPN シグナルが強く、検索流入はゼロ
  • ローカライズ方針を再検討:当初「英語デフォルト化」「Accept-Language 自動振り分け」を検討したが、実データで「真のUSユーザーは多くない・/en/ への到達なし」が判明。代わりに 「ブラウザ言語が日本語以外なら案内バナーを表示」 方式に切替
  • 言語案内バナーを全 10 ページに追加navigator.language でブラウザ言語を判定、Cookie ではなく LocalStorage で「閉じた」状態を記憶(GitHub / Stripe / Wikipedia 等の標準パターン)。日本語ページは英語版へ、英語ページは日本語版へ案内
  • URL 正規化(Cloudflare)
    • A. SSL/TLS → Edge Certificates → Always Use HTTPS を ON(http://* を 301 で https:// に統一)
    • B. Rules → Redirect Rules → www→non-www の 301 リダイレクトを追加(Hostname equals www.yclip.orgconcat("https://yclip.org", http.request.uri.path)、preserve query string)
    • 結果:http://yclip.org, http://www.yclip.org, https://www.yclip.org のすべてが https://yclip.org/ に 301 で正規化された
  • dev-timer 登録:5/18 朝に「Search Console の重複・代替ページ警告の解消状況確認」のリマインダ(# 17)
  • 指摘.md フィードバックループ運用gods-talk-commission / gods-talk-feedback スキルを発動し、ユーザー獲得戦略について別 LLM に issue-001 をレビュー依頼 → feedback-001 で対応方針整理(短期バズより検索意図ページ作成優先)。これは前回ラウンドの続き

決めたこと:

  • ローカライズ表示は URL を変えず、ブラウザ言語判定によるバナー案内で対応(自動リダイレクトや英語デフォルト化は採用せず)
  • URL 正規化:HTTP 全削除(HTTPS 強制)と www サブドメインの 301 統一を Cloudflare 側で実施

詰まったこと / 気づき:

  • Cloudflare の Redirect Rules は「Custom filter expression」モードを選び、Hostname equals www.yclip.org を指定すれば www 限定のリダイレクトが可能。Free プランでも問題なく作れる
  • Chrome headless で 512×512 を直接スクショすると、レイアウト計算誤差で下端が数 px 欠ける。1024 で生成 → リサイズで安全。OGP 画像生成にも同じ知見が活きる
  • Codex Computer Use 等の「別ツール」に外部調査を投げる依頼文を作るフローが回せたのは収穫。Cloudflare ダッシュボードのような認証必須・人間操作前提の領域でデータが集められた
  • 「実装計画を提示してからユーザー確認を取って着手」を運用ルールとして memory に保存(複数ファイル / 設計判断を伴う規模が対象、軽微な編集は対象外)

次回やること:

  • 獲得戦略 W1:検索意図別ページ4本(/youtube-save-iphone, /youtube-save-android, /youtube-save-pc, /youtube-download-without-install)を作成 → Search Console インデックス送信
  • 1週間後(5/18):Search Console の重複・代替ページ警告の解消状況確認(dev-timer 設定済み)
  • 1週間後(5/9 既設定):英語版の検索パフォーマンス・流入確認(dev-timer 設定済み)

2026-04-28

20:56 - 別LLMからのレビュー指摘を検証・P0/P1を全対応(セキュリティ・濫用対策)

やったこと:

  • tmp/指摘.md に置かれた別 LLM のレビューを実コードと照合して検証
  • P0/P1 の指摘を全対応
    • /save<meta name="robots" content="noindex, nofollow"> 追加、robots.txt/save Disallow を削除(noindex を Google に読ませるため)
    • backend /extract に YouTube ホスト正規表現チェックを追加(youtube.com, www.youtube.com, m.youtube.com, youtu.be のみ許可)。SSRF寄りの濫用とプロキシ消費を遮断
    • /health/deepHEALTH_DEEP_KEY 環境変数による API キー必須化(未設定なら 404 で隠蔽)。第三者の負荷攻撃を防ぐ
    • CORS を ["*"]["https://yclip.org", "https://www.yclip.org"] に制限(ブラウザ経由の API 横利用を遮断)
    • /extractasyncio.Semaphore(5) で同時抽出数を制限(メモリ・プロキシ枯渇の暴発防止)
  • 小指摘も対応
    • 音声ラベル「音声のみ (MP3相当)」→「音声のみ」(誤解防止)
    • target="_blank" リンクに rel="noopener noreferrer" を追加(タブナビゲーション乗っ取り対策)
  • Cloudflare Rate Limiting(IP単位) を Cloudflare ダッシュボードで設定
    • URI Path = /extract、10秒で5リクエスト超過 → 10秒ブロック
    • Free プランなので Period/Duration は 10秒固定の制約あり、それでも実質 0.5 req/秒/IP に絞れる

決めたこと:

  • レビュー指摘 P0(抽出IPと再生IPの食い違い)と P2(hash 経由 CDN URL の第三者JS露出)は据え置き判断。P0 は実検証で住宅IP同士なら成功率高、P2 は CDN URL が短命IPバインドで実害低
  • セマフォは早期拒否(locked() で 503 を即返す)を採用せず、async with でキュー化する設計に。フロントエンドのタイムアウトと Cloudflare Rate Limiting で十分緩衝されるため
  • Cloudflare Free の Rate Limiting 制約(10秒固定)は受け入れて運用する

詰まったこと / 気づき:

  • セマフォの早期拒否は実装上のレースコンディションがあり、扱いを誤るとブロッキングしうる。async with の単純利用 + 上流での流量制限の方が堅実
  • Cloudflare Free プランの Rate Limiting Rule は 1 ルール上限。複数の保護をかけたい場合は Pro プラン($20/月)が必要
  • Cloudflare の robots.txt は管理コンテンツが先頭に prepend される。我々が編集できるのは末尾の User-agent ブロックだけ

次回やること:

  • 公開・宣伝(Twitter / Reddit / HackerNews / 個人ブログで告知)
  • 競合比較ページ("y2mate vs yclip" 等の SEO 強化)
  • ユーザー数が伸びたら:1080p 対応、Adsterra マネタイズ、抽出IP/再生IP 失敗率の E2E 計測

20:10 - SEO 整備完了 + 1080p 後回し判断 + 保存ファイル名のUX改善

やったこと:

  • SEO 整備フェーズ完了
    • sitemap.xml(4URL:トップ・FAQ・利用規約・プライバシー)と robots.txt を追加
    • backend/main.py にそれぞれの配信ルートを追加(/sitemap.xml/robots.txt
    • JSON-LD 構造化データを追加:トップは WebApplication、FAQ は FAQPage(リッチスニペット狙い)
    • 各ページに canonical リンクと固有の description メタタグを追加
    • og:site_nameog:locale も追加
    • Google Search Console にドメインプロパティを登録、DNS TXT レコード(google-site-verification=...)を Cloudflare に追加して所有権確認
    • サイトマップを Search Console に送信(Domain プロパティはフルURL https://yclip.org/sitemap.xml を要求した)
  • 1080p高画質対応 は後回し決定
    • YouTube は 1080p 以上を映像と音声に分離して配信するため、結合に ffmpeg が必要
    • 3案を比較:A)別々にDLして自分で結合、B)ブラウザで ffmpeg.wasm 結合、C)サーバーで結合・配信
    • C はダサ方式の前提(帯域ゼロ)を破る、A は UX が悪い、B は ffmpeg.wasm が30MBでモバイル弱い → 結論として今は後回し
  • 保存ファイル名 UX 改善
    • 「videoplayback」になる問題は技術的に不可避と説明(CDN URL が直接、Content-Disposition なし)
    • save.html にタイトルコピーボタンを追加(ワンクリックでクリップボードへ、緑色フィードバック)
    • PC/iOS/Android の各保存手順にリネームステップを追加(各プラットフォームに応じた具体的な操作)
    • コピーボタン下に「ファイル名は『videoplayback』になります。コピーして保存時に貼り付けてください」のヒント追加
  • Android UX 修正
    • 「↑ ここで右クリック」矢印ヒントが Android 大画面で表示されていた問題を修正(PC のみ表示に変更)

決めたこと:

  • 1080p 以上の高画質対応は当面後回し。ダサ方式の帯域ゼロ原則を維持するため、サーバー結合は採用しない
  • ファイル名「videoplayback」問題は技術的制約として受け入れ、タイトルコピー+リネーム手順案内で UX を補う

詰まったこと / 気づき:

  • Cloudflare の robots.txt は自動的に AI クローラー制御(GPTBot、ClaudeBot 等を Disallow)を先頭に prepend してくれる仕様。サイト側で書いた内容は後ろに連結される
  • Google Search Console の Domain プロパティでは、サイトマップ送信時にフルURL(https://yclip.org/sitemap.xml)の入力が必要。URL Prefix プロパティとは挙動が異なる
  • DNS TXT 値は dig で表示されるとダブルクォートが付くが、それは表示フォーマットで実際の値には含まれない

次回やること:

  • 公開・宣伝(Twitter / Reddit / HackerNews / 個人ブログ)
  • 競合比較ページ("y2mate vs yclip" 等)
  • ユーザー増加後:Adsterra マネタイズ
  • ユーザー増加後:1080p 対応(ffmpeg.wasm 検討)

19:27 - Cloudflare Web Analytics 導入、Adsterra マネタイズはユーザー増加後に延期

やったこと:

  • アクセス解析として Cloudflare Web Analytics(無料・Cookie不使用・GDPR準拠)を採用
    • Cloudflare ダッシュボードで yclip.org をサイト登録、トークン取得
    • 全5ページ(index.html / save.html / terms.html / privacy.html / faq.html)にビーコン JS スニペットを sed で一括挿入
    • privacy.html §3 に「Cookie不使用の匿名アクセス解析」の説明を追記(透明性のため)
  • Adsterra マネタイズ準備として「広告なし」コピーを削除 → 一度復元 → 最終的に再削除
    • ヒーロー文言「貼って、取得、保存。広告なし。」→「貼って、取得、保存。」
    • meta description / OG description から「広告に邪魔されない」を削除
    • faq.html の「広告で邪魔したり」表現も削除
  • マネタイズは「ある程度ユーザーが増えるまで延期」と判断 → 約束しない素のコピーで運用

決めたこと:

  • アクセス解析は Cloudflare Web Analytics を採用
  • Adsterra マネタイズはユーザー数が一定規模になるまで実施しない
  • 「広告なし」「広告に邪魔されない」など広告に関する約束コピーは将来の柔軟性のため使わない

詰まったこと / 気づき:

  • C方針(ガッツリ広告化)でコピーを削除した直後、ユーザーが「ある程度ユーザー増えるまで広告なし」と方針転換 → 復元 → さらに「いまのうちから消す」と決定で再削除という3回更新になった
  • 最終的にコピーは「貼って、取得、保存。」のみに落ち着き、メタタグからも広告関連の主張を全削除

次回やること:

  • SEO 整備(sitemap.xml、robots.txt、構造化データ、Search Console 登録)
  • 公開・宣伝(SNS / Reddit / HackerNews / 個人ブログ)
  • 1080p 以上の高画質対応(ffmpeg マージ)

19:02 - UX/デザインフェーズを一気に完了(ブランド〜エラー〜OGP)

やったこと:

  • フェーズ① ブランド確定:方向A「Trust First」採用、favicon.svg、Inter + Noto Sans JP、ink/brand カラーシステム、ヘッダー/フッター、結果なし時の3ステップヒント、OGP/twitter meta タグ整備
  • フェーズ② ランディング体験:信頼バッジ(登録不要/無料/インストール不要)、/terms /privacy /faq の3ページを新規追加、フッターリンク統一、support@yclip.org を Cloudflare Email Routing で gmail 転送(無料)
  • フェーズ③ コアフロー磨き:段階的ローディング(4段階のメッセージ変化)、フォーマットを動画/音声でセクション分け、最高画質に「推奨」バッジ、autofocus 入力欄
  • フェーズ⑤ モバイル細部
    • iPhone 保存手順を実機検証に基づき修正(動画プレイヤー右下 → Safari 下部ツールバー中央)
    • iPhone手順② に Safari 下部ツールバー風のモックアップ(共有ボタンを glow + 「↑ココ」点滅キャプション)
    • iPhone手順③ に共有メニュー(アクションシート)風モックアップ(「"ファイル"に保存」を強調)
    • URL入力欄のフォントサイズをモバイルで 16px に(iOS Safari の自動拡大を抑制)
    • placeholder を「動画のURLを貼る」に短縮
    • ヘッダーロゴ全ページで 1.2 倍に拡大
    • ヒーロー部モバイル表示整理(見出し改行位置調整、サブタイトル「貼って、取得、保存。広告なし。」、バッジ4→3)
  • フェーズ④ エラー・エッジケース
    • バックエンドで yt-dlp エラーを日本語に分類(削除済み/限定公開/メンバー限定/地域制限/年齢制限/ボット検知/対応外URL)
    • 再試行ボタン付きのエラー表示
    • フロントで URL 形式の事前検証
    • 30秒タイムアウトと AbortController によるネットワークエラー
    • フォーマット 0 件時の案内
  • OGP画像:1200×630 を Chrome headless で生成、最初は日本語タグライン入りだったが、ローカライズ対応のため言語ニュートラル版(ロゴ + yclip + yclip.org)に作り直し
  • プライバシーポリシーから具体的なサービス名(Nginx / FastAPI / Cloudflare / AWS / Webshare)を全削除し、カテゴリ表現に変更
  • 「貼付」ボタンとクリップボード自動取り込みを削除(autofocus + Cmd+V で十分との判断)

決めたこと:

  • ブランド方向は「Trust First」(深いネイビー + 落ち着いたブルー、Inter + Noto Sans JP、Stripe / Linear 系の信頼感)
  • 法的グレーゾーンへの姿勢は「攻めない・予防線重視」(私的利用範囲を明示、削除依頼窓口、YouTube ToS 遵守は利用者責任を明記)
  • お問い合わせ窓口は support@yclip.org(Cloudflare Email Routing で gmail 転送、無料)
  • 貼付ボタンとクリップボード自動取り込みは廃止
  • OGP画像は言語ニュートラル化し、ローカライズ時の運用を簡素化

詰まったこと / 気づき:

  • iOS Safari の <video> 要素は長押し保存に対応していない。Safari の下部ツールバー(タブバー中央)の共有ボタンから「ファイルに保存」が正解
  • <input> のフォントサイズが 16px 未満だと iOS Safari が自動的に拡大表示する(既知のクセ)
  • macOS で SVG → PNG 変換ツールがなかったが、Chrome の --headless=new --screenshot で HTML を直接 1200×630 PNG にレンダリングできた(Hiragino Sans が使える)
  • meta property="og:locale" 等を使えばマルチランゲージOGPは可能だが、現状は1言語想定のため割愛

次回やること:

  • アクセス解析の導入(Plausible / Umami / GA4 のいずれか)
  • Adsterra 広告の埋め込み(マネタイズ開始)
  • 1080p 以上の高画質対応(ffmpeg マージ)
  • Hetzner アカウント Close(5月の最終請求後)

15:05 - 次フェーズの方針確認(マネタイズ前にデザイン・UXを固める)

やったこと:

  • 今後の方針について議論:ユーザー獲得施策(Adsterra など)の前に、デザインとUXを固めるフェーズを入れる方針を確定
  • UX 改善の取り組み領域を5つに整理:
    1. ブランド・第一印象(ロゴ/カラー/タイポ/favicon/OGP)
    2. ランディング体験(ヒーロー、3ステップ説明、法的注意、FAQ、利用規約・プライバシーポリシー)
    3. コアフロー(フォーマット選択UI、save.html手順カード、ローディング進捗演出、成功時UX)
    4. エラー・エッジケース(状況別メッセージ、リトライ、空状態)
    5. モバイル細部(iPhone共有メニュー実例、タップ領域、クリップボード自動取り込み)
  • 進める順番:① → ② → ③ → ⑤ → ④(ブランドを最優先で固めて後の判断軸にする)

決めたこと:

  • マネタイズ施策の前に UX/デザインを固めるフェーズを挟む
  • ブランド(ロゴ・カラー・タイポ)から手をつける

次回やること:

  • ① ブランドの確定(ロゴ、カラーパレット、タイポ、favicon、OGP)

14:51 - Webshareでダサ方式成立確認、AWS Lightsail へ移行、AWSネイティブ無料監視構成を構築

やったこと:

  • iPhone Safari で <video> 要素の長押し保存が効かない問題を解決
    • frontend/save.html をデバイス判定し iPhone/Android/PC で別フローを表示するよう改修
    • iPhone は「動画を別タブで開く → 共有ボタン → ファイルに保存」を主導線にした
  • Webshare Rotating Residential($3.50/月)を購入・検証
    • 出口IPがベトナム FPT Telecom の住宅用と確認
    • Hetzner 上で yt-dlp + Webshare proxy で抽出成功(プレーンの Hetzner では Sign in to confirm you're not a bot で弾かれていた)
    • 抽出された CDN URL を別IP(私の Mac)で curl すると HTTP 206 → 200 で 27MB 動画が 12MB/s で取得できることを確認
    • YouTube CDN は ipbypass=yes を redirect で付与し、住宅IPからのアクセスを許可していた
    • ダサ方式 + Webshare extraction の完全成立を確認
  • yclip を ダサ方式に完全移行
    • backend/main.py: ジョブキュー削除、VPS で同期的に yt-dlp 抽出(Webshare proxy 経由)、/download プロキシ削除、/extract を JSON 直接返却に変更
    • frontend/index.html: ポーリング廃止、ダサ方式(/save ページへの新タブ遷移)に統一
    • 自宅 Mac ワーカー、Cloudflare Tunnel、systemd 起動コマンドが不要になった
  • インフラを Hetzner → AWS Lightsail Tokyo へ移行
    • 最初 micro_ipv6_3_0($5、IPv6-only、1GB RAM)で構築 → Webshare の p.webshare.io が IPv4-only で到達不可
    • nano_3_0($5、IPv4、512MB RAM、+swap 1GB)に作り直して成功
    • 静的IP 13.158.151.98、SSH 鍵 ~/.ssh/lightsail-yclip~/.ssh/configyclip-server で登録
    • Cloudflare DNS の AAAA → A レコードに切替
    • Hetzner インスタンス削除(月 ¥600 削減)
  • AWSネイティブ無料監視構成を構築
    • SNS トピック yclip-alerts 作成、ichirokisanuki@gmail.com 購読
    • CloudWatch アラーム3つ:インスタンスステータス異常、CPU>90%、バースト容量<20%
    • サーバー内 cron(5分間隔)で /health を curl、状態遷移時のみ SNS publish
    • IAM ユーザー yclip-server-publishersns:Publish に絞った最小権限)を作成
    • 障害シミュレーションでDOWN/RECOVERED通知の到達を確認
  • ~/cdev/youtube-downloader/CLAUDE.md をダサ方式構成に合わせて全面更新(IP、SSH、systemd、nginx、Webshare 等)
  • 不要ファイル削除(worker/backend/extractor.pyrailway.toml、古い AGENTS.md

決めたこと:

  • ダサ方式に完全移行:Webshare 経由で抽出、動画はブラウザが直接 YouTube CDN から取得
  • インフラを Lightsail Tokyo nano_3_0 に統一(東京リージョン優先、Hetzner 解約)
  • 監視は AWS ネイティブ無料構成を採用(UptimeRobot 不採用)
  • 管理リポジトリ ~/cdev/yclip-lightsail-server/ は作らない(CLAUDE.md に集約)

詰まったこと / 気づき:

  • IPv6-only Lightsail は IPv4-only な外部サービス(Webshare の p.webshare.io)に到達できない。 AWS には NAT64 が VPC レベルで自動提供されない
  • yt-dlp の extractor_args.youtube.player_client=["web","android"] は dictionary でも yt-dlp 内部で list として処理される
  • YouTube CDN の ip=... パラメータは **クラスベース判定(住宅 vs DC)**で、住宅IPなら任意のIPから OK、DC IPからは弾かれる
  • rsync の IPv6 アドレスは zsh のコロン解釈と相性が悪く、SSH config alias 経由が安全
  • Lightsail の CloudWatch メトリクス(AWS/Lightsail namespace)は起動直後だと取得できない(5〜15分かかる)が、アラームは先に作っておける

次回やること:

  • Adsterra 広告の埋め込み(マネタイズ開始)
  • 1080p 以上の高画質対応(ffmpeg マージ)
  • アクセス増加で /health/deep(Webshare 死活)監視の追加検討

12:50 - ダサ方式(直リン保存)UX 実装・Hetzner 単独運用の不可を検証

やったこと:

  • 別 LLM から提案された「静的 ISP プロキシで自宅 Mac ワーカーを廃止する案」(tmp/TEIAN.md)をレビュー
    • 月額 ¥1,600〜¥4,000 でワーカー排除可能との内容
    • ただし YouTube が ISP プロキシIPを通すかは未検証、マネタイズ前にコスト発生は得策でないと判断
  • ダウンロード方式の呼称を整理:
    • クール方式 = yclip 現状(サーバー中継、1クリック)
    • ダサ方式 = awakest.net 系(CDN URL を直接ブラウザに渡し、右クリック保存)
    • 呼称をメモリに保存
  • ダサ方式の UX を磨いた専用ページを実装
    • frontend/save.html を新規作成(動画プレビュー、PC/モバイル別の手順、URLコピー、新タブ表示のフォールバック)
    • backend/main.py/save ルート追加
    • frontend/index.html の各フォーマット行に🌱ボタン(ダサ方式)を追加
  • ワーカー Mac を完全排除できるか検証するため、Hetzner で yt-dlp を直接実行
    • player_client=web,android tv_embedded,ios tv,web_safari,mweb を最新 yt-dlp(2026.04.10.dev)で試行
    • すべて「Sign in to confirm you're not a bot」で失敗
    • Hetzner の AS(データセンター)IP は YouTube に無条件でブロックされていることを確認

決めたこと:

  • 静的 ISP プロキシへの移行は当面見送り(Adsterra でマネタイズが立つまで固定費を増やさない)
  • ワーカー Mac 排除は不可能。Hetzner 単独では yt-dlp 抽出ができない
  • ダウンロード方式の呼称:「クール方式」「ダサ方式」を以後使用

詰まったこと / 気づき:

  • rsync 時にディレクトリ階層を間違えて /opt/yclip/ 直下にファイルを送ってしまった(後で mv で復旧)
  • 「ダサ方式は自宅 Mac 不要」とユーザーが理解していたが、URL 抽出は両方式とも自宅 Mac が必要(ダウンロードのみダサ方式は不要)
  • 最新 yt-dlp dev 版でも Hetzner IP のブロック回避不可。Cookie 注入か有料プロキシしか選択肢がない

次回やること:

  • ダサ方式の動作確認(IP 制限で動画再生できるかどうか実検証)
  • Adsterra 広告の埋め込み
  • 1080p 以上の高画質対応

2026-04-25

18:43 - 特定動画で This video is not available が出る問題を解決

やったこと:

  • 一部の動画(例:KjgWWjkNbhU)で yt-dlp が This video is not available を返す問題を調査
  • ブラウザでは普通に再生できるのに yt-dlp だけ弾かれる症状を確認
  • yt-dlp の --extractor-args "youtube:player_client=web,android" で取得成功することを確認
  • worker.py の YDL_OPTSextractor_args を追加して恒久対応

決めたこと:

  • yt-dlp の player_clientweb,android を明示指定する(デフォルトの ANDROID_VR では一部動画で失敗するため)

気づき:

  • yt-dlp のデフォルト player client 選択は YouTube 側の制限変更で挙動が変わる。明示指定が安定運用には必要

14:36 - ダウンロード速度問題の解決(named tunnel + range requests)

やったこと:

  • Quick Tunnel 起動時に cloudflared サブプロセスのパイプバッファ詰まりで接続が確立しないバグを修正(バックグラウンドスレッドでstdoutをドレイン)
  • Quick Tunnel の速度が遅い問題を分析し、named tunnel への移行を実施
    • cloudflared tunnel create yclip-worker で名前付きトンネルを作成
    • cloudflared tunnel route dns yclip-worker worker.yclip.org で DNS 登録
    • ~/.cloudflared/config.ymlworker.yclip.org → localhost:8081 を設定
    • cloudflared tunnel run yclip-worker で常時起動(4本接続が NRT エッジに張られる)
  • ワーカーは WORKER_TUNNEL_URL=https://worker.yclip.org を環境変数で受け取り VPS に登録
  • それでもダウンロードが遅い問題(7MB に5分)を調査
    • ローカルプロキシ・トンネルとも単体では速いことを確認
    • yt-dlp 直接ダウンロードは一瞬で完了 → YouTube CDN による単一接続スロットリングが原因と特定
    • プロキシを range リクエスト(10MBチャンク)方式に変更
  • yclip.org でダウンロードが瞬時に完了することを確認

決めたこと:

  • ダウンロードプロキシは10MB の range リクエストで取得する(YouTube スロットリング回避)
  • Cloudflare Tunnel は named tunnel(worker.yclip.org)を使う

詰まったこと / 気づき:

  • cloudflared tunnel create のスペルを crete と誤入力していた
  • cloudflared を subprocess で起動して URL 取得後にパイプを読まないと、出力バッファが詰まりトンネル接続自体がブロックされる
  • YouTube CDN は単一の長時間接続を意図的にスロットルする(ratebypass=yes パラメータがあっても)。range リクエストで分割するとスロットルされない
  • Quick Tunnel(trycloudflare.com)は実験用で速度が出にくい。本番運用は named tunnel が必須

次回やること:

  • Adsterra 広告の埋め込み
  • 1080p 以上の高画質対応(ffmpeg マージ)
  • モバイル対応・UX 改善

00:13 - ダウンロードプロキシをワーカーMac経由(Cloudflare Tunnel)に変更・動作確認

やったこと:

  • /download がエラーになる原因を特定:YouTube CDN URL に ip=<ワーカーMacのIP> が埋め込まれており、Hetzner VPS からのアクセスが 403 で弾かれていた
  • ダウンロードプロキシをワーカーMac側に移す構成に変更
    • worker/worker.py: DownloadProxyHandler(port 8081)を追加、cloudflared Quick Tunnel を自動起動し VPS へ URL 登録する処理を追加
    • backend/main.py: /downloadRedirectResponse に変更(ワーカープロキシへリダイレクト)、POST /worker/register エンドポイントを追加
  • cloudflared を自宅 Mac にインストール・Cloudflare アカウントにログイン
  • ワーカー起動でトンネルURL自動取得・VPS登録が動作することを確認
  • yclip.org でダウンロードが正常に動作することを確認

決めたこと:

  • ダウンロードプロキシはワーカーMac(Cloudflare Tunnel経由)が担う。VPS はリダイレクトするのみ。

詰まったこと / 気づき:

  • YouTube CDN URL は yt-dlp を実行した IP にバインドされている。VPS や別 IP からはアクセス不可。
  • cloudflared tunnel create のスペルミス(crete)でハマったが、Quick Tunnel で代替。
  • Quick Tunnel はワーカー再起動ごとに URL が変わるが、起動時の自動登録で対処。

次回やること:

  • Adsterra 広告の埋め込み
  • named tunnel 設定(Quick Tunnel の URL 変動問題の恒久対策)
  • 1080p 以上の高画質対応

2026-04-24

20:00 - 自宅 Mac ワーカー構成で YouTube IP ブロック問題を解決・エンドツーエンド動作確認

やったこと:

  • ジョブキュー構成を設計・実装(VPS が受付、自宅 Mac が処理)
    • backend/main.py: SQLite ジョブキュー + /extract/jobs/{id}/worker/* エンドポイントを追加
    • worker/worker.py: 自宅 Mac 用ワーカースクリプトを新規作成
    • frontend/index.html: ジョブポーリング対応(2秒ごとに status を確認)
  • Hetzner に新コードをデプロイ
  • 別の Mac にワーカーをセットアップして起動
  • https://yclip.org でエンドツーエンドのダウンロードが動作することを確認
  • YouTube Mix URL(&list=...&start_radio=1)を自動でクリーニングする処理を追加

気づき:

  • &list=... 付きの URL は yt-dlp がプレイリスト全体を解析しようとしてタイムアウトする
  • 別 Mac の pip が壊れていたため venv 経由でインストールが必要だった

決めたこと:

  • Residential Proxy(有料)や Cookie 注入ではなく、自宅 Mac の住宅用 IP をワーカーとして使う構成を採用

次回やること:

  • Adsterra 広告の埋め込み
  • 1080p 以上の高画質対応

17:00 - Hetzner 本番デプロイ完了・YouTube IP ブロック問題発覚

やったこと:

  • yclip.org ドメインをお名前.com で取得(初年無料、.com プレミアム問題を回避し .org に変更)
  • Hetzner アカウント作成・VPS 立ち上げ(Nuremberg / Regular Performance / Ubuntu 24.04)
  • サーバーセットアップ: Python 仮想環境・uvicorn・nginx・systemd 設定
  • Cloudflare に yclip.org を登録、DNS + SSL を設定
  • https://yclip.org が外部公開できた
  • YouTube がブロックしている問題を確認(Hetzner のデータセンター IP が弾かれる)

決めたこと:

  • インフラを Railway → Hetzner Nuremberg に変更(20TB 帯域付きで月 €4 程度)
  • ドメインは yclip.org(お名前.com 初年無料。1年でサービスがうまくいかなければサ終予定)
  • Cloudflare を DNS + SSL レイヤーとして採用(無料)
  • /download プロキシエンドポイントを追加(ブラウザのクロスオリジン制約でダウンロードできない問題を解決するため。帯域コストが発生する妥協点)

詰まったこと / 気づき:

  • yclip.com はプレミアムドメインで 774,312円、yclip.org は初年無料だった
  • Singapore VPS は月 $9.49 + 0.5TB のみ。Nuremberg は月 €4 + 20TB で全然違う
  • Hetzner のクレジットカード払いが弾かれ PayPal で解決
  • Cloudflare SSL モードを「Flexible」にしないと Error 521 が出る
  • ブラウザの download 属性はクロスオリジン URL には効かない → サーバープロキシが必要
  • Hetzner のデータセンター IP は YouTube にボットとして弾かれる(ローカルは通る)

次回やること:

  • YouTube IP ブロック対策(Residential Proxy または Cookie 認証)

14:30 - session-wrap-up スキルテスト(4ファイル運用に移行)

やったこと:

  • session-wrap-up スキルの動作確認(DEVLOG/WIP 2ファイル→4ファイル運用への移行確認)
  • DECISIONS.md・ROADMAP.md を新規作成・初期内容を記録

次回やること:

  • Railway にデプロイして公開(最優先)

14:00 - アーキテクチャ設計 & Phase 1 MVP 実装

やったこと:

  • YouTube ダウンローダーサイトのアーキテクチャを壁打ちしながら設計
  • Phase 1 MVP を実装・ローカル動作確認・GitHub push まで完了

決めたこと:

  • サーバーは URL 抽出のみ(動画データを触らない)。yt-dlp で YouTube CDN の直リンクを返し、ユーザーのブラウザが直接 CDN からダウンロードする。自サーバーの帯域コストをほぼゼロに抑えるための核心設計。
  • バックエンド: Python 3.12 + FastAPI + yt-dlp
  • フロントエンド: Vanilla JS + Tailwind CSS(単一 index.html)
  • インフラ: Railway(無料枠スタート)
  • 広告: AdSense ではなく Adsterra / PropellerAds(グレーゾーンサイトへの審査リスクを避けるため)

実装したファイル:

  • backend/main.py — FastAPI エントリポイント(POST /extractGET /
  • backend/extractor.py — yt-dlp ラッパー(直リンク・タイトル・サムネイル・フォーマット一覧)
  • backend/requirements.txt
  • frontend/index.html — URL 入力→フォーマット選択→CDN 直 DL の UI
  • railway.toml — Railway デプロイ設定

気づき:

  • yt-dlp は Python ネイティブなので loop.run_in_executor で非同期化した(FastAPI のブロッキング対策)
  • backend/ ディレクトリ内から uvicorn を起動しないと from extractor import が解決できない(同じ階層問題)

次回やること:

  • Railway にデプロイして公開
  • 1080p 以上の対応(映像・音声トラックが分離しているため ffmpeg マージが必要)
  • Adsterra 広告の埋め込み

最近のコミット

README

youtube-downloader

概要

(記入予定)

セットアップ

(記入予定)

使い方

(記入予定)