Sample code for 30+ languages & platforms
Zig

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 Zig Downloads

Zig
const std = @import("std");
const chilkat = @import("chilkat");

pub fn main(init: std.process.Init) !void {
    const alloc = init.arena.allocator();

    // 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.
    const fb_cache = try chilkat.Cache.init();
    defer fb_cache.deinit();
    // The cache will use 1 level of 256 sub-directories.
    fb_cache.setLevel(1);
    // Use a directory path that makes sense on your operating system..
    fb_cache.addRoot("C:/fbCache");

    // This example assumes a previously obtained an access token
    const oauth2 = try chilkat.OAuth2.init();
    defer oauth2.deinit();
    oauth2.setAccessToken("FACEBOOK-ACCESS-TOKEN");

    const rest = try chilkat.Rest.init();
    defer rest.deinit();

    // Connect to Facebook.
    rest.connect("graph.facebook.com", 443, true, true) catch {
        std.debug.print("{s}\n", .{try rest.getLastErrorText(alloc)});
        return;
    };

    // Provide the authentication credentials (i.e. the access key)
    rest.setAuthOAuth2(oauth2) catch {};

    // 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".
    rest.addQueryParam("type", "uploaded") catch {};

    // 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.
    rest.addQueryParam("limit", "100") catch {};

    // Get the 1st page of photos ids.
    // See https://developers.facebook.com/docs/graph-api/reference/user/photos/ for more information.
    var response_json: [:0]const u8 = rest.fullRequestNoBody(alloc, "GET", "/v2.7/me/photos") catch {
        std.debug.print("{s}\n", .{try rest.getLastErrorText(alloc)});
        return;
    };

    const photo_json = try chilkat.JsonObject.init();
    defer photo_json.deinit();
    const sa_photo_urls = try chilkat.StringArray.init();
    defer sa_photo_urls.deinit();
    const sb_photo_id_path = try chilkat.StringBuilder.init();
    defer sb_photo_id_path.deinit();

    const json = try chilkat.JsonObject.init();
    defer json.deinit();
    json.setEmitCompact(false);
    json.load(response_json) catch {};

    var i: i32 = 0;
    var photo_id: [:0]const u8 = "";
    var image_url: [:0]const u8 = "";

    // Get the "after" cursor.
    var after_cursor: [:0]const u8 = try json.stringOf(alloc, "paging.cursors.after");
    while (json.getLastMethodSuccess()) {
        std.debug.print("-------------------\n", .{});
        std.debug.print("afterCursor = {s}\n", .{after_cursor});

        // For each photo id in this page...
        i = 0;
        const num_items = json.sizeOfArray("data");
        while (i < num_items) {
            json.setI(i);
            photo_id = try json.stringOf(alloc, "data[i].id");
            std.debug.print("photoId = {s}\n", .{photo_id});

            // 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.
            var photo_json_str: [:0]const u8 = fb_cache.fetchText(alloc, photo_id) catch "";
            if (!fb_cache.getLastMethodSuccess()) {
                // It's not locally available, so get it from Facebook..
                sb_photo_id_path.clear();
                sb_photo_id_path.append("/v2.7/") catch {};
                sb_photo_id_path.append(photo_id) catch {};

                rest.clearAllQueryParams() catch {};
                rest.addQueryParam("fields", "id,album,images") catch {};

                std.debug.print("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.
                photo_json_str = rest.fullRequestNoBody(alloc, "GET", try sb_photo_id_path.getAsString(alloc)) catch {
                    std.debug.print("{s}\n", .{try rest.getLastErrorText(alloc)});
                    return;
                };

                // Add the photo JSON to the local cache.
                fb_cache.saveTextNoExpire(photo_id, "", photo_json_str) catch {};
            }

            // 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.
            photo_json.load(photo_json_str) catch {};
            image_url = try photo_json.stringOf(alloc, "images[0].source");
            if (photo_json.getLastMethodSuccess()) {
                // Actually, we'll add a small JSON document that contains both the image ID and the URL.
                const img_url_json = try chilkat.JsonObject.init();
                defer img_url_json.deinit();
                img_url_json.appendString("id", photo_id) catch {};
                img_url_json.appendString("url", image_url) catch {};
                sa_photo_urls.append(try img_url_json.emit(alloc)) catch {};
                std.debug.print("imageUrl = {s}\n", .{image_url});
            }

            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.
        rest.clearAllQueryParams() catch {};
        rest.addQueryParam("type", "uploaded") catch {};
        rest.addQueryParam("limit", "20") catch {};
        rest.addQueryParam("after", after_cursor) catch {};

        // Get the next page of photo ids.
        response_json = rest.fullRequestNoBody(alloc, "GET", "/v2.7/me/photos") catch {
            std.debug.print("{s}\n", .{try rest.getLastErrorText(alloc)});
            return;
        };

        json.load(response_json) catch {};
        after_cursor = try json.stringOf(alloc, "paging.cursors.after");
    }

    std.debug.print("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.
    const http = try chilkat.Http.init();
    defer http.deinit();

    // We'll cache the image data so that if run again, we don't re-download the same image again.
    const num_urls = sa_photo_urls.getCount();
    i = 0;
    const url_json = try chilkat.JsonObject.init();
    defer url_json.deinit();

    const fac = try chilkat.FileAccess.init();
    defer fac.deinit();

    while (i < num_urls) {
        url_json.load(try sa_photo_urls.getString(alloc, i)) catch {};
        photo_id = try url_json.stringOf(alloc, "id");
        image_url = try url_json.stringOf(alloc, "url");

        // Check the local cache for the image data.
        // Only download and save if not already cached.
ERROR: Method not in the Zig package: Cache.FetchFromCache
ERROR: Method not in the Zig package: Cache.FetchFromCache
        image_bytes = fb_cache.ERROR();
        if (!fb_cache.getLastMethodSuccess()) {
            //  This photo needs to be downloaded.

            const sb_image_url = try chilkat.StringBuilder.init();
            defer sb_image_url.deinit();
            sb_image_url.append(image_url) catch {};

            // Let's form a filename..
            var extension: [:0]const u8 = ".jpg";
            if (sb_image_url.contains(".gif", false)) {
                extension = ".gif";
            }

            if (sb_image_url.contains(".png", false)) {
                extension = ".png";
            }

            if (sb_image_url.contains(".tiff", false)) {
                extension = ".tiff";
            }

            if (sb_image_url.contains(".bmp", false)) {
                extension = ".bmp";
            }

            const sb_local_file_path = try chilkat.StringBuilder.init();
            defer sb_local_file_path.deinit();
            sb_local_file_path.append("C:/Photos/facebook/uploaded/") catch {};
            sb_local_file_path.append(photo_id) catch {};
            sb_local_file_path.append(extension) catch {};

ERROR: Method not in the Zig package: Http.QuickGet
ERROR: Method not in the Zig package: Http.QuickGet
            image_bytes = http.ERROR();
            if (!http.getLastMethodSuccess()) {
                std.debug.print("{s}\n", .{try http.getLastErrorText(alloc)});
                return;
            }

            // We've downloaded the photo image bytes into memory.
            // Save it to the cache AND save it to the output file.
ERROR: Method not in the Zig package: Cache.SaveToCacheNoExpire
            _ = fb_cache.ERROR();
ERROR: Method not in the Zig package: FileAccess.WriteEntireFile
            _ = fac.ERROR();

            std.debug.print("Downloaded to {s}\n", .{try sb_local_file_path.getAsString(alloc)});
        }

        i = i + 1;
    }

    std.debug.print("Finished downloading all Facebook photos!\n", .{});
}