0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flickr動画のダウンロード技術を解剖する:APIレスポンス解析から実装の勘所まで

0
Posted at

Flickr動画のダウンロード技術を解剖する:APIレスポンス解析から実装の勘所まで

※本記事は技術的な学習・研究を目的としており、著作権で保護されたコンテンツの無断利用を推奨するものではありません。利用の際は必ず各プラットフォームの利用規約および著作権法を遵守してください。

はじめに:「あの風景動画、資料として保存したい」から始まった技術的探求

こんにちは、普段はメディアアーカイブシステムの開発に関わっているエンジニアです。

先日、Flickrで公開されていた旅行先の風景動画を見つけたんですが、「プレゼン資料に引用したい」「オフライン環境でも再生して確認したい」と思った瞬間、あの「ダウンロードオプションが限定的」という現実に直面しました。

「APIを叩けば取れるでしょ?」と思った方もいるかもしれません。実際、Flickr APIは比較的ドキュメントが整備されており、flickr.photos.getSizes を使えば動画プレイヤー用URLやMP4リンクが取得できることが公式ブログでも言及されています[[22]]。

しかし、2024年現在、単純なAPIコールだけでは対応できないケースも増えています。例えば、非公開設定の動画、地域制限付きコンテンツ、あるいはAPIキーのレート制限に引っかかる大量取得など…。

かといって、怪しいサードパーティ製ツールにAPIキーやアカウント情報を渡すのも抵抗がある…。

そんな「技術的には可能なのに、手軽に安全に使える手段がない」というギャップを埋めたくて、今回ご紹介する flickr_downloader_ja の技術アーキテクチャを、開発者の視点から分解してみようと思います。

本記事では、単なる「使い方の紹介」ではなく、「Flickrの動画メタデータをどう抽出し、どう最適化しているか」 という技術的な中身に焦点を当てます。コード例も交えつつ、実装の勘所を共有できれば幸いです。


Flickr動画配信の技術的構造:APIとHTMLの二重アプローチ

1. Flickr API を使った正規アプローチ

Flickrでは、動画メタデータの取得に公式APIを活用するのが最も確実な方法です。特に flickr.photos.getSizes エンドポイントは、動画に対して複数の解像度オプションを返してくれるため、ダウンロード用途に最適です。

以下は、APIレスポンスの簡易イメージです:

{
  "sizes": {
    "size": [
      {
        "label": "Mobile MP4",
        "width": 640,
        "height": 360,
        "source": "https://video-downloads.flickr.com/xxx/mobile.mp4"
      },
      {
        "label": "Site MP4",
        "width": 1280,
        "height": 720,
        "source": "https://video-downloads.flickr.com/xxx/site.mp4"
      },
      {
        "label": "HD MP4",
        "width": 1920,
        "height": 1080,
        "source": "https://video-downloads.flickr.com/xxx/hd.mp4"
      }
    ]
  }
}

💡 補足:label フィールドに "Video Player" とある場合は、Flashプレイヤー用URL(stewart.swf)が返されることがあります。これは直接ダウンロードには不向きなため、MP4形式のエントリを優先して選択するロジックが必要です[[22]]。
flickr_pic (1) low.png

2. HTML解析による代替アプローチ

APIキーの取得が面倒な場合や、簡易ツールを作りたい場合には、動画ページのHTMLソースから直接リンクを抽出する方法も有効です。

Flickrの動画ページには、以下のようなメタタグやJSON-LDが含まれていることがあります:

<meta property="og:video" content="https://video-downloads.flickr.com/xxx/site.mp4">
<meta property="og:video:secure_url" content="https://video-downloads.flickr.com/xxx/site.mp4">

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "contentUrl": "https://video-downloads.flickr.com/xxx/hd.mp4"
}
</script>

これらをBeautifulSoup や正規表現で抽出すれば、APIキーなしでも動画リンクを取得可能です。ただし、Flickrはフロントエンドの構造を頻繁に変更するため、この手法は「その時点で動作する」保証がない点に注意が必要です。


簡易実装:PythonでAPIコールからダウンロードまで

以下は、学習目的のサンプルコードです。実際の運用では、APIキーの安全な管理、エラーリトライ、レート制限対応など、より多くの配慮が必要になります。

import requests
from urllib.parse import urlencode

def get_video_sizes(photo_id: str, api_key: str) -> list[dict]:
    """flickr.photos.getSizes API から動画サイズ一覧を取得"""
    base_url = "https://www.flickr.com/services/rest/"
    params = {
        "method": "flickr.photos.getSizes",
        "api_key": api_key,
        "photo_id": photo_id,
        "format": "json",
        "nojsoncallback": 1
    }
    
    resp = requests.get(base_url, params=params, timeout=10)
    resp.raise_for_status()
    data = resp.json()
    
    if data.get("stat") != "ok":
        raise ValueError(f"API Error: {data.get('message')}")
    
    # MP4形式のエントリのみをフィルタリング
    return [
        s for s in data["sizes"]["size"]
        if s["label"].endswith("MP4") and "source" in s
    ]

def select_best_quality(sizes: list[dict]) -> dict:
    """HD > Site > Mobile の優先順位で最適解を選択"""
    priority = ["HD MP4", "Site MP4", "Mobile MP4"]
    for label in priority:
        match = next((s for s in sizes if s["label"] == label), None)
        if match:
            return match
    return sizes[0] if sizes else None

# 使用例(APIキーは環境変数等で管理推奨)
photo_id = "14740171524"  # Flickr写真/動画ID
api_key = "your_api_key_here"

sizes = get_video_sizes(photo_id, api_key)
best = select_best_quality(sizes)
if best:
    print(f"選択: {best['label']} ({best['width']}x{best['height']})")
    print(f"URL: {best['source']}")

⚠️ 注意点:Flickr API は1時間あたり一定数のリクエスト制限があります。大量取得が必要な場合は、キャッシュ機構の導入や、APIキーの複数発行を検討しましょう。


当サービスのアーキテクチャ:なぜ「サーバーに保存しない」設計なのか

flickr_downloader_ja の最大の特徴は、「ユーザーのダウンロードファイルを一切サーバーにキャッシュしない」 という設計思想にあります。これには明確な技術的・法的な理由があります。

1. プライバシーとセキュリティの観点

  • ユーザーがダウンロードした動画のURL、IPアドレス、利用履歴などを記録しない
  • サーバー側にファイルを一時保存しないため、情報漏洩リスクが原理的に排除される
  • すべてクライアントサイドで完結するフロー(またはプロキシ経由のストリーミング転送)を採用

2. 著作権対応の設計

当サービスは「ダウンロード支援ツール」であり、「コンテンツの再配布プラットフォーム」ではありません。技術的には、以下のようなフローで実現しています:

[ユーザーブラウザ] 
    ↓ (1) Flickr動画URLを送信
[当サーバー] 
    ↓ (2) APIまたはページ解析で動画メタデータを取得(キャッシュなし)
    ↓ (3) 直接ダウンロード用リンクを生成
[ユーザーブラウザ] 
    ↓ (4) Flickr CDN から直接ファイルをダウンロード

この「中継のみで保存しない」アーキテクチャにより、当サーバーには著作権対象ファイルが一切存在しない 状態を維持できています。これは法的リスクの低減だけでなく、ストレージコストの削減、スケーラビリティの向上にも寄与しています。

3. 品質選択とフォールバック処理の実装方針

Flickrの動画は、投稿者によってアップロード時のエンコード設定が異なるため、同じ動画でも複数の解像度が用意されている場合があります。当サービスでは、以下のような優先順位で最適解を選択しています:

// 品質選択ロジックの簡易例
const QUALITY_PRIORITY = ["HD MP4", "Site MP4", "Mobile MP4", "Original"];

function selectBestVideo(sizes) {
  for (const label of QUALITY_PRIORITY) {
    const match = sizes.find(s => s.label === label && s.source);
    if (match) return match;
  }
  // どれにもマッチしない場合は、最初の有効エントリを返す
  return sizes.find(s => s.source) || null;
}

実際の運用では、ユーザーに選択肢を表示するUI、ファイルサイズの事前取得、ダウンロード進捗のリアルタイム表示など、ユーザー体験を考慮した設計が必要です。


実際の使い方:3ステップで完了するシンプル設計

技術的な中身は複雑でも、ユーザー体験はシンプルであるべき。当サービスのUIは以下の3ステップのみで構成されています。

  1. Flickr動画のURLをコピー
    例:https://www.flickr.com/photos/flickr/14740171524/

  2. 入力欄に貼り付けて「解析を開始」をクリック
    約2〜5秒でメタデータ解析完了。利用可能な解像度オプションが表示されます。

  3. 希望の品質を選択して保存
    ブラウザの標準ダウンロード機能を使用するため、追加ソフト不要。

スマホでも同じ操作性

レスポンシブデザインを採用しているため、iPhone / Android のブラウザからも全く同じ手順で利用可能です。iOSの場合、Largeファイルのダウンロード時に「ファイル」アプリ経由での保存が必要になることがありますが、これはOSのセキュリティポリシーによるものです。


技術的なメリット:なぜこのツールが「軽量で高速」なのか

✅ 1. ステートレスなAPI設計

各リクエストが独立して処理されるため、セッション管理やデータベース接続が不要。これにより、サーバーリソースの効率的な利用と、突発的なトラフィック増加への耐性を実現しています。

✅ 2. CDNフレンドリーな配信

動画ファイルはFlickrのCDN(video-downloads.flickr.com)から直接取得するため、当サーバーの帯域幅を圧迫しません。メタデータ取得のみをサーバー側で担当し、実際のファイル転送はクライアント↔Flickr間で行う設計です。

✅ 3. クライアントサイドでの進捗表示

解析・ダウンロード中のステータスは、Server-Sent Events(SSE)でリアルタイムにクライアントへ通知。ユーザーが「待たされている感」を感じないよう、技術的に配慮しています。

// SSEによる進捗通知の簡易例
const eventSource = new EventSource('/api/progress?job_id=xxx');
eventSource.onmessage = (e) => {
  const data = JSON.parse(e.data);
  // { step: "fetching_metadata", percent: 30, message: "APIレスポンス待機中..." }
  updateStatusUI(data);
};

開発者としての想い:オープンな技術を、より多くの人に

私自身、長年デジタルアーカイブやメディア処理の開発に携わってきましたが、「技術的にできること」と「ユーザーが実際に使えるもの」の間には、常に大きなギャップがあると感じています。

このツールを作った理由はシンプルです:

「クリエイティブなコンテンツを、正当な目的で、手軽に活用したい」

という当たり前の欲求を、技術でサポートしたかったからです。

もちろん、Flickrのプラットフォームポリシーや著作権法とのバランスは常に意識しています。本サービスは:

  • 公開動画のメタデータのみを処理
  • 非公開・友達限定コンテンツには対応しない(認証フロー未実装)
  • 商用利用・再配布を目的とした利用を規約で禁止

といった制限を設けています。技術は中立ですが、その使い方は責任を持って設計すべきだと考えています。


Qiita読者への技術的プレゼント:自分で作ってみるためのヒント

もし「自分でも似たツールを作ってみたい」と思われた方に向けて、学習リソースをいくつかご紹介します。

🔍 参考になる技術スタック

用途 推奨技術
APIリクエスト requests (Python), axios (Node.js)
HTML/JSON解析 BeautifulSoup, lxml, cheerio
動画メタデータ処理 ffmpeg (情報取得用), mediainfo
APIキー管理 環境変数、AWS Secrets Manager、Vault
フロントエンド Next.js + Tailwind, Streamlit(プロトタイプ用)
非同期処理 asyncio + aiohttp, BullMQ + Redis

📚 学習に役立つリソース

💡 実装時のアドバイス

  1. APIキーの安全な管理:コードにハードコードせず、環境変数やシークレット管理サービスを活用。
  2. レート制限の尊重:Flickr API は1時間あたり一定数のリクエスト制限があります。time.sleep() などで間隔を空け、429エラーへのリトライロジックを実装しましょう。
  3. エラーハンドリングの充実:動画が見つからない、非公開設定、地域制限など、想定される失敗ケースを網羅し、ユーザーに分かりやすいメッセージを表示。
  4. ユーザーへの選択肢提供:複数の解像度が存在する場合、ファイルサイズと画質のバランスを考慮して選択肢を提示すると親切です。

おわりに:技術は、誰かの「ちょっと嬉しい」を創れる

最後になりましたが、flickr_downloader_ja は、個人開発者が「自分の不便を自分で解決した」ことから始まったプロジェクトです。

Qiitaのコミュニティでは、技術的な深掘りと実用性のバランスが取れた記事が好まれる傾向があります。本記事が、単なる「ツール紹介」ではなく、「技術的な仕組みへの理解」を深めるきっかけになれば幸いです。

もし実際に使ってみて、「ここが分かりにくい」「こういう機能が欲しい」といったフィードバックがありましたら、ぜひサイトの問い合わせフォームからご連絡ください。オープンな技術開発は、ユーザーとの対話から進化していくものと信じています。


📌 免責事項
本サービスは、SmugMug, Inc.(Flickr運営元)とは一切関係ありません。
ダウンロードしたコンテンツの利用は、必ず著作権法および各プラットフォームの利用規約に従ってください。
個人での視聴・学習・正当な引用目的以外の利用(再配布、商用利用、改変など)はご遠慮ください。


タグ: #Flickr #動画ダウンロード #API #Webスクレイピング #Python #JavaScript #ffmpeg #Qiita #技術記事 #メディア処理

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?