Synchronize MediaObjects

MediaObjects can be synchronized with Limecraft Flow (or imported) using the synchronization endpoint:

POST /api/production/:productionId/mo

The body of the call consists of a MediaObjectRequest object, or a list of such objects.

In return, the response will include the corresponding clip responses for each of the MediaObjectRequest objects.

Each MediaObjectRequest declares:

  • the desired state of the clip on Limecraft Flow including the base media object properties and the media object annotation properties (name, customFields, clipMetadata, …​)

  • a list of media object instances, including tracks and material instances (mediaObjectInstances, mediaInfo, …​)

  • the collections to which the clip should be attached

  • the annotations of the clip

  • options steering the synchronization process (synchronizeOptions)

The response will be a MediaObjectResponse, or a list of such objects.

During synchronization, Limecraft Flow will attempt to match each object in the MediaObjectRequest tree with an existing object in the database and put the object in the desired state.

There are two phases in handling a clip synchronization request:

  1. Matching

  2. Updating

Those two steps are applied to each object defined in the MediaObjectRequest.

Matching

Clips itself are matched by using the resolveMethod property set at the root level of the MediaObjectRequest.

At the time of writing, CRITERIA is the only supported value for resolveMethod.

When selecting the CRITERIA resolve method, the matching criteria are specified in a synchronizeOptions object. Learn more about synchronizeOptions here.

The below example will use CRITERIA to match on the MediaObject name:

[
    {
        name: 'synctest01.jpg',
        type: 'IMAGE',
        resolveMethod: 'CRITERIA',
        synchronizeOptions: {
            clip: {
                options: {
                    failOnMultipleMatches: true,
                },
                matchingCriteria: [
                    {
                        properties: ['name'],
                    }
                ]
            }
        }
    },
    {
        name: 'synctest02.jpg',
        type: 'IMAGE',
        resolveMethod: 'CRITERIA',
        synchronizeOptions: {
            ...
        }
    }
]

Given matching criteria defined in the synchronization options, Limecraft Flow will look for the object at hand in the database. The matching criteria object defines how and on which properties the object will be matched. The list of criteria is iterated and for each matching object a matching score is attached. The object with the highest matching score is selected for updating.

Updating

When no match is found, a new clip or collection is created.

When a match is found, the existing entry is updated to correspond with the desired state described in the MediaObjectRequest.

return style

The return objects can be controlled using the returnStyle query parameter:

  • returnStyle=included — The return object will be in a tree-like structure, closely representing the data model structure.

  • returnStyle=legacy — The return object will be a flat list of MediaObjectResponse. If only one MediaObjectRequest was passed, the response will not be a list, but a single MediaObjectResponse object.

The default value is legacy.

Examples

Simple name-based synchronize

When this is the body of the POST

[
    {
        name: 'synctest20.jpg',
        type: 'IMAGE',
        customFields: {},
        resolveMethod: 'CRITERIA',
        synchronizeOptions: {
            clip: {
                options: {
                    failOnMultipleMatches: true,
                },
                matchingCriteria: [
                    {
                        properties: ['name'],
                    }
                ]
            }
        }
    },
    {
        name: 'synctest21.jpg',
        type: 'IMAGE',
        customFields: {},
        resolveMethod: 'CRITERIA',
        synchronizeOptions: {
            clip: {
                options: {
                    failOnMultipleMatches: true,
                },
                matchingCriteria: [
                    {
                        properties: ['name'],
                    }
                ]
            }
        }
    }
]

The response could look the snippet shown below (which is shortened for readability). The synctest20.jpg already existed in the example, the synctest21.jpg did not. This can be seen in the syncReport.mediaObjectResolve.newMediaObject values.

[
    {
        "createdObjects": [
            {
                "annotations": null,
                "id": 579943,
                "mediaObjectInstances": null,
                "name": "synctest20.jpg",
                "objectType": "MediaObject",
                "tracks": null,
                "type": "IMAGE",
                "workflowId": "edf4f45f-7743-4092-9044-90219f8b748c",
                ...
            },
            {
                "description": "this is a description",
                "funnel": "MediaObjectAnnotation",
                "id": 1023789,
                "mediaObjectId": 579943,
                "objectType": "MediaObjectAnnotation",
                ...
            }
        ],
        "id": 579943,
        "isNew": false,
        "mediaObjectAnnotation": {
            "description": "this is a description",
            "funnel": "MediaObjectAnnotation",
            "id": 1023789,
            ...
        },
        "mediaObjectAnnotationId": 1023789,
        "mediaObjectId": 579943,
        "name": "synctest20.jpg",
        "objectType": "MediaObject",
        "syncReport": {
            "annotationResolve": [],
            "collectionResolve": [],
            "createdComponents": [],
            "materialInstanceResolve": [],
            "mediaObjectInstanceResolve": [],
            "mediaObjectResolve": {
                "indexUsed": true,
                "newMediaObject": false,
                "noMatch": false,
                "noMediaInfoGiven": false
            },
            "trackResolve": []
        },
        "workflowId": "edf4f45f-7743-4092-9044-90219f8b748c",
        ...
    },
    {
        "createdObjects": [
            {
                "annotations": [],
                "id": 579962,
                "mediaObjectInstances": [],
                "name": "synctest21.jpg",
                "objectType": "MediaObject",
                "tracks": [],
                "type": "IMAGE",
                "workflowId": "b696fff7-1b48-417c-81c3-fc39895ec318",
                ...
            },
            {
                "funnel": "MediaObjectAnnotation",
                "id": 1023858,
                "mediaObjectId": 579962,
                "objectType": "MediaObjectAnnotation",
                ...
            }
        ],
        "creatorId": 3,
        "duration": 0,
        "durationSeconds": 0,
        "growing": false,
        "id": 579962,
        "isNew": true,
        "keyFrame": 0,
        "lastUpdated": 1700750723449,
        "mediaObjectAnnotation": {
            "funnel": "MediaObjectAnnotation",
            "id": 1023858,
            "mediaObjectId": 579962,
            "objectType": "MediaObjectAnnotation",
            ...
        },
        "mediaObjectAnnotationId": 1023858,
        "mediaObjectId": 579962,
        "name": "synctest21.jpg",
        "objectType": "MediaObject",
        "syncReport": {
            "annotationResolve": [],
            "collectionResolve": [],
            "createdComponents": [],
            "materialInstanceResolve": [],
            "mediaObjectInstanceResolve": [],
            "mediaObjectResolve": {
                "indexUsed": true,
                "newMediaObject": true,
                "noMatch": false,
                "noMediaInfoGiven": false
            },
            "trackResolve": []
        },
        "tracks": [],
        "type": "IMAGE",
        "workflowId": "b696fff7-1b48-417c-81c3-fc39895ec318",
        ...
    }
]

Synchronize and upload a particular version

Now let’s look at a more advanced scenario. Now, we set up the low-level clip properties ourselves. This assumes some kind of "media probing" happened locally first, to be able to set the mediaInfo properties.

Synchronize call to create the MediaObject, MediaObjectInstance, MaterialInstance

In the example below, we set up RAW version of the MediaObject provided, with one MaterialInstance, and two, separate, tracks — AUDIO and VIDEO.

{
  "resolveMethod": "CRITERIA",
  "synchronizeOptions": {
    "clip": {
      "options": {
        "failOnMultipleMatches": true
      },
      "matchingCriteria": [
        {
          "properties": [
            "name"
          ]
        }
      ]
    }
  },
  "name": "My super clip",
  "type": "VIDEO",
  "duration": 110.11,
  "sampleRate": {
    "drop_frame": false,
    "numerator": 25,
    "denumerator": 1
  },
  "mediaInfo": {
    "mimeType": "video/mp4",
    "tracks": [
      {
        "type": "VIDEO",
        "width": 1280,
        "height": 720,
        "fps": {
          "numerator": 25,
          "denumerator": 1
        },
        "duration": 110.11,
        "codingFormat": "h264",
        "kBitRate": 1901.94,
        "subsampling": "4:2:0",
        "size": 184915,
        "fileName": "1.mp4",
        "timecodeOffset": 0,
        "tape": "14392787",
        "file_index": 0,
        "uuid": "track_1"
      },
      {
        "type": "AUDIO",
        "duration": 110,
        "codingFormat": "aac",
        "kBitRate": 191.238,
        "samplingFrequency": 44100,
        "channels": 2,
        "index": 1,
        "number": 1,
        "name": "1439278785225_df5ff499-fb7d-4311-9046-fdbd02183e7f",
        "segmentDuration": -1,
        "size": 184915,
        "fileName": "1.mp4",
        "timecodeOffset": 0,
        "tape": "14392787",
        "file_index": 0,
        "uuid": "track_2"
      }
    ],
    "length": 184915,
    "timecode": 0,
    "duration": 110.11,
    "frames": 2752
  },
  "mediaObjectInstances": [
    {
      "type": "RAW",
      "duration": 110.11,
      "size": 123456,
      "mediaInfo": {
        "mimeType": "video/mp4",
        "frames": 2752,
        "length": 184915,
        "timecode": 0,
        "duration": 110.11,
        "tracks": [
          {
            "type": "VIDEO",
            "width": 1280,
            "height": 720,
            "fps": {
              "numerator": 25,
              "denumerator": 1
            },
            "duration": 110.11,
            "codingFormat": "h264",
            "kBitRate": 1901.94,
            "subsampling": "4:2:0",
            "size": 123456,
            "fileName": "1.mp4",
            "timecodeOffset": 0,
            "tape": "14392787",
            "file_index": 0,
            "uuid": "track_1"
          },
          {
            "type": "AUDIO",
            "duration": 110,
            "codingFormat": "aac",
            "kBitRate": 191.238,
            "samplingFrequency": 44100,
            "channels": 2,
            "index": 1,
            "number": 1,
            "name": "1439278785225_df5ff499-fb7d-4311-9046-fdbd02183e7f",
            "segmentDuration": -1,
            "size": 123456,
            "fileName": "1.mp4",
            "timecodeOffset": 0,
            "tape": "14392787",
            "file_index": 0,
            "uuid": "track_2"
          }
        ]
      },
      "tracks": [
        {
          "type": "VIDEO",
          "width": 1280,
          "height": 720,
          "fps": {
            "numerator": 25,
            "denumerator": 1
          },
          "duration": 110.11,
          "codingFormat": "h264",
          "kBitRate": 1901.94,
          "subsampling": "4:2:0",
          "size": 184915,
          "fileName": "1.mp4",
          "timecodeOffset": 0,
          "tape": "14392787",
          "file_index": 0,
          "uuid": "track_1",
          "materials": [
            {
              "alternateBackupLocation": "/Volumes/Nearline/Production Name/collection1/collection2/test.mp4",
              "onAlternateBackup": true,
              "size": 123456,
              "filename": "test.mp4"
            }
          ]
        },
        {
          "type": "AUDIO",
          "duration": 110,
          "codingFormat": "aac",
          "kBitRate": 191.238,
          "samplingFrequency": 44100,
          "channels": 2,
          "index": 1,
          "number": 1,
          "name": "1439278785225_df5ff499-fb7d-4311-9046-fdbd02183e7f",
          "segmentDuration": -1,
          "size": 184915,
          "fileName": "1.mp4",
          "timecodeOffset": 0,
          "tape": "14392787",
          "file_index": 0,
          "uuid": "track_2",
          "materials": [
            {
              "alternateBackupLocation": "/Volumes/Nearline/Production Name/collection1/collection2/test.mp4",
              "onAlternateBackup": true,
              "size": 123456,
              "filename": "test.mp4"
            }
          ]
        }
      ]
    }
  ]
}

Initiate the upload

Now, we have to explicitly ask the API where we should send the bytes to, for uploading them to the MaterialInstance it created in the previous call. The response of the call contained a materialInstanceId property, which we need to construct the url to kick off the upload.

POST /production/{prId}/mo/{mediaObjectId}/mai/{materialInstanceId}/upload

This call will prepare the API to receive the upload of the file.

Details
Description

The returned json object will contain a field uploadLocation that is to receive the upload.

Parameters
Path Parameters
Name Description Required Type

prId

ID of the production.

Long

mediaObjectId

ID of the MediaObject.

Long

materialInstanceId

ID of the MaterialInstance.

Long

Body Parameters
Name Description Required Type

MaterialInstanceRequest

MaterialInstanceRequest

MaterialInstanceRequest

Field Name Required Type Description Format

acceptedType

String

accessToken

String

alternateBackupLocation

String

alternateBackupMetadata

Object

alternateBackupType

String

archive1Location

String

archive1Metadata

Object

archive1Type

String

archive2Location

String

archive2Metadata

Object

archive2Type

String

archive3Location

String

archive3Metadata

Object

archive3Type

String

attachToEdlId

Long

int64

backupCompleted

Date

date-time

backupStarted

Date

date-time

businessKey

String

content

String

created

Date

The time when this resource was created

date-time

createdBy

String

The request or process that created this resource

creatorId

Long

The id of the user who created this resource

int64

deleted

Boolean

deletedTimestamp

Date

date-time

description

String

duration

Double

double

enableHDProxy

Boolean

enableProxy

Boolean

enableShot

Boolean

enableSpeaker

Boolean

enableSpeech

Boolean

enableStitch

Boolean

fileName

String

filename

String

fingerprints

Set of string

forceOverwrite

Boolean

growing

Boolean

hash

String

id

Long

The id of this resource

int64

isCloud

Boolean

isData

Boolean

isProxy

Boolean

lastUpdated

Date

The time when this resource was last updated

date-time

location

String

locationMetadata

Object

markForRemoval

Boolean

materialInstanceId

Long

int64

md5

String

md5Partials

String

md5VerificationCompleted

Date

date-time

md5VerificationStatus

String

Enum: NOT_VERIFIED, VERIFIED, REJECTED,

mediaInfo

String

mediaInfoProxy

String

mediaObjectId

Long

int64

mediaObjectInstanceId

Long

int64

mediaObjectType

String

Enum: IMAGE, DOCUMENT, PENDING, AUDIO, VIDEO, SNIPPET, PACKAGE,

metadata

Boolean

modifiedBy

String

The request or process responsible for the last update of this resource

moiType

String

Enum: RAW, PROXY, EDL, SHOTSTITCH, STITCH, THUMB, THUMB_SHOT, THUMB_SIXTY, WAVEFORM, AUDIO_MONO, AUDIO_SPEECH, VOLDEMORT_XML, ATTACHMENT, HDR_PROXY, MEZZANINE_PROXY,

mxfReport

Boolean

objectType

String

The data model type or class name of this resource

onAlternateBackup

Boolean

onAlternateBackupTimestamp

Date

date-time

onArchive1

Boolean

onArchive1Timestamp

Date

date-time

onArchive2

Boolean

onArchive2Timestamp

Date

date-time

onArchive3

Boolean

onArchive3Timestamp

Date

date-time

onBackup

Boolean

onBackupTimestamp

Date

date-time

onFlow

Boolean

onFlowTimestamp

Date

date-time

onsite

Boolean

pathOnCard

String

pattern

String

prefix

String

productionId

Long

int64

proxyProfile

String

rawPath

String

removeFromQuota

Boolean

screenshot

List of ByteArray

byte

screenshotMimeType

String

shouldBeOnAlternateBackup

Boolean

shouldBeOnAlternateBackupTimestamp

Date

date-time

shouldBeOnBackup

Boolean

shouldBeOnBackupTimestamp

Date

date-time

shouldBeOnFlow

Boolean

shouldBeOnFlowTimestamp

Date

date-time

size

Long

int64

smallHash

String

tags

String

tracks

Set of Track

transferDetails

TransferDetails

uid

String

uploading

Boolean

url

String

version

Long

The version of this resource, used for Optimistic Locking

int64

volumeLocations

List of VolumeLocation

zone

String

Return Type

MaterialInstance

Field Name Required Type Description Format

alternateBackupLocation

String

alternateBackupMetadata

Object

alternateBackupType

String

archive1Location

String

archive1Metadata

Object

archive1Type

String

archive2Location

String

archive2Metadata

Object

archive2Type

String

archive3Location

String

archive3Metadata

Object

archive3Type

String

backupCompleted

Date

date-time

backupStarted

Date

date-time

businessKey

String

created

Date

The time when this resource was created

date-time

createdBy

String

The request or process that created this resource

creatorId

Long

The id of the user who created this resource

int64

deleted

Boolean

deletedTimestamp

Date

date-time

filename

String

fingerprints

Set of string

growing

Boolean

id

Long

The id of this resource

int64

lastUpdated

Date

The time when this resource was last updated

date-time

location

String

locationMetadata

Object

md5

String

md5Partials

String

md5VerificationCompleted

Date

date-time

md5VerificationStatus

String

Enum: NOT_VERIFIED, VERIFIED, REJECTED,

mediaObjectId

Long

int64

mediaObjectType

String

Enum: IMAGE, DOCUMENT, PENDING, AUDIO, VIDEO, SNIPPET, PACKAGE,

metadata

Boolean

modifiedBy

String

The request or process responsible for the last update of this resource

moiType

String

Enum: RAW, PROXY, EDL, SHOTSTITCH, STITCH, THUMB, THUMB_SHOT, THUMB_SIXTY, WAVEFORM, AUDIO_MONO, AUDIO_SPEECH, VOLDEMORT_XML, ATTACHMENT, HDR_PROXY, MEZZANINE_PROXY,

mxfReport

Boolean

objectType

String

The data model type or class name of this resource

onAlternateBackup

Boolean

onAlternateBackupTimestamp

Date

date-time

onArchive1

Boolean

onArchive1Timestamp

Date

date-time

onArchive2

Boolean

onArchive2Timestamp

Date

date-time

onArchive3

Boolean

onArchive3Timestamp

Date

date-time

onBackup

Boolean

onBackupTimestamp

Date

date-time

onFlow

Boolean

onFlowTimestamp

Date

date-time

onsite

Boolean

pathOnCard

String

pattern

String

productionId

Long

int64

removeFromQuota

Boolean

shouldBeOnAlternateBackup

Boolean

shouldBeOnAlternateBackupTimestamp

Date

date-time

shouldBeOnBackup

Boolean

shouldBeOnBackupTimestamp

Date

date-time

shouldBeOnFlow

Boolean

shouldBeOnFlowTimestamp

Date

date-time

size

Long

int64

tracks

Set of Track

transferDetails

TransferDetails

uid

String

uploading

Boolean

version

Long

The version of this resource, used for Optimistic Locking

int64

volumeLocations

List of VolumeLocation

zone

String

Content Type
  • application/json

Responses
Table 1. http response codes
Code Description Datatype

200

The request was successful.

MaterialInstance

402

There are not enough subscription resources available to complete this request.

QuotaExceededError

403

The user needs LIBRARY_UPLOAD rights.

ForbiddenError

404

The production, media object or material instance was not found.

NotFoundError

This call in turn returns a JSON object containing an uploadLocation field. Now, as before, we can start sending bytes to this location.

Send the bytes

PUT {{uploadLocation}}

Close the upload

And once all bytes are uploaded successfully, we should again close the upload to signal to the API that all bytes were send and it can start processing the file in the Ingest workflow.

POST /production/{prId}/mo/{mediaObjectId}/mai/{materialInstanceId}/close

Signal that the upload is finished.

Details
Description
Parameters
Path Parameters
Name Description Required Type

prId

ID of the production.

Long

mediaObjectId

ID of the MediaObject.

Long

materialInstanceId

ID of the MaterialInstance.

Long

Body Parameters
Name Description Required Type

CloseRequest

CloseRequest

CloseRequest

Field Name Required Type Description Format

skipIngest

Boolean

skipVerification

Boolean

Return Type

MediaObjectInstance

Field Name Required Type Description Format

audioLayoutProperties

AudioLayoutProperties

confidentiality

Integer

int32

created

Date

The time when this resource was created

date-time

createdBy

String

The request or process that created this resource

creatorId

Long

The id of the user who created this resource

int64

description

String

duration

Double

double

id

Long

The id of this resource

int64

lastUpdated

Date

The time when this resource was last updated

date-time

materialInfo

MaterialInfo

materialUploadComplete

Date

date-time

mediaInfo

MediaInfo

mediaObjectId

Long

int64

mimeType

String

modifiedBy

String

The request or process responsible for the last update of this resource

objectType

String

The data model type or class name of this resource

profile

String

quality

String

Enum: HIGH, MEDIUM, LOW, ULTRA,

size

Long

int64

sourceMediaObjectInstance

MediaObjectInstance

sourceMediaObjectInstanceId

Long

int64

tracks

Set of Track

transcoderProfileUuid

String

type

String

Enum: RAW, PROXY, EDL, SHOTSTITCH, STITCH, THUMB, THUMB_SHOT, THUMB_SIXTY, WAVEFORM, AUDIO_MONO, AUDIO_SPEECH, VOLDEMORT_XML, ATTACHMENT, HDR_PROXY, MEZZANINE_PROXY,

version

Long

The version of this resource, used for Optimistic Locking

int64

Content Type
  • application/json

Responses
Table 2. http response codes
Code Description Datatype

200

The request was successful.

MediaObjectInstance

403

The user needs LIBRARY_UPLOAD rights.

ForbiddenError

404

The production, media object or material instance was not found.

NotFoundError

412

The upload was not complete.

PreconditionFailedError

More control

It is clear that this method is more complicated than the simple upload we described earlier. So why do it? The reason is that this method gives you much more control. For example, you can set up a PROXY MediaObjectInstance, and send that to Limecraft Flow so you get a browser-friendly preview while not having to send the original media to Limecraft Flow.

To add a MediaObjectInstance to a MediaObject, you can use this call:

POST /production/{prId}/mo/{moId}/moi

This call creates a new MediaObjectInstance.

Details
Description
Parameters
Path Parameters
Name Description Required Type

prId

ID of the production.

Long

moId

ID of the MediaObject.

Long

Body Parameters
Name Description Required Type

BasicObjectNode

The mediaObjectInstance object.

BasicObjectNode

BasicObjectNode
Node that maps to JSON Object structures in JSON content.

Field Name Required Type Description Format

id

Integer

int32

Return Type

MediaObjectInstance

Field Name Required Type Description Format

audioLayoutProperties

AudioLayoutProperties

confidentiality

Integer

int32

created

Date

The time when this resource was created

date-time

createdBy

String

The request or process that created this resource

creatorId

Long

The id of the user who created this resource

int64

description

String

duration

Double

double

id

Long

The id of this resource

int64

lastUpdated

Date

The time when this resource was last updated

date-time

materialInfo

MaterialInfo

materialUploadComplete

Date

date-time

mediaInfo

MediaInfo

mediaObjectId

Long

int64

mimeType

String

modifiedBy

String

The request or process responsible for the last update of this resource

objectType

String

The data model type or class name of this resource

profile

String

quality

String

Enum: HIGH, MEDIUM, LOW, ULTRA,

size

Long

int64

sourceMediaObjectInstance

MediaObjectInstance

sourceMediaObjectInstanceId

Long

int64

tracks

Set of Track

transcoderProfileUuid

String

type

String

Enum: RAW, PROXY, EDL, SHOTSTITCH, STITCH, THUMB, THUMB_SHOT, THUMB_SIXTY, WAVEFORM, AUDIO_MONO, AUDIO_SPEECH, VOLDEMORT_XML, ATTACHMENT, HDR_PROXY, MEZZANINE_PROXY,

version

Long

The version of this resource, used for Optimistic Locking

int64

Content Type
  • application/json

Responses
Table 3. http response codes
Code Description Datatype

201

The request was successful.

MediaObjectInstance

403

The user needs LIBRARY_UPLOAD rights.

ForbiddenError

404

The production or media object was not found.

NotFoundError