Merge branch 'master' into PHRAS-3091-search-on-contains-operator

This commit is contained in:
Nicolas Maillat
2020-05-29 12:17:44 +02:00
committed by GitHub
11 changed files with 246 additions and 115 deletions

44
.env
View File

@@ -14,7 +14,7 @@ MYSQL_ROOT_PASSWORD=root
SERVER_NAME=phraseanet-docker
# --------------- APPLICATION CONFIGURATION --------------------
# --------------- PHP CONFIGURATION --------------------
# Max upload size
MAX_BODY_SIZE=2G
@@ -29,26 +29,41 @@ SESSION_CACHE_LIMITER=off
# PHP LOG LEVEL : Possible Values: alert, error, warning, notice, debug
PHP_LOG_LEVEL=warning
# --------------- APPLICATION STARTUP CONFIGURATION --------------------
# --------------- PHRASEANET CONFIGURATION --------------------
# These variables are only used if the configuration.yml file is not present, in order to automate the installation procedure
# These variables are used in the configuration.yml .
# set here the first user / email couple
INSTALL_ACCOUNT_EMAIL=admin@alchemy.fr
INSTALL_ACCOUNT_PASSWORD=iJRqXU0MwbyJewQLBbra6IWHsWly
PHRASEANET_ADMIN_ACCOUNT_EMAIL=admin@alchemy.fr
PHRASEANET_ADMIN_ACCOUNT_PASSWORD=iJRqXU0MwbyJewQLBbra6IWHsWly
# Database parameters
INSTALL_DB_HOST=db
INSTALL_DB_PORT=3306
INSTALL_DB_USER=root
INSTALL_DB_PASSWORD=root
INSTALL_DB_TEMPLATE=en-simple
PHRASEANET_DB_HOST=db
PHRASEANET_DB_PORT=3306
PHRASEANET_DB_USER=root
PHRASEANET_DB_PASSWORD=root
INSTALL_DB_TEMPLATE=DublinCore
INSTALL_APPBOX=ab_master
INSTALL_DATABOX=db_databox1
INSTALL_SERVER_NAME=localhost
PHRASEANET_SERVER_NAME=localhost
# Mysql max allowed packet
MYSQL_MAX_ALLOWED_PACKET=16M
# api
PHRASEANET_API_ENABLED=true
PHRASEANET_API_SSL=true
# Phraseanet mail configuration
PHRASEANET_EMITTER_EMAIL=phraseanet@example.com
PHRASEANET_MAIL_OBJECT_PREFIX=
PHRASEANET_SMTP_ENABLED=false
PHRASEANET_SMTP_HOST=
PHRASEANET_SMTP_PORT=
PHRASEANET_SMTP_AUTH_ENABLED=false
PHRASEANET_SMTP_SECURE_MODE=tls
PHRASEANET_SMTP_USER=
PHRASEANET_SMTP_PASSWORD=
# --- DEV purpose ---
@@ -63,7 +78,7 @@ PHRASEANET_SUBNET_IPS=172.32.0.0/16
XDEBUG_REMOTE_HOST=172.32.0.1
PHP_IDE_CONFIG=serverName=docker-server-phraseanet
# Volumes location for dev
# Volumes location
PHRASEANET_CONFIG_DIR=./config
PHRASEANET_LOGS_DIR=./logs
PHRASEANET_DATA_DIR=./datas
@@ -73,6 +88,11 @@ PHRASEANET_THUMBNAILS_DIR=./www/thumbnails
PHRASEANET_CUSTOM_DIR=./www/custom
PHRASEANET_TMP_DIR=./tmp
PHRASEANET_CACHE_DIR=./cache
PHRASEANET_DOWNLOAD_DIR=./datas/download
PHRASEANET_LAZARET_DIR=./datas/lazaret
PHRASEANET_CAPTION_DIR=./tmp/caption
PHRASEANET_WORKER_TMP=./tmp/worker
# For dev who don't have SSH_AUTH_SOCK (avoid an empty volume name)

View File

@@ -35,6 +35,7 @@ services:
- ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw
- ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
- ${SSH_AUTH_SOCK}:/ssh-auth-sock
- ${HOME}/.ssh:/home/app/.ssh
- dev_vol:/home/app
@@ -54,6 +55,7 @@ services:
- ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw
- ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
worker:
@@ -65,6 +67,7 @@ services:
- ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw
- ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
rabbitmq:
@@ -75,12 +78,6 @@ services:
volumes:
- ${PHRASEANET_DB_DIR}:/var/lib/mysql:rw
mailhog:
image: mailhog/mailhog
ports:
- 1025:1025
- 8025:8025
elasticsearch:
ports:
- 9200:9200
@@ -121,7 +118,3 @@ networks:
ipam:
config:
- subnet: $PHRASEANET_SUBNET_IPS
volumes:
dev_vol:
driver: local

View File

@@ -11,9 +11,9 @@ services:
image: $PHRASEANET_DOCKER_REGISTRY/phraseanet-nginx:$PHRASEANET_DOCKER_TAG
restart: on-failure
volumes:
- data_vol:/var/alchemy/Phraseanet/datas:rw
- thumbnails_vol:/var/alchemy/Phraseanet/www/thumbnails:rw
- custom_vol:/var/alchemy/Phraseanet/www/custom:rw
- ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw
- ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
depends_on:
- phraseanet
environment:
@@ -42,18 +42,27 @@ services:
- OPCACHE_ENABLED
- SESSION_CACHE_LIMITER
- PHP_LOG_LEVEL
- INSTALL_ACCOUNT_EMAIL
- INSTALL_ACCOUNT_PASSWORD
- INSTALL_DB_HOST
- INSTALL_DB_PORT
- INSTALL_DB_USER
- INSTALL_DB_PASSWORD
- PHRASEANET_ADMIN_ACCOUNT_EMAIL
- PHRASEANET_ADMIN_ACCOUNT_PASSWORD
- PHRASEANET_DB_HOST
- PHRASEANET_DB_PORT
- PHRASEANET_DB_USER
- PHRASEANET_DB_PASSWORD
- INSTALL_DB_TEMPLATE
- INSTALL_APPBOX
- INSTALL_DATABOX
- INSTALL_SERVER_NAME
- INSTALL_RABBITMQ_USER=$RABBITMQ_DEFAULT_USER
- INSTALL_RABBITMQ_PASSWORD=$RABBITMQ_DEFAULT_PASS
- PHRASEANET_SERVER_NAME
- PHRASEANET_RABBITMQ_USER=$RABBITMQ_DEFAULT_USER
- PHRASEANET_RABBITMQ_PASSWORD=$RABBITMQ_DEFAULT_PASS
- PHRASEANET_EMITTER_EMAIL
- PHRASEANET_MAIL_OBJECT_PREFIX
- PHRASEANET_SMTP_ENABLED
- PHRASEANET_SMTP_HOST
- PHRASEANET_SMTP_PORT
- PHRASEANET_SMTP_AUTH_ENABLED
- PHRASEANET_SMTP_SECURE_MODE
- PHRASEANET_SMTP_USER
- PHRASEANET_SMTP_PASSWORD
volumes:
- config_vol:/var/alchemy/Phraseanet/config:rw
- data_vol:/var/alchemy/Phraseanet/datas:rw
@@ -101,7 +110,7 @@ services:
- MYSQL_ROOT_PASSWORD
- MYSQL_MAX_ALLOWED_PACKET
volumes:
- db_vol:/var/lib/mysql
- ${PHRASEANET_DB_DIR}:/var/lib/mysql
rabbitmq:
image: rabbitmq:3-management
@@ -119,7 +128,13 @@ services:
build: ./docker/elasticsearch
restart: on-failure
volumes:
- elasticsearch_vol:/usr/share/elasticsearch/data
- ${PHRASEANET_ELASTICSEARCH_DIR}:/usr/share/elasticsearch/data
mailhog:
image: mailhog/mailhog
ports:
- 1025:1025
- 8025:8025
volumes:
config_vol:
@@ -141,3 +156,5 @@ volumes:
# to be replacer by stdout/stderr
logs_vol:
driver: local
dev_vol:
driver: local

View File

@@ -2,29 +2,41 @@
set -xe
if [ -z "$INSTALL_ACCOUNT_EMAIL" ]; then
echo "INSTALL_ACCOUNT_EMAIL var is not set."
if [ -z "$PHRASEANET_ADMIN_ACCOUNT_EMAIL" ]; then
echo "PHRASEANET_ADMIN_ACCOUNT_EMAIL, Phraseanet admin account var is not set."
exit 1
fi
if [ -z "$INSTALL_ACCOUNT_PASSWORD" ]; then
echo "INSTALL_ACCOUNT_PASSWORD var is not set."
if [ -z "$PHRASEANET_ADMIN_ACCOUNT_PASSWORD " ]; then
echo "$PHRASEANET_ADMIN_ACCOUNT_PASSWORD, Phaseanet admin password var is not set."
exit 1
fi
/var/alchemy/Phraseanet/bin/setup system:install \
--email=$INSTALL_ACCOUNT_EMAIL \
--password=$INSTALL_ACCOUNT_PASSWORD \
--db-host=$INSTALL_DB_HOST \
--db-port=$INSTALL_DB_PORT \
--db-user=$INSTALL_DB_USER \
--db-password=$INSTALL_DB_PASSWORD \
--email=$PHRASEANET_ADMIN_ACCOUNT_EMAIL \
--password=$PHRASEANET_ADMIN_ACCOUNT_PASSWORD \
--db-host=$PHRASEANET_DB_HOST \
--db-port=$PHRASEANET_DB_PORT \
--db-user=$PHRASEANET_DB_USER \
--db-password=$PHRASEANET_DB_PASSWORD \
--db-template=$INSTALL_DB_TEMPLATE \
--appbox=$INSTALL_APPBOX \
--databox=$INSTALL_DATABOX \
--server-name=$INSTALL_SERVER_NAME \
--server-name=$PHRASEANET_SERVER_NAME \
--download-path=$PHRASEANET_DOWNLOAD_DIR \
--lazaret-path=$PHRASEANET_LAZARET_DIR \
--caption-path=$PHRASEANET_CAPTION_DIR \
--worker-tmp-files=$PHRASEANET_WORKER_TMP \
--data-path=/var/alchemy/Phraseanet/datas -y
# Bus configuration for scheduler & worker
bin/setup system:config set workers.queue.worker-queue.registry alchemy_worker.queue_registry
bin/setup system:config set workers.queue.worker-queue.host rabbitmq
bin/setup system:config set workers.queue.worker-queue.port 5672
bin/setup system:config set workers.queue.worker-queue.user $PHRASEANET_RABBITMQ_USER
bin/setup system:config set workers.queue.worker-queue.password $PHRASEANET_RABBITMQ_PASSWORD
bin/setup system:config set workers.queue.worker-queue.vhost /
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.host elasticsearch
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.minScore 2
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.minScore 2
@@ -38,22 +50,19 @@ fi
/var/alchemy/Phraseanet/bin/setup system:config set main.cache.options.namespace $INSTALL_SERVER_NAME
/var/alchemy/Phraseanet/bin/setup system:config set main.cache.type redis
# Bus configuration for scheduler & worker
bin/setup system:config set workers.queue.worker-queue.registry alchemy_worker.queue_registry
bin/setup system:config set workers.queue.worker-queue.host rabbitmq
bin/setup system:config set workers.queue.worker-queue.port 5672
bin/setup system:config set workers.queue.worker-queue.user $INSTALL_RABBITMQ_USER
bin/setup system:config set workers.queue.worker-queue.password $INSTALL_RABBITMQ_PASSWORD
bin/setup system:config set workers.queue.worker-queue.vhost /
# Create elasticsearch index
/var/alchemy/Phraseanet/bin/console searchengine:index -c
## enable API and disable ssl on it
/var/alchemy/Phraseanet/bin/setup system:config set registry.api-clients.api-enabled true
/var/alchemy/Phraseanet/bin/setup system:config set main.api_require_ssl false
/var/alchemy/Phraseanet/bin/setup system:config set registry.api-clients.api-enabled $PHRASEANET_API_ENABLED
/var/alchemy/Phraseanet/bin/setup system:config set main.api_require_ssl $PHRASEANET_API_SSL
# set instance title
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
/var/alchemy/Phraseanet/bin/console compile:configuration
# Create elasticsearch index
/var/alchemy/Phraseanet/bin/console searchengine:index -c
# Create _TRASH_ collection on first databox
/var/alchemy/Phraseanet/bin/console collection:create 1 Public -d 1
/var/alchemy/Phraseanet/bin/console collection:create 1 Private -d 1
/var/alchemy/Phraseanet/bin/console collection:create 1 _TRASH_ -d 1

View File

@@ -18,8 +18,20 @@ chown -R app:app \
FILE=config/configuration.yml
if [ -f "$FILE" ]; then
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
echo "$FILE exists, skip setup."
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
if [[ $PHRASEANET_SMTP_ENABLED=true ]]; then
bin/setup system:config set registry.email.smtp-enabled $PHRASEANET_SMTP_ENABLED
bin/setup system:config set registry.email.smtp-auth-enabled $PHRASEANET_SMTP_AUTH_ENABLED
bin/setup system:config set registry.email.smtp-auth-secure-mode $PHRASEANET_SMTP_SECURE_MODE
bin/setup system:config set registry.email.smtp-auth-host $PHRASEANET_SMTP_HOST
bin/setup system:config set registry.email.smtp-auth-port $PHRASEANET_SMTP_PORT
bin/setup system:config set registry.email.smtp-user $PHRASEANET_SMTP_USER
bin/setup system:config set registry.email.smtp-password $PHRASEANET_SMTP_PASSWORD
bin/setup system:config set registry.email.emitter-email $PHRASEANET_EMITTER_EMAIL
bin/setup system:config set registry.email.prefix $PHRASEANET_MAIL_OBJECT_PREFIX
fi
bin/console user:password --user_id=1 --password $PHRASEANET_ADMIN_ACCOUNT_PASSWORD -y
else
echo "$FILE doesn't exist, entering setup..."
runuser app -c docker/phraseanet/auto-install.sh

View File

@@ -102,4 +102,12 @@ class WorkerRunningJobRepository extends EntityRepository
{
return parent::getEntityManager();
}
public function reconnect()
{
if($this->_em->getConnection()->ping() === false) {
$this->_em->getConnection()->close();
$this->_em->getConnection()->connect();
}
}
}

View File

@@ -101,6 +101,9 @@ class RecordSubscriber implements EventSubscriberInterface
$repoWorker = $this->getRepoWorker();
$em = $repoWorker->getEntityManager();
// check connection an re-connect if needed
$repoWorker->reconnect();
$workerRunningJob = $repoWorker->findOneBy([
'databoxId' => $event->getRecord()->getDataboxId(),
'recordId' => $event->getRecord()->getRecordId(),
@@ -108,6 +111,7 @@ class RecordSubscriber implements EventSubscriberInterface
'workOn' => $event->getSubdefName()
]);
if ($workerRunningJob) {
$em->beginTransaction();
try {
$em->remove($workerRunningJob);
@@ -116,6 +120,7 @@ class RecordSubscriber implements EventSubscriberInterface
} catch (\Exception $e) {
$em->rollback();
}
}
$this->messagePublisher->publishMessage(
$payload,
@@ -223,6 +228,9 @@ class RecordSubscriber implements EventSubscriberInterface
$repoWorker = $this->getRepoWorker();
$em = $repoWorker->getEntityManager();
// check connection an re-connect if needed
$repoWorker->reconnect();
$workerRunningJob = $repoWorker->findOneBy([
'databoxId' => $event->getRecord()->getDataboxId(),
'recordId' => $event->getRecord()->getRecordId(),
@@ -230,6 +238,7 @@ class RecordSubscriber implements EventSubscriberInterface
'workOn' => $event->getSubdefName()
]);
if ($workerRunningJob) {
$em->beginTransaction();
try {
$em->remove($workerRunningJob);
@@ -238,6 +247,7 @@ class RecordSubscriber implements EventSubscriberInterface
} catch (\Exception $e) {
$em->rollback();
}
}
$this->messagePublisher->publishMessage(
$payload,

View File

@@ -81,6 +81,7 @@ class SubdefCreationWorker implements WorkerInterface
// tell that a file is in used to create subdef
$em = $this->repoWorker->getEntityManager();
$this->repoWorker->reconnect();
$em->beginTransaction();
try {
@@ -108,14 +109,28 @@ class SubdefCreationWorker implements WorkerInterface
try {
$this->subdefGenerator->generateSubdefs($record, $wantedSubdef);
} catch (\Exception $e) {
$em->beginTransaction();
try {
$this->repoWorker->reconnect();
$em->getConnection()->beginTransaction();
$em->remove($workerRunningJob);
$em->flush();
$em->commit();
} catch (\Exception $e) {
$em->rollback();
}
} catch (\Throwable $e) {
$count = isset($payload['count']) ? $payload['count'] + 1 : 2 ;
$workerMessage = "Exception throwable catched when create subdef for the recordID: " .$recordId;
$this->logger->error($workerMessage);
$this->dispatcher->dispatch(WorkerEvents::SUBDEFINITION_CREATION_FAILURE, new SubdefinitionCreationFailureEvent(
$record,
$payload['subdefName'],
$workerMessage,
$count
));
return ;
}
// begin to check if the subdef is successfully generated
@@ -170,7 +185,8 @@ class SubdefCreationWorker implements WorkerInterface
$this->indexer->flushQueue();
// tell that we have finished to work on this file
$em->beginTransaction();
$this->repoWorker->reconnect();
$em->getConnection()->beginTransaction();
try {
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
$workerRunningJob->setFinished(new \DateTime('now'));
@@ -178,8 +194,18 @@ class SubdefCreationWorker implements WorkerInterface
$em->flush();
$em->commit();
} catch (\Exception $e) {
try {
$em->getConnection()->beginTransaction();
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
$em->persist($workerRunningJob);
$em->flush();
$em->commit();
} catch (\Exception $e) {
$this->messagePublisher->pushLog("rollback on recordID :" . $workerRunningJob->getRecordId());
$em->rollback();
}
}
}
}
}

View File

@@ -82,6 +82,7 @@ class WriteMetadatasWorker implements WorkerInterface
// tell that a file is in used to create subdef
$em = $this->getEntityManager();
$this->repoWorker->reconnect();
$em->beginTransaction();
try {
@@ -106,7 +107,24 @@ class WriteMetadatasWorker implements WorkerInterface
$record = $databox->get_record($recordId);
try {
$subdef = $record->get_subdef($payload['subdefName']);
} catch (\Exception $e) {
$workerMessage = "Exception catched when try to get subdef " .$payload['subdefName']. " from DB for the recordID: " .$recordId;
$this->logger->error($workerMessage);
$count = isset($payload['count']) ? $payload['count'] + 1 : 2 ;
$this->dispatch(WorkerEvents::SUBDEFINITION_WRITE_META, new SubdefinitionWritemetaEvent(
$record,
$payload['subdefName'],
SubdefinitionWritemetaEvent::FAILED,
$workerMessage,
$count
));
return ;
}
if ($subdef->is_physically_present()) {
$metadata = new MetadataBag();
@@ -245,6 +263,7 @@ class WriteMetadatasWorker implements WorkerInterface
// tell that we have finished to work on this file
$this->repoWorker->reconnect();
$em->beginTransaction();
try {
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);

View File

@@ -48,7 +48,7 @@ main:
_doctype:
limit: 10
_camera_model:
limit: 0
limit: 10
_iso:
limit: 0
_aperture:
@@ -159,7 +159,7 @@ border-manager:
type: Checker\MediaType
enabled: false
options:
mediatypes: [Audio, Document, Flash, Image, Video]
mediatypes: [Audio, Document, Image, Video]
user_account:
deleting_policies:
email_confirmation: true
@@ -244,7 +244,7 @@ embed_bundle:
video:
player: videojs
autoplay: false
cover_subdef: thumbnail
cover_subdef: poster
message_start: StartOfMessage
available_speeds:
- 1

View File

@@ -8,7 +8,7 @@
<size>1024</size>
<method>resample</method>
<dpi>72</dpi>
<strip>no</strip>
<strip>yes</strip>
<quality>75</quality>
<meta>yes</meta>
<devices>screen</devices>
@@ -90,6 +90,21 @@
<label lang="fr">Prévisualisation</label>
<label lang="en">Preview</label>
</subdef>
<subdef class="preview" name="poster" downloadable="true">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<meta>1</meta>
<size>1280</size>
<mediatype>image</mediatype>
<writeDatas>yes</writeDatas>
<devices>screen</devices>
<dpi>72</dpi>
<strip>yes</strip>
<flatten>yes</flatten>
<quality>75</quality>
<icodec>jpeg</icodec>
<label lang="fr">Poster video</label>
<label lang="en">Poster video</label>
</subdef>
<subdef class="preview" name="preview_webm" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<size>748</size>
@@ -102,8 +117,30 @@
<fps>25</fps>
<GOPsize>25</GOPsize>
<vcodec>libvpx</vcodec>
<label lang="fr">Prévisualisation WebM</label>
<label lang="en">WebM Preview</label>
</subdef>
<subdef class="preview" name="audiovideowav" downloadable="true" orderable="true" presets="Wave Mono 8 kHz">
<path>{{datapathnoweb}}{{basename}}/subview</path>
<meta>no</meta>
<mediatype>audio</mediatype>
<audiobitrate>128</audiobitrate>
<audiosamplerate>8000</audiosamplerate>
<acodec>pcm_s16le</acodec>
<audiochannel>mono</audiochannel>
<devices>all</devices>
<label lang="fr">Audio WAVE 8 kHz</label>
<label lang="en">Audio WAVE 8 kHz</label>
</subdef>
<subdef class="preview" name="audiovideomp3" downloadable="true" orderable="true" presets="Normal MP3 128 kbit/s">
<path>{{datapathnoweb}}{{basename}}/subview</path>
<meta>no</meta>
<mediatype>audio</mediatype>
<audiobitrate>180</audiobitrate>
<audiosamplerate>44100</audiosamplerate>
<acodec>libmp3lame</acodec>
<audiochannel/>
<devices>all</devices>
<label lang="fr">Audio MP3 128 kbit/s</label>
<label lang="en">Audio MP3 128 kbit/s</label>
</subdef>
</subdefgroup>
<subdefgroup name="audio">
@@ -155,30 +192,6 @@
<label lang="en">Preview</label>
</subdef>
</subdefgroup>
<subdefgroup name="flash">
<subdef class="thumbnail" name="thumbnail" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>image</mediatype>
<size>240</size>
<writeDatas>no</writeDatas>
<method>resample</method>
<dpi>72</dpi>
<devices>screen</devices>
<label lang="fr">Vignette</label>
<label lang="en">Thumbnail</label>
</subdef>
<subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>image</mediatype>
<size>800</size>
<writeDatas>no</writeDatas>
<method>resample</method>
<dpi>72</dpi>
<devices>screen</devices>
<label lang="fr">Prévisualisation</label>
<label lang="en">Preview</label>
</subdef>
</subdefgroup>
</subdefs>
<description>
@@ -199,9 +212,13 @@
<Rights src="XMP-dc:Rights" type="string" report="0" />
<Comments src="" business="1" type="string" report="0" />
<Filename src="Phraseanet:tf-basename" readonly="1" type="string" report="1"/>
<CameraDevice src="IFD0:Model" type="string" readonly="1" report="0" />
<Latitude src="GPS:GPSLatitude" type="number" readonly="1" report="0" />
<Longitude src="GPS:GPSLongitude" type="number" readonly="1" report="0"/>
<Latitude src="Composite:GPSLatitude" type="number" readonly="1" report="0" />
<Longitude src="Composite:GPSLongitude" type="number" readonly="1" report="0"/>
<StartOfMessage src="Phraseanet:no-source" readonly="0" required="0" multi="0" report="0" business="0" aggregable="0" type="number" gui_editable="1" gui_visible="1"/>
<VideoTextTrackChapters src="Phraseanet:no-source" readonly="0" required="0" multi="0" report="0" business="0" aggregable="0" type="string" gui_editable="0" gui_visible="0"/>
<VideoTextTrackFr src="Phraseanet:no-source" readonly="0" required="0" multi="0" report="0" business="0" aggregable="0" type="string" gui_editable="1" gui_visible="0"/>
<VideoTextTrackEn src="Phraseanet:no-source" readonly="0" required="0" multi="0" report="0" business="0" aggregable="0" type="string" gui_editable="1" gui_visible="0"/>
<VideoTextTrackDe src="Phraseanet:no-source" readonly="0" required="0" multi="0" report="0" business="0" aggregable="0" type="string" gui_editable="1" gui_visible="0"/>
<ArchiveDate src="Phraseanet:tf-archivedate" readonly="1" type="date" report="0" />
<LastEditDate src="Phraseanet:tf-editdate" readonly="1" type="date" report="0" />
</description>