在試過ASP.NET整合Live ID登入後,只取回使用者姓名跟MSN大頭照感覺有點像辦家家酒不夠刺激,Live SDK應該拿來搞點實用的功能才過癮 -- 例如: 瀏覽SkyDrive文件與檔案。

Live Connect API提供了SkyDrive相關的REST API,只要取得Access Token,便可透過API瀏覽、讀取、變更、刪除SkyDrive下的文件、相片、影音等檔案,MSDN上有兩篇不錯的教學文章(入門概念檔案存取API)可當成動手前的參考。

我的構想是在使用者以Live ID登入時,增加SkyDrive讀取的範圍請求,經同意後,程式先展開使用者SkyDrive的根目錄,列出資料夾與檔案;點選資料夾項目則可展開該資料夾,列出其下檔案與子資料夾;若為檔案,則點選可檢視或下載其內容。(瀏覽器依附檔名自行決定檢視或下載,例如: gif, png, jpg, txt, htm可直接開啟,zip, rar則是下載另存) 簡單來說,就是實現一個只能用來檢視的超陽春SkyDrive檔案總管!

整理需用到的SkyDrive REST API有:

  1. httqs://apis.live.net/v5.0/me/skydrive?access_token=ACCESS_TOKEN
    取得使用者SkyDrive主資料夾的folderId
  2. httqs://apis.live.net/v5.0/folderId/files?access_token=ACCESS_TOKEN
    列出指定資料夾下的資料夾及檔案項目清單
  3. httqs://apis.live.net/v5.0/fileId/content?access_token=ACCESS_TOKEN
    取得檔案屬性,其中location屬性會指向一個可直接下載檔案的URL(格式如: httq://storage.live.com/s1pZfcNs…很長,省略...SotQ/Seattle.JPG),連向它就可直接下載檔案內容。值得注意的是,前述包含冗長編碼的URL是所謂的Preauthenticated URL,意思是只要得知此連結,將不再做任何權限檢查,任何人都可用它直接下載檔案內容,在開發應用時宜留意此特性,做適當管控及避免外流。

是的,要做到SkyDrive檔案檢視功能,就只需要上述三個API即可搞定。

至於JavaScript操作的部分,我結合了jQuery BBQ外掛的AJAX Hisotry功能,在檢視不同資料夾時指定不同的state,以做到按瀏覽器回上頁也可回上層目錄的效果。除此之外,就是蠻單純的jQuery技巧,補充說明我寫在註解中,程式碼如下:

<!DOCTYPE html>
 
<html>
<head>
    <title>SkyDrive Test</title>
    <script type='text/javascript' 
     src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js'></script>   
    <script src="jquery.ba-bbq.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            //取得Access Token,未成功登入時傳回null
            function getAccessToken() {
                var session = WL.getSession();
                if (session != null && !session.error)
                    return session.access_token;
                return null;
            }
            //AJAX History支援,state改變時顥示不同資料夾內容
            window.lastId = null;
            $(window).bind("hashchange", function (e) {
                var f = e.getState("f");
                if (f) listFiles(f);
            });
            var goUpper = "回上層";
            var frmViewer = document.getElementById("frmViewer");
            //列出檔案
            function listFiles(folderId) {
                if (!getAccessToken()) return;
                //REST folderId/files可列出資料夾下的檔案清單
                WL.api({
                    path: folderId + "/files"
                }, function (res) {
                    var $ul = $("<ul class='f-item' />");
                    //folderId若以"."分成三段,代表非根目錄
                    //增加一個"回上層"連結
                    if (folderId.split('.').length > 2)
                        $ul.append(
                        "<li><img src='images/parent.png' class='icon' />" +
                            goUpper + "</li>");
                    //每個資料夾或檔案對應一個li
                    for (var i = 0; i < res.data.length; i++) {
                        var item = res.data[i];
                        var $li = $("<li />", {
                            "data-id": item.id,
                            "data-count": item.count,
                            "data-name": item.name,
                            "data-parent-id": item.parent_id,
                            "data-link": item.link
                        });
                        //id若為folder****,表示為資料夾
                        var isFolder = item.id.indexOf("folder") == 0;
                        $li.html(
                            "<img class='icon' src='images/" +
                        //資料夾與檔案Icon不同
                            (isFolder ? "folder" : "save") + ".png' />" +
                            "<span class='item-name'></span>")
                        .find(".item-name").text(
                             item.name +
                        //資料夾時,加顯示其下檔案數量
                            (isFolder ? "(" + item.count + ")" : "")
                        );
                        $ul.append($li);
                    }
                    $("#dFolder").empty().append($ul);
                    frmViewer.src = "";
                });
            }
            //下載檔案內容
            function downloadFile(id, name) {
                //REST fileId/content可取得下載檔案內容用的連結
                WL.api({
                    path: id + "/content"
                }, function (res) {
                    if (res.error)
                        alert(res.error.message);
                    else {
                        //res.location指向可直接下載檔案二進位內容的連結
                        //指定成為IFrame.src,
                        //可直接顯示或另存檔案(由瀏覽器依附檔名決定)
                        frmViewer.src = res.location;
                    }
                });
            }
            //點選檔案項目觸發事件
            $("#dFolder").on("click", "li", function () {
                var $li = $(this);
                //若為回上層,則透過記憶中的前一層目錄回去
                if ($li.text() == goUpper) {
                    $.bbq.pushState({ f: lastId });
                    return;
                }
                var id = $li.data("id");
                if (id.indexOf("file") == 0)
                    downloadFile(id);
                else {
                    //保留目前的folderId供稍後回上層用
                    lastId = $.bbq.getState("f");
                    $.bbq.pushState({ f: id });
                }
            });
            $("#bList").click(function () {
                if (!getAccessToken()) return;
            });
        });
    </script>
    <style>
        table { width: 400px; }
        td { border: 1px solid gray; }
        div { margin: 2px; }
        #dFolder li { color: white; text-decoration: underline; cursor: pointer; }
        .bw-style { background-color: Black; color: White; }
        .bw-style .icon { width: 16px; height: 16px; vertical-align: middle; }
    </style>
</head>
<body>
<h1>SkyDrive Test</h1>
<table>
<tr><td style="width: 120px; vertical-align: top;">
<div id="signin"></div>
<div id="meName" class="Name"></div>
<div id="meImg"></div>
</td><td style="vertical-align: top;" class='bw-style'>
<div id="dFolder">
</div>
</td></tr>
<tr><td colspan="2">
<iframe style="width: 100%; height: 400px;" id="frmViewer"></iframe>
</td></tr>
</table>
<script src="wl.debug.js" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        WL.Event.subscribe("auth.login", function () {
            var session = WL.getSession();
            if (session.error)
                alert("Error:" + session.error);
            else {
                var token = session != null ? session.access_token : null;
                if (token != null) {
                    var url = "https://apis.live.net/v5.0/me/picture?access_token=" 
                    + escape(token);
                    $("#meImg").html("<img src='" + url + "' />");
                    WL.api({ path: "me", method: "get" }, function (response) {
                        if (!response.error) {
                            $("#meName").html(response.name);
                        }
                    });
                    //取得SkyDrive Id,透過AJAX History方式觸發瀏覽
                    $.bbq.pushState({ f: "" });
                    WL.api({
                        path: "me/skydrive"
                    }, function (prop) {
                        $.bbq.pushState({ f: prop.id });
                    });
 
                }
            }
        });
        WL.Event.subscribe("auth.logout", function () {
            $("#meImg,#meName").html("");
        });
        WL.init({
            client_id: "0000000048076EE5",
            redirect_uri: "http://www.darkthread.net/LiveSDK/callback.aspx",
            scope: ["wl.signin", "wl.basic", "wl.offline_access", "wl.skydrive" ],
            response_type: "code"
        });
        WL.ui({
            name: "signin",
            element: "signin"
        });
    });
</script>
</body>
</html>

程式執行起來的樣子如下圖,右方是檔案清單,下方放了一個IFrame。當點選資料夾(前方圖示為資料夾)時,清單會變成該資料夾展開後的項目;當點選檔案清單中檔案項目(前方Icon為小磁片),IFrame.src將指向該檔案的下載網址,若是圖檔可直接顯示,其他如ZIP檔等,則可另存新檔。(但有個小缺點,另存新檔時,SkyDrive伺服器傳回內容未提供檔名,預設URL中又臭又長像亂數的編碼預設會被當成檔名,故需要人工另外命名再存檔,此點可透過另外寫個Download Proxy ASPX來解決,但為避免失焦,並未納入範例中)

還有一點值得注意,相較於前次整合Live ID登入範例,這回我們還增加了wl.skydrive讀取範圍(Scope,可參見前文),因此同意頁面(Consent Page)可看到SkyDrive的提示(下圖紅框)。

另外,要弄出上圖中文版登入及同意網頁有個小訣竅: 依文件的說法,我們可由http://js.live.net/v5.0/zh-tw/wl.js取得正體中文版的JavaScript Library,但目前這個版本的最下方仍設定了wl_app._locale = "en";,其中的訊息也都還是英文。因此,呼叫Live帳號登入視窗時仍會顯示英文介面。暫時解法是將wl.js另存一份,並修改為wl_app._locale="zh-tw";,網頁改用此修改版就可以獲得中文版登入及同意畫面囉! 但有個缺點,未來若wl.js改版,修改版wl.js不會自動更新,我想不久後,等微軟RD真的落實wl.js多國語系化,就不用煩惱了。

程式執行後,我們點開ForApps資料夾,可以看到其下的資料夾結構,共有兩個圖檔,圖檔也可以點選檢視其內容:

跟SkyDrive網頁的瀏覽結果比對,我們查到的結果與ForApps目錄下的檔案項目與內容相符,一個陽春版SkyDrive檔案檢視工具就算大功告成囉!!


Comments

Be the first to post a comment

Post a comment