[Facebook][C#] 透過 Graph API 上傳照片至粉絲專頁(Page)並將之設為封面照片(Cover)

Standard

最近看到一個有趣的 Facebook 網路行銷案例,是 Nescafe 的 Facebook 粉絲專頁活動。它們的封面照片(Cover)一開始是一張滿是咖啡豆的圖片,隨著粉絲數的增加,封面照片的咖啡豆會越來越少,最後會露出它們的新產品。
影片在這:

從技術端來看,就對「如何自動更換粉絲專頁的封面照片」這件事感到好奇了。當然粉絲數增加不快的話,用手動換也是可行的,但我想應該還能串上其他的應用吧!讓換粉絲專頁的封面照片是即時又有趣的。

總之來看如何實作囉。

這邊我用 ASP.NET (C#) ,搭配 Facebook C# SDK 6.1.1-beta 作為範例。
也許之後應用可以做成單機執行檔服務,讓它每隔一段時間自己跑應該也滿有趣的。

其實不難,Facebook 技術文件中就有提到如何設定粉絲專頁的封面:https://developers.facebook.com/docs/reference/api/page/Setting a Cover Photo 這個區塊。
一樣可以透過 Graph API 達成,但比較特別的是還要加上粉絲專頁的 Access Token 才能做事,這邊有說明


資料查到了,那麼大致流程是這樣:

  1. 取得授權(publish_stream 與 manage_pages)
  2. 使用指定粉絲專頁的 Access Token 將某個圖檔上傳至粉絲專頁相簿中
  3. 將之設為封面照片

取得粉絲專頁的 code 如下:(當然你必須是粉絲專頁的管理者)

FacebookClient fb = new FacebookClient("使用者授權取得的 Access Token");
IDictionary<string, object> dic = (IDictionary<string, object>)fb.Get("/me/accounts");

// 列出所有我管理的粉絲專頁
IList<object> dicy = (IList<object>)dic["data"];
IDictionary<string, object> page = null;

for (int i = 0; i <= dicy.Count - 1; i++)
{
    page = (IDictionary<string, object>)dicy[i];

    // 如果是這次要上傳的粉絲專頁 ID
    if (page["id"].ToString() == "你指定的粉絲專頁 ID")
    {
        // 取得粉絲專頁的 access_token,才能針對粉絲專頁做 graph api 動作
        fb.AccessToken = page["access_token"].ToString();
        Session["PageAccessToken"] = page["access_token"].ToString();
        break;
    }
}

上傳照片至粉絲專頁的 code 如下:

FacebookMediaObject media = new FacebookMediaObject();
media.ContentType = "image/jpeg";
media.FileName = ImagePath;

byte[] filebytes = System.IO.File.ReadAllBytes(ImagePath);
media.SetValue(filebytes);
Dictionary<string, object> upload = new Dictionary<string, object>();
upload.Add("name", "照片名稱");
upload.Add("message", "照片描述");
upload.Add("no_story", "1"); // 是否要發佈訊息
upload.Add("access_token", "粉絲專頁的 Token");
upload.Add("@file.jpg", media);

fbApp.Post(_pageID + "/photos", upload); // fbApp 是 Facebook C# SDK 的 FacebookClient

設為粉絲專頁封面照片的 code 很短,就這樣:

dynamic param = new ExpandoObject();
param = new {
    access_token = Session["PageAccessToken"].ToString(),
    cover = PhotoID,
    no_feed_story = true
};

fbApp.Post(_pageID, param); // fbApp 是 Facebook C# SDK 的 FacebookClient

最後完整的 code 就是這樣囉:

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Web.UI.WebControls;
using Facebook;

public partial class UploadPhotoToPage : System.Web.UI.Page
{
    private string _pageID = "";
    private string _fileName = "";

    private string _appID = "應用程式的 APP ID";
    private string _appSecret = "應用程式的 APP SECRET";
    private string _scope = "SCOPE,至少須包含 publish_stream 跟 manage_pages";
    private string _redirect_url = "轉頁的網址,可以設為同一頁";

    protected void Page_Load(object sender, EventArgs e)
    {
        // 若已授權,querystring 應當取得 code,接下來要換回 access_token 再做事
        if (Request.Params.AllKeys.Contains("code"))
        {
            try
            {
                var fb = new FacebookClient();

                #region 取得 Access Token
                dynamic result = fb.Get("oauth/access_token", new
                {
                    client_id = _appID,
                    client_secret = _appSecret,
                    redirect_uri = _redirect_url,
                    code = Request["code"]
                });

                Session["accessToken"] = result.access_token;
                #endregion

                #region 檢查 Scope 權限

                fb = new FacebookClient(Session["accessToken"].ToString());

                var query = string.Format("SELECT publish_stream, manage_pages FROM permissions WHERE uid = me()");
                dynamic parameters = new ExpandoObject();
                parameters.q = query;
                dynamic results = (IDictionary<string, object>)fb.Get("/fql", parameters);

                foreach (dynamic item in results.data)
                {
                    Dictionary<string, object>.KeyCollection keys = item.Keys;
                    if (!keys.Contains<string>("publish_stream") || !keys.Contains<string>("manage_pages"))
                    {
                        Response.Write("請允許 publish_stream 跟 manage_pages!");
                        Response.End();
                        return;
                    }
                }
                #endregion

                #region 列出所有可管理的專頁

                try
                {
                    IDictionary<string, object> dic = (IDictionary<string, object>)fb.Get("/me/accounts");

                    // 列出所有我管理的粉絲專頁
                    IList<object> dicy = (IList<object>)dic["data"];
                    IDictionary<string, object> page = null;

                    ddlPageID.Items.Clear();
                    for (int i = 0; i <= dicy.Count - 1; i++)
                    {
                        page = (IDictionary<string, object>)dicy[i];
                        ddlPageID.Items.Add(new ListItem(page["name"].ToString(), page["id"].ToString()));
                    }
                }
                catch (Exception ex)
                {

                }
                #endregion

                PanelUpload.Visible = true;

            }
            catch(Exception ex)
            {
                Response.Write("發生例外" + ex.Message);
                Response.End();
                return;
            }
        }
    }

    protected void btnUpload_Click(object sender, EventArgs e)
    {
        // 選擇的粉絲專頁
        _pageID = ddlPageID.SelectedValue;
        // 照片檔名
        _fileName = tbFileName.Text;

        Facebook.FacebookClient fb = new Facebook.FacebookClient(Session["accessToken"].ToString());
        IDictionary<string, object> dic = (IDictionary<string, object>)fb.Get("/me/accounts");

        // 列出所有我管理的粉絲專頁
        IList<object> dicy = (IList<object>)dic["data"];
        IDictionary<string, object> page = null;

        for (int i = 0; i <= dicy.Count - 1; i++)
        {
            page = (IDictionary<string, object>)dicy[i];

            // 如果是這次要上傳的粉絲專頁 ID
            if (page["id"].ToString() == _pageID)
            {
                // 取得粉絲專頁的 access_token,才能針對粉絲專頁做 graph api 動作
                fb.AccessToken = page["access_token"].ToString();
                Session["PageAccessToken"] = page["access_token"].ToString();
                break;
            }
        }

        if (Session["PageAccessToken"] == null || string.IsNullOrEmpty(Session["PageAccessToken"].ToString()))
        {
            Response.Write("無法管理此粉絲專頁: " + _pageID);
            Response.End();
        }

        // 上傳照片
        JsonObject result = UploadPhoto(fb, Server.MapPath("~/img/" + _fileName));

        // 設為封面
        SetCoverPhoto(fb, result["id"].ToString());

        string txt = string.Format("<p>上傳成功: <a href='https://www.facebook.com/photo.php?fbid={0}' target='_blank'>點擊這裡查看照片</a>,並<a href='https://www.facebook.com/{1}' target='_blank'>看看</a>是否已經設為封面了", result["id"].ToString(), _pageID);
        Response.Write(txt);
    }

    protected void btnFBConnect_Click(object sender, EventArgs e)
    {
        Response.Redirect(GetFacebookLoginUrl().AbsoluteUri);
    }

    /// <summary>
    /// 上傳照片方法
    /// </summary>
    /// <param name="fbApp"></param>
    /// <param name="ImagePath"></param>
    /// <returns></returns>
    private JsonObject UploadPhoto(Facebook.FacebookClient fbApp, string ImagePath)
    {
        Facebook.FacebookMediaObject media = new Facebook.FacebookMediaObject();
        media.ContentType = "image/jpeg";
        media.FileName = ImagePath;

        byte[] filebytes = System.IO.File.ReadAllBytes(ImagePath);
        media.SetValue(filebytes);
        Dictionary<string, object> upload = new Dictionary<string, object>();
        upload.Add("name", "照片名稱");
        upload.Add("message", "照片描述");
        upload.Add("no_story", "1"); // 是否要發佈訊息
        upload.Add("access_token", Session["PageAccessToken"]);
        upload.Add("@file.jpg", media);

        return fbApp.Post(_pageID + "/photos", upload) as JsonObject;
    }

    /// <summary>
    /// 設為封面照片
    /// </summary>
    /// <param name="fbApp"></param>
    /// <param name="PhotoID"></param>
    private void SetCoverPhoto(Facebook.FacebookClient fbApp, string PhotoID)
    {
        dynamic param = new ExpandoObject();
        param = new {
            access_token = Session["PageAccessToken"].ToString(),
            cover = PhotoID,
            no_feed_story = true
        };

        fbApp.Post(_pageID, param);
    }

    /// <summary>
    /// 取得授權登入網址
    /// </summary>
    /// <returns></returns>
    private System.Uri GetFacebookLoginUrl()
    {
        var fb = new FacebookClient();
        dynamic result = fb.GetLoginUrl(new
        {
            client_id = _appID,
            client_secret = _appSecret,
            grant_type = "client_credentials",
            scope = _scope,
            redirect_uri = _redirect_url
        });

        return result;
    }
}

WebForm 上控制項的配置如下:

檔名那邊… 我偷懶,就是指定 img/ 資料夾裡面的圖檔檔名,有興趣的人自己再改寫吧 XD

最後是範例原始檔下載,點這邊(ASP.NET C# 4.0)。

參考資料:


 

2012/12/12 更新:

有些朋友在問,那能不能自動更換個人的封面照片呢?

答案是:自動不行,半自動可以!

流程是:先將圖片生成至相簿中(這部分不在此贅述),取得照片的 id→然後連結下面網址,讓使用者自己按確認,就更換完成啦。

https://www.facebook.com/profile.php?preview_cover={這邊放照片的 id}

要換大頭照也是一樣喔,半自動!

一樣生成照片之後,取得照片 id,連結下面網址,讓使用者自己確認。

https://www.facebook.com/photo.php?fbid={照片 id}&makeprofile=1

3 thoughts on “[Facebook][C#] 透過 Graph API 上傳照片至粉絲專頁(Page)並將之設為封面照片(Cover)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *