Adding Metadata to a Media Entry

I have defined a couple custom data items in the Kaltura dashboard with the hopes of programmatically setting metadata on media entries during the upload process. Video uploading works, but unfortunately I haven’t been able to figure out how to get the metadata part working. Documentation seems to be non-existent here. I’m using the Python client library. After starting the session and getting an upload token, the code that adds the media entry is this:

input_entry = KalturaMediaEntry() input_entry.setMediaType(KalturaMediaType.VIDEO) output_entry = self.client.media.addFromUploadedFile(input_entry, upload_token_id)

I’m attempting to create the metadata this way, but after this I don’t know what to do with it.

xml_data = '<metadata><organization_id>2001</organization_id></metadata>' meta_data = KalturaMetadata(id=<metadata_id>, metadataObjectType=KalturaMetadataObjectType.ENTRY, objectId=input_entry.id, xml=xml_data)

Looking at the few examples in other-language client libs I could find, I tried looking for this API, but could not find one in the python lib.
client.metadata.add(...)

Anyone know how to get this working?

Hello,

Below is a full code sample you can run as a standalone CLI script:

#!/usr/bin/python
import os, sys, inspect, re
from KalturaClient import *
from KalturaClient.Base import KalturaConfiguration
from KalturaClient.Plugins.Core import KalturaSessionType
from KalturaClient.Plugins.Core import KalturaFilterPager
from KalturaClient.Plugins.Core import KalturaException
from KalturaClient.Plugins.Core import KalturaMediaEntry, KalturaMediaEntryFilter, KalturaMediaEntryOrderBy,KalturaMediaType
from KalturaClient.Plugins.Metadata import KalturaMetadataProfile
from KalturaClient.Plugins.Metadata import KalturaMetadataObjectType
from KalturaClient.Plugins.Metadata import KalturaMetadataProfileFilter
from KalturaClient.Plugins.Metadata import KalturaMetadataFilter        
        
if len(sys.argv) < 4:
        print ("Usage: " + sys.argv[0] + " <Kaltura endpoint/service URL> <partner id> <admin secret>")
        exit (1)

def getTestFile(filename, mode='rb'):
    testFileDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
    return file(testFileDir+'/'+filename, mode)

config = KalturaConfiguration(sys.argv[2])
config.serviceUrl = sys.argv[1]
client = KalturaClient(config)
ks = client.session.start(sys.argv[3], None,KalturaSessionType.ADMIN,sys.argv[2], 86400, "")
client.setKs(ks)


# The metadata field we'll add/update
metaDataFieldName = "SubtitleFormat"
fieldValue = "VobSub"
testString = "PyTest"
# The Schema file for the field
# Currently, you must build the xsd yourself. There is no utility provided.
xsdFile = "MetadataSchema.xsd"

# Setup a pager and search to use
pager = KalturaFilterPager()
search = KalturaMediaEntryFilter()
search.setMediaTypeEqual(KalturaMediaType.VIDEO)  # Video only
pager.setPageSize(1)
pager.setPageIndex(1)

entries = client.media.list(search, pager).objects

# For the test, we'll just use the first entry returned by media.list()
name = entries[0].getName()
id = entries[0].getId()

# make sure we have a metadata profile
profile = KalturaMetadataProfile() 
profile.setName('TestProfile %s' % (testString,))
MetadataObjectType = KalturaMetadataObjectType.ENTRY

profile.setMetadataObjectType(MetadataObjectType)
viewsData = ""

xsdFh = getTestFile(xsdFile)
newProfile = client.metadata.metadataProfile.add(profile, xsdFh.read(), viewsData)

# for the first item returned by the previous list action
filter = KalturaMetadataProfileFilter()
metadata = client.metadata.metadataProfile.list(filter, pager).objects

if metadata[0].getXsd() != None:
    print ("There are EXISTING custom fields for video: " + name + ", entryid: " + id)
else:
    print ("There are NO custom fields for video: " + name + ", entryid: " + id)


profile = KalturaMetadataProfile()
profile.setName('TestProfile %s' % (testString,))
profile.setMetadataObjectType(KalturaMetadataObjectType.ENTRY)
viewsData = ""

metadataResult = client.metadata.metadataProfile.update(newProfile.id, profile, xsdFh.read(), viewsData)

assert(metadataResult.xsd != None)

# Add the custom metadata value to the first video
filter2 = KalturaMetadataFilter()
filter2.setObjectIdEqual(entries[0].id)
xmlData = "<metadata><SubtitleFormat>" + fieldValue + "</SubtitleFormat></metadata>"
metadata2 = client.metadata.metadata.add(newProfile.id, profile.metadataObjectType, entries[0].id, xmlData)

assert(metadata2.xml != None)

print ("Successfully added the custom data field for video: " + name + ", entryid: " + id)
xmlStr = metadata2.xml
print ("XML used: " + xmlStr)

# Now lets change the value (update) of the custom field
# Get the metadata for the video
filter3 = KalturaMetadataFilter()
filter3.setObjectIdEqual(entries[0].id)
filter3.setMetadataProfileIdEqual(newProfile.id)
metadataList = client.metadata.metadata.list(filter3).objects
assert(metadataList[0].xml != None)

print ("Current metadata for video: " + name + ", entryid: " + id)
xmlquoted = metadataList[0].xml
print ("XML: " + xmlquoted)
xml = metadataList[0].xml
# Make sure we find the old value in the current metadata
pos = xml.find("<" + metaDataFieldName + ">" + fieldValue + "</" + metaDataFieldName + ">")
assert(pos >= 0)

pattern = re.compile("<" + metaDataFieldName + ">([^<]+)</" + metaDataFieldName + ">")
xml = pattern.sub("<" + metaDataFieldName + ">Ogg Writ</" + metaDataFieldName + ">", xml)
rc = client.metadata.metadata.update(metadataList[0].id, xml)
print ("Updated metadata for video: " + name + ", entryid: " + id)
xmlquoted = rc.xml
print ("XML: " + xmlquoted)

And just to make is a complete as possible, here is a sample XSD:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="metadata">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element id="md_62DE8EE5-4AED-23FF-FC42-CB8E7093E347" name="SubtitleFormat" minOccurs="0" maxOccurs="1">
          <xsd:annotation>
            <xsd:documentation></xsd:documentation>
            <xsd:appinfo>
              <label>Subtitle Format</label>
              <key>Subtitle Format</key>
              <searchable>false</searchable>
              <description>Choice of subtitle format</description>
            </xsd:appinfo>
          </xsd:annotation>
          <xsd:simpleType>
            <xsd:restriction base="listType">
              <xsd:enumeration value="AQTitle"/>
              <xsd:enumeration value="MicroDVD"/>
              <xsd:enumeration value="MPSub"/>
              <xsd:enumeration value="Ogg Writ"/>
              <xsd:enumeration value="RealText"/>
              <xsd:enumeration value="SAMI"/>
              <xsd:enumeration value="SubRip"/>
              <xsd:enumeration value="Gloss Subtitle"/>
              <xsd:enumeration value="VobSub"/>
              <xsd:enumeration value="XSUB"/>
            </xsd:restriction>
          </xsd:simpleType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  <xsd:complexType name="textType">
    <xsd:simpleContent>
      <xsd:extension base="xsd:string"/>
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:complexType name="dateType">
    <xsd:simpleContent>
      <xsd:extension base="xsd:long"/>
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:complexType name="objectType">
    <xsd:simpleContent>
      <xsd:extension base="xsd:string"/>
    </xsd:simpleContent>
  </xsd:complexType>
  <xsd:simpleType name="listType">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
</xsd:schema>

Should be enough to get you started.
BTW, a good place to look at code samples is the unittests for the Python client lib, start here:

Thank you, @jess - I was able to get meta data working following the code you posted.

I’ll keep the unit tests in mind for the future, but it is not a very intuitive way to figure out how an API or client library works. Actual documentation would be a good start - Kaltura has almost none, and the stuff that is out there is sparse, fragmented, and incomplete.

Hi @kylehuang,

I’m sorry but I must disagree about the documentation. https://developer.kaltura.com has plenty of API documentation and even includes step by step code tutorials which you can find here: https://developer.kaltura.com/recipes, including one for working with metadata [https://developer.kaltura.com/recipes/metadata#]

Granted, the code samples are currently available for the PHP, Ruby, JS and NodeJS clients [not Python] and we do plan to support additional clients in the future but saying the documentation is sparse and incomplete sounds very harsh considering the content available.

That said, if there is anything specific you feel is missing, you’re welcome to provide feedback and we’ll do our best to add it.

It looks like there is more API documentation now compared to when I first started working with Kaltura. This is good, but I find documentation of the client libraries sorely lacking. The recipes may cover common scenarios, but are missing most of the the functionality of the libraries. Furthermore, the libraries are inconsistent: there may be examples for one client lib in PHP, but they doesn’t immediately apply to the client lib in another language. For example, the “Update entry metadata” recipe in PHP calls:
$result = $client->metadata->update(...)

Ruby:
results = client.metadata_service.update(...)

Python:
result = client.metadata.metadataProfile.update(...)

Three client libs, three slightly different function calls which aren’t documented anywhere that I was able to find. Looking at unit tests is fine, but this is not documentation.

I’ve been trying to figure out if there was a way to get the metadata for a single entry, given the entry ID, and haven’t found anything that suggests this is possible (seems like pretty basic functionality). Do you have to use the KalturaMetadataFilter for this?

Hi @kylehuang,

Here is a code sample in Python that will accomplish that:

from KalturaClient import *
from KalturaClient.Plugins.Core import *
from KalturaClient.Plugins.Metadata import *

partnerId=
kalturaEndpoint=""
userSecret=''
userId=''
entryId=''
config = KalturaConfiguration(partnerId)
config.serviceUrl = kalturaEndpoint
client = KalturaClient(config)
ks = client.session.start(
userSecret,
userId,
KalturaSessionType.USER,
partnerId) 

client.setKs(ks)
filter = KalturaMetadataFilter()
filter.objectIdEqual = entryId
pager = KalturaFilterPager()

result = client.metadata.metadata.list(filter, pager);
for item in result.objects:
    print(item.__dict__);