Databox Indexer: Phraseanet Configuration
Example Configuration
Below is an example configuration for a Phraseanet location. Explanations for each field are provided after the code block.
...
"locations": [
{
"name": "phraseanet-full-example",
"type": "phraseanet",
"options": {
"url": "https://phraseanet.phrasea.local/",
"token": "-------mytoken-------",
"verifySSL": false,
"importFiles": false,
"searchOrder": "%env(PHRASEANET_SEARCH_ORDER)%",
"idempotencePrefixes": {
"asset": "idmp_asset",
"collection": "idmp_collection",
"attributeDefinition": "idmp_attributeDefinition",
"renditionDefinition": "idmp_renditionDefinition"
},
"databoxMapping": [
{
"databox": "db_databox1",
"collections": "",
"workspaceSlug": "phnet",
"searchQuery": "",
"importStories": true,
"recordsCollectionPath": "/Records/{{ collection.name | escapePath }}/{{ record.getMetadata('Country', '_').value | escapePath }}/{{ record.getMetadata('City', '_').value | escapePath }}",
"storiesCollectionPath": "/Stories/{{ collection.name | escapePath }}/{{ record.getMetadata('Country', '_').value | escapePath }}/{{ record.getMetadata('City', '_').value | escapePath }}",
"copyTo": [
"{% for s in record.getMetadata('Subject', 'no_subject').values %}/classification/{{ record.getMetadata('Creator', 'no_creator').value | escapePath }}/{{ s | escapePath }}\n{% endfor %}"
],
"fieldMap": {
"Title": {
"values": [
{
"locale": "fr",
"type": "metadata",
"value": "Titre"
},
{
"locale": "en",
"type": "metadata",
"value": "Title"
}
]
},
"Subject": {
"type": "string",
"values": [
{
"type": "template",
"value": "{% for v in record.getMetadata('Subject').values %}{{v}}\n{% endfor %}"
}
]
},
"Copyright": {
"type": "string",
"values": [
{
"type": "template",
"value": "(c){{record.getMetadata('ArchiveDate', '').value | date('Y')}} {{record.getMetadata('Creator', '').value}}"
}
]
},
"Filename": {
"values": [
{
"type": "metadata",
"value": "Filename"
}
]
}
}
}
]
}
}
...
databox
The name or id of the Phraseanet databox to import.
collections
A list/filter of Phraseanet collections (id or name, delimited by ,) to import/search on. If unset or empty, will query all collections.
searchQuery
The Phraseanet query to search for records to import. If empty: import all.
workspaceSlug
The Databox workspace where to import (created if not exists).
recordsCollectionPath
Collection-path where to import records as "main" assets. The asset name will always be the same ase the "original_name" of the record.
-
The
recordsCollectionPathcan be a Twig expression (see About Twig), allowing to dispatch the assets into a tree of collections.e.g.: Dispatch by phraseanet collection name, then country and city:
"recordsCollectionPath": "/Collections/{{ collection.name | escapePath }}/{{ record.getMetadata('Country', '_').value | escapePath }}/{{ record.getMetadata('City', '_').value | escapePath }}",-->
/Collections/MyPhraseanetCollection/France/Paris/IMG_1234.jpg -
/!\ For backward compatibility: If the
recordsCollectionPathis a simple string (no twig tags), it will be used as a root path and completd with phraseanet collection name"recordsCollectionPath": "/Collections",-->
/Collections/MyPhraseanetCollection/IMG_1234.jpg -
recordsCollectionPathcan be empty string (or not set): Since this is a simple (empty) string, the backward compatibility applies, so the phraseanet collection name will be used as first-level collection.-->
/MyPhraseanetCollection/IMG_1234.jpg
importStories & storiesCollectionPath
storiesCollectionPath and storiesCollectionPath define how to import Phraseanet stories, with 3 combinations:
- Do not import stories.
importStories: false
- Import stories as Phrasea stories
importStories: true
A "storyAsset" is created at root of the workspace, and "points" to a collection invisible / noname / not-indexed "storyCollection".
Each contained record (imported elsewhere as an asset) is copied / aliased to this (invisible) collection.
The title of the storyAsset will be the same as the title of the story.
- import stories as Phrasea collections
importStories: true # or unset, for bc
storiesCollectionPath: "/Stories" # where to import stories
Each story becomes a collection, and each contained record (imported elsewhere as an asset) is copied / aliased to this collection.
The name of the collection will be the same as the title of the story.
/!\ There is no "storyAsset" created, the Phraseanet "story-record" is not imported.
The storiesCollectionPath can be a Twig expression, allowing to dispatch the stories into a tree of collections.
e.g. 1: Import all stories, as Phrasea stories:
"recordsCollectionPath": "/Collections", # where to import records AND stories
"importStories": true,
--> /Stories/JO-2024 where "JO-2024" is the name of a phraseanet story.
e.g. 2: Import all stories in the same collection, as Phrasea collections:
"importStories": true,
"storiesCollectionPath": "/Stories",
--> /Stories/JO-2024 where "JO-2024" is the name of a phraseanet story.
e.g. 3: Dispatch by phraseanet collection name, then country and city:
"importStories": true,
"storiesCollectionPath": "/Stories/{{ collection.name | escapePath }}/{{ record.getMetadata('Country', '_').value | escapePath }}/{{ record.getMetadata('City', '_').value | escapePath }}",
--> /Stories/MyPhraseanetCollection/France/Paris/JO-2024 where "JO-2024" is the name of a phraseanet story.
copyTo
list (array) of paths where to copy / alias "main" assets.
Each path is a Twig expressions that must generate databox path(s), depending on run-time values like record metadata.
If the asset is to be copied in many places (paths), the twig must generate one line per path.
-
e.g. 1: Two levels dispatch with unique destination (mono-value fields):
"copyTo": [
"/classification/{{record.getMetadata('Category', 'unknown_category').value | escapePath}}/{{record.getMetadata('SubCategory', 'unknown_subcategory').value | escapePath}}"
] -
e.g. 2: Multiples destinations (multi-values field):
"copyTo": [
"{% for s in record.getMetadata('Keywords', 'no_keyword').values %}/classification/{{ s | escapePath }}\n{% endfor %}"
]note: The
\nis used to output one line (= one path) per keyword.note: The default value "no_keyword" is a must-have, because if the record had no keyword, it would not be copied anywhere.
-
e.g. 3: multiples destinations :
To dispatch the records in many "classification" places, one can set multiple
copyTosettings."copyTo": [
"/classification/author/{{record.getMetadata('Author', 'unknown_author').value | escapePath}},
"/classification/category/{{record.getMetadata('Category', 'unknown_category').value | escapePath}},
"/classification/year/{{record.getMetadata('Date', '').value is empty ? 'unknown_date' : {{record.getMetadata('Date').value | date('Y')}}
]
fieldMap
Map (key=AttributeDefinition name) of attributes to create / import.
AttributeDefinition settings:
-
type: "text", "number" or "json" (more todo) ; Default: "text" -
multivalue: boolean -
readonly: boolean -
labels: map, e.g.{"fr": "Titre", "en": "Title"} -
values: Array of objects to declare initial metadata value(s).values:
locale: e.g. "fr"type: how to evaluate thevalue("metadata", "template", "text" ; default: "text")value: value expression, as metadata (=phraseanet field name), template (twig) code or simple text
text type: The value is the immediate value for the attribute.
metadata type: The value is the name of a Phraseanet field, like "Title".
template type: The value is a Twig code, to compose complex value(s)
For the template type, the Attribute value(s) is the result of the Twig expression,
which must generate one item per line for multi-values.
The Twig context is the same as copyTo
note 1:
If the attribute-definition name matches exactly a Phraseanet field name, some AttributeDefinition settings will be copied from the Phraseanet metadata-structure (type, multivalue, readonly, labels).
If the name does not match a Phraseanet field, those settings can be set in conf block.
note 2:
If FieldMap is not set: Phraseanet full equivalent configuration is dumped.
note 3:
If an AttributeDefinition setting is declared with a locale, it will be created
with translatable=true.
All the different AttributeDefinition locales are copied to the "Enabled locales" of the workspace.
sourceFile
Declare le phraseanet subdef to be used as source file for the asset.
Mostly "sourceFile": "document" for the original file.
If not set, assets will be created without source file.
renditions
Allows to map Phraseanet subdef / (structures) to Phrasea renditions / (definitions).
A Phraseanet subdef is identified by it type (image, video, audio, document, unknown) and its name. e.g. image:thumbnail.
A Phrasea rendition-definition is declared by its name and build settings (sections image, video, ...).
note:
-
If
renditionsis not set, Phraseanet full equivalent configuration is dumped. -
To not import / create any rendition / rendition-definition: set both
"sourceFile":falseand"renditions": false -
It is possible to declare a rendition with no
from: not imported from Phraseanet, but created in Phrasea.
parent
One can declare a parent relation between renditions, the parent rendition must be declared before the child.
If not set, the rendition will be built from the asset file.
useAsMain, useAsPreview, useAsThumbnail, useAsAnimatedThumbnail
Declare the rendition to be used as main, preview, thumbnail or animated thumbnail.
buildMode
Tells the builder how to "build" the rendition.
- 0: Do not build the rendition
- 1: Copy the parent file (if no parent: copy the asset file); Mostly used to copy the asset file to the "main" rendition.
- 2: Build the rendition using build rules defined in
buildersblocks.
class
Phrasea rendition class, mostly "public" or "private". If not set, the value will be "guessed" from the subdef class (document, preview, ...).
builders
A builder can be defined for each family of renditions (image, video, audio, ...).
from
Inside the builder, the from maps the phrasea rendition-definition - for the family -,
to the phraseanet subdef.
The from value (phraseanet subdef) is a string like \<document_type>:\<subdef_name>, e.g. video:preview.
The build settings will be generated from the phraseanet to match the subdef.
e.g.
...
"sourceFile": "document",
"renditions": {
"main": {
"useAsMain": true,
"buildMode": 1,
"class": "public"
},
"preview": {
"useAsPreview": true,
"class": "public",
"builders": {
"image": {
"from": "image:preview"
},
"video": {
"from": "video:preview"
}
}
},
"thumbnail": {
"useAsThumbnail": true,
"class": "public",
"parent": "preview",
"builders": {
"image": {
"from": "image:thumbnail"
},
"video": {
"from": "video:thumbnail"
}
}
}
}
...
About Twig
When using twig expressions in the configuration, the context is the following:
record: record objectrecord.record_id: stringrecord.resource_id: stringrecord.databox_id: stringrecord.base_id: stringrecord.uuid: stringrecord.title: stringrecord.original_name: stringrecord.mime_type: stringrecord.created_on: stringrecord.updated_on: stringrecord.status: status[] usegetStatus()methodrecord.getStatus(\<bit> [, \<valueIfTrue> [, \<valueIfFalse>]]): boolean ; Value of sb <bit> (4...63). Boolean value can be replaced by string value(s)valueIf...record.subdef: subdef[] usegetSubdef()methodrecord.getSubdef(\<name>): subdef objectrecord.getSubdef(...).height: numberrecord.getSubdef(...).width: numberrecord.getSubdef(...).filesize: numberrecord.getSubdef(...).player_type: stringrecord.getSubdef(...).mime_type: numberrecord.getSubdef(...).created_on: stringrecord.getSubdef(...).updated_on: stringrecord.getSubdef(...).url: stringrecord.getSubdef(...).permalink: permalink objectrecord.getSubdef(...).permalink.url: string
record.metadata: metata[] usegetMetadata()methodrecord.getMetadata(\<fieldName> [,\<default>]): metadata object, with default value(s) if the field is not set for this record.record.getMetadata(...).value: The mono-value (if the field is multi-value : concat values with " ; ").record.getMetadata(...).values: The multi-values as array (if the field is mono-value : array with a single value).
collection: collection object (of the record)collection.databox_id: string (same asrecord.databox_id)collection.base_id: string (same asrecord.base_id)collection.collection_id: numbercollection.name: string
Twig context technical note:
To prevent twig to crash if a field doest not exists in a record (when trying to access a property like .value),
getMetadata(...) will return a "fake" empty metadata object.
Same method applies for subdefs: record.getSubdef('missingSubdef').permalink.url will return null.