C
C
Facebook Download all Photos to Local Files
See more Facebook Examples
Demonstrates how to download all of one's Facebook photos to a local filesystem directory. This sample code keeps a local cache to avoid re-downloading the same photos twice. The program can be run again after a time, and it will download only photos that haven't yet been downloaded.Chilkat C Downloads
#include <C_CkCache.h>
#include <C_CkOAuth2.h>
#include <C_CkRest.h>
#include <C_CkJsonObject.h>
#include <C_CkStringArray.h>
#include <C_CkStringBuilder.h>
#include <C_CkHttp.h>
#include <C_CkByteData.h>
#include <C_CkFileAccess.h>
void ChilkatSample(void)
{
BOOL success;
HCkCache fbCache;
HCkOAuth2 oauth2;
HCkRest rest;
const char *responseJson;
HCkJsonObject photoJson;
HCkStringArray saPhotoUrls;
HCkStringBuilder sbPhotoIdPath;
HCkJsonObject json;
int i;
const char *photoId;
const char *imageUrl;
const char *afterCursor;
int numItems;
const char *photoJsonStr;
HCkJsonObject imgUrlJson;
HCkHttp http;
int numUrls;
HCkJsonObject urlJson;
HCkByteData imageBytes;
HCkFileAccess fac;
HCkStringBuilder sbImageUrl;
const char *extension;
HCkStringBuilder sbLocalFilePath;
success = FALSE;
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// This example will use a local disk cache to avoid re-fetching the same
// photo id after it's been fetched once.
fbCache = CkCache_Create();
// The cache will use 1 level of 256 sub-directories.
CkCache_putLevel(fbCache,1);
// Use a directory path that makes sense on your operating system..
CkCache_AddRoot(fbCache,"C:/fbCache");
// This example assumes a previously obtained an access token
oauth2 = CkOAuth2_Create();
CkOAuth2_putAccessToken(oauth2,"FACEBOOK-ACCESS-TOKEN");
rest = CkRest_Create();
// Connect to Facebook.
success = CkRest_Connect(rest,"graph.facebook.com",443,TRUE,TRUE);
if (success != TRUE) {
printf("%s\n",CkRest_lastErrorText(rest));
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
return;
}
// Provide the authentication credentials (i.e. the access key)
CkRest_SetAuthOAuth2(rest,oauth2);
// There are two choices:
// We can choose to download the photos the person is tagged in or has uploaded
// by setting type to "tagged" or "uploaded".
CkRest_AddQueryParam(rest,"type","uploaded");
// To download all photos, we begin with an outer loop that iterates over
// the list of photo nodes in pages. Each page returned contains a list of
// photo node ids. Each photo node id must be retrieved to get the download URL(s)
// of the actual image.
// I don't know the max limit for the number of records that can be downloaded at once.
CkRest_AddQueryParam(rest,"limit","100");
// Get the 1st page of photos ids.
// See https://developers.facebook.com/docs/graph-api/reference/user/photos/ for more information.
responseJson = CkRest_fullRequestNoBody(rest,"GET","/v2.7/me/photos");
if (CkRest_getLastMethodSuccess(rest) != TRUE) {
printf("%s\n",CkRest_lastErrorText(rest));
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
return;
}
photoJson = CkJsonObject_Create();
saPhotoUrls = CkStringArray_Create();
sbPhotoIdPath = CkStringBuilder_Create();
json = CkJsonObject_Create();
CkJsonObject_putEmitCompact(json,FALSE);
CkJsonObject_Load(json,responseJson);
// Get the "after" cursor.
afterCursor = CkJsonObject_stringOf(json,"paging.cursors.after");
while (CkJsonObject_getLastMethodSuccess(json) == TRUE) {
printf("-------------------\n");
printf("afterCursor = %s\n",afterCursor);
// For each photo id in this page...
i = 0;
numItems = CkJsonObject_SizeOfArray(json,"data");
while (i < numItems) {
CkJsonObject_putI(json,i);
photoId = CkJsonObject_stringOf(json,"data[i].id");
printf("photoId = %s\n",photoId);
// We need to fetch the JSON for this photo. Check to see if it's in the local disk cache,
// and if not, then get it from Facebook.
photoJsonStr = CkCache_fetchText(fbCache,photoId);
if (CkCache_getLastMethodSuccess(fbCache) == FALSE) {
// It's not locally available, so get it from Facebook..
CkStringBuilder_Clear(sbPhotoIdPath);
CkStringBuilder_Append(sbPhotoIdPath,"/v2.7/");
CkStringBuilder_Append(sbPhotoIdPath,photoId);
CkRest_ClearAllQueryParams(rest);
CkRest_AddQueryParam(rest,"fields","id,album,images");
printf("Fetching photo node from Facebook...\n");
// This REST request will continue using the existing connection.
// If the connection was closed, it will automatically reconnect to send the request.
photoJsonStr = CkRest_fullRequestNoBody(rest,"GET",CkStringBuilder_getAsString(sbPhotoIdPath));
if (CkRest_getLastMethodSuccess(rest) != TRUE) {
printf("%s\n",CkRest_lastErrorText(rest));
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
CkJsonObject_Dispose(photoJson);
CkStringArray_Dispose(saPhotoUrls);
CkStringBuilder_Dispose(sbPhotoIdPath);
CkJsonObject_Dispose(json);
return;
}
// Add the photo JSON to the local cache.
CkCache_SaveTextNoExpire(fbCache,photoId,"",photoJsonStr);
}
// Parse the photo JSON and add the main photo download URL to saPhotoUrls
// There may be multiple URLs in the images array, but the 1st one is the largest and main photo URL.
// The others are smaller sizes of the same photo.
CkJsonObject_Load(photoJson,photoJsonStr);
imageUrl = CkJsonObject_stringOf(photoJson,"images[0].source");
if (CkJsonObject_getLastMethodSuccess(photoJson) == TRUE) {
// Actually, we'll add a small JSON document that contains both the image ID and the URL.
imgUrlJson = CkJsonObject_Create();
CkJsonObject_AppendString(imgUrlJson,"id",photoId);
CkJsonObject_AppendString(imgUrlJson,"url",imageUrl);
CkStringArray_Append(saPhotoUrls,CkJsonObject_emit(imgUrlJson));
printf("imageUrl = %s\n",imageUrl);
}
i = i + 1;
}
// Prepare for getting the next page of photos ids.
// We can continue using the same REST object.
// If already connected, we'll continue using the existing connection.
// Otherwise, a new connection will automatically be made if needed.
CkRest_ClearAllQueryParams(rest);
CkRest_AddQueryParam(rest,"type","uploaded");
CkRest_AddQueryParam(rest,"limit","20");
CkRest_AddQueryParam(rest,"after",afterCursor);
// Get the next page of photo ids.
responseJson = CkRest_fullRequestNoBody(rest,"GET","/v2.7/me/photos");
if (CkRest_getLastMethodSuccess(rest) != TRUE) {
printf("%s\n",CkRest_lastErrorText(rest));
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
CkJsonObject_Dispose(photoJson);
CkStringArray_Dispose(saPhotoUrls);
CkStringBuilder_Dispose(sbPhotoIdPath);
CkJsonObject_Dispose(json);
CkJsonObject_Dispose(imgUrlJson);
return;
}
CkJsonObject_Load(json,responseJson);
afterCursor = CkJsonObject_stringOf(json,"paging.cursors.after");
}
printf("No more pages of photos.\n");
// Now iterate over the photo URLs and download each to a file.
// We can use Chilkat HTTP. No Facebook authorization (access token) is required to download
// the photo once the URL is known.
http = CkHttp_Create();
// We'll cache the image data so that if run again, we don't re-download the same image again.
numUrls = CkStringArray_getCount(saPhotoUrls);
i = 0;
urlJson = CkJsonObject_Create();
imageBytes = CkByteData_Create();
fac = CkFileAccess_Create();
while (i < numUrls) {
CkJsonObject_Load(urlJson,CkStringArray_getString(saPhotoUrls,i));
photoId = CkJsonObject_stringOf(urlJson,"id");
imageUrl = CkJsonObject_stringOf(urlJson,"url");
// Check the local cache for the image data.
// Only download and save if not already cached.
success = CkCache_FetchFromCache(fbCache,imageUrl,imageBytes);
if (CkCache_getLastMethodSuccess(fbCache) == FALSE) {
// This photo needs to be downloaded.
sbImageUrl = CkStringBuilder_Create();
CkStringBuilder_Append(sbImageUrl,imageUrl);
// Let's form a filename..
extension = ".jpg";
if (CkStringBuilder_Contains(sbImageUrl,".gif",FALSE) == TRUE) {
extension = ".gif";
}
if (CkStringBuilder_Contains(sbImageUrl,".png",FALSE) == TRUE) {
extension = ".png";
}
if (CkStringBuilder_Contains(sbImageUrl,".tiff",FALSE) == TRUE) {
extension = ".tiff";
}
if (CkStringBuilder_Contains(sbImageUrl,".bmp",FALSE) == TRUE) {
extension = ".bmp";
}
sbLocalFilePath = CkStringBuilder_Create();
CkStringBuilder_Append(sbLocalFilePath,"C:/Photos/facebook/uploaded/");
CkStringBuilder_Append(sbLocalFilePath,photoId);
CkStringBuilder_Append(sbLocalFilePath,extension);
success = CkHttp_QuickGet(http,imageUrl,imageBytes);
if (CkHttp_getLastMethodSuccess(http) != TRUE) {
printf("%s\n",CkHttp_lastErrorText(http));
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
CkJsonObject_Dispose(photoJson);
CkStringArray_Dispose(saPhotoUrls);
CkStringBuilder_Dispose(sbPhotoIdPath);
CkJsonObject_Dispose(json);
CkJsonObject_Dispose(imgUrlJson);
CkHttp_Dispose(http);
CkJsonObject_Dispose(urlJson);
CkByteData_Dispose(imageBytes);
CkFileAccess_Dispose(fac);
CkStringBuilder_Dispose(sbImageUrl);
CkStringBuilder_Dispose(sbLocalFilePath);
return;
}
// We've downloaded the photo image bytes into memory.
// Save it to the cache AND save it to the output file.
CkCache_SaveToCacheNoExpire(fbCache,imageUrl,"",imageBytes);
CkFileAccess_WriteEntireFile(fac,CkStringBuilder_getAsString(sbLocalFilePath),imageBytes);
printf("Downloaded to %s\n",CkStringBuilder_getAsString(sbLocalFilePath));
}
i = i + 1;
}
printf("Finished downloading all Facebook photos!\n");
CkCache_Dispose(fbCache);
CkOAuth2_Dispose(oauth2);
CkRest_Dispose(rest);
CkJsonObject_Dispose(photoJson);
CkStringArray_Dispose(saPhotoUrls);
CkStringBuilder_Dispose(sbPhotoIdPath);
CkJsonObject_Dispose(json);
CkJsonObject_Dispose(imgUrlJson);
CkHttp_Dispose(http);
CkJsonObject_Dispose(urlJson);
CkByteData_Dispose(imageBytes);
CkFileAccess_Dispose(fac);
CkStringBuilder_Dispose(sbImageUrl);
CkStringBuilder_Dispose(sbLocalFilePath);
}