All files / src/controllers MediaConnectorController.ts

89.58% Statements 43/48
33.33% Branches 5/15
95.24% Functions 20/21
92.68% Lines 38/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183    5x                   5x             5x                             5x       10x 10x           10x 10x                     10x 2x 2x   2x                       10x 1x 1x   1x                         10x         2x 2x     2x 2x               2x                   10x 1x 1x   1x                 10x 1x 1x   1x               10x                           2x       1x   1x                       10x 1x 1x   1x      
import { CallSender } from 'penpal';
import { EditorAPI, EditorRawAPI, EditorResponse, Id } from '../types/CommonTypes';
import {
    ConnectorConfigOptions,
    DeprecatedMediaConnectorDownloadType,
    DeprecatedMediaType,
    FilePointer,
    MediaType,
    MetaData,
    QueryOptions,
    QueryPage,
} from '../types/ConnectorTypes';
import {
    Media,
    MediaConnectorCapabilities,
    MediaDetail,
    MediaDownloadIntent,
    MediaDownloadType,
} from '../types/MediaConnectorTypes';
import { getEditorResponseData } from '../utils/EditorResponseData';
 
/**
 * The MediaConnectorController is responsible for all communication regarding media connectors.
 * Methods inside this controller can be called by `window.SDK.mediaConnector.{method-name}`
 *
 * The way GraFx Studio handles different sources of media is called 'MediaConnector'.
 * A MediaConnector is an implementation of a set of capabilities we need
 * to interact with a certain Digital Asset Management system.
 * In essence, a connector is the combination of a JavaScript snippet and some metadata.
 * The JavaScript snippet is loaded in the studio engine using a sandboxed JavaScript execution engine (QuickJs).
 * This allows us to execute the media connector
 * both on web using webassembly and on the server side during e.g. animation output generation.
 * This controller is an interface to the running connector instance inside the studio engine.
 */
export class MediaConnectorController {
    /**
     * @ignore
     */
    #editorAPI: EditorAPI;
    #blobAPI: EditorRawAPI;
 
    /**
     * @ignore
     */
    constructor(editorAPI: EditorAPI) {
        this.#editorAPI = editorAPI;
        this.#blobAPI = editorAPI as CallSender as EditorRawAPI;
    }
 
    /**
     * Query a specific MediaConnector for data using both standardized queryOptions and the dynamic
     * context as parameters. This call returns an array of Media items.
     * @param id unique id of the media connector
     * @param queryOptions stringified instance of `QueryOptions`
     * @param context context that will be available in the connector script.
     * @returns array of Media items
     */
    query = async (id: Id, queryOptions: QueryOptions, context: MetaData = {}) => {
        const res = await this.#editorAPI;
        return res
            .mediaConnectorQuery(id, JSON.stringify(queryOptions), JSON.stringify(context))
            .then((result) => getEditorResponseData<QueryPage<Media>>(result));
    };
 
    /**
     * Returns a single media using a specific MediaConnector.
     *
     * The connector needs to list `detail` as a supported capability.
     * @param id unique id of the Media connector
     * @param mediaId unique id of the Media
     * @param context context that will be available in the connector script.
     * @returns Media item
     */
    detail = async (id: Id, mediaId: string, context: MetaData = {}) => {
        const res = await this.#editorAPI;
        return res
            .mediaConnectorDetail(id, mediaId, JSON.stringify(context))
            .then((result) => getEditorResponseData<MediaDetail>(result));
    };
 
    /**
     * The combination of a `connectorId` and `mediaId` is typically enough for a media connector to
     * perform the download of this asset. The `download` endpoint is capable of relaying this information to the
     * media connector instance running in the editor engine.
     * @param id unique id of the media connector
     * @param mediaId unique id of the media to download
     * @param downloadType hint to the media connector about desired quality of the downloaded media
     * @param context context that will be available in the connector script.
     * @returns
     */
    download = async (
        id: Id,
        mediaId: Id,
        downloadType: MediaDownloadType,
        context: MetaData = {},
    ): Promise<Uint8Array> => {
        const compatibleDownloadType = this.parseDeprecatedMediaDownloadType(
            downloadType as unknown as DeprecatedMediaConnectorDownloadType,
        ) as MediaDownloadType;
        const res = await this.#blobAPI;
        return res
            .mediaConnectorDownload(
                id,
                mediaId,
                compatibleDownloadType,
                MediaDownloadIntent.web,
                JSON.stringify(context),
            )
            .then((result) => (result as Uint8Array) ?? (result as EditorResponse<null>));
    };
 
    /**
     * All connectors have a certain set of mappings they allow to be passed into the connector methods their context. This
     * method allows you to discover which mappings are available for a given connector. If you want to use any of these
     * mappings, they will be available in the `context` parameter of any connector method.
     * @param id unique id of the media connector
     * @returns connector mappings
     */
    getConfigurationOptions = async (id: Id) => {
        const res = await this.#editorAPI;
        return res
            .mediaConnectorGetConfigurationOptions(id)
            .then((result) => getEditorResponseData<ConnectorConfigOptions>(result));
    };
 
    /**
     * This method returns what capabilities the selected connector has. It gives an indication what methods can
     * be used successfully for a certain connector.
     * @param id unique id of the media connector
     * @returns MediaConnectorCapabilities
     */
    getCapabilities = async (id: Id) => {
        const res = await this.#editorAPI;
        return res
            .mediaConnectorGetCapabilities(id)
            .then((result) => getEditorResponseData<MediaConnectorCapabilities>(result));
    };
 
    /**
     * This method will parse the deprecatedMediaType to the new media type. This method will be removed once the deprecatedMediaType is out of use
     * @param deprecatedType is 0 or 1
     * @returns connector capabilities
     */
    parseDeprecatedMediaType = (deprecatedType: DeprecatedMediaType) => {
        if (deprecatedType === DeprecatedMediaType.file) return MediaType.file;
        if (deprecatedType === DeprecatedMediaType.collection) return MediaType.collection;
    };
 
    /**
     * This method will parse the deprecatedMediaDownloadType to the new media download type.
     * This method will be removed once the deprecatedMediaDownloadType is out of use
     * @param deprecatedMediaDownloadType legacy download type
     * @returns MediaDownloadType
     */
    parseDeprecatedMediaDownloadType(
        deprecatedMediaDownloadType: DeprecatedMediaConnectorDownloadType,
    ): MediaDownloadType {
        switch (deprecatedMediaDownloadType) {
            case DeprecatedMediaConnectorDownloadType.HighResolutionWeb:
                return MediaDownloadType.highres;
            case DeprecatedMediaConnectorDownloadType.LowResolutionWeb:
                return MediaDownloadType.thumbnail;
            default:
                return deprecatedMediaDownloadType as unknown as MediaDownloadType;
        }
    }
 
    /**
     * Invokes the upload on the connector, using the given staged pointer(s).
     * If you want help with staging files, use the `stageFiles` method from the UtilsController.
     * @param connectorId The MediaConnector instance to use (just like download API).
     * @param filePointers Array of FilePointer as staged by stageFile(s).
     * @param context Arbitrary metadata/context for the upload (auth, meta fields, etc).
     * @returns Promise<Media[]>
     */
    upload = async (connectorId: Id, filePointers: FilePointer[], context: MetaData = {}) => {
        const res = await this.#editorAPI;
        return res
            .mediaConnectorUpload(connectorId, JSON.stringify(filePointers), JSON.stringify(context))
            .then((result) => getEditorResponseData<Media[]>(result));
    };
}