Skip to content

Commit

Permalink
get story content by pagination ; fix mismatch with "original" (add `…
Browse files Browse the repository at this point in the history
…sourceFile` setting) ; update doc
  • Loading branch information
jygaulier committed Jan 15, 2025
1 parent 121fdfd commit 78a2081
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 88 deletions.
12 changes: 6 additions & 6 deletions databox/api/src/Api/Model/Input/RenditionDefinitionInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,37 +39,37 @@ class RenditionDefinitionInput
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $download = true;
public $download = null;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $pickSourceFile = false;
public $pickSourceFile = null;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsOriginal = false;
public $useAsOriginal = null;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsPreview = false;
public $useAsPreview = null;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsThumbnail = false;
public $useAsThumbnail = null;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsThumbnailActive = false;
public $useAsThumbnailActive = null;

/**
* @var string|null
Expand Down
45 changes: 31 additions & 14 deletions databox/indexer/doc/conf_phraseanet.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,12 @@ 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`

Expand All @@ -254,40 +260,49 @@ A Phraseanet subdef is identified by it **type** (image, video, audio, document,

A Phrasea rendition-definition is declared by its **name** and **build settings** (sections image, video, ...).

### `from`
The `from` setting maps the phrasea rendition-definition to the phraseanet subdef.
The build settings will be generated from the phraseanet to match the subdef.

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.

/!\ `original` is **not** a rendition, but a place to declare settings specifics to the file of the asset.
If not set, the rendition will be built from the asset file.

### `useAsOriginal`, `useAsPreview`, `useAsThumbnail`, `useAsActiveThumbnail`

The special `original` has no build settings, so the `from` setting is top-level.
Mostly it will be mapped to the Phraseanet special `document` subdef, but one could map it to any phraseanet subdef.
Declare the rendition to be used as original, preview, thumbnail or active thumbnail.

If a rendition is to be created from the original file, do **not** set it a parent.
### `pickFromFile`
Tells the builder to copy the parent file (if no parent: copy the source file) to the rendition file.

### `class`
Phrasea rendition class, mostly "public" or "private". If not set, the value will be "guessed" from the subdef **class** (document, preview, ...).

### `useAsOriginal`, `useAsPreview`, `useAsThumbnail`, `class`, ...
### `builders`
A builder can be defined for each family of renditions (image, video, audio, ...).

Common settings for all renditions. If not set, the value will be "guessed" from the subdef name / class.
#### `from`
Inside the builder, the `from` maps the phrasea rendition-definition - for the family -,
to the phraseanet subdef.

e.g.
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.

```json lines
...
"sourceFile": "document",
"renditions": {
"original": {
"from": "document",
"useAsOriginal": true,
"class": "document"
"pickFromFile": true,
"class": "public"
},
"preview": {
"useAsPreview": true,
"class": "public_preview",
"class": "public",
"builders": {
"image": {
"from": "image:preview"
Expand All @@ -299,6 +314,7 @@ e.g.
},
"thumbnail": {
"useAsThumbnail": true,
"class": "public",
"parent": "preview",
"builders": {
"image": {
Expand All @@ -313,6 +329,7 @@ e.g.
...
```


-------------------

# About Twig
Expand Down
6 changes: 4 additions & 2 deletions databox/indexer/src/handlers/phraseanet/CPhraseanetRecord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ export class CPhraseanetRecord extends CPhraseanetRecordBase {

export class CPhraseanetStory extends CPhraseanetRecordBase {
story_id: string = '';
children: CPhraseanetRecord[] = [];
constructor(s: PhraseanetStory, client: PhraseanetClient) {
super(s, client);
this.story_id = s.story_id;
this.children = s.children.map(r => new CPhraseanetRecord(r, client));
}

async getChildren() {
return this.client.getStoryChildren(this.databox_id, this.story_id);
}
}
88 changes: 44 additions & 44 deletions databox/indexer/src/handlers/phraseanet/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,16 @@ export const phraseanetIndexer: IndexIterator<PhraseanetConfig> =
:
storiesCollectionPath;

const tpath: string[] = splitPath(path);
const storyPathParts: string[] = splitPath(path);
const storyPath = '/' + storyPathParts.join('/');

// create the base
let storyParent: string|undefined = undefined;
if (tpath.length > 0) {
if (storyPathParts.length > 0) {
storyParent = '/collections/' + await databoxClient.createCollectionTreeBranch(
workspaceId,
collectionKeyPrefix,
tpath.map(k => ({
storyPathParts.map(k => ({
key: k,
title: k,
}))
Expand Down Expand Up @@ -195,13 +196,14 @@ export const phraseanetIndexer: IndexIterator<PhraseanetConfig> =
phraseanetDatabox.collections[s.base_id].name
}" (#${s.base_id}) ==> collection (#${storyCollId})`
);
for (const rs of s.children) {
if (recordStories[rs.record_id] === undefined) {
recordStories[rs.record_id] = [];

for await (const child_rid of phraseanetClient.getStoryChildren(s.databox_id, s.story_id)) {
if (recordStories[child_rid] === undefined) {
recordStories[child_rid] = [];
}
recordStories[rs.record_id].push({
recordStories[child_rid].push({
id: storyCollId,
path: tpath.join('/') + '/' + s.title,
path: storyPath + '/' + s.title,
});
}
}
Expand All @@ -218,63 +220,65 @@ export const phraseanetIndexer: IndexIterator<PhraseanetConfig> =
offset,
dm.searchQuery ?? ''
);
for (const r of records) {
for (const record of records) {
logger.info(
`Phraseanet record "${r.title}" (#${
r.record_id
`Phraseanet record "${record.title}" (#${
record.record_id
}) from base "${
phraseanetDatabox.collections[r.base_id].name
}" (#${r.base_id})`
phraseanetDatabox.collections[record.base_id].name
}" (#${record.base_id})`
);

const copyTo = recordStories[r.record_id] ?? [];
const copyTo = recordStories[record.record_id] ?? [];

// copy the asset to other location(s) ?
for (const ct of dm.copyTo ?? []) {
const template = Twig.twig({data: ct});
const paths = (await template.renderAsync({record: r, collection: phraseanetDatabox.collections[r.base_id]}))
const paths = (await template.renderAsync({record: record, collection: phraseanetDatabox.collections[record.base_id]}))
.split('\n')
.map((p: string) => p.trim())
.filter((p: string) => p);

for (const path of paths) {
const branch = splitPath(path);
const collId = await databoxClient.createCollectionTreeBranch(
workspaceId,
collectionKeyPrefix,
branch.map(k => ({
key: k,
title: k,
}))
);
copyTo.push({
id: await databoxClient.createCollectionTreeBranch(
workspaceId,
collectionKeyPrefix,
branch.map(k => ({
key: k,
title: k,
}))
),
id: collId,
path: path,
});
}
}

let path: string = '';
if(recordsCollectionPathTwig !== null) {
path = await recordsCollectionPathTwig.renderAsync({record: r, collection: phraseanetDatabox.collections[r.base_id]});
path = await recordsCollectionPathTwig.renderAsync({record: record, collection: phraseanetDatabox.collections[record.base_id]});
} else {
// bc: dispatch in original phraseanet collection.name
path = `${recordsCollectionPath}/${escapeSlashes(phraseanetDatabox.collections[r.base_id].name)}`;
path = `${recordsCollectionPath}/${escapeSlashes(phraseanetDatabox.collections[record.base_id].name)}`;
}
path += '/' + escapeSlashes(r.original_name);
path += '/' + escapeSlashes(record.original_name);

yield createAsset(
workspaceId,
importFiles,
r,
record,
path,
collectionKeyPrefix,
idempotencePrefixes['asset'] +
r.databox_id +
record.databox_id +
'_' +
r.record_id,
record.record_id,
fieldMap,
tagIndex,
copyTo,
dm.sourceFile,
subdefToRendition,
logger,
);
Expand Down Expand Up @@ -336,6 +340,7 @@ async function importSubdefsStructure(
const sdByName: Record<string, {
name: string;
parent: string | null;
pickSourceFile: boolean;
useAsOriginal: boolean;
useAsPreview: boolean;
useAsThumbnail: boolean;
Expand All @@ -354,18 +359,18 @@ async function importSubdefsStructure(
// import all subdefs from phraseanet
dm['renditions'] = {
"original": {
"from": "document",
"useAsOriginal": true,
"pickSourceFile": true,
"class": "original"
} as ConfigPhraseanetOriginal
};

for(const sd of subdefs) {
if(!dm.renditions[sd.name]) {
dm.renditions[sd.name] = {
parent: null,
class: sd.class,
useAsOriginal: sd.name === 'document',
pickSourceFile: sd.name === 'document',
useAsPreview: sd.name === 'preview',
useAsThumbnail: sd.name === 'thumbnail',
useAsThumbnailActive: sd.name === 'thumbnailgif',
Expand All @@ -386,6 +391,7 @@ async function importSubdefsStructure(
name: name,
parent: 'parent' in rendition ? rendition['parent'] : null,
useAsOriginal: rendition['useAsOriginal'] ?? false,
pickSourceFile: rendition['pickSourceFile'] ?? false,
useAsPreview: rendition['useAsPreview'] ?? false,
useAsThumbnail: rendition['useAsThumbnail'] ?? false,
useAsThumbnailActive: rendition['useAsThumbnailActive'] ?? false,
Expand All @@ -394,10 +400,7 @@ async function importSubdefsStructure(
labels: {},
};
}
if('from' in rendition && rendition['from'] === 'document') {
// phrnet original is not a subdef
continue;
}

for(const [family, settings] of Object.entries('builders' in rendition ? rendition['builders'] : [])) {
if('build' in settings && 'from' in settings) {
logger.error(` Rendition-definition "${name}" for family "${family}": Use "build" OR "from", not both. Rendition definition ignored`);
Expand Down Expand Up @@ -484,7 +487,6 @@ async function importSubdefsStructure(
}
}


if(sd['parent'] && !renditionIdByName[sd['parent']]) {
logger.error(` Parent rendition definition "${sd['parent']}" for "${sd.name}" not found: no parent set. Check declaration order`);
sd['parent'] = null;
Expand All @@ -495,6 +497,7 @@ async function importSubdefsStructure(
parent: sd['parent'] ? `/rendition-definitions/${renditionIdByName[sd['parent']]}` : null,
key: `${idempotencePrefix}${sd.name}`,
class: `/rendition-classes/${classIndex[sd.class]}`,
pickSourceFile: sd.pickSourceFile,
useAsOriginal: sd.useAsOriginal,
useAsPreview: sd.useAsPreview,
useAsThumbnail: sd.useAsThumbnail,
Expand All @@ -506,7 +509,6 @@ async function importSubdefsStructure(
},
definition: jsToYaml(jsConf, 0).trim(),
});

}

return subdefToRendition;
Expand Down Expand Up @@ -864,13 +866,11 @@ function translateVideoSettings_targetImageFrame(sd: PhraseanetSubdefStruct): ob
{
module: 'imagine',
options: {
filters: [
{
thumbnail: {
size: [size, size],
},
filters: {
thumbnail: {
size: [size, size],
},
],
},
},
},
],
Expand All @@ -889,7 +889,7 @@ function translateVideoSettings_targetAnimatedGif(sd: PhraseanetSubdefStruct): o
options: {
'format': 'animated-gif',
'start': 0,
'#0': 'duration: 5',
'duration': 5,
'fps': fps,
'width': size,
'height': size,
Expand Down
Loading

0 comments on commit 78a2081

Please sign in to comment.