2013年6月28日星期五

使用 Picasa Web API 進行批次上載、下載、更新及刪除

Picasa Web Album 是一個由 Google 提供網絡相簿服務
Google 雖然提供了對 Picasa Web Album 操作的 Picasa ,但只有 Windows 及 Mac 版
Google 曾推出支援 Linux 的 Picasa ,但都只是綑綁於 WineHQ 的 Windows 版,並非真正 Linux 版
往後更完全取消了綑綁於 WineHQ 的 Picasa ,由於 Google 已經改寫 Picasa Web Album 的後端操作
即使能夠安裝,仍只能進行基本圖片管理操作,卻不能進行網絡操作(因為 Picasa 登入是使用 IE 作為後端登入,但 Linux 並沒有 IE ……)
莫非 Linux 就沒有方便方法操作 Picasa Web Album ?

以在下的認知中,真的沒有真正方便讓 Linux 使用者操作 Picasa Web Album 的方法
最方便的已經是使用 ShotwellF-Spot
兩者都是能支援 Linux 的圖片管理軟件,亦具備操作 Picasa Web Album 的功能,一般操作上都與 Picasa 相似
只需要登記 Google 帳戶便可以進行上載及下載,相當簡單,但兩者都沒有針對更新及刪除的操作

需要針對個別操作便需要透過 Picasa Web API 處理
Google 允許軟件開發者根據 Picasa Web API 所提供的操作,讓程序能讀取及控制 Picasa Web Album 的資料
資料都是以 XML 傳回,能讓大部分高階語言輕易分析
根據 Picasa Web API 官方 所提供的說明文件
Google 提供了不少官方及第三方 API 讓開發輕易傳取資料如 Java, .NET, PHP, Python, Objective-C
不過當中只有 Java 有新版本,其他語言都已經過期,部分操作說明文件更沒有有效連結,令人擔心 API 能否使用……

Picasa Web API 透過不同連結及參數傳回對應的資料
在使用 Picasa Web API 前必須先認知 Google Authorization
Google Authorization 同樣是使用 Google 其中一種 API 所得的(虛擬)授權證書
它的作用類似使用於網頁瀏覽上登入帳戶後的操作權相同
Google 提供 OAuth2.0, OAuth1.0, AuthSub 及 ClientLogin 的授權操作
由於針對網頁操作及 ClientLogin 是(在下認為)最簡單的授權操作,所以往下的程式碼都是以 PHP 及 ClientLogin 編寫

需要獲得授權證書,便需要到 https://www.google.com/accounts/ClientLogin ,使用者需要以 HTTP POST 來拿取授權證書
最基本,使用者必須提交 Email, Passwd, service 及 source
Email 是使用者電郵帳戶,必須提供
Passwd 是使用者密碼,必須提供
service 是使用者需要使用的 Google Service ,必須提供, Picasa 是 lh2
source 是使用者為了獲得授權證書所提供的計劃名稱,可以當為專案名稱,可以是空白字串
填妥後以 HTTP POST 提交的資料,若果成功,會傳回像以下的資料
SID=...
LSID=...
Auth=...
當中 Auth= 往後的字串,就是授權證書,授權證書有效時期為24小時
但若果相同帳戶再次申請新授權證書,舊授權證書大約在10分鐘左右過期
只要每進行 Picasa Web API 操作前加入授權證書的 Header 便相當於擁有該使用者於當前服務中的操作權
以下是使用 PHP 的簡單操作
function login($user, $password){
    $authToken = null;
    $path = 'https://www.google.com/accounts/ClientLogin';
    $parameters = array(
        'Email' => $user,
        'Passwd' => $password,
        'service' => 'lh2',
        'source' => '',
    );
    $data = http_build_query($parameters);
    $headers = array(
        'Content-Type: application/x-www-form-urlencoded',
        'Content-Length: ' . strlen($data),
    );
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_URL, $path);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    $response = @curl_exec($curl);
    curl_close($curl);
    if ($response !== false){
        $responses = explode("\n", str_replace("\r", '', $response));
        foreach ($responses as $response){
            $matches = array();
            if (preg_match('/^(?:Auth=)(.*)$/', $response, $matches) > 0){
                $authToken = $matches[1];
                break;
            }
        }
    }
    return $authToken;
}
當中運用了 curl 需要安裝 php5-curl ,可以輸入
DEB
sudo apt-get install php5-curl
或 RPM
yum install php5-curl
Windows 版的 PHP 需要在 php.ini 中啟用 php_curl.dll
獲得授權證書後,便可以開始透過 Picasa Web API 操作 Picasa Web Album

一切 Picasa Web API 的操作,都需要透過
http://picasaweb.google.com/data/feed/api/
或使用 SSL 的
https://picasaweb.google.com/data/feed/api/
需要獲取某使用的 Picasa Web Album 列表
https://picasaweb.google.com/data/feed/api/user/google-account
可以顯示該帳戶所有公開相簿

加入 Authorization: GoogleLogin auth="auth token"
$headers = array(
    'Content-Type: application/x-www-form-urlencoded',
    'Content-Length: ' . strlen($data),
    'Authorization: GoogleLogin auth="<auth token>"',
);
可以顯示該帳戶公開及非公開相簿,同時可發佈評論(comment)及標籤(tag)

若果帳戶為獲得授權證書的帳戶(即授權人帳戶),便可以顯示公開、非公開及私人(所有)相簿,同時獲得全面操作權

操作權包括
針對帳戶:建立相簿,更新相簿,刪除相簿
針對相簿:上載圖片及影片、更新圖片及影片,刪除圖片及影片
針對圖片及影片:發佈評論及標籤,刪除評論及標籤
除了發佈評論及標籤,所有操作權都需要獲得該帳戶的授權證書才能操作

建立相簿
相簿的各項屬性是透過 XML 的指定格式所給予,樣式如下
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gphoto="http://schemas.google.com/photos/2007" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
    <title type="text">required title</title>
    <summary type="text">summary</summary>
    <icon>photo path in album</icon>
    <gphoto:id>integer of album id</gphoto:id>
    <gphoto:timestamp>unix timestamp * 1000</gphoto:timestamp>
    <georss:where>
        <gml:Point>
            <gml:pos>longitude latitude</gml:pos>
        </gml:Point>
    </georss:where>
    <gphoto:location>some location</gphoto:location>
    <gphoto:access>access level</gphoto:access>
    <gphoto:commentingEnabled>string of true or false</gphoto:commentingEnabled>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#album"></category>
</entry>
title 是指相簿的標題,必須填寫,長度必須大於 1
summary 是指相簿的總結資料,類似描述的資料,可以不填寫
icon 是指相簿的封面圖示,可以不填寫
gphoto:id 是指相簿的 id ,建立相簿不會使用 id,在更新相簿時才需要使用
gphoto:timestamp 是指相簿建立日期及時間,以 Unix timestamp * 1000 計算,即 1999 是 Unix timestamp 1970年1月1日0時0分1秒999毫秒,不填寫預設為當前時間
georss:where > gml:Point > gml:pos 是指相簿地理位置,以經度及緯度定義(以空格分隔),數值可準確至小數後6位,用於連結 Google Maps ,可以不填寫
gphoto:location 是指對於相簿的文字描述,可以不填寫
gphoto:access 是指相簿的存取等級,指定以 public 為公開, private 為非公開, protected 為私人(開發者比較容易誤會 private 及 protected),不填寫預設為 private
gphoto:commentingEnabled 是指相簿能否給予評論,指定以 true 為允許, false 為不允許,不填寫預設為 true
建構時,可以除去格式化的 新行(newline), 製表符(tab), 空格(space) 讓 XML 字串更簡短
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP POST 提交資料到
function createAlbum(){
    $data = //some XML string
    $headers = array(
        'Content-Type: application/atom+xml',
        'Content-Length: ' . strlen($data),
        'Authorization: GoogleLogin auth="<auth token>"',
    );
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_URL, 'https://picasaweb.google.com/data/feed/api/user/some-google-account');
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    $response = @curl_exec($curl);
    curl_close($curl);
    return $response;
}
若果成功,便會傳回該相簿的 XML ;若果失敗,便會傳錯誤訊息

更新相簿
與建立相簿相似,不過必須先獲得更新的網址
更新的網址可以在建立相簿時獲得的 XML

以 application/x-www-form-urlencoded 的 Content-Type 及授權證書 的 Header ,並以 HTTP GET 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id
獲取 XML 資料,而 XML 中的包含如下的標籤
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/an-integer"/>
link 的標籤, rel屬性 為 edit , type 為 application/atom+xml , href 便是更新的網址
更新的網址,與原來的網址前端完全相同,只是最後會有一個整數
獲得更新的網址後,編製與建立相簿相同的 XML ,但 gphoto:id 的必須填上
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP PUT 提交資料到更新的網址
若果成功,便會傳回該相簿的 XML ;若果失敗,便會傳錯誤訊息

刪除相簿
與更新相簿相似,同樣需要先獲得更新的網址,分別是刪除相簿不需要編製 XML ,並以 HTTP DELETE 提交資料到更新的網址
若果成功,不會傳回任何資料:若果失敗,便會傳錯誤訊息

上載圖片
與建立相簿相似,若果上載圖片時需要加入 metadata
各項屬性是透過 XML 的指定格式所給予,樣式如下
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gphoto="http://schemas.google.com/photos/2007" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
    <title>required title</title>
    <summary>summary</summary>
    <gphoto:commentingEnabled>string of true or false</gphoto:commentingEnabled>
    <gphoto:timestamp>unix timestamp * 1000</gphoto:timestamp>
    <georss:where>
        <gml:Point>
            <gml:pos>longitude latitude</gml:pos>
        </gml:Point>
    </georss:where>
    <media:group>
        <media:keywords>keywords</media:keywords>
    </media:group>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo"></category>
</entry>
與建立相簿的 XML 很相似,額外的 media:group > media:keywords 是指於 Picasa 中的關鍵字,可以方便搜尋相簿中的圖片
雖標籤眾多,其實只有 title 是必填項目,指上載的圖片的檔案名
而 Header 則會變成
Content-Type: multipart/related; boundary="END_OF_PART"
Content-Length: <length of xml string>
Authorization: GoogleLogin auth="<auth token>"
MIME-Version: 1.0

Media multipart posting
--END_OF_PART
Content-Type: application/atom+xml

<xml data>
--END_OF_PART
Content-Type: <mime type of data>

<file data in byte>
--END_OF_PART--
當中需要留意
  1. 第一個 Content-Type 需要以 multipart/related; boundary="END_OF_PART"
    boundary 可以是任何分隔字串,Picasa Web API 的範例是使用 END_OF_PART
  2. Content-Length 是整個由 Media multipart posting 開始至 --END_OF_PART-- 結尾的的文字長度
    削減不必要的新行、製表符、空格,可以減少字串長度,以 PHP 為例可以使用
    strlen($data);
  3. <xml data> 是 XML 資料,給予圖片的 metadata
  4. 第三個 Content-Type 是上載的圖片的 Mime 類型,Picasa Web API 只接受 image/jpeg, image/png, image/gif, image/bmp
    <mime type of data> 是讀取圖片的 Mime 類型,以 PHP 為例可以使用
    mime_content_type($image);
    留意 mime_content_type 已經被 PHP 宣告為 deprecated
    有需要可以使用 getimagesize (需要 php5-gd) 或 FileInfo (需要 php5-dev)
  5. <file data in byte> 是直接讀取圖片的位元組資料,以 PHP 為例可以使用
    file_get_contents($image);
    或以 fopen 讀取
  6. 另外需要留意 Media multipart posting, <xml data>, <file data in byte> 之上,必須要有一行空行
  7. 及最後的 END_OF_PART 還有 -- 於最後

若果不需要加入 metadata ,可以很簡單使用以下 Header
Content-Type: <mime type of data>
Content-Length: <filesize>
Authorization: GoogleLogin auth="<auth token>"
Slug: "<uploaded file name>"

<file data in byte>
Header 中的 Slug 相當於 XML 的 title ,由於不能保證檔案名沒有空格,所以用 double quotation mark 包著

以授權證書 的 Header ,並以 HTTP POST 提交資料到
https://picasaweb.google.com/data/feed/api/user/google-account/albumid/album-id
若果成功,便會傳回該圖片的 XML ;若果失敗,便會傳錯誤訊息

更新圖片
與更新圖片相似,不過必須先獲得更新的網址
更新的網址可以在上載圖片時獲得的 XML

以 application/x-www-form-urlencoded 的 Content-Type 及授權證書 的 Header ,並以 HTTP GET 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id
獲取 XML 資料,而 XML 中的包含如下的標籤
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id/an-integer"/>
link 的標籤, rel屬性 為 edit , type 為 application/atom+xml , href 便是更新的網址
更新的網址,與原來的網址前端完全相同,只是最後會有一個整數
獲得更新的網址後,編製與上載圖片相同的 XML
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP PUT 提交資料到更新的網址
若果成功,便會傳回該相簿的 XML ;若果失敗,便會傳錯誤訊息

刪除圖片
與刪除相簿相似,同樣需要先獲得更新的網址,分別是刪除相簿不需要編製 XML ,並以 HTTP DELETE 提交資料到更新的網址
若果成功,不會傳回任何資料:若果失敗,便會傳錯誤訊息

發佈評論
評論的各項屬性是透過 XML 的指定格式所給予,樣式如下
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gphoto="http://schemas.google.com/photos/2007" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
    <content>comment</content>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#comment"></category>
</entry>
content 就是評論
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP POST 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id
若果成功,便會傳回該圖片的 XML ;若果失敗,便會傳錯誤訊息

刪除評論
與刪除相簿相似,不過必須先獲得更新的網址
更新的網址可以在建立相簿時獲得的 XML

以 application/x-www-form-urlencoded 的 Content-Type 及授權證書 的 Header ,並以 HTTP GET 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id/commentid/comment-id
獲取 XML 資料,而 XML 中的包含如下的標籤
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id/commentid/comment-id/an-integer"/>
link 的標籤, rel屬性 為 edit , type 為 application/atom+xml , href 便是更新的網址
更新的網址,與原來的網址前端完全相同,只是最後會有一個整數
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP DELETE 提交資料到更新的網址
若果成功,不會傳回任何資料:若果失敗,便會傳錯誤訊息

發佈標籤
標籤的各項屬性是透過 XML 的指定格式所給予,樣式如下
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gphoto="http://schemas.google.com/photos/2007" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
    <title>tag</title>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#tag"></category>
</entry>
tag 就是標籤
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP POST 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id
若果成功,便會傳回該圖片的 XML ;若果失敗,便會傳錯誤訊息

刪除標籤
與刪除相簿相似,不過必須先獲得更新的網址
更新的網址可以在建立相簿時獲得的 XML

以 application/x-www-form-urlencoded 的 Content-Type 及授權證書 的 Header ,並以 HTTP GET 提交資料到
https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id/tag/tag-text
獲取 XML 資料,而 XML 中的包含如下的標籤
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/google-account/albumid/album-id/photoid/photo-id/tag/tag-text/an-integer"/>
link 的標籤, rel屬性 為 edit , type 為 application/atom+xml , href 便是更新的網址
更新的網址,與原來的網址前端完全相同,只是最後會有一個整數
以 application/atom+xml 的 Content-Type 及授權證書 的 Header ,並以 HTTP DELETE 提交資料到更新的網址
若果成功,不會傳回任何資料:若果失敗,便會傳錯誤訊息

利用這種方法上載有一個很大的好處
可以不需要下載相關檔案至本機磁碟中,可以直接將網絡串流上載至相簿

閣下可以參巧以下程序碼
或到以下連結 https://bitbucket.org/hkgoldenmra/php-picasa
或利用 git 下載專案
git clone https://hkgoldenmra@bitbucket.org/hkgoldenmra/php-picasa.git
下載專案後可以利用
phpdoc -f Picasa.php,PicasaAlbum.php,PicasaPhoto.php,PicasaComment.php,PicasaTag.php -t .
製作 PHP Document

2 則留言 :

  1. 你好 ,
    我想使用JAVA 以 GOOGLE ACCOUNT 帳號登入
    請問該怎麼下手 ...?

    回覆刪除
    回覆
    1. 在我的 bitbucket.org 帳戶下有一個未完成的 project 叫 Google API for Java
      雖然未完成,但 Google Login 及 Picasa API 已經完成

      刪除