Facebookへのアップロード

このチュートリアルでは、Facebookにファイルをアップロードしてみます。 本サイトでは、Facebookへアップロードする サンプルプログラムを公開していますので、ここでは、サンプルプログラムがどのように動作するかをみていきます。


Facebook.html

facebook.htmlは、FacebookのOAuthサービスへリダイレクトするためにjavascriptを使用します。これは、認証トークンを取得するために使用します。


fb_get_token.lua

fb_get_token.luaは、長期アクセストークン(60日間有効)を取得するために使用します。

まず、現在のアクセストークン(有効期限が1時間)が有効であることを確認するために、 fa.requestとcjsonを使用します。

local function hasValidToken(t)
  local b, c, h = fa.request {
    url = 'https://graph.facebook.com/debug_token?input_token='
      ..t.user_access_token..'&access_token='
      ..t.app_access_token,
      headers = {Connection = 'close'}
    }
  if (c == 200) then
    local cjson = require("cjson")
    local res = cjson.decode(b)
    cjson = nil
    if (res.error ~= nil) then
      t.message = res.error.message
    else
      t.long_term = res.data.issued_at
      if (res.data.error ~= nil) then
        t.message = res.data.error.message
      else
        t.message = res.data.message
      end
    end
    return res.data.is_valid
  else
    t.message = b
    return false
  end
end

レスポンスコード(c)を確認し、200の場合、JSONレスポンスへデコードします。いずれかのステップで失敗した場合、有効なトークンが取得できず、showAuthorizationURL()が呼ばれ、新しいキーを取得するよう指示する文字が表示されます。

hasValidTokenが「true」を返した場合、長期アクセストークンを取得しにいきます。ここで、FacebookのOAuth APIを呼び出すために、 fa.requestを再び使用します。一時的なアクセストークンを渡すと、60日間有効なアクセストークンに更新され、表示されるはずです。

local function getLongtermToken(t)
  local b, c, h = fa.request {
  url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token'
    ..'&client_id='..t.app_id
    ..'&client_secret='..t.app_secret
    ..'&fb_exchange_token='..t.user_access_token,
    headers = {Connection = 'close'}
  }

  if (c == 200) then
    local s, e = b:find("&")
    local longtermToken = b:sub(1, s - 1)
    local file = io.open( t.token_fullpath, "w" )
    file:write( longtermToken )
    io.close( file )
    file = nil

    s, e = longtermToken:find("=")
    -- Store the returned token
    t.user_access_token = longtermToken:sub(e+1, #longtermToken)
  end
end

fb_token_handler.lua

このスクリプトは、fb_get_token.lua用の設定ファイル(facebook.cfg)を管理します。結果を含むテーブル(mod)を返します。


fb_auto_up.lua

最後に、このスクリプトは、Facebookにアップロードするためのスクリプトです。まず、無線LANが接続されるのを待ちます(waitWlanConnect())。そして、接続が確立されると、アップロードディレクトリ内の各フォルダをを探索し、1回に1ファイルをアップロードします。

各ファイルを選択するために、LuaFileSystemを利用します(autoUpload())。

--...
--For each directory...
for aDirectory in lfs.dir("/DCIM") do
  local _dir_id = tonumber(aDirectory:sub(1, 3))
    --  print("DIR:"..aDirectory, lfs.attributes("/DCIM/"..aDirectory, "modification"))
    if (_dir_id ~= nil and _dir_id >= lastDirectory) then
      --for each file in that directory...
      for aFile in lfs.dir("/DCIM/"..aDirectory) do
    	  --Process and upload!
        --...

次に、フォルダをアップロードする前に、アルバムを作成するためにFacebookのGraph APIを使います。これは、基本的な fa.requestでリクエストを発行します。正しい場所にアップロードするために、レスポンス文字列をデコードし、アルバムIDを取得します。

local function createAlbum(_name, _message)
  local req = {}
  req["url"] = 'https://graph.facebook.com/v2.1/me/albums?access_token='..user_access_token
    ..'&name='..string.gsub (_name, " ", "+")
    ..'&message='..string.gsub (_message, " ", "+")
    ..'&privacy=%7B%22value%22%3A+%22SELF%22%7D'
  req["method"] = 'POST'
  req["headers"] = {Connection = "close"}

  local b,c,h = fa.request(req)
  if (c ~= 200) then
    print(h, b)
    return nil
  end
  req = nil

  c, h = nil
  local cjson = require("cjson")
  local res = cjson.decode(b)
  collectgarbage()
  return res["id"]
end

最後に、POSTリクエストを発行するために、 fa.requestを使用して各ファイルのアップロードを行います。(uploadFile(filePath,_album_id))

local function uploadFile(filePath, _album_id)
  local boundary = '--bnfDxpKY69NKk'
  local headers = {}
  local place_holder = '<!--WLANSDFILE-->'

  headers['Connection'] = 'close'
  headers['Content-Type'] = 'multipart/form-data; boundary="'..boundary..'"'

  local body = '--'..boundary..'\r\n'
      ..'Content-Disposition: form-data; name="source"; filename="'
      ..filePath..'"\r\n'
      ..'Content-Type: image/jpeg\r\n\r\n'
      ..'<!--WLANSDFILE-->\r\n'
      .. '--' .. boundary .. '--\r\n'

  headers['Content-Length'] =
      lfs.attributes(filePath, 'size')
      + string.len(body)
      - string.len(place_holder)

  local args = {}
  args["url"] = 'https://graph.facebook.com/v2.1/'
          .._album_id..'/photos?access_token='
          ..user_access_token
          ..'&message='..filePath
  args["method"] = "POST"
  args["headers"] = headers
  args["body"] = body
  args["file"] = filePath
  args["bufsize"] = 1460*10
  local b,c,h = fa.request(args)
  b, h = nil
  collectgarbage()
  if (c ~= 200) then
      print(h, b)
      return nil
  end
  return c
end

アップロードには数分かかる場合があります。


サンプルコード

リポジトリを見る(GitHub)

このサイトのサンプルコードは二条項BSDライセンスで提供されています。