最近看到一個有趣的 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 才能做事,這邊有說明。
資料查到了,那麼大致流程是這樣:
- 取得授權(publish_stream 與 manage_pages)
- 使用指定粉絲專頁的 Access Token 將某個圖檔上傳至粉絲專頁相簿中
- 將之設為封面照片
取得粉絲專頁的 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)。
參考資料:
- https://developers.facebook.com/docs/reference/api/page/
- http://stackoverflow.com/questions/9685511/uploading-photos-to-facebook-album-via-facebook-c-sharp-sdk
2012/12/12 更新:
有些朋友在問,那能不能自動更換個人的封面照片呢?
答案是:自動不行,半自動可以!
流程是:先將圖片生成至相簿中(這部分不在此贅述),取得照片的 id→然後連結下面網址,讓使用者自己按確認,就更換完成啦。
https://www.facebook.com/profile.php?preview_cover={這邊放照片的 id}
要換大頭照也是一樣喔,半自動!
一樣生成照片之後,取得照片 id,連結下面網址,讓使用者自己確認。
https://www.facebook.com/photo.php?fbid={照片 id}&makeprofile=1
請問文中提到的access_token是app access_token還是user access_token呢?
是粉絲專頁的 page access token 喔