Xbase++
Xbase++
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 Xbase++ Downloads
LOCAL nSuccess
LOCAL oFbCache
LOCAL oOauth2
LOCAL oRest
LOCAL cResponseJson
LOCAL oPhotoJson
LOCAL oSaPhotoUrls
LOCAL oSbPhotoIdPath
LOCAL oJson
LOCAL i
LOCAL cPhotoId
LOCAL cImageUrl
LOCAL cAfterCursor
LOCAL nNumItems
LOCAL cPhotoJsonStr
LOCAL oImgUrlJson
LOCAL oHttp
LOCAL nNumUrls
LOCAL oUrlJson
LOCAL oFac
LOCAL oSbImageUrl
LOCAL cExtension
LOCAL oSbLocalFilePath
nSuccess := 0
// 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.
oFbCache := CreateObject("Chilkat.Cache")
// The cache will use 1 level of 256 sub-directories.
oFbCache:Level := 1
// Use a directory path that makes sense on your operating system..
oFbCache:AddRoot("C:/fbCache")
// This example assumes a previously obtained an access token
oOauth2 := CreateObject("Chilkat.OAuth2")
oOauth2:AccessToken := "FACEBOOK-ACCESS-TOKEN"
oRest := CreateObject("Chilkat.Rest")
// Connect to Facebook.
nSuccess := oRest:Connect("graph.facebook.com", 443, 1, 1)
IF (nSuccess != 1)
? oRest:LastErrorText
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
RETURN
ENDIF
// Provide the authentication credentials (i.e. the access key)
oRest:SetAuthOAuth2(oOauth2)
// 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".
oRest:AddQueryParam("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.
oRest:AddQueryParam("limit", "100")
// Get the 1st page of photos ids.
// See https://developers.facebook.com/docs/graph-api/reference/user/photos/ for more information.
cResponseJson := oRest:FullRequestNoBody("GET", "/v2.7/me/photos")
IF (oRest:LastMethodSuccess != 1)
? oRest:LastErrorText
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
RETURN
ENDIF
oPhotoJson := CreateObject("Chilkat.JsonObject")
oSaPhotoUrls := CreateObject("Chilkat.StringArray")
oSbPhotoIdPath := CreateObject("Chilkat.StringBuilder")
oJson := CreateObject("Chilkat.JsonObject")
oJson:EmitCompact := 0
oJson:Load(cResponseJson)
// Get the "after" cursor.
cAfterCursor := oJson:StringOf("paging.cursors.after")
DO WHILE oJson:LastMethodSuccess == 1
? "-------------------"
? "afterCursor = " + cAfterCursor
// For each photo id in this page...
i := 0
nNumItems := oJson:SizeOfArray("data")
DO WHILE i < nNumItems
oJson:I := i
cPhotoId := oJson:StringOf("data[i].id")
? "photoId = " + cPhotoId
// 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.
cPhotoJsonStr := oFbCache:FetchText(cPhotoId)
IF (oFbCache:LastMethodSuccess == 0)
// It's not locally available, so get it from Facebook..
oSbPhotoIdPath:Clear()
oSbPhotoIdPath:Append("/v2.7/")
oSbPhotoIdPath:Append(cPhotoId)
oRest:ClearAllQueryParams()
oRest:AddQueryParam("fields", "id,album,images")
? "Fetching photo node from Facebook..."
// This REST request will continue using the existing connection.
// If the connection was closed, it will automatically reconnect to send the request.
cPhotoJsonStr := oRest:FullRequestNoBody("GET", oSbPhotoIdPath:GetAsString())
IF (oRest:LastMethodSuccess != 1)
? oRest:LastErrorText
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
oPhotoJson:destroy()
oSaPhotoUrls:destroy()
oSbPhotoIdPath:destroy()
oJson:destroy()
RETURN
ENDIF
// Add the photo JSON to the local cache.
oFbCache:SaveTextNoExpire(cPhotoId, "", cPhotoJsonStr)
ENDIF
// 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.
oPhotoJson:Load(cPhotoJsonStr)
cImageUrl := oPhotoJson:StringOf("images[0].source")
IF (oPhotoJson:LastMethodSuccess == 1)
// Actually, we'll add a small JSON document that contains both the image ID and the URL.
oImgUrlJson := CreateObject("Chilkat.JsonObject")
oImgUrlJson:AppendString("id", cPhotoId)
oImgUrlJson:AppendString("url", cImageUrl)
oSaPhotoUrls:Append(oImgUrlJson:Emit())
? "imageUrl = " + cImageUrl
ENDIF
i := i + 1
ENDDO
// 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.
oRest:ClearAllQueryParams()
oRest:AddQueryParam("type", "uploaded")
oRest:AddQueryParam("limit", "20")
oRest:AddQueryParam("after", cAfterCursor)
// Get the next page of photo ids.
cResponseJson := oRest:FullRequestNoBody("GET", "/v2.7/me/photos")
IF (oRest:LastMethodSuccess != 1)
? oRest:LastErrorText
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
oPhotoJson:destroy()
oSaPhotoUrls:destroy()
oSbPhotoIdPath:destroy()
oJson:destroy()
oImgUrlJson:destroy()
RETURN
ENDIF
oJson:Load(cResponseJson)
cAfterCursor := oJson:StringOf("paging.cursors.after")
ENDDO
? "No more pages of photos."
// 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.
oHttp := CreateObject("Chilkat.Http")
// We'll cache the image data so that if run again, we don't re-download the same image again.
nNumUrls := oSaPhotoUrls:Count
i := 0
oUrlJson := CreateObject("Chilkat.JsonObject")
oFac := CreateObject("Chilkat.FileAccess")
DO WHILE i < nNumUrls
oUrlJson:Load(oSaPhotoUrls:GetString(i))
cPhotoId := oUrlJson:StringOf("id")
cImageUrl := oUrlJson:StringOf("url")
// Check the local cache for the image data.
// Only download and save if not already cached.
oImageBytes := oFbCache:FetchFromCache(cImageUrl)
IF (oFbCache:LastMethodSuccess == 0)
// This photo needs to be downloaded.
oSbImageUrl := CreateObject("Chilkat.StringBuilder")
oSbImageUrl:Append(cImageUrl)
// Let's form a filename..
cExtension := ".jpg"
IF (oSbImageUrl:Contains(".gif", 0) == 1)
cExtension := ".gif"
ENDIF
IF (oSbImageUrl:Contains(".png", 0) == 1)
cExtension := ".png"
ENDIF
IF (oSbImageUrl:Contains(".tiff", 0) == 1)
cExtension := ".tiff"
ENDIF
IF (oSbImageUrl:Contains(".bmp", 0) == 1)
cExtension := ".bmp"
ENDIF
oSbLocalFilePath := CreateObject("Chilkat.StringBuilder")
oSbLocalFilePath:Append("C:/Photos/facebook/uploaded/")
oSbLocalFilePath:Append(cPhotoId)
oSbLocalFilePath:Append(cExtension)
oImageBytes := oHttp:QuickGet(cImageUrl)
IF (oHttp:LastMethodSuccess != 1)
? oHttp:LastErrorText
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
oPhotoJson:destroy()
oSaPhotoUrls:destroy()
oSbPhotoIdPath:destroy()
oJson:destroy()
oImgUrlJson:destroy()
oHttp:destroy()
oUrlJson:destroy()
oFac:destroy()
oSbImageUrl:destroy()
oSbLocalFilePath:destroy()
RETURN
ENDIF
// We've downloaded the photo image bytes into memory.
// Save it to the cache AND save it to the output file.
oFbCache:SaveToCacheNoExpire(cImageUrl, "", oImageBytes)
oFac:WriteEntireFile(oSbLocalFilePath:GetAsString(), oImageBytes)
? "Downloaded to " + oSbLocalFilePath:GetAsString()
ENDIF
i := i + 1
ENDDO
? "Finished downloading all Facebook photos!"
oFbCache:destroy()
oOauth2:destroy()
oRest:destroy()
oPhotoJson:destroy()
oSaPhotoUrls:destroy()
oSbPhotoIdPath:destroy()
oJson:destroy()
oImgUrlJson:destroy()
oHttp:destroy()
oUrlJson:destroy()
oFac:destroy()
oSbImageUrl:destroy()
oSbLocalFilePath:destroy()