Using the FilePicker to interact with the Assets Library

Introduction

This documentation explains how Foundry package developers can detect if they’re running on the Forge platform, and how to interact with a user’s Assets Library. Specifically, it covers checking the existence of directories and files, and creating directories and assets without needing to make calls recursively in code.

Foundry VTT packages do not need to integrate this to function on The Forge. However, while it is not required to work on The Forge, adding this check can provide a boost to performance for both the user’s browser, and for the hosting server. This can be useful when a package needs to perform a particularly demanding operation.

1. Checking if Running on The Forge

To determine if the module is running on the Forge platform, use:

if (ForgeVTT != undefined && ForgeVTT.usingTheForge) {
    // Running on The Forge
}

If the above condition evaluates to true, the application is running on the Forge platform and can benefit from the below enhancements.

2. Recursively Browsing the User’s Assets Library

To get all directories, subdirectories, and files in the target directory of a user’s Assets Library:

// Specify the target directory, receive data for all dirs and subdirs
const forgeAssetsLibrary = await FilePicker.browse("forgevtt", "/", {"recursive": true})

This returns an object with the following structure:

{
    dirs: ["path", "path/to", "path/to/subdirectory", "path/to/subdirectory2" ],
    files: [assetPrefix + "path/to/subdirectory" + assetName],
    // Other expected attributes from FilePicker.browse...
}

Where:

  • dirs: Contains an array of paths to directories and their subdirectories.
  • files: Contains an array of absolute paths to files. These paths will be prefixed with the user’s specific Assets Library prefix.
    • You can still reference assets by relative path, but we recommend using the absolute path if you’re setting paths to assets, so that this can benefit from the CDN.

2.1 Getting the Asset Prefix

To retrieve the asset prefix for a user’s Assets Library:

const assetPrefix = ForgeVTT.ASSETS_LIBRARY_URL_PREFIX + await ForgeAPI.getUserId() + "/"

This is useful if you want to get a specific file exists in the user’s Assets Library directly. You can do a fetch on the assetPrefix + the relative path of the asset.

Since this benefits from the CDN, it is a lot faster than using the relative path of the asset or using FilePicker.browse and checking the files.

The assetPrefix is essentially the root of the user’s Assets Library.

3. Creating Nested Directories and Assets

3.1 Creating Nested Directories

To create a deeply nested folder (e.g., foo/bar/baz) in a single request, use:

const createDirectoryRsp = FilePicker.createDirectory("forgevtt", "foo/bar/baz")

This method ensures that each directory in the deeply nested path is created, whether or not they already existed, and is a great way to ensure that specific directories required by your module exist without having to browse recursively.

3.2 Uploading Assets to Nested Directories

To create a deeply nested asset (e.g., foo/bar/baz/assetName.png) in a single request:

const uploadRsp = FilePicker.upload("forgevtt", "foo/bar/baz", file)

This method uploads the file to the specific target directory, creating the path to that asset if it does not exist. If successful, the uploadRsp.path will contain the absolute path to the asset in the Assets Library, and is a great way to create an asset in a specific folder without needing to browse recursively to confirm that the directory already exists.

4. Understanding the forgevtt Source Parameter

When interacting with the FilePicker, several functions such as upload, createDirectory, and browse, require a source parameter. The value of this parameter dictates where the operation will take place.

4.1 Assets Library source: forgevtt

By specifying forgevtt as the source:

FilePicker.browse("forgevtt", "path/to/subdirectory");

You are specifically targeting the user’s Assets Library on the Forge platform. This is the primary location we store assets for users.

4.2 Alternative Source: data

If you do not find what you’re looking for in the forgevtt source, you can also target the data source. The data source represents a user’s data directory and is a standard approach in FoundryVTT.

FilePicker.browse("data", "path/to/subdirectory");

If the path does not exist in the user’s data directory but does exist in the Assets library, the result from the Assets Library will be returned for browse. Similarly, upload or createDirectory operations that target the data source will create files or directories in the user’s Assets Library instead, with the same path.

We recommend specifying forgevtt as the source when working on The Forge, if possible, to directly use the Assets Library.

Conclusion

By following this guide, developers can easily interact with the Assets Library on The Forge, allowing for seamless directory and file operations without the need for recursive browsing. As mentioned in the introduction, this is not a requirement for your module to work on The Forge, but it may improve performance where recursive network calls such as browse operations are involved.

If you encounter any problems or have any questions, please reach out to us by posting on this topic or contacting Forge Support, and we’ll do our best to help you out!

Please consider lending your comment to Add `recursive` option to `FilePicker#browse` method · Issue #10163 · foundryvtt/foundryvtt · GitHub should you have a need to recursively browse with the FIlepicker in core.