├── .gitignore ├── .gitattributes ├── Resources ├── views │ ├── Media │ │ ├── RemoteAudio │ │ │ ├── show.html.twig │ │ │ └── preview.html.twig │ │ ├── RemoteSlide │ │ │ ├── show.html.twig │ │ │ └── preview.html.twig │ │ ├── RemoteVideo │ │ │ ├── show.html.twig │ │ │ └── preview.html.twig │ │ ├── File │ │ │ └── show.html.twig │ │ ├── Image │ │ │ ├── aviary.html.twig │ │ │ └── show.html.twig │ │ ├── delete-modal.html.twig │ │ ├── addType-modal.html.twig │ │ ├── create.html.twig │ │ └── bulkUpload.html.twig │ ├── Default │ │ └── layout.html.twig │ ├── AdminList │ │ └── ItemAction │ │ │ └── select.html.twig │ ├── Folder │ │ ├── bulk-move-modal.html.twig │ │ ├── foldertreeview.html.twig │ │ ├── bulk-move-modal_form.html.twig │ │ ├── breadcrumbs.html.twig │ │ ├── addsub-modal.html.twig │ │ ├── delete-modal.html.twig │ │ └── empty-modal.html.twig │ ├── Chooser │ │ ├── chooserShowRecTreeView.html.twig │ │ └── breadcrumbs.html.twig │ ├── IconFont │ │ └── iconFontChooser.html.twig │ └── Form │ │ └── _focus-point-block.html.twig ├── ui │ └── js │ │ ├── app.js │ │ ├── _bulk-move.js │ │ ├── _dnd-upload.js │ │ └── _bulk-upload.js ├── config │ ├── imagine.xml │ ├── routing.yml │ ├── imagine_filters.yml │ ├── pdf_preview.yml │ └── handlers.yml ├── doc │ └── MediaBundle.md └── translations │ ├── messages.es.yml │ ├── messages.pl.yml │ ├── messages.hu.yml │ ├── messages.it.yml │ └── messages.fr.yml ├── Helper ├── IconFont │ ├── IconFontLoaderInterface.php │ ├── AbstractIconFontLoader.php │ ├── IconFontManager.php │ └── DefaultIconFontLoader.php ├── MimeTypeGuesserFactoryInterface.php ├── ExtensionGuesserFactoryInterface.php ├── Transformer │ ├── PreviewTransformerInterface.php │ └── PdfTransformer.php ├── RemoteAudio │ ├── RemoteAudioHelper.php │ └── RemoteAudioHandler.php ├── RemoteSlide │ └── RemoteSlideHelper.php ├── RemoteVideo │ └── RemoteVideoHelper.php ├── Imagine │ ├── BackgroundFilterLoader.php │ ├── ImagineController.php │ ├── WebPathResolver.php │ └── CacheManager.php ├── File │ ├── SVGExtensionGuesser.php │ ├── SVGMimeTypeGuesser.php │ └── PdfHandler.php ├── MimeTypeGuesserFactory.php ├── ExtensionGuesserFactory.php ├── FolderManager.php ├── Remote │ ├── RemoteInterface.php │ └── AbstractRemoteHelper.php ├── Media │ └── AbstractMediaHandler.php ├── Services │ └── MediaCreatorService.php ├── Menu │ └── MediaMenuAdaptor.php ├── Image │ └── ImageHandler.php ├── ManipulateImageService.php └── MediaManager.php ├── Changelog.md ├── Validator └── Constraints │ ├── HasGuessableExtension.php │ ├── Media.php │ └── HasGuessableExtensionValidator.php ├── Form ├── Type │ ├── CurrentValueContainer.php │ ├── IconFontType.php │ ├── IdToMediaTransformer.php │ └── MediaType.php ├── BulkUploadType.php ├── BulkMoveMediaType.php ├── RemoteSlide │ └── RemoteSlideType.php ├── RemoteAudio │ └── RemoteAudioType.php ├── RemoteVideo │ └── RemoteVideoType.php ├── EditableMediaWrapperAdminType.php ├── FolderType.php └── AbstractRemoteType.php ├── KunstmaanMediaBundle.php ├── Utils └── SymfonyVersion.php ├── AdminList └── ItemAction │ ├── MediaSelectItemAction.php │ ├── MediaEditItemAction.php │ └── MediaDeleteItemAction.php ├── Controller ├── IconFontController.php └── AviaryController.php ├── LICENSE ├── Repository └── MediaRepository.php ├── UPGRADE.md ├── Entity └── EditableMediaWrapper.php ├── Twig └── MediaTwigExtension.php ├── DependencyInjection └── Compiler │ ├── MediaHandlerCompilerPass.php │ └── DeprecateClassParametersPass.php ├── composer.json ├── Command ├── RebuildFolderTreeCommand.php ├── CleanDeletedMediaCommand.php └── CreatePdfPreviewCommand.php ├── README.md ├── EventListener └── DoctrineMediaListener.php └── DataFixtures └── ORM └── FolderFixtures.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | composer.phar 3 | vendor/* 4 | *~ 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /Tests export-ignore 2 | /phpunit.xml.dist export-ignore 3 | -------------------------------------------------------------------------------- /Resources/views/Media/RemoteAudio/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Media/show.html.twig' %} 2 | 3 | {% block preview %} 4 | {% include '@KunstmaanMedia/Media/RemoteAudio/preview.html.twig' with {'media': media} %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /Resources/views/Media/RemoteSlide/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Media/show.html.twig' %} 2 | 3 | {% block preview %} 4 | {% include '@KunstmaanMedia/Media/RemoteSlide/preview.html.twig' with {'media': media} %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /Resources/views/Media/RemoteVideo/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Media/show.html.twig' %} 2 | 3 | {% block preview %} 4 | {% include '@KunstmaanMedia/Media/RemoteVideo/preview.html.twig' with {'media': media} %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /Helper/IconFont/IconFontLoaderInterface.php: -------------------------------------------------------------------------------- 1 | 5 | {% embed "@KunstmaanAdmin/Default/_js_footer.html.twig" %} 6 | {% block extra_async_javascripts %} 7 | {{ parent() }} 8 | '{{ asset('bundles/kunstmaanmedia/js/media-bundle.min.js') }}', 9 | {% endblock %} 10 | {% endembed %} 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /Helper/MimeTypeGuesserFactoryInterface.php: -------------------------------------------------------------------------------- 1 | rootPath = $kernel->getProjectDir(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Resources/ui/js/app.js: -------------------------------------------------------------------------------- 1 | var kunstmaanMediaBundle = kunstmaanMediaBundle || {}; 2 | 3 | kunstmaanMediaBundle.app = (function($, window, undefined) { 4 | 5 | var init; 6 | 7 | init = function() { 8 | kunstmaanMediaBundle.bulkUpload.init(); 9 | kunstmaanMediaBundle.bulkMove.init(); 10 | kunstmaanMediaBundle.dndUpload.init(); 11 | }; 12 | 13 | return { 14 | init: init 15 | }; 16 | 17 | }(jQuery, window)); 18 | 19 | $(function() { 20 | kunstmaanMediaBundle.app.init(); 21 | }); 22 | -------------------------------------------------------------------------------- /Resources/views/AdminList/ItemAction/select.html.twig: -------------------------------------------------------------------------------- 1 | {% set mediaHandler = mediamanager.getHandler(item) %} 2 | {% set thumbnailurl = mediaHandler.getImageUrl(item, app.request.basePath) %} 3 | 4 | {% set cke = (app.request and app.request.get('CKEditorFuncNum')) %} 5 | {% set path = "[%s]" | format("M" ~ item.id) %} 6 | 7 | Select 8 | 9 | 10 | -------------------------------------------------------------------------------- /Validator/Constraints/HasGuessableExtension.php: -------------------------------------------------------------------------------- 1 | 'NOT_GUESSABLE_ERROR', 16 | ]; 17 | 18 | public $notGuessableErrorMessage = 'The uploaded file has no extension and could not be automatically guessed by the system.'; 19 | } 20 | -------------------------------------------------------------------------------- /Form/Type/CurrentValueContainer.php: -------------------------------------------------------------------------------- 1 | currentValue; 21 | } 22 | 23 | /** 24 | * @param object $currentValue 25 | */ 26 | public function setCurrentValue($currentValue) 27 | { 28 | $this->currentValue = $currentValue; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Resources/views/Media/RemoteSlide/preview.html.twig: -------------------------------------------------------------------------------- 1 | {% set handler = mediamanager.getHandler(media) %} 2 | {% set helper = handler.getFormHelper(media) %} 3 | 4 | {% if helper.type == 'slideshare' %} 5 |
6 | 7 |
8 | {{ media.name }} 9 |
10 |
11 | {% endif %} 12 | -------------------------------------------------------------------------------- /Helper/Transformer/PreviewTransformerInterface.php: -------------------------------------------------------------------------------- 1 | media->setContentType(RemoteAudioHandler::CONTENT_TYPE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Helper/RemoteSlide/RemoteSlideHelper.php: -------------------------------------------------------------------------------- 1 | media->setContentType(RemoteSlideHandler::CONTENT_TYPE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Helper/RemoteVideo/RemoteVideoHelper.php: -------------------------------------------------------------------------------- 1 | media->setContentType(RemoteVideoHandler::CONTENT_TYPE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Resources/views/Folder/bulk-move-modal.html.twig: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /Resources/views/Media/RemoteAudio/preview.html.twig: -------------------------------------------------------------------------------- 1 | {% set handler = mediamanager.getHandler(media) %} 2 | {% set helper = handler.getFormHelper(media) %} 3 | 4 | {% if helper.type is defined and helper.type == 'soundcloud' %} 5 |
6 | 7 |
8 | {% elseif 'audio' in media.contentType %} 9 | 12 | {% endif %} 13 | -------------------------------------------------------------------------------- /Resources/views/Media/File/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Media/show.html.twig' %} 2 | 3 | {% block extraactions %} 4 | 5 | {{ 'media.media.download.action'|trans }} 6 | 7 | {% endblock %} 8 | 9 | {% block preview %}{% endblock %} 10 | 11 | {% block mediainfo %} 12 | {{ parent() }} 13 |
14 | {{ 'media.media.mediainfo.downloadlink'|trans }}: 15 |
16 |
17 | {% set mediaUrl = media.url %} 18 | 19 | {{ absolute_url(asset(mediaUrl)) }} 20 | 21 |
22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /Helper/Imagine/BackgroundFilterLoader.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ mediaFolder.name }} 4 | 5 | {% if mediaFolder.__children is not empty %} 6 | 11 | {% endif %} 12 | 13 | -------------------------------------------------------------------------------- /Resources/views/Folder/foldertreeview.html.twig: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | {{ mediaFolder.name }} 4 | 5 | 6 | {% if mediaFolder.__children is not empty %} 7 | 12 | {% endif %} 13 |
  • 14 | -------------------------------------------------------------------------------- /Resources/views/IconFont/iconFontChooser.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanAdmin/Default/layout.html.twig' %} 2 | 3 | {% block extracss %} 4 | 5 | {% endblock %} 6 | 7 | {% block extraparamsinbody %} 8 | id="smallWindow" 9 | {% endblock %} 10 | 11 | {% block body %} 12 |
    13 | 14 |
    15 | {% for class in loader.cssClasses %} 16 |
    17 | {% endfor %} 18 |
    19 |
    20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /Resources/views/Folder/bulk-move-modal_form.html.twig: -------------------------------------------------------------------------------- 1 | {% form_theme form '@KunstmaanAdmin/Form/fields.html.twig' %} 2 | 3 | {{ form_start(form, {'method': 'POST', 'action': path('KunstmaanMediaBundle_media_bulk_move'), 'attr': {'id': 'bulk-move-modal-form'}}) }} 4 | 5 | 6 | 10 | 11 | 12 | 20 | {{ form_end(form) }} 21 | -------------------------------------------------------------------------------- /KunstmaanMediaBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new MediaHandlerCompilerPass()); 23 | $container->addCompilerPass(new DeprecateClassParametersPass()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Resources/views/Folder/breadcrumbs.html.twig: -------------------------------------------------------------------------------- 1 | {% set breadcrumbitems = foldermanager.getParents(folder) %} 2 | {% if breadcrumbitems | length > 0 %} 3 | 19 | {% endif %} 20 | -------------------------------------------------------------------------------- /Resources/views/Chooser/breadcrumbs.html.twig: -------------------------------------------------------------------------------- 1 | {% set breadcrumbitems = foldermanager.getParents(folder) %} 2 | {% if breadcrumbitems | length > 0 %} 3 | 19 | {% endif %} 20 | -------------------------------------------------------------------------------- /Helper/File/SVGExtensionGuesser.php: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Utils/SymfonyVersion.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | {% elseif helper.type == 'vimeo' %} 8 |
    9 | 10 |
    11 | {% elseif helper.type == 'dailymotion' %} 12 |
    13 | 14 |
    15 | {% endif %} 16 | -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | KunstmaanMediaBundle_media: 2 | resource: '@KunstmaanMediaBundle/Controller/MediaController.php' 3 | type: annotation 4 | prefix: /%kunstmaan_admin.admin_prefix%/media 5 | 6 | KunstmaanMediaBundle_aviary: 7 | resource: '@KunstmaanMediaBundle/Controller/AviaryController.php' 8 | type: annotation 9 | prefix: / 10 | 11 | KunstmaanMediaBundle_media_chooser: 12 | resource: '@KunstmaanMediaBundle/Controller/ChooserController.php' 13 | type: annotation 14 | prefix: /%kunstmaan_admin.admin_prefix%/media 15 | 16 | KunstmaanMediaBundle_media_folder: 17 | resource: '@KunstmaanMediaBundle/Controller/FolderController.php' 18 | type: annotation 19 | prefix: /%kunstmaan_admin.admin_prefix%/media/folder 20 | 21 | KunstmaanMediaBundle_icon_font: 22 | resource: '@KunstmaanMediaBundle/Controller/IconFontController.php' 23 | type: annotation 24 | prefix: /%kunstmaan_admin.admin_prefix%/media/icon-font 25 | -------------------------------------------------------------------------------- /AdminList/ItemAction/MediaSelectItemAction.php: -------------------------------------------------------------------------------- 1 | register(new SVGMimeTypeGuesser()); 25 | 26 | return $guesser; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Resources/config/imagine_filters.yml: -------------------------------------------------------------------------------- 1 | liip_imagine: 2 | resolvers: 3 | default: 4 | web_path: 5 | cache_prefix: uploads/cache 6 | driver: imagick 7 | data_loader: default 8 | filter_sets: 9 | media_list_thumbnail: 10 | quality: 75 11 | filters: 12 | auto_rotate: ~ 13 | thumbnail: { size: [210, 150], mode: outbound } 14 | relative_resize: { widen: 210 } 15 | media_list_thumbnail_retina: 16 | quality: 85 17 | filters: 18 | auto_rotate: ~ 19 | thumbnail: { size: [420, 300], mode: outbound } 20 | relative_resize: { widen: 420 } 21 | media_detail_thumbnail: 22 | quality: 75 23 | filters: 24 | auto_rotate: ~ 25 | thumbnail: { size: [700, 500], mode: inset } 26 | optim: 27 | quality: 85 28 | format: jpg 29 | filters: 30 | strip: ~ 31 | -------------------------------------------------------------------------------- /Resources/views/Media/Image/aviary.html.twig: -------------------------------------------------------------------------------- 1 | {% deprecated 'The "' ~ _self ~ '" template is deprecated since kunstmaanMediaBundle 5.7 and will be removed in kunstmaanMediaBundle 6.0. The aviary service is discontinued.' %} 2 | 3 | 4 | 5 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /Helper/ExtensionGuesserFactory.php: -------------------------------------------------------------------------------- 1 | register(new SVGExtensionGuesser()); 25 | 26 | return $guesser; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdminList/ItemAction/MediaEditItemAction.php: -------------------------------------------------------------------------------- 1 | 'KunstmaanMediaBundle_media_show', 18 | 'params' => ['mediaId' => $item->getId()], 19 | ]; 20 | } 21 | 22 | /** 23 | * @param mixed $item 24 | * 25 | * @return string 26 | */ 27 | public function getLabelFor($item) 28 | { 29 | return 'Edit'; 30 | } 31 | 32 | /** 33 | * @param mixed $item 34 | * 35 | * @return string 36 | */ 37 | public function getIconFor($item) 38 | { 39 | return 'edit'; 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function getTemplate() 46 | { 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Controller/IconFontController.php: -------------------------------------------------------------------------------- 1 | query->get('loader'); 24 | $loaderData = json_decode($request->query->get('loader_data'), true); 25 | 26 | $iconFontManager = $this->get('kunstmaan_media.icon_font_manager'); 27 | if (empty($loader)) { 28 | $loader = $iconFontManager->getDefaultLoader(); 29 | } else { 30 | $loader = $iconFontManager->getLoader($loader); 31 | } 32 | $loader->setData($loaderData); 33 | 34 | return [ 35 | 'loader' => $loader, 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Original Copyright (c) 2010 thomas.rabaix@sonata-project.org 4 | Portions are Copyright (c) 2010 Benjamin Dulau 5 | Portions are Copyright (c) 2012 Kunstmaan (http://www.kunstmaan.be) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Helper/IconFont/IconFontManager.php: -------------------------------------------------------------------------------- 1 | loaders[$serviceId] = $loader; 26 | } 27 | 28 | public function setDefaultLoader(IconFontLoaderInterface $loader) 29 | { 30 | $this->defaultLoader = $loader; 31 | } 32 | 33 | /** 34 | * @param string $serviceId 35 | * 36 | * @return IconFontLoaderInterface 37 | */ 38 | public function getLoader($serviceId) 39 | { 40 | return $this->loaders[$serviceId]; 41 | } 42 | 43 | /** 44 | * @return IconFontLoaderInterface[] 45 | */ 46 | public function getLoaders() 47 | { 48 | return $this->loaders; 49 | } 50 | 51 | /** 52 | * @return IconFontLoaderInterface|null 53 | */ 54 | public function getDefaultLoader() 55 | { 56 | return $this->defaultLoader; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Resources/config/pdf_preview.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | kunstmaan_media.pdf_transformer.class: 'Kunstmaan\MediaBundle\Helper\Transformer\PdfTransformer' 3 | kunstmaan_media.media_handler.pdf.class: 'Kunstmaan\MediaBundle\Helper\File\PdfHandler' 4 | 5 | services: 6 | kunstmaan_media.imagick: 7 | class: 'Imagick' 8 | 9 | kunstmaan_media.pdf_transformer: 10 | class: '%kunstmaan_media.pdf_transformer.class%' 11 | arguments: ['@kunstmaan_media.imagick'] 12 | 13 | kunstmaan_media.media_handlers.pdf: 14 | class: '%kunstmaan_media.media_handler.pdf.class%' 15 | parent: kunstmaan_media.media_handlers.file 16 | arguments: [1, '@mime_types'] 17 | calls: 18 | - [ setMediaPath, [ '%kernel.project_dir%' ] ] 19 | - [ setPdfTransformer, [ '@kunstmaan_media.pdf_transformer' ]] 20 | tags: 21 | - { name: 'kunstmaan_media.media_handler' } 22 | 23 | kunstmaan_media.command.createpdfpreview: 24 | class: Kunstmaan\MediaBundle\Command\CreatePdfPreviewCommand 25 | arguments: 26 | - '@doctrine.orm.entity_manager' 27 | - '@kunstmaan_media.pdf_transformer' 28 | - '%kunstmaan_media.web_root%' 29 | - '%kunstmaan_media.enable_pdf_preview%' 30 | tags: 31 | - { name: console.command } 32 | -------------------------------------------------------------------------------- /Resources/views/Media/Image/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Media/File/show.html.twig' %} 2 | 3 | {% block extraactions %} 4 | 5 | {% if handler.aviaryApiKey and not (handler.aviaryApiKey starts with 'Register') %} 6 | 9 | 10 | {% include '@KunstmaanMedia/Media/Image/aviary.html.twig' %} 11 | {% endif %} 12 | 13 | 14 | {{ 'media.media.download.action'|trans }} 15 | 16 | {% endblock %} 17 | 18 | {% block preview %} 19 | {% set imageurl = handler.getImageUrl(media, app.request.basePath) %} 20 | {% if imageurl is not empty and media.location == 'local' %} 21 | {% if imageurl|lower|split('.')|last == 'svg' or 'image/svg' in media.contentType %} 22 | {% set imageurl = imageurl %} 23 | {% else %} 24 | {% set imageurl = asset(imageurl | imagine_filter('media_detail_thumbnail')) %} 25 | {% endif %} 26 | {% endif %} 27 | {{ media.name }} 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /Form/BulkUploadType.php: -------------------------------------------------------------------------------- 1 | add( 18 | 'files', 19 | FileType::class, 20 | [ 21 | 'label' => 'media.form.bulk_upload.files.label', 22 | 'required' => false, 23 | 'attr' => [ 24 | 'accept' => $options['accept'], 25 | 'multiple' => 'multiple', 26 | ], 27 | 'data_class' => null, 28 | ] 29 | ); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function configureOptions(OptionsResolver $resolver) 36 | { 37 | $resolver->setDefault('accept', null); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | * 43 | * @return string 44 | */ 45 | public function getBlockPrefix() 46 | { 47 | return 'kunstmaan_mediabundle_bulkupload'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Helper/Imagine/ImagineController.php: -------------------------------------------------------------------------------- 1 | query->has('originalExtension')) { 18 | $info = pathinfo($path); 19 | $path = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '.' . $request->query->getAlpha('originalExtension'); 20 | } 21 | 22 | return parent::filterAction($request, $path, $filter); 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | * 28 | * @return RedirectResponse 29 | */ 30 | public function filterRuntimeAction(Request $request, $hash, $path, $filter) 31 | { 32 | if ($request->query->has('originalExtension')) { 33 | $info = pathinfo($path); 34 | $path = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '.' . $request->query->getAlpha('originalExtension'); 35 | } 36 | 37 | return parent::filterRuntimeAction($request, $hash, $path, $filter); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Helper/FolderManager.php: -------------------------------------------------------------------------------- 1 | repository = $repository; 19 | } 20 | 21 | /** 22 | * @return array|string 23 | */ 24 | public function getFolderHierarchy(Folder $rootFolder) 25 | { 26 | return $this->repository->childrenHierarchy($rootFolder); 27 | } 28 | 29 | /** 30 | * @return Folder 31 | */ 32 | public function getRootFolderFor(Folder $folder) 33 | { 34 | $parentIds = $this->getParentIds($folder); 35 | 36 | return $this->repository->getFolder($parentIds[0]); 37 | } 38 | 39 | /** 40 | * @return array 41 | */ 42 | public function getParentIds(Folder $folder) 43 | { 44 | return $this->repository->getParentIds($folder); 45 | } 46 | 47 | /** 48 | * @return array 49 | */ 50 | public function getParents(Folder $folder) 51 | { 52 | return $this->repository->getPath($folder); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /AdminList/ItemAction/MediaDeleteItemAction.php: -------------------------------------------------------------------------------- 1 | redirectUrl = $redirectUrl; 20 | } 21 | 22 | /** 23 | * @param mixed $item 24 | * 25 | * @return array 26 | */ 27 | public function getUrlFor($item) 28 | { 29 | return [ 30 | 'path' => 'KunstmaanMediaBundle_media_delete', 31 | 'params' => ['mediaId' => $item->getId(), 'redirectUrl' => $this->redirectUrl], 32 | ]; 33 | } 34 | 35 | /** 36 | * @param mixed $item 37 | * 38 | * @return string 39 | */ 40 | public function getLabelFor($item) 41 | { 42 | return 'Delete'; 43 | } 44 | 45 | /** 46 | * @param mixed $item 47 | * 48 | * @return string 49 | */ 50 | public function getIconFor($item) 51 | { 52 | return 'remove-sign'; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function getTemplate() 59 | { 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Resources/ui/js/_bulk-move.js: -------------------------------------------------------------------------------- 1 | var kunstmaanMediaBundle = kunstmaanMediaBundle || {}; 2 | 3 | kunstmaanMediaBundle.bulkMove = (function(window, undefined) { 4 | 5 | var init; 6 | 7 | init = function() { 8 | // Get values and elements 9 | var $form = $('#bulk-move-modal-form'), 10 | $mediaInput = $('#kunstmaan_mediabundle_folder_bulk_move_media'); 11 | 12 | $form.submit(function(e) { 13 | e.preventDefault(); 14 | 15 | var action = e.currentTarget.action; 16 | var method = e.currentTarget.method; 17 | var selectedMedia = $.map($('.js-bulk-move-media'), function (el) { 18 | if ($(el).is(":checked")) { 19 | return $(el).data('media-id'); 20 | } 21 | }); 22 | $mediaInput.val(selectedMedia); 23 | 24 | $.ajax({ 25 | url: action, 26 | type: method, 27 | data: $form.serialize(), 28 | success: function() { 29 | window.location.reload(true); 30 | } 31 | }); 32 | 33 | }); 34 | 35 | $(document).on("change",".js-bulk-move-media",function () { 36 | $(this).parent().prev('.media-thumbnail').toggleClass('bulk_selected'); 37 | }); 38 | }; 39 | 40 | return { 41 | init: init 42 | }; 43 | 44 | }(window)); 45 | -------------------------------------------------------------------------------- /Repository/MediaRepository.php: -------------------------------------------------------------------------------- 1 | getEntityManager(); 17 | $em->persist($media); 18 | $em->flush(); 19 | } 20 | 21 | public function delete(Media $media) 22 | { 23 | $em = $this->getEntityManager(); 24 | $media->setDeleted(true); 25 | $em->persist($media); 26 | $em->flush(); 27 | } 28 | 29 | /** 30 | * @param int $mediaId 31 | * 32 | * @return object 33 | * 34 | * @throws EntityNotFoundException 35 | */ 36 | public function getMedia($mediaId) 37 | { 38 | $media = $this->find($mediaId); 39 | if (!$media) { 40 | throw new EntityNotFoundException(); 41 | } 42 | 43 | return $media; 44 | } 45 | 46 | /** 47 | * Finds all Media that has their deleted flag set to 1 48 | * and have their remove_from_file_system flag set to 0 49 | * 50 | * @return object[] 51 | */ 52 | public function findAllDeleted() 53 | { 54 | return $this->findBy(['deleted' => true, 'removedFromFileSystem' => false]); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | Upgrade Instructions 2 | ==================== 3 | 4 | ## To v2.3.18 with extra fields, indexes and folder tree 5 | 6 | When upgrading from a previous version, make sure you update the table structure ( 7 | ```bin/console doctrine:schema:update --force``` 8 | or ```bin/console doctrine:migrations:diff && bin/console doctrine:migrations:migrate```). 9 | 10 | A new field to store the original filename was added to the Media table, so you will have to update the table structure 11 | when upgrading from a version prior to 2.3.18. 12 | 13 | You can use ```bin/console kuma:media:migrate-name``` to initialize the original filename field for already 14 | uploaded media (it will just copy the contents of name field into the original_filename field, so you could also just 15 | update this using a simple SQL query if you want). 16 | 17 | The Folder entity has been refactored to be a nested tree, which should speed up the media section (this will 18 | especially be noticeable if you have lots of media folders). 19 | 20 | To migrate your current media tree to the new format, you have to execute ```bin/console kuma:media:rebuild-folder-tree``` 21 | to initialize the folder tree. If you decide to undelete folders you should run this command as well. 22 | 23 | If you want to create PDF preview images for PDF files that have already been uploaded (provided that you have the 24 | necessary PDF support enabled), you can run the ```bin/console kuma:media:create-pdf-previews``` command. 25 | -------------------------------------------------------------------------------- /Entity/EditableMediaWrapper.php: -------------------------------------------------------------------------------- 1 | media; 32 | } 33 | 34 | public function setMedia(?Media $media): EditableMediaWrapper 35 | { 36 | $this->media = $media; 37 | 38 | return $this; 39 | } 40 | 41 | public function getRunTimeConfig() 42 | { 43 | return $this->runTimeConfig; 44 | } 45 | 46 | public function setRunTimeConfig($runTimeConfig): EditableMediaWrapper 47 | { 48 | $this->runTimeConfig = $runTimeConfig; 49 | 50 | return $this; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Resources/views/Media/delete-modal.html.twig: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /Helper/Remote/RemoteInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 35 | 36 | -------------------------------------------------------------------------------- /Resources/views/Folder/delete-modal.html.twig: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /Twig/MediaTwigExtension.php: -------------------------------------------------------------------------------- 1 | manipulateImageService = $manipulateImageService; 21 | } 22 | 23 | public function getFunctions() 24 | { 25 | return [ 26 | new TwigFunction('cropped_imagine_filter', [$this, 'getCroppedImage']), 27 | new TwigFunction('get_focus_point_class', [$this, 'getFocusPointClass']), 28 | ]; 29 | } 30 | 31 | public function getCroppedImage(EditableMediaWrapper $editableMediaWrapper, string $view = '', string $filter = null) 32 | { 33 | if ($filter) { 34 | return $this->manipulateImageService->cropImage($editableMediaWrapper, $view, $filter); 35 | } 36 | 37 | return $this->manipulateImageService->cropImage($editableMediaWrapper, $view); 38 | } 39 | 40 | public function getFocusPointClass(EditableMediaWrapper $editableMediaWrapper, string $view = '') 41 | { 42 | return $this->manipulateImageService->getFocusPointClass($editableMediaWrapper, $view); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Resources/views/Folder/empty-modal.html.twig: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /Helper/Transformer/PdfTransformer.php: -------------------------------------------------------------------------------- 1 | imagick = $imagick; 13 | } 14 | 15 | /** 16 | * Apply the transformer on the absolute path and return an altered version of it. 17 | * 18 | * @param string $absolutePath 19 | * 20 | * @return string|false 21 | */ 22 | public function apply($absolutePath) 23 | { 24 | $info = pathinfo($absolutePath); 25 | 26 | if (isset($info['extension']) && false !== strpos(strtolower($info['extension']), 'pdf') && file_exists($absolutePath)) { 27 | // If it doesn't exist yet, extract the first page of the PDF 28 | $previewFilename = $this->getPreviewFilename($absolutePath); 29 | if (!file_exists($previewFilename)) { 30 | $this->imagick->readImage($absolutePath . '[0]'); 31 | $this->imagick->setImageFormat('jpg'); 32 | $this->imagick->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN); 33 | $this->imagick->writeImage($previewFilename); 34 | $this->imagick->clear(); 35 | } 36 | 37 | $absolutePath = $previewFilename; 38 | } 39 | 40 | return $absolutePath; 41 | } 42 | 43 | /** 44 | * @param string $absolutePath 45 | * 46 | * @return string 47 | */ 48 | public function getPreviewFilename($absolutePath) 49 | { 50 | return $absolutePath . '.jpg'; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Resources/views/Media/addType-modal.html.twig: -------------------------------------------------------------------------------- 1 | {% for type, form in forms %} 2 | 38 | {% endfor %} 39 | -------------------------------------------------------------------------------- /Form/BulkMoveMediaType.php: -------------------------------------------------------------------------------- 1 | add( 29 | 'folder', 30 | EntityType::class, 31 | [ 32 | 'class' => Folder::class, 33 | 'choice_label' => 'optionLabel', 34 | 'label' => false, 35 | 'required' => true, 36 | 'query_builder' => function (FolderRepository $er) { 37 | return $er->selectFolderQueryBuilder(); 38 | }, 39 | ] 40 | ) 41 | ->add( 42 | 'media', 43 | HiddenType::class 44 | ); 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function getBlockPrefix() 51 | { 52 | return 'kunstmaan_mediabundle_folder_bulk_move'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Helper/IconFont/DefaultIconFontLoader.php: -------------------------------------------------------------------------------- 1 | cssPath = trim($data['css'], '/'); 29 | $pathInfo = pathinfo($this->cssPath); 30 | 31 | if ($pathInfo['extension'] !== 'css') { 32 | throw new InvalidOptionsException(sprintf('The loader data requires a valid css file. "%s" given', $pathInfo['extension'])); 33 | } 34 | 35 | $cssPath = $this->rootPath . '/web/' . $this->cssPath; 36 | if (!file_exists($cssPath)) { 37 | throw new InvalidOptionsException(sprintf('Could not find the css file with this path "%s"', $cssPath)); 38 | } 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function getCssLink() 45 | { 46 | return '/' . $this->cssPath; 47 | } 48 | 49 | /** 50 | * @return array 51 | */ 52 | public function getCssClasses() 53 | { 54 | $contents = file_get_contents($this->rootPath . '/web/' . $this->cssPath); 55 | 56 | preg_match_all('/\.([a-zA-Z0-9-_]+):before[ ]*\{[ \n]*content:/', $contents, $matches); 57 | 58 | return $matches[1]; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/MediaHandlerCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('kunstmaan_media.media_manager')) { 20 | $definition = $container->getDefinition('kunstmaan_media.media_manager'); 21 | 22 | foreach ($container->findTaggedServiceIds('kunstmaan_media.media_handler') as $id => $attributes) { 23 | $definition->addMethodCall('addHandler', [new Reference($id)]); 24 | } 25 | } 26 | 27 | if ($container->hasDefinition('kunstmaan_media.icon_font_manager')) { 28 | $definition = $container->getDefinition('kunstmaan_media.icon_font_manager'); 29 | 30 | foreach ($container->findTaggedServiceIds('kunstmaan_media.icon_font.loader') as $id => $attributes) { 31 | $definition->addMethodCall('addLoader', [new Reference($id), $id]); 32 | } 33 | } 34 | 35 | // Inject the tagged resolvers into our cache manager override 36 | if ($container->hasDefinition('Kunstmaan\MediaBundle\Helper\Imagine\CacheManager')) { 37 | $manager = $container->getDefinition('Kunstmaan\MediaBundle\Helper\Imagine\CacheManager'); 38 | 39 | foreach ($container->findTaggedServiceIds('liip_imagine.cache.resolver') as $id => $tag) { 40 | $manager->addMethodCall('addResolver', [$tag[0]['resolver'], new Reference($id)]); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kunstmaan/media-bundle", 3 | "type": "symfony-bundle", 4 | "description": "To build your perfect website you probably need images, video's or maybe even a presentation too. The Kunstmaan Media Bundle handles all those media assets and centralizes them so you can find your content just the way you like it: fast and efficiently. No central asset management module is useful without some pretty advanced image editing functionality. To provide this we have integrated the Aviary image editing service right from the interface.", 5 | "keywords": ["kunstmaan", "cms", "media"], 6 | "homepage": "https://github.com/Kunstmaan/KunstmaanMediaBundle", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Kunstmaan Team", 11 | "homepage": "http://www.kunstmaan.be/", 12 | "email": "support@kunstmaan.be" 13 | } 14 | ], 15 | "require": { 16 | "php": "^7.2|^8.0", 17 | "gedmo/doctrine-extensions": "^2.4.34|^3.1.0", 18 | "stof/doctrine-extensions-bundle": "^1.3", 19 | "liip/imagine-bundle": "^2.4", 20 | "symfony/mime": "^4.4", 21 | "imagine/imagine": "^1.1", 22 | "knplabs/knp-gaufrette-bundle": "~0.1", 23 | "kunstmaan/adminlist-bundle": "^5.9|^6.0", 24 | "pagerfanta/twig": "^2.4" 25 | }, 26 | "require-dev": { 27 | "matthiasnoback/symfony-config-test": "^4.0", 28 | "matthiasnoback/symfony-dependency-injection-test": "^4.1", 29 | "symfony/phpunit-bridge": "^5.1", 30 | "phpunit/phpunit": "^8.5" 31 | }, 32 | "conflict": { 33 | "doctrine/persistence": "<1.3" 34 | }, 35 | "suggest": { 36 | "ext-imagick": "to support PDF preview images" 37 | }, 38 | "minimum-stability": "dev", 39 | "autoload": { 40 | "psr-4": { "Kunstmaan\\MediaBundle\\": "" } 41 | }, 42 | "extra": { 43 | "branch-alias": { 44 | "dev-master": "5.10-dev" 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Form/RemoteSlide/RemoteSlideType.php: -------------------------------------------------------------------------------- 1 | add( 32 | 'type', 33 | ChoiceType::class, 34 | [ 35 | 'label' => 'media.form.remote_slide.type.label', 36 | 'choices' => ['slideshare' => 'slideshare'], 37 | 'constraints' => [new NotBlank()], 38 | 'required' => true, 39 | ] 40 | ); 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getBlockPrefix() 47 | { 48 | return 'kunstmaan_mediabundle_slidetype'; 49 | } 50 | 51 | /** 52 | * Sets the default options for this type. 53 | * 54 | * @param OptionsResolver $resolver the resolver for the options 55 | */ 56 | public function configureOptions(OptionsResolver $resolver) 57 | { 58 | $resolver->setDefaults( 59 | [ 60 | 'data_class' => 'Kunstmaan\MediaBundle\Helper\RemoteSlide\RemoteSlideHelper', 61 | ] 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Form/RemoteAudio/RemoteAudioType.php: -------------------------------------------------------------------------------- 1 | add( 33 | 'type', 34 | ChoiceType::class, 35 | [ 36 | 'label' => 'media.form.remote_audio.type.label', 37 | 'choices' => ['soundcloud' => 'soundcloud'], 38 | 'constraints' => [new NotBlank()], 39 | 'required' => true, 40 | ] 41 | ); 42 | } 43 | 44 | /** 45 | * @return string 46 | */ 47 | public function getBlockPrefix() 48 | { 49 | return 'kunstmaan_mediabundle_audiotype'; 50 | } 51 | 52 | /** 53 | * Sets the default options for this type. 54 | * 55 | * @param OptionsResolver $resolver the resolver for the options 56 | */ 57 | public function configureOptions(OptionsResolver $resolver) 58 | { 59 | $resolver->setDefaults( 60 | [ 61 | 'data_class' => 'Kunstmaan\MediaBundle\Helper\RemoteAudio\RemoteAudioHelper', 62 | ] 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Helper/Media/AbstractMediaHandler.php: -------------------------------------------------------------------------------- 1 | priority = $priority; 17 | } 18 | 19 | /** 20 | * @return int 21 | */ 22 | public function getPriority() 23 | { 24 | return $this->priority; 25 | } 26 | 27 | /** 28 | * Return the default form type options 29 | * 30 | * @return array 31 | */ 32 | public function getFormTypeOptions() 33 | { 34 | return []; 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | abstract public function getName(); 41 | 42 | /** 43 | * @return string 44 | */ 45 | abstract public function getType(); 46 | 47 | /** 48 | * @return string 49 | */ 50 | abstract public function getFormType(); 51 | 52 | /** 53 | * @param mixed $media 54 | */ 55 | abstract public function canHandle($media); 56 | 57 | /** 58 | * @return mixed 59 | */ 60 | abstract public function getFormHelper(Media $media); 61 | 62 | abstract public function prepareMedia(Media $media); 63 | 64 | abstract public function saveMedia(Media $media); 65 | 66 | abstract public function updateMedia(Media $media); 67 | 68 | abstract public function removeMedia(Media $media); 69 | 70 | /** 71 | * @param mixed $data 72 | * 73 | * @return Media 74 | */ 75 | abstract public function createNew($data); 76 | 77 | public function getShowTemplate(Media $media) 78 | { 79 | return '@KunstmaanMedia/Media/show.html.twig'; 80 | } 81 | 82 | /** 83 | * @param Media $media The media entity 84 | * @param string $basepath The base path 85 | * 86 | * @return string 87 | */ 88 | public function getImageUrl(Media $media, $basepath) 89 | { 90 | return null; 91 | } 92 | 93 | /** 94 | * @return array 95 | */ 96 | abstract public function getAddFolderActions(); 97 | } 98 | -------------------------------------------------------------------------------- /Helper/Services/MediaCreatorService.php: -------------------------------------------------------------------------------- 1 | container = $container; 36 | $this->em = $container->get('doctrine')->getManager(); 37 | $this->folderRepository = $this->em->getRepository('KunstmaanMediaBundle:Folder'); 38 | } 39 | 40 | /** 41 | * @param string $filePath The full filepath of the asset you want to upload. The filetype will be automatically detected. 42 | * @param int $folderId For now you still have to manually pass the correct folder ID 43 | * 44 | * @return Media 45 | */ 46 | public function createFile($filePath, $folderId) 47 | { 48 | $fileHandler = $this->container->get('kunstmaan_media.media_handlers.file'); 49 | 50 | // Get file from FilePath. 51 | $data = new File($filePath, true); 52 | 53 | /** @var $media Media */ 54 | $media = $fileHandler->createNew($data); 55 | /** @var $folder Folder */ 56 | $folder = $this->folderRepository->getFolder($folderId); 57 | 58 | $media->setFolder($folder); 59 | 60 | $fileHandler->prepareMedia($media); 61 | $fileHandler->updateMedia($media); 62 | $fileHandler->saveMedia($media); 63 | 64 | $this->em->persist($media); 65 | $this->em->flush(); 66 | 67 | return $media; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Command/RebuildFolderTreeCommand.php: -------------------------------------------------------------------------------- 1 | getContainer` usages 14 | */ 15 | class RebuildFolderTreeCommand extends ContainerAwareCommand 16 | { 17 | /** 18 | * @var EntityManager 19 | */ 20 | private $em; 21 | 22 | /** 23 | * @param EntityManagerInterface|null $em 24 | */ 25 | public function __construct(/* EntityManagerInterface */ $em = null) 26 | { 27 | parent::__construct(); 28 | 29 | if (!$em instanceof EntityManagerInterface) { 30 | @trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version symfony 3.4 and will be removed in symfony 4.0. If the command was registered by convention, make it a service instead. ', __METHOD__), E_USER_DEPRECATED); 31 | 32 | $this->setName(null === $em ? 'kuma:media:rebuild-folder-tree' : $em); 33 | 34 | return; 35 | } 36 | 37 | $this->em = $em; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | protected function configure() 44 | { 45 | parent::configure(); 46 | 47 | $this->setName('kuma:media:rebuild-folder-tree') 48 | ->setDescription('Rebuild the media folder tree.') 49 | ->setHelp('The kuma:media:rebuild-folder-tree will loop over all media folders and update the media folder tree.'); 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | * 55 | * @return int 56 | */ 57 | protected function execute(InputInterface $input, OutputInterface $output) 58 | { 59 | if (null === $this->em) { 60 | $this->em = $this->getContainer()->get('doctrine.orm.entity_manager'); 61 | } 62 | 63 | $this->em->getRepository('KunstmaanMediaBundle:Folder')->rebuildTree(); 64 | $output->writeln('Updated all folders'); 65 | 66 | return 0; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Helper/File/SVGMimeTypeGuesser.php: -------------------------------------------------------------------------------- 1 | 'image/svg+xml', 21 | ]; 22 | 23 | /** 24 | * @return string|null 25 | */ 26 | public function guess($path) 27 | { 28 | if (!is_file($path)) { 29 | throw new FileNotFoundException($path); 30 | } 31 | 32 | if (!is_readable($path)) { 33 | throw new AccessDeniedException($path); 34 | } 35 | 36 | if (!self::isSupported()) { 37 | return null; 38 | } 39 | 40 | $dom = new \DOMDocument(); 41 | $xml = $dom->load($path, LIBXML_NOERROR + LIBXML_ERR_FATAL + LIBXML_ERR_NONE); 42 | if ($xml === false) { 43 | return null; 44 | } 45 | $xpath = new \DOMXPath($dom); 46 | foreach ($xpath->query('namespace::*') as $node) { 47 | if (isset($this->_MIMETYPE_NAMESPACES[$node->nodeValue])) { 48 | return $this->_MIMETYPE_NAMESPACES[$node->nodeValue]; 49 | } 50 | } 51 | 52 | return null; 53 | } 54 | 55 | /** 56 | * Returns whether this guesser is supported on the current OS 57 | * 58 | * @return bool 59 | */ 60 | public static function isSupported() 61 | { 62 | return class_exists('DOMDocument') && class_exists('DOMXPath'); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Helper/Menu/MediaMenuAdaptor.php: -------------------------------------------------------------------------------- 1 | repo = $repo; 29 | } 30 | 31 | public function adaptChildren(MenuBuilder $menu, array &$children, MenuItem $parent = null, Request $request = null) 32 | { 33 | if (\is_null($parent)) { 34 | // Add menu item for root gallery 35 | $rootFolders = $this->repo->getRootNodes(); 36 | $currentId = $request->get('folderId'); 37 | $currentFolder = null; 38 | if (isset($currentId)) { 39 | /* @var Folder $currentFolder */ 40 | $currentFolder = $this->repo->find($currentId); 41 | } 42 | 43 | /** @var Folder $rootFolder */ 44 | foreach ($rootFolders as $rootFolder) { 45 | $menuItem = new TopMenuItem($menu); 46 | $menuItem 47 | ->setRoute('KunstmaanMediaBundle_folder_show') 48 | ->setRouteparams(['folderId' => $rootFolder->getId()]) 49 | ->setUniqueId('folder-' . $rootFolder->getId()) 50 | ->setLabel($rootFolder->getName()) 51 | ->setParent(null) 52 | ->setRole($rootFolder->getRel()); 53 | 54 | if (!\is_null($currentFolder)) { 55 | $parentIds = $this->repo->getParentIds($currentFolder); 56 | if (\in_array($rootFolder->getId(), $parentIds)) { 57 | $menuItem->setActive(true); 58 | } 59 | } 60 | $children[] = $menuItem; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Controller/AviaryController.php: -------------------------------------------------------------------------------- 1 | getDoctrine()->getManager(); 31 | 32 | /* @var Folder $folder */ 33 | $folder = $em->getRepository(Folder::class)->getFolder($folderId); 34 | /* @var Media $media */ 35 | $media = $em->getRepository(Media::class)->getMedia($mediaId); 36 | /* @var MediaManager $mediaManager */ 37 | $mediaManager = $this->get('kunstmaan_media.media_manager'); 38 | 39 | $media = clone $media; 40 | $handler = $mediaManager->getHandler($media); 41 | $fileHelper = $handler->getFormHelper($media); 42 | $fileHelper->getMediaFromUrl($request->get('url')); 43 | $media = $fileHelper->getMedia(); 44 | 45 | $media->setUuid(null); 46 | $handler->prepareMedia($media); 47 | 48 | $em->persist($media); 49 | $em->flush(); 50 | 51 | $media->setCreatedAt($media->getUpdatedAt()); 52 | $em->persist($media); 53 | $em->flush(); 54 | 55 | return new RedirectResponse( 56 | $this->generateUrl( 57 | 'KunstmaanMediaBundle_folder_show', 58 | ['folderId' => $folder->getId()] 59 | ) 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Resources/doc/MediaBundle.md: -------------------------------------------------------------------------------- 1 | # MediaBundle 2 | 3 | 4 | ## Add media handler 5 | 6 | This document describes how you can add a new media handlers to the [KunstmaanMediaBundle][KunstmaanMediaBundle]. 7 | 8 | ### Create a MediaHandler 9 | 10 | ### Create a MediaHelper 11 | 12 | ### Add the mediahandler service: 13 | 14 | ```yaml 15 | service: 16 | ... 17 | pdf: 18 | default: false 19 | id: kunstmaan_media.provider.pdf 20 | 21 | ``` 22 | 23 | [KunstmaanMediaBundle]: https://github.com/Kunstmaan/KunstmaanMediaBundle "KunstmaanMediaBundle" 24 | 25 | ## MediaField 26 | 27 | A field for media references. It has a "choose" button which opens a popup where you can select your media item from the media repository. 28 | 29 | ### Example Usage: 30 | 31 | ```php 32 | $builder->add('ogImage', 'media', array( 33 | 'mediatype' => 'image', 34 | 'label' => 'OG image' 35 | )); 36 | ``` 37 | 38 | ### Options: 39 | 40 | mediatype: 41 | type: string 42 | default: null 43 | description: 44 | You can specify a specific mediahandler by its name, when this is null all media items are possible. 45 | Knows possible values are: image|file|remotevideo|remoteslide 46 | 47 | ### Parent type: 48 | 49 | form 50 | 51 | ### Class: 52 | 53 | Kunstmaan\MediaBundle\Form\Type\MediaType 54 | 55 | ## Uploading Media in Your Code 56 | 57 | Using the ```MediaCreatorService``` you can easily upload a media-asset to a Folder. 58 | 59 | The API is straightforward: 60 | 61 | ``` 62 | $mediaCreatorService = $this->container->get('kunstmaan_media.media_creator_service'); 63 | $media = $mediaCreatorService->createFile('./app/Content/Images/placeholder.jpg', 1); 64 | ``` 65 | 66 | The path is relevant to the root of your Symfony project. The context can be either web or console. 67 | You'll have to set this to console when you are calling the code from an environment outside of your webserver. 68 | For example for a migration you would use the console context. Otherwise you can just omit the parameter 69 | so the default web context is used. 70 | 71 | ## Commands: 72 | 73 | ### Clean Deleted Media Command: 74 | 75 | Description: 76 | 77 | Removes all files from the filesystem related to Media that has been flagged as deleted in the database. 78 | 79 | Invoked by: ```bin/console kuma:media:clean-deleted-media``` 80 | 81 | Options: 82 | 83 | --force/-f : Does not prompt the user if he is certain he wants to remove all deleted Media from the filesystem. 84 | -------------------------------------------------------------------------------- /Form/RemoteVideo/RemoteVideoType.php: -------------------------------------------------------------------------------- 1 | add( 30 | 'type', 31 | ChoiceType::class, 32 | [ 33 | 'label' => 'media.form.remote_video.type.label', 34 | 'choices' => $this->getRemoteVideoChoices($options['configuration']), 35 | 'constraints' => [new NotBlank()], 36 | 'required' => true, 37 | ] 38 | ); 39 | } 40 | 41 | protected function getRemoteVideoChoices($configuration) 42 | { 43 | $choices = []; 44 | if (\count($configuration)) { 45 | foreach ($configuration as $config => $enabled) { 46 | if (!$enabled) { 47 | continue; 48 | } 49 | $choices[$config] = $config; 50 | } 51 | } 52 | 53 | return $choices; 54 | } 55 | 56 | /** 57 | * @return string 58 | */ 59 | public function getBlockPrefix() 60 | { 61 | return 'kunstmaan_mediabundle_videotype'; 62 | } 63 | 64 | /** 65 | * Sets the default options for this type. 66 | * 67 | * @param OptionsResolver $resolver the resolver for the options 68 | */ 69 | public function configureOptions(OptionsResolver $resolver) 70 | { 71 | $resolver->setDefaults( 72 | [ 73 | 'data_class' => 'Kunstmaan\MediaBundle\Helper\RemoteVideo\RemoteVideoHelper', 74 | 'configuration' => [], 75 | ] 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Resources/views/Media/create.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Default/layout.html.twig' %} 2 | {% form_theme form '@KunstmaanAdmin/Form/fields.html.twig' %} 3 | 4 | {% block title %} 5 | {{ 'media.media.new' | trans({'%folder%': folder.name|trans }) }} 6 | {% endblock %} 7 | 8 | {% block header %}{% endblock %} 9 | 10 | {% block content %} 11 | {{ form_start(form, {'method': 'POST', 'action': path('KunstmaanMediaBundle_media_create', { 'folderId' : folder.id, 'type': type }), 'attr': {'novalidate': 'novalidate'}}) }} 12 | 13 | 14 |
    15 |
    16 |
    17 |

    18 | {{ 'media.media.addto'| trans({'%folder%': folder.name|trans }) }} 19 |

    20 |
    21 |
    22 | 23 |
    24 |
    25 | {% block actions %} 26 | 29 | 30 | {{ 'form.cancel' | trans }} 31 | 32 | {% endblock %} 33 |
    34 |
    35 |
    36 |
    37 |
    38 | 39 | 40 |
    41 |
    42 | {{ block('actions') }} 43 | 46 |
    47 |
    48 | 49 | 50 |
    51 | {{ form_widget(form) }} 52 |
    53 | {{ form_end(form) }} 54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /Resources/config/handlers.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | kunstmaan_media.media_handler.remote_slide.class: 'Kunstmaan\MediaBundle\Helper\RemoteSlide\RemoteSlideHandler' 3 | kunstmaan_media.media_handler.remote_video.class: 'Kunstmaan\MediaBundle\Helper\RemoteVideo\RemoteVideoHandler' 4 | kunstmaan_media.media_handler.remote_audio.class: 'Kunstmaan\MediaBundle\Helper\RemoteAudio\RemoteAudioHandler' 5 | kunstmaan_media.media_handler.image.class: 'Kunstmaan\MediaBundle\Helper\Image\ImageHandler' 6 | kunstmaan_media.media_handler.file.class: 'Kunstmaan\MediaBundle\Helper\File\FileHandler' 7 | kunstmaan_media.media_path: '/uploads/media/' 8 | 9 | services: 10 | kunstmaan_media.media_handlers.remote_slide: 11 | class: '%kunstmaan_media.media_handler.remote_slide.class%' 12 | arguments: [1] 13 | tags: 14 | - { name: 'kunstmaan_media.media_handler' } 15 | 16 | kunstmaan_media.media_handlers.remote_video: 17 | class: '%kunstmaan_media.media_handler.remote_video.class%' 18 | arguments: [1, '%kunstmaan_media.remote_video%'] 19 | tags: 20 | - { name: 'kunstmaan_media.media_handler' } 21 | 22 | kunstmaan_media.media_handlers.remote_audio: 23 | class: '%kunstmaan_media.media_handler.remote_audio.class%' 24 | arguments: [1, '%kunstmaan_media.soundcloud_api_key%'] 25 | tags: 26 | - { name: 'kunstmaan_media.media_handler' } 27 | 28 | kunstmaan_media.media_handlers.image: 29 | class: '%kunstmaan_media.media_handler.image.class%' 30 | arguments: [1, '@mime_types', null, '%kunstmaan_media.aviary_api_key%'] 31 | calls: 32 | - [ setFileSystem, [ '@kunstmaan_media.filesystem' ] ] 33 | - [ setMediaPath, [ '%kunstmaan_media.media_path%' ] ] 34 | - [ setBlacklistedExtensions, [ '%kunstmaan_media.blacklisted_extensions%' ] ] 35 | - [ setSlugifier, ['@kunstmaan_utilities.slugifier']] 36 | tags: 37 | - { name: 'kunstmaan_media.media_handler' } 38 | 39 | kunstmaan_media.media_handlers.file: 40 | class: '%kunstmaan_media.media_handler.file.class%' 41 | arguments: [0, '@mime_types'] 42 | calls: 43 | - [ setFileSystem, [ '@kunstmaan_media.filesystem' ] ] 44 | - [ setMediaPath, [ '%kunstmaan_media.media_path%' ] ] 45 | - [ setBlacklistedExtensions, [ '%kunstmaan_media.blacklisted_extensions%' ] ] 46 | - [ setSlugifier, ['@kunstmaan_utilities.slugifier']] 47 | tags: 48 | - { name: 'kunstmaan_media.media_handler' } 49 | public: true 50 | -------------------------------------------------------------------------------- /Helper/Imagine/WebPathResolver.php: -------------------------------------------------------------------------------- 1 | filterConfig = $filterConfig; 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | protected function getFileUrl($path, $filter) 31 | { 32 | $filterConf = $this->filterConfig->get($filter); 33 | $path = $this->changeFileExtension($path, $filterConf['format']); 34 | 35 | return parent::getFileUrl($path, $filter); 36 | } 37 | 38 | protected function getFilePath($path, $filter) 39 | { 40 | $filterConf = $this->filterConfig->get($filter); 41 | $path = $this->changeFileExtension($path, $filterConf['format']); 42 | $fullPath = $this->getFullPath($path, $filter); 43 | 44 | return $this->webRoot . '/' . $fullPath; 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | * 50 | * @return string 51 | */ 52 | public function resolve($path, $filter) 53 | { 54 | return sprintf('%s/%s', $this->getBaseUrl(), $this->getFileUrl($path, $filter)); 55 | } 56 | 57 | /** 58 | * @param string $path 59 | * @param string $format 60 | * 61 | * @return string 62 | */ 63 | private function changeFileExtension($path, $format) 64 | { 65 | if (!$format) { 66 | return $path; 67 | } 68 | 69 | $info = pathinfo($path); 70 | $path = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '.' . $format; 71 | 72 | return $path; 73 | } 74 | 75 | /** 76 | * Copy from \Liip\ImagineBundle\Imagine\Cache\Resolver\WebPathResolver::getFullPath 77 | */ 78 | private function getFullPath($path, $filter) 79 | { 80 | // crude way of sanitizing URL scheme ("protocol") part 81 | $path = str_replace('://', '---', $path); 82 | 83 | return $this->cachePrefix . '/' . $filter . '/' . ltrim($path, '/'); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Helper/File/PdfHandler.php: -------------------------------------------------------------------------------- 1 | setWebPath(realpath(str_replace('/', DIRECTORY_SEPARATOR, $kernelRootDir . sprintf('/%s/', Kernel::VERSION_ID >= 40000 ? 'public' : 'web')) . DIRECTORY_SEPARATOR)); 32 | } 33 | 34 | /** 35 | * @param string $webPath 36 | */ 37 | public function setWebPath($webPath) 38 | { 39 | $this->webPath = $webPath; 40 | } 41 | 42 | public function setPdfTransformer(PreviewTransformerInterface $pdfTransformer) 43 | { 44 | $this->pdfTransformer = $pdfTransformer; 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function getType() 51 | { 52 | return PdfHandler::TYPE; 53 | } 54 | 55 | /** 56 | * @param mixed $object 57 | * 58 | * @return bool 59 | */ 60 | public function canHandle($object) 61 | { 62 | if (parent::canHandle($object) && 63 | ($object instanceof Media && $object->getContentType() == 'application/pdf') 64 | ) { 65 | return true; 66 | } 67 | 68 | return false; 69 | } 70 | 71 | public function saveMedia(Media $media) 72 | { 73 | parent::saveMedia($media); 74 | 75 | try { 76 | // Generate preview for PDF 77 | $this->pdfTransformer->apply($this->webPath . $media->getUrl()); 78 | } catch (\ImagickException $e) { 79 | // Fail silently () 80 | } 81 | } 82 | 83 | /** 84 | * @param Media $media The media entity 85 | * @param string $basepath The base path 86 | * 87 | * @return string 88 | */ 89 | public function getImageUrl(Media $media, $basepath) 90 | { 91 | $filename = $this->pdfTransformer->getPreviewFilename($basepath . $media->getUrl()); 92 | if (!file_exists($this->webPath . $filename)) { 93 | return null; 94 | } 95 | 96 | return $filename; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Form/EditableMediaWrapperAdminType.php: -------------------------------------------------------------------------------- 1 | croppingViews = $croppingViews; 27 | } 28 | 29 | public function buildForm(FormBuilderInterface $builder, array $options) 30 | { 31 | $croppingViewGroup = $options['cropping_views_group']; 32 | $selectedCroppingViews = $this->croppingViews[self::DEFAULT]; 33 | $useFocusPoint = false; 34 | $useCropper = true; 35 | $focusPointClasses = $this->croppingViews[self::FOCUS_POINT_CLASSES]; 36 | if ($croppingViewGroup !== self::DEFAULT && isset($this->croppingViews[self::CUSTOM_VIEWS][$croppingViewGroup]['views'])) { 37 | $selectedCroppingViews = $this->croppingViews[self::CUSTOM_VIEWS][$croppingViewGroup]['views']; 38 | $useFocusPoint = $this->croppingViews[self::CUSTOM_VIEWS][$croppingViewGroup]['use_focus_point'] ?? false; 39 | $useCropper = $this->croppingViews[self::CUSTOM_VIEWS][$croppingViewGroup]['use_cropping'] ?? true; 40 | } 41 | $builder->add('media', MediaType::class, [ 42 | 'label' => false, 43 | 'mediatype' => 'image', 44 | 'show_image_edit_modal' => true, 45 | 'use_focus_point' => $useFocusPoint, 46 | 'use_cropping' => $useCropper, 47 | 'focus_point_classes' => json_encode($focusPointClasses), 48 | 'cropping_views' => json_encode($selectedCroppingViews), 49 | ]); 50 | $builder->add('runTimeConfig', HiddenType::class, [ 51 | 'label' => false, 52 | ]); 53 | } 54 | 55 | public function configureOptions(OptionsResolver $resolver) 56 | { 57 | $resolver->setDefaults( 58 | [ 59 | 'data_class' => EditableMediaWrapper::class, 60 | 'cropping_views_group' => self::DEFAULT, 61 | ] 62 | ); 63 | $groups = array_keys($this->croppingViews[self::CUSTOM_VIEWS]); 64 | $groups[] = self::DEFAULT; 65 | $resolver->setAllowedValues('cropping_views_group', $groups); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Form/Type/IconFontType.php: -------------------------------------------------------------------------------- 1 | iconFontManager = $iconFontManager; 26 | } 27 | 28 | /** 29 | * @return string 30 | */ 31 | public function getParent() 32 | { 33 | return TextType::class; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getBlockPrefix() 40 | { 41 | return 'iconfont'; 42 | } 43 | 44 | /** 45 | * Sets the default options for this type. 46 | * 47 | * @param OptionsResolver $resolver the resolver for the options 48 | */ 49 | public function configureOptions(OptionsResolver $resolver) 50 | { 51 | $resolver->setDefaults( 52 | [ 53 | 'loader' => null, 54 | 'loader_data' => null, 55 | ] 56 | ); 57 | } 58 | 59 | /** 60 | * Builds the form. 61 | * 62 | * This method is called for each type in the hierarchy starting form the 63 | * top most type. Type extensions can further modify the form. 64 | * 65 | * @param FormBuilderInterface $builder The form builder 66 | * @param array $options The options 67 | * 68 | * @see FormTypeExtensionInterface::buildForm() 69 | */ 70 | public function buildForm(FormBuilderInterface $builder, array $options) 71 | { 72 | if (!$options['loader']) { 73 | $loader = $this->iconFontManager->getDefaultLoader(); 74 | } else { 75 | $loader = $this->iconFontManager->getLoader($options['loader']); 76 | } 77 | $loader->setData($options['loader_data']); 78 | 79 | $builder->setAttribute('loader', $options['loader']); 80 | $builder->setAttribute('loader_object', $loader); 81 | $builder->setAttribute('loader_data', $options['loader_data']); 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function buildView(FormView $view, FormInterface $form, array $options) 88 | { 89 | $view->vars['loader'] = $form->getConfig()->getAttribute('loader'); 90 | $view->vars['loader_object'] = $form->getConfig()->getAttribute('loader_object'); 91 | $view->vars['loader_data'] = json_encode($form->getConfig()->getAttribute('loader_data')); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Validator/Constraints/Media.php: -------------------------------------------------------------------------------- 1 | 'NOT_FOUND_ERROR', 23 | self::NOT_READABLE_ERROR => 'NOT_READABLE_ERROR', 24 | self::EMPTY_ERROR => 'EMPTY_ERROR', 25 | self::INVALID_MIME_TYPE_ERROR => 'INVALID_MIME_TYPE_ERROR', 26 | self::TOO_HIGH_ERROR => 'TOO_HIGH_ERROR', 27 | self::TOO_LOW_ERROR => 'TOO_LOW_ERROR', 28 | self::TOO_WIDE_ERROR => 'TOO_WIDE_ERROR', 29 | self::TOO_NARROW_ERROR => 'TOO_NARROW_ERROR', 30 | ]; 31 | 32 | public $minHeight; 33 | 34 | public $maxHeight; 35 | 36 | public $minWidth; 37 | 38 | public $maxWidth; 39 | 40 | public $binaryFormat; 41 | 42 | public $mimeTypes = []; 43 | 44 | public $notFoundMessage = 'The file could not be found.'; 45 | 46 | public $notReadableMessage = 'The file is not readable.'; 47 | 48 | public $mimeTypesMessage = 'The type of the file is invalid ({{ type }}). Allowed types are {{ types }}.'; 49 | 50 | public $disallowEmptyMessage = 'An empty file is not allowed.'; 51 | 52 | public $maxWidthMessage = 'The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.'; 53 | 54 | public $minWidthMessage = 'The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.'; 55 | 56 | public $maxHeightMessage = 'The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.'; 57 | 58 | public $minHeightMessage = 'The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.'; 59 | 60 | public $uploadPartialErrorMessage = 'The file was only partially uploaded.'; 61 | 62 | public $uploadNoFileErrorMessage = 'No file was uploaded.'; 63 | 64 | public $uploadNoTmpDirErrorMessage = 'No temporary folder was configured in php.ini.'; 65 | 66 | public $uploadCantWriteErrorMessage = 'Cannot write temporary file to disk.'; 67 | 68 | public $uploadExtensionErrorMessage = 'A PHP extension caused the upload to fail.'; 69 | 70 | public $uploadErrorMessage = 'The file could not be uploaded.'; 71 | } 72 | -------------------------------------------------------------------------------- /Helper/Imagine/CacheManager.php: -------------------------------------------------------------------------------- 1 | filterConfig->get($filter); 18 | $path = $this->changeFileExtension(ltrim($path, '/'), $filterConf['format']); 19 | 20 | $params = [ 21 | 'path' => ltrim($path, '/'), 22 | 'filter' => $filter, 23 | ]; 24 | 25 | if ($resolver) { 26 | $params['resolver'] = $resolver; 27 | } 28 | 29 | if (empty($runtimeConfig)) { 30 | $filterUrl = $this->router->generate('liip_imagine_filter', $params, $referenceType); 31 | } else { 32 | $params['filters'] = $runtimeConfig; 33 | $params['hash'] = $this->signer->sign($originalPath, $runtimeConfig); 34 | 35 | $filterUrl = $this->router->generate('liip_imagine_filter_runtime', $params, $referenceType); 36 | } 37 | 38 | return $filterUrl; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | * 44 | * @return string 45 | */ 46 | public function resolve($path, $filter, $resolver = null) 47 | { 48 | $filterConf = $this->filterConfig->get($filter); 49 | $path = $this->changeFileExtension($path, $filterConf['format']); 50 | 51 | return parent::resolve($path, $filter, $resolver); 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | * 57 | * @return string 58 | */ 59 | public function getBrowserPath($path, $filter, array $runtimeConfig = [], $resolver = null, $referenceType = UrlGeneratorInterface::ABSOLUTE_URL) 60 | { 61 | $infoPath = parse_url($path, PHP_URL_PATH); 62 | $info = pathinfo($infoPath); 63 | $url = parent::getBrowserPath($path, $filter, $runtimeConfig, $resolver, $referenceType); 64 | $newPath = parse_url($url, PHP_URL_PATH); 65 | $newInfo = pathinfo($newPath); 66 | if ($info['extension'] != $newInfo['extension']) { 67 | $query = parse_url($url, PHP_URL_QUERY); 68 | $url .= ($query ? '&' : '?') . 'originalExtension=' . $info['extension']; 69 | } 70 | 71 | return $url; 72 | } 73 | 74 | /** 75 | * @param string $path 76 | * @param string $format 77 | * 78 | * @return string 79 | */ 80 | private function changeFileExtension($path, $format) 81 | { 82 | if (!$format) { 83 | return $path; 84 | } 85 | 86 | $info = pathinfo($path); 87 | 88 | return $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '.' . $format; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Form/Type/IdToMediaTransformer.php: -------------------------------------------------------------------------------- 1 | objectManager = $objectManager; 34 | $this->currentValueContainer = $currentValueContainer; 35 | } 36 | 37 | /** 38 | * @param Media $entity The value in the original representation 39 | * 40 | * @return mixed The value in the transformed representation 41 | * 42 | * @throws UnexpectedTypeException when the argument is not an object 43 | * @throws \InvalidArgumentException when the parameter is a collection 44 | */ 45 | public function transform($entity) 46 | { 47 | if (empty($entity)) { 48 | return ''; 49 | } 50 | if (!\is_object($entity)) { 51 | throw new UnexpectedTypeException($entity, 'object'); 52 | } 53 | if ($entity instanceof Collection) { 54 | throw new \InvalidArgumentException('Expected an object, but got a collection. Did you forget to pass "multiple=true" to an entity field?'); 55 | } 56 | $this->currentValueContainer->setCurrentValue($entity); 57 | 58 | return [ 59 | 'ent' => $entity, 60 | 'id' => $entity->getId(), 61 | ]; 62 | } 63 | 64 | /** 65 | * @param string $key 66 | * 67 | * @return Media 68 | * 69 | * @throws UnexpectedTypeException when the parameter is not numeric 70 | * @throws TransformationFailedException when the media item cannot be loaded/found 71 | */ 72 | public function reverseTransform($key) 73 | { 74 | if (empty($key)) { 75 | return null; 76 | } 77 | if (!is_numeric($key)) { 78 | throw new UnexpectedTypeException($key, 'numeric'); 79 | } 80 | if (!($entity = $this->objectManager->getRepository(Media::class)->find($key))) { 81 | throw new TransformationFailedException(sprintf('The entity with key "%s" could not be found', $key)); 82 | } 83 | $this->currentValueContainer->setCurrentValue($entity); 84 | 85 | return $entity; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Resources/ui/js/_dnd-upload.js: -------------------------------------------------------------------------------- 1 | var kunstmaanMediaBundle = kunstmaanMediaBundle || {}; 2 | 3 | kunstmaanMediaBundle.dndUpload = (function(window, undefined) { 4 | 5 | var init, initUpload; 6 | 7 | 8 | // Init 9 | init = function() { 10 | var $area = $('#dnd-area'); 11 | 12 | if($area.length) { 13 | var $container = $('#dnd-container'), 14 | $status = $('#dnd-area__upload-status'), 15 | dropUrl = $area.data('drop-url'), 16 | currentUrl = $area.data('current-url'); 17 | 18 | initUpload($area, $container, $status, dropUrl, currentUrl); 19 | } 20 | }; 21 | 22 | 23 | // Upload 24 | initUpload = function($area, $container, $status, dropUrl, currentUrl) { 25 | var dndUploader = new plupload.Uploader({ 26 | runtimes : 'html5', 27 | dragdrop: true, 28 | drop_element: 'dnd-area', 29 | browse_button : 'dnd-area-link', 30 | url: dropUrl, 31 | processing_id: null, 32 | 33 | filters : { 34 | max_file_size : '100mb' 35 | }, 36 | 37 | init: { 38 | PostInit: function() { 39 | $(window).on('dragenter', function(e) { 40 | if($.inArray('text/html', e.originalEvent.dataTransfer.types) === -1 && $.inArray('text/plain', e.originalEvent.dataTransfer.types) === -1) { 41 | $area.addClass('dnd-area--dragover'); 42 | } 43 | }); 44 | 45 | $area.on('dragleave drop dragend', function() { 46 | $area.removeClass('dnd-area--dragover'); 47 | }); 48 | }, 49 | 50 | FilesAdded: function(up, files) { 51 | plupload.each(files, function(file) { 52 | $status.append('
  • ' + file.name + ' (' + plupload.formatSize(file.size) + ')
  • ') 53 | }); 54 | 55 | dndUploader.start(); 56 | }, 57 | 58 | UploadProgress: function(up, file) { 59 | var $fileLine = $('#' + file.id); 60 | 61 | $fileLine.find('.js-status').html(file.percent + '%'); 62 | }, 63 | 64 | UploadComplete: function(up, files) { 65 | // Set Loading 66 | $('body').addClass('app--loading'); 67 | 68 | $area.addClass('dnd-area--upload-done'); 69 | 70 | window.location = currentUrl; 71 | } 72 | } 73 | }); 74 | 75 | 76 | // Initialize uploader 77 | dndUploader.init(); 78 | }; 79 | 80 | 81 | return { 82 | init: init 83 | }; 84 | 85 | }(window)); 86 | -------------------------------------------------------------------------------- /Resources/views/Media/bulkUpload.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@KunstmaanMedia/Default/layout.html.twig' %} 2 | 3 | {% block title %} 4 | {% set title = 'media.media.bulkupload.addto' %} 5 | {{ title | trans({'%folder%': folder.name|trans }) }} 6 | {% endblock%} 7 | 8 | {% block header %} 9 |
    10 | {% set title = 'media.media.bulkupload.addto' %} 11 |

    12 | {{ title | trans({'%folder%': folder.name|trans }) | capitalize }} 13 |

    14 |
    15 | {% endblock %} 16 | 17 | {% block content %} 18 |
    19 |
    20 |
    21 |
      22 |
    • 23 | {{ 'media.bulkupload.not_available' | trans }} 24 |
    • 25 |
    26 | 27 |
    28 | 29 | 30 |
    31 | 34 | 37 | 38 | {{ 'form.cancel' | trans }} 39 | 40 |
    41 | 42 | 43 | 54 |
    55 |
    56 |
    57 |
    58 | {% endblock %} 59 | -------------------------------------------------------------------------------- /Form/FolderType.php: -------------------------------------------------------------------------------- 1 | add( 32 | 'name', 33 | TextType::class, 34 | [ 35 | 'label' => 'media.folder.addsub.form.name', 36 | ] 37 | ) 38 | ->add( 39 | 'rel', 40 | ChoiceType::class, 41 | [ 42 | 'choices' => Folder::allTypes(), 43 | 'label' => 'media.folder.addsub.form.rel', 44 | ] 45 | ) 46 | ->add( 47 | 'parent', 48 | EntityType::class, 49 | [ 50 | 'class' => 'KunstmaanMediaBundle:Folder', 51 | 'choice_label' => 'optionLabel', 52 | 'label' => 'media.folder.addsub.form.parent', 53 | 'required' => true, 54 | 'query_builder' => function (FolderRepository $er) use ($folder) { 55 | return $er->selectFolderQueryBuilder($folder); 56 | }, 57 | ] 58 | ) 59 | ->add( 60 | 'internalName', 61 | TextType::class, 62 | [ 63 | 'label' => 'media.folder.addsub.form.internal_name', 64 | 'required' => false, 65 | ] 66 | ); 67 | } 68 | 69 | /** 70 | * @return string 71 | */ 72 | public function getBlockPrefix() 73 | { 74 | return 'kunstmaan_mediabundle_FolderType'; 75 | } 76 | 77 | /** 78 | * Sets the default options for this type. 79 | * 80 | * @param OptionsResolver $resolver the resolver for the options 81 | */ 82 | public function configureOptions(OptionsResolver $resolver) 83 | { 84 | $resolver->setDefaults( 85 | [ 86 | 'data_class' => 'Kunstmaan\MediaBundle\Entity\Folder', 87 | 'folder' => null, 88 | ] 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/DeprecateClassParametersPass.php: -------------------------------------------------------------------------------- 1 | \Kunstmaan\MediaBundle\Helper\RemoteSlide\RemoteSlideHandler::class, 17 | 'kunstmaan_media.media_handler.remote_video.class' => \Kunstmaan\MediaBundle\Helper\RemoteVideo\RemoteVideoHandler::class, 18 | 'kunstmaan_media.media_handler.remote_audio.class' => \Kunstmaan\MediaBundle\Helper\RemoteAudio\RemoteAudioHandler::class, 19 | 'kunstmaan_media.media_handler.image.class' => \Kunstmaan\MediaBundle\Helper\Image\ImageHandler::class, 20 | 'kunstmaan_media.media_handler.file.class' => \Kunstmaan\MediaBundle\Helper\File\FileHandler::class, 21 | 'kunstmaan_media.pdf_transformer.class' => \Kunstmaan\MediaBundle\Helper\Transformer\PdfTransformer::class, 22 | 'kunstmaan_media.media_handler.pdf.class' => \Kunstmaan\MediaBundle\Helper\File\PdfHandler::class, 23 | 'kunstmaan_media.media_manager.class' => \Kunstmaan\MediaBundle\Helper\MediaManager::class, 24 | 'kunstmaan_media.folder_manager.class' => \Kunstmaan\MediaBundle\Helper\FolderManager::class, 25 | 'kunstmaan_media.menu.adaptor.class' => \Kunstmaan\MediaBundle\Helper\Menu\MediaMenuAdaptor::class, 26 | 'kunstmaan_media.listener.doctrine.class' => \Kunstmaan\MediaBundle\EventListener\DoctrineMediaListener::class, 27 | 'kunstmaan_media.form.type.media.class' => \Kunstmaan\MediaBundle\Form\Type\MediaType::class, 28 | 'kunstmaan_media.form.type.iconfont.class' => \Kunstmaan\MediaBundle\Form\Type\IconFontType::class, 29 | 'kunstmaan_media.icon_font_manager.class' => \Kunstmaan\MediaBundle\Helper\IconFont\IconFontManager::class, 30 | 'kunstmaan_media.icon_font.default_loader.class' => \Kunstmaan\MediaBundle\Helper\IconFont\DefaultIconFontLoader::class, 31 | 'kunstmaan_media.media_creator_service.class' => \Kunstmaan\MediaBundle\Helper\Services\MediaCreatorService::class, 32 | 'kunstmaan_media.mimetype_guesser.factory.class' => \Kunstmaan\MediaBundle\Helper\MimeTypeGuesserFactory::class, 33 | 'kunstmaan_media.extension_guesser.factory.class' => \Kunstmaan\MediaBundle\Helper\ExtensionGuesserFactory::class, 34 | 'kunstmaan_media.validator.has_guessable_extension.class' => \Kunstmaan\MediaBundle\Validator\Constraints\HasGuessableExtensionValidator::class, 35 | ]; 36 | 37 | foreach ($expectedValues as $parameter => $expectedValue) { 38 | if (false === $container->hasParameter($parameter)) { 39 | continue; 40 | } 41 | 42 | $currentValue = $container->getParameter($parameter); 43 | if ($currentValue !== $expectedValue) { 44 | @trigger_error(sprintf('Using the "%s" parameter to change the class of the service definition is deprecated in KunstmaanMediaBundle 5.2 and will be removed in KunstmaanMediaBundle 6.0. Use service decoration or a service alias instead.', $parameter), E_USER_DEPRECATED); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KunstmaanMediaBundle 2 | 3 | [![Build Status](https://travis-ci.org/Kunstmaan/KunstmaanMediaBundle.png?branch=master)](http://travis-ci.org/Kunstmaan/KunstmaanMediaBundle) 4 | [![Total Downloads](https://poser.pugx.org/kunstmaan/media-bundle/downloads.png)](https://packagist.org/packages/kunstmaan/media-bundle) 5 | [![Latest Stable Version](https://poser.pugx.org/kunstmaan/media-bundle/v/stable.png)](https://packagist.org/packages/kunstmaan/media-bundle) 6 | [![Analytics](https://ga-beacon.appspot.com/UA-3160735-7/Kunstmaan/KunstmaanMediaBundle)](https://github.com/igrigorik/ga-beacon) 7 | 8 | To build your perfect website you probably need images, video's or maybe even a presentation too. The Kunstmaan Media Bundle handles all those media assets and centralizes them so you can find your content just the way you like it: fast and efficiently. No central asset management module is useful without some pretty advanced image editing functionality. To provide this we have integrated the Aviary image editing service right from the interface. 9 | 10 | View more screenshots and information [https://cms.kunstmaan.be](https://cms.kunstmaan.be). 11 | 12 | ## Installation 13 | 14 | This bundle is compatible with all Symfony 3.* releases. More information about installing can be found in this line by line walkthrough of installing Symfony and all our bundles, please refer to the [Getting Started guide](https://kunstmaanbundlescms.readthedocs.io/en/stable/installation/) and enjoy the full blown experience. 15 | 16 | ## Symfony 2.2 17 | 18 | If you want to use this bundle for a Symfony 2.2 release, use the 2.2 branch. 19 | 20 | ## Audio 21 | 22 | If you want to use your own api key for SoundCloud, you can define this in the config.yml of your application but it works fine without it as well. 23 | 24 | ```yml 25 | kunstmaan_media: 26 | soundcloud_api_key: YOUR_CLIENT_ID 27 | ``` 28 | 29 | ## Tooltips 30 | 31 | If you want to add a nifty tooltip to your media chooser in the admin, you can just add the following to your form type: 32 | 33 | ```php 34 | $builder 35 | ->add( 36 | 'media', 37 | 'media', 38 | array( 39 | 'pattern' => 'KunstmaanMediaBundle_chooser', 40 | 'mediatype' => 'image', 41 | 'attr' => array('info_text' => 'YOUR TOOLTIP TEXT'), 42 | ) 43 | ); 44 | ``` 45 | 46 | ## Generating PDF preview thumbnails 47 | 48 | For this functionality to work, you need to install the ImageMagick extension with PDF support (using 49 | Ghostscript). You will also have to make sure that the Ghostscript executable (gs) can be found 50 | in the path of the user that is executing the code (apache/www or a custom user depending on your setup). 51 | 52 | You can determine that path by running ```which gs``` on the command line in Linux/OS X. 53 | 54 | To install Ghostscript on Mac OS X you can use ```brew install gs```. 55 | 56 | On OS X with apache you will probably have to add that path to the apache environment settings in 57 | ```/System/Library/LaunchDaemons/org.apache.httpd.plist```. Make sure it contains the following : 58 | ``` 59 | EnvironmentVariables 60 | 61 | PATH 62 | /usr/bin:/bin:/usr/sbin:/sbin:/path/to/gs 63 | 64 | ``` 65 | 66 | Where ```/path/to/gs``` is just the actual path where the gs binary is stored. 67 | 68 | *NOTE:* This functionality has to be enabled by setting the ```enable_pdf_preview``` configuration option to true, ie. : 69 | 70 | ```yml 71 | kunstmaan_media: 72 | enable_pdf_preview: true 73 | ``` 74 | -------------------------------------------------------------------------------- /Helper/Remote/AbstractRemoteHelper.php: -------------------------------------------------------------------------------- 1 | media = $media; 20 | } 21 | 22 | /** 23 | * @return string 24 | */ 25 | public function getName() 26 | { 27 | return $this->media->getName(); 28 | } 29 | 30 | /** 31 | * @param string $name 32 | */ 33 | public function setName($name) 34 | { 35 | $this->media->setName($name); 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getCopyright() 42 | { 43 | return $this->media->getCopyright(); 44 | } 45 | 46 | /** 47 | * @param string $copyright 48 | */ 49 | public function setCopyright($copyright) 50 | { 51 | $this->media->setCopyright($copyright); 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getDescription() 58 | { 59 | return $this->media->getDescription(); 60 | } 61 | 62 | /** 63 | * @param string $description 64 | */ 65 | public function setDescription($description) 66 | { 67 | $this->media->setDescription($description); 68 | } 69 | 70 | /** 71 | * @return Media 72 | */ 73 | public function getMedia() 74 | { 75 | return $this->media; 76 | } 77 | 78 | /** 79 | * @return string 80 | */ 81 | public function getCode() 82 | { 83 | return $this->media->getMetadataValue('code'); 84 | } 85 | 86 | /** 87 | * Set code 88 | * 89 | * @param string $code 90 | * 91 | * @return self 92 | */ 93 | public function setCode($code) 94 | { 95 | $this->media->setMetadataValue('code', $code); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * @return string|null 102 | */ 103 | public function getThumbnailUrl() 104 | { 105 | return $this->media->getMetadataValue('thumbnail_url'); 106 | } 107 | 108 | /** 109 | * Set thumbnail url 110 | * 111 | * @param string $url 112 | * 113 | * @return self 114 | */ 115 | public function setThumbnailUrl($url) 116 | { 117 | $this->media->setMetadataValue('thumbnail_url', $url); 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Get type 124 | * 125 | * @return string|null 126 | */ 127 | public function getType() 128 | { 129 | return $this->media->getMetadataValue('type'); 130 | } 131 | 132 | /** 133 | * Set type 134 | * 135 | * @param string $type 136 | * 137 | * @return self 138 | */ 139 | public function setType($type) 140 | { 141 | $this->media->setMetadataValue('type', $type); 142 | 143 | return $this; 144 | } 145 | 146 | /** 147 | * @return Folder 148 | */ 149 | public function getFolder() 150 | { 151 | return $this->media->getFolder(); 152 | } 153 | 154 | public function setFolder(Folder $folder) 155 | { 156 | $this->media->setFolder($folder); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Form/Type/MediaType.php: -------------------------------------------------------------------------------- 1 | mediaManager = $mediaManager; 36 | $this->objectManager = $objectManager; 37 | } 38 | 39 | /** 40 | * Builds the form. 41 | * 42 | * This method is called for each type in the hierarchy starting form the 43 | * top most type. Type extensions can further modify the form. 44 | * 45 | * @param FormBuilderInterface $builder The form builder 46 | * @param array $options The options 47 | * 48 | * @see FormTypeExtensionInterface::buildForm() 49 | */ 50 | public function buildForm(FormBuilderInterface $builder, array $options) 51 | { 52 | $builder->addViewTransformer( 53 | new IdToMediaTransformer($this->objectManager, $options['current_value_container']), 54 | true 55 | ); 56 | $builder->setAttribute('chooser', $options['chooser']); 57 | $builder->setAttribute('mediatype', $options['mediatype']); 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getParent() 64 | { 65 | return FormType::class; 66 | } 67 | 68 | /** 69 | * Sets the default options for this type. 70 | * 71 | * @param OptionsResolver $resolver the resolver for the options 72 | */ 73 | public function configureOptions(OptionsResolver $resolver) 74 | { 75 | $resolver->setDefaults( 76 | [ 77 | 'compound' => false, 78 | 'chooser' => 'KunstmaanMediaBundle_chooser', 79 | 'mediatype' => null, 80 | 'current_value_container' => new CurrentValueContainer(), 81 | // @experimental The option below are for a feature is experimental and is a subject to change, be advised when using this feature and classes. 82 | 'show_image_edit_modal' => false, 83 | 'use_focus_point' => false, 84 | 'use_cropping' => false, 85 | 'focus_point_classes' => '', 86 | 'cropping_views' => '', 87 | ] 88 | ); 89 | } 90 | 91 | /** 92 | * @return string 93 | */ 94 | public function getBlockPrefix() 95 | { 96 | return 'media'; 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | */ 102 | public function buildView(FormView $view, FormInterface $form, array $options) 103 | { 104 | $view->vars['chooser'] = $form->getConfig()->getAttribute('chooser'); 105 | $view->vars['mediatype'] = $form->getConfig()->getAttribute('mediatype'); 106 | $view->vars['mediamanager'] = $this->mediaManager; 107 | $view->vars['show_image_edit_modal'] = $options['show_image_edit_modal']; 108 | $view->vars['use_focus_point'] = $options['use_focus_point']; 109 | $view->vars['use_cropping'] = $options['use_cropping']; 110 | $view->vars['focus_point_classes'] = $options['focus_point_classes']; 111 | $view->vars['cropping_views'] = $options['cropping_views']; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Helper/Image/ImageHandler.php: -------------------------------------------------------------------------------- 1 | aviaryApiKey = $aviaryApiKey; 36 | } 37 | 38 | /** 39 | * @deprecated This method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. The aviary service is discontinued. 40 | * 41 | * @return string 42 | */ 43 | public function getAviaryApiKey() 44 | { 45 | @trigger_error(sprintf('The "%s" method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. The aviary service is discontinued.', __METHOD__), E_USER_DEPRECATED); 46 | 47 | return $this->aviaryApiKey; 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function getName() 54 | { 55 | return 'Image Handler'; 56 | } 57 | 58 | /** 59 | * @return string 60 | */ 61 | public function getType() 62 | { 63 | return 'image'; 64 | } 65 | 66 | /** 67 | * @param mixed $object 68 | * 69 | * @return bool 70 | */ 71 | public function canHandle($object) 72 | { 73 | if (parent::canHandle($object) && ($object instanceof File || strncmp($object->getContentType(), 'image', 5) === 0)) { 74 | return true; 75 | } 76 | 77 | return false; 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public function getShowTemplate(Media $media) 84 | { 85 | return '@KunstmaanMedia/Media/Image/show.html.twig'; 86 | } 87 | 88 | /** 89 | * @param Media $media The media entity 90 | * @param string $basepath The base path 91 | * 92 | * @return string 93 | */ 94 | public function getImageUrl(Media $media, $basepath) 95 | { 96 | return $basepath . $media->getUrl(); 97 | } 98 | 99 | public function prepareMedia(Media $media) 100 | { 101 | parent::prepareMedia($media); 102 | 103 | if ($media->getContent()) { 104 | $imageInfo = getimagesize($media->getContent()); 105 | 106 | $width = $height = null; 107 | if (false !== $imageInfo) { 108 | [$width, $height] = $imageInfo; 109 | } 110 | 111 | $media 112 | ->setMetadataValue('original_width', $width) 113 | ->setMetadataValue('original_height', $height); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Form/AbstractRemoteType.php: -------------------------------------------------------------------------------- 1 | add( 36 | 'name', 37 | TextType::class, 38 | [ 39 | 'label' => 'media.form.remote.name.label', 40 | 'constraints' => [new NotBlank()], 41 | 'required' => true, 42 | ] 43 | ) 44 | ->add( 45 | 'code', 46 | TextType::class, 47 | [ 48 | 'label' => 'media.form.remote.code.label', 49 | 'constraints' => [new NotBlank()], 50 | 'required' => true, 51 | ] 52 | ) 53 | ->add( 54 | 'type', 55 | ChoiceType::class, 56 | [ 57 | 'label' => 'media.form.remote.type.label', 58 | 'choices' => [], 59 | 'constraints' => [new NotBlank()], 60 | 'required' => true, 61 | ] 62 | ) 63 | ->add( 64 | 'copyright', 65 | TextType::class, 66 | [ 67 | 'label' => 'media.form.remote.copyright.label', 68 | 'required' => false, 69 | ] 70 | ) 71 | ->add( 72 | 'description', 73 | TextareaType::class, 74 | [ 75 | 'label' => 'media.form.remote.description.label', 76 | 'required' => false, 77 | ] 78 | ); 79 | 80 | $builder->addEventListener( 81 | FormEvents::PRE_SET_DATA, 82 | function (FormEvent $event) { 83 | $helper = $event->getData(); 84 | $form = $event->getForm(); 85 | 86 | // Make sure file field is when creating new (not persisted) objects 87 | if (null !== $helper->getMedia()->getId()) { 88 | // Allow changing folder on edit 89 | $form->add( 90 | 'folder', 91 | EntityType::class, 92 | [ 93 | 'class' => 'KunstmaanMediaBundle:Folder', 94 | 'choice_label' => 'optionLabel', 95 | 'query_builder' => function (FolderRepository $er) { 96 | return $er->selectFolderQueryBuilder() 97 | ->andWhere('f.parent IS NOT NULL'); 98 | }, 99 | 'required' => true, 100 | ] 101 | ); 102 | } 103 | } 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Resources/ui/js/_bulk-upload.js: -------------------------------------------------------------------------------- 1 | var kunstmaanMediaBundle = kunstmaanMediaBundle || {}; 2 | 3 | kunstmaanMediaBundle.bulkUpload = (function(window, undefined) { 4 | 5 | var init, initUploader; 6 | 7 | init = function() { 8 | initUploader(); 9 | }; 10 | 11 | 12 | initUploader = function() { 13 | // Get values and elements 14 | var $uploader = $('#bulk-upload'), 15 | url = $uploader.data('url'), 16 | $token = $uploader.data('token'); 17 | 18 | var $fileList = $('#bulk-upload__file-list'), 19 | $uploadWrapper = $('#bulk-button-wrapper--upload'), 20 | $completedWrapper = $('#bulk-button-wrapper--completed'), 21 | $pickFilesBtn = $('#bulk-button--pick-files'), 22 | $uploadFilesBtn = $('#bulk-button--upload-files'); 23 | 24 | 25 | // Setup 26 | var bulkUploader = new plupload.Uploader({ 27 | runtimes : 'html5', 28 | browse_button: 'bulk-button--pick-files', 29 | container: 'bulk-upload__container', 30 | headers: {'x-upload-token': $token}, 31 | url: url, 32 | processing_id: null, 33 | 34 | filters : { 35 | max_file_size : '100mb' 36 | }, 37 | 38 | init: { 39 | PostInit: function() { 40 | $fileList.html('

    No files selected

    '); 41 | 42 | $uploadFilesBtn.on('click', function() { 43 | bulkUploader.start(); 44 | }); 45 | }, 46 | 47 | FilesAdded: function(up, files) { 48 | $fileList.html(''); 49 | 50 | plupload.each(files, function(file) { 51 | $fileList.append('
  • ' + file.name + ' (' + plupload.formatSize(file.size) + ')
  • ') 52 | }); 53 | 54 | $uploadFilesBtn.removeClass('disabled'); 55 | $uploadFilesBtn.prop('disabled', false); 56 | $uploadFilesBtn.addClass('btn-primary'); 57 | $pickFilesBtn.removeClass('btn-primary').addClass('btn-default'); 58 | }, 59 | 60 | UploadProgress: function(up, file) { 61 | var $fileLine = $('#' + file.id); 62 | 63 | $fileLine.find('.js-status').html(file.percent + '%'); 64 | }, 65 | 66 | Error: function(up, err) { 67 | var $fileLine = $('#' + up.processing_id); 68 | 69 | $fileLine.find('.js-status').html('ERROR: ' + err.message); 70 | }, 71 | 72 | FileUploaded: function(up, file, res) { 73 | var $fileLine = $('#' + file.id); 74 | 75 | $fileLine.addClass('list-group-item-success'); 76 | 77 | var obj = null; 78 | obj = JSON.parse(res.response); 79 | 80 | if (obj.error) { 81 | $fileLine.addClass('list-group-item-danger'); 82 | $fileLine.find('.js-status').html('ERROR: ' + obj.error.message); 83 | } else { 84 | $fileLine.addClass('list-group-item-success'); 85 | } 86 | }, 87 | 88 | UploadComplete: function(up, files) { 89 | $completedWrapper.removeClass('hidden'); 90 | }, 91 | 92 | BeforeUpload: function(up, file) { 93 | up.processing_id = file.id; 94 | $uploadWrapper.addClass('hidden'); 95 | } 96 | } 97 | }); 98 | 99 | // Initialize uploader 100 | bulkUploader.init(); 101 | }; 102 | 103 | 104 | return { 105 | init: init 106 | }; 107 | 108 | }(window)); 109 | -------------------------------------------------------------------------------- /Helper/ManipulateImageService.php: -------------------------------------------------------------------------------- 1 | slugifier = $slugifier; 28 | $this->filterService = $filterService; 29 | $this->filterConfiguration = $filterConfiguration; 30 | } 31 | 32 | public function getFocusPointClass(EditableMediaWrapper $editableMediaWrapper, string $view = ''): string 33 | { 34 | if (null === $editableMediaWrapper->getRunTimeConfig()) { 35 | return ''; 36 | } 37 | 38 | $runTimeConfig = json_decode($editableMediaWrapper->getRunTimeConfig(), true); 39 | 40 | if (!is_array($runTimeConfig) || empty($view) || !isset($runTimeConfig[$view]['class'])) { 41 | return ''; 42 | } 43 | 44 | return $runTimeConfig[$view]['class']; 45 | } 46 | 47 | public function cropImage(EditableMediaWrapper $editableMediaWrapper, string $view = '', string $filter = 'optim'): string 48 | { 49 | $media = $editableMediaWrapper->getMedia(); 50 | if (null === $media) { 51 | return ''; 52 | } 53 | if (strpos($media->getContentType(), 'svg') !== false) { 54 | return $media->getUrl(); 55 | } 56 | 57 | $path = $media->getUrl(); 58 | $path = str_replace('://', '---', $path); 59 | 60 | $runTimeConfigForView = []; 61 | if ($editableMediaWrapper->getRunTimeConfig() !== null) { 62 | $runTimeConfig = json_decode($editableMediaWrapper->getRunTimeConfig(), true); 63 | 64 | if ( 65 | is_array($runTimeConfig) 66 | && !empty($view) 67 | && isset($runTimeConfig[$view]['start'], $runTimeConfig[$view]['size']) 68 | ) { 69 | $runTimeConfigForView = [ 70 | 'crop' => [ 71 | 'start' => $runTimeConfig[$view]['start'], 72 | 'size' => $runTimeConfig[$view]['size'], 73 | ], 74 | ]; 75 | } 76 | } 77 | 78 | try { 79 | $filterConfig = $this->filterConfiguration->get($filter); 80 | } catch (NonExistingFilterException $exception) { 81 | $filterConfig = $this->filterConfiguration->get('optim'); 82 | } 83 | 84 | $oemConfig = null; 85 | if (isset($filterConfig['filters'])) { 86 | $oemConfig = $filterConfig; 87 | unset($filterConfig['filters']['crop']); 88 | $runTimeConfigForView = array_merge_recursive($runTimeConfigForView, $filterConfig['filters']); 89 | unset($filterConfig['filters']); 90 | $this->filterConfiguration->set($filter, $filterConfig); 91 | } 92 | 93 | try { 94 | $response = $this->filterService->getUrlOfFilteredImageWithRuntimeFilters($path, $filter, $runTimeConfigForView); 95 | } catch (\Exception $exception) { 96 | $runTimeConfigForView = []; 97 | 98 | $response = $this->filterService->getUrlOfFilteredImageWithRuntimeFilters($path, 'optim', $runTimeConfigForView); 99 | } 100 | 101 | if ($oemConfig !== null) { 102 | $this->filterConfiguration->set($filter, $oemConfig); 103 | } 104 | 105 | return $response; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Command/CleanDeletedMediaCommand.php: -------------------------------------------------------------------------------- 1 | getContainer` usages 17 | */ 18 | class CleanDeletedMediaCommand extends ContainerAwareCommand 19 | { 20 | /** 21 | * @var EntityManager 22 | */ 23 | private $em; 24 | 25 | /** 26 | * @var MediaManager 27 | */ 28 | private $mediaManager; 29 | 30 | /** 31 | * @param EntityManagerInterface|null $em 32 | * @param MediaManager|null $mediaManager 33 | */ 34 | public function __construct(/* EntityManagerInterface */ $em = null, /* MediaManager */ $mediaManager = null) 35 | { 36 | parent::__construct(); 37 | 38 | if (!$em instanceof EntityManagerInterface) { 39 | @trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version symfony 3.4 and will be removed in symfony 4.0. If the command was registered by convention, make it a service instead. ', __METHOD__), E_USER_DEPRECATED); 40 | 41 | $this->setName(null === $em ? 'kuma:media:clean-deleted-media' : $em); 42 | 43 | return; 44 | } 45 | 46 | $this->em = $em; 47 | $this->mediaManager = $mediaManager; 48 | } 49 | 50 | protected function configure() 51 | { 52 | parent::configure(); 53 | 54 | $this 55 | ->setName('kuma:media:clean-deleted-media') 56 | ->setDescription('Throw away all files from the file system that have been deleted in the database') 57 | ->setHelp( 58 | 'The kuma:media:clean-deleted-media command can be used to clean up your file system after having deleted Media items using the backend.' 59 | ) 60 | ->addOption( 61 | 'force', 62 | 'f', 63 | InputOption::VALUE_NONE, 64 | 'If set does not prompt the user if he is certain he wants to remove Media' 65 | ); 66 | } 67 | 68 | /** 69 | * @return int 70 | */ 71 | protected function execute(InputInterface $input, OutputInterface $output) 72 | { 73 | if (null === $this->em) { 74 | $this->em = $this->getContainer()->get('doctrine.orm.entity_manager'); 75 | $this->mediaManager = $this->getContainer()->get('kunstmaan_media.media_manager'); 76 | } 77 | 78 | if ($input->getOption('force') !== true) { 79 | $helper = $this->getHelper('question'); 80 | $question = new ConfirmationQuestion('Are you sure you want to remove all deleted Media from the file system? ', false); 81 | 82 | if (!$helper->ask($input, $output, $question)) { 83 | return 0; 84 | } 85 | } 86 | 87 | $output->writeln('Removing all Media from the file system that have their status set to deleted in the database.'); 88 | 89 | $medias = $this->em->getRepository('KunstmaanMediaBundle:Media')->findAllDeleted(); 90 | 91 | try { 92 | $this->em->beginTransaction(); 93 | foreach ($medias as $media) { 94 | $this->mediaManager->removeMedia($media); 95 | } 96 | $this->em->flush(); 97 | $this->em->commit(); 98 | $output->writeln('All Media flagged as deleted, have now been removed from the file system.'); 99 | 100 | return 0; 101 | } catch (\Exception $e) { 102 | $this->em->rollback(); 103 | $output->writeln('An error occured while trying to delete Media from the file system:'); 104 | $output->writeln('' . $e->getMessage() . ''); 105 | 106 | return 1; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /EventListener/DoctrineMediaListener.php: -------------------------------------------------------------------------------- 1 | mediaManager = $mediaManager; 30 | } 31 | 32 | public function prePersist(LifecycleEventArgs $eventArgs) 33 | { 34 | $this->prepareMedia($eventArgs->getEntity()); 35 | } 36 | 37 | /** 38 | * @param object $entity 39 | * 40 | * @return bool 41 | */ 42 | private function prepareMedia($entity) 43 | { 44 | if (!$entity instanceof Media) { 45 | return false; 46 | } 47 | 48 | $this->mediaManager->prepareMedia($entity); 49 | 50 | return true; 51 | } 52 | 53 | public function preUpdate(PreUpdateEventArgs $eventArgs) 54 | { 55 | $entity = $eventArgs->getEntity(); 56 | if ($this->prepareMedia($entity)) { 57 | // Hack ? Don't know, that's the behaviour Doctrine 2 seems to want 58 | // See : http://www.doctrine-project.org/jira/browse/DDC-1020 59 | $em = $eventArgs->getEntityManager(); 60 | $uow = $em->getUnitOfWork(); 61 | $uow->recomputeSingleEntityChangeSet( 62 | $em->getClassMetadata(ClassLookup::getClass($entity)), 63 | $eventArgs->getEntity() 64 | ); 65 | 66 | // local media is soft-deleted or soft-delete is reverted 67 | $changeSet = $eventArgs->getEntityChangeSet(); 68 | if (isset($changeSet['deleted']) && $entity->getLocation() === 'local') { 69 | $deleted = (!$changeSet['deleted'][0] && $changeSet['deleted'][1]); 70 | $reverted = ($changeSet['deleted'][0] && !$changeSet['deleted'][1]); 71 | if ($deleted || $reverted) { 72 | $oldFileUrl = $entity->getUrl(); 73 | $newFileName = ($reverted ? $entity->getOriginalFilename() : uniqid()); 74 | $newFileUrl = \dirname($oldFileUrl) . '/' . $newFileName . '.' . pathinfo($oldFileUrl, PATHINFO_EXTENSION); 75 | $entity->setUrl($newFileUrl); 76 | $this->fileUrlMap[$newFileUrl] = $oldFileUrl; 77 | } 78 | } 79 | } 80 | } 81 | 82 | public function postPersist(LifecycleEventArgs $eventArgs) 83 | { 84 | $this->saveMedia($eventArgs->getEntity(), true); 85 | } 86 | 87 | /** 88 | * @param object $entity The entity 89 | * @param bool $new Is new 90 | */ 91 | private function saveMedia($entity, $new = false) 92 | { 93 | if (!$entity instanceof Media) { 94 | return; 95 | } 96 | 97 | $this->mediaManager->saveMedia($entity, $new); 98 | $url = $entity->getUrl(); 99 | $handler = $this->mediaManager->getHandler($entity); 100 | if (isset($this->fileUrlMap[$url]) && $handler instanceof FileHandler) { 101 | $regex = '~^' . preg_quote($handler->mediaPath, '~') . '~'; 102 | $originalFileName = preg_replace($regex, '/', $this->fileUrlMap[$url]); 103 | // Check if file exists on filesystem. 104 | if ($handler->fileSystem->has($originalFileName)) { 105 | $handler->fileSystem->rename( 106 | $originalFileName, 107 | preg_replace($regex, '/', $url) 108 | ); 109 | } 110 | unset($this->fileUrlMap[$url]); 111 | } 112 | } 113 | 114 | public function postUpdate(LifecycleEventArgs $eventArgs) 115 | { 116 | $this->saveMedia($eventArgs->getEntity()); 117 | } 118 | 119 | public function preRemove(LifecycleEventArgs $eventArgs) 120 | { 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Helper/MediaManager.php: -------------------------------------------------------------------------------- 1 | handlers[$handler->getName()] = $handler; 32 | 33 | return $this; 34 | } 35 | 36 | /** 37 | * @param AbstractMediaHandler $handler Media handler 38 | * 39 | * @return MediaManager 40 | */ 41 | public function setDefaultHandler(AbstractMediaHandler $handler) 42 | { 43 | $this->defaultHandler = $handler; 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * Returns handler with the highest priority to handle the Media item which can handle the item. If no handler is found, it returns FileHandler 50 | * 51 | * @param Media|File $media 52 | * 53 | * @return AbstractMediaHandler 54 | */ 55 | public function getHandler($media) 56 | { 57 | $bestHandler = $this->defaultHandler; 58 | foreach ($this->handlers as $handler) { 59 | if ($handler->canHandle($media) && $handler->getPriority() > $bestHandler->getPriority()) { 60 | $bestHandler = $handler; 61 | } 62 | } 63 | 64 | return $bestHandler; 65 | } 66 | 67 | /** 68 | * Returns handler with the highest priority to handle the Media item based on the Type. If no handler is found, it returns FileHandler 69 | * 70 | * @param string $type 71 | * 72 | * @return AbstractMediaHandler 73 | */ 74 | public function getHandlerForType($type) 75 | { 76 | $bestHandler = $this->defaultHandler; 77 | foreach ($this->handlers as $handler) { 78 | if ($handler->getType() == $type && $handler->getPriority() > $bestHandler->getPriority()) { 79 | $bestHandler = $handler; 80 | } 81 | } 82 | 83 | return $bestHandler; 84 | } 85 | 86 | /** 87 | * @return AbstractMediaHandler[] 88 | */ 89 | public function getHandlers() 90 | { 91 | return $this->handlers; 92 | } 93 | 94 | /** 95 | * @return MediaManager 96 | */ 97 | public function prepareMedia(Media $media) 98 | { 99 | $handler = $this->getHandler($media); 100 | $handler->prepareMedia($media); 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * @param Media $media The media 107 | * @param bool $new Is new 108 | */ 109 | public function saveMedia(Media $media, $new = false) 110 | { 111 | $handler = $this->getHandler($media); 112 | 113 | if ($new) { 114 | $handler->saveMedia($media); 115 | } else { 116 | $handler->updateMedia($media); 117 | } 118 | } 119 | 120 | public function removeMedia(Media $media) 121 | { 122 | $handler = $this->getHandler($media); 123 | $handler->removeMedia($media); 124 | } 125 | 126 | /** 127 | * @param mixed $data 128 | * 129 | * @return Media 130 | */ 131 | public function createNew($data) 132 | { 133 | foreach ($this->handlers as $handler) { 134 | $result = $handler->createNew($data); 135 | if ($result) { 136 | return $result; 137 | } 138 | } 139 | 140 | return null; 141 | } 142 | 143 | /** 144 | * @return array 145 | */ 146 | public function getFolderAddActions() 147 | { 148 | $result = []; 149 | foreach ($this->handlers as $handler) { 150 | $actions = $handler->getAddFolderActions(); 151 | if ($actions) { 152 | $result = array_merge($actions, $result); 153 | } 154 | } 155 | 156 | return $result; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Validator/Constraints/HasGuessableExtensionValidator.php: -------------------------------------------------------------------------------- 1 | mimeTypes = $mimeTypes; 38 | } 39 | 40 | /** 41 | * @throws ConstraintDefinitionException 42 | * @throws UnexpectedTypeException 43 | */ 44 | public function validate($value, Constraint $constraint) 45 | { 46 | if (!$constraint instanceof HasGuessableExtension) { 47 | throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\HasGuessableExtension'); 48 | } 49 | 50 | if (!$value instanceof UploadedFile) { 51 | return; 52 | } 53 | 54 | $contentType = $this->guessMimeType($value->getPathname()); 55 | $pathInfo = pathinfo($value->getClientOriginalName()); 56 | if (!\array_key_exists('extension', $pathInfo)) { 57 | $pathInfo['extension'] = $this->getExtension($contentType); 58 | } 59 | 60 | if ($pathInfo['extension'] === null) { 61 | $this->context->buildViolation($constraint->notGuessableErrorMessage) 62 | ->setCode(HasGuessableExtension::NOT_GUESSABLE_ERROR) 63 | ->addViolation(); 64 | } 65 | } 66 | 67 | private function guessMimeType($pathName) 68 | { 69 | if ($this->mimeTypeGuesser !== null) { 70 | return $this->mimeTypeGuesser->guess($pathName); 71 | } 72 | 73 | return $this->mimeTypes->guessMimeType($pathName); 74 | } 75 | 76 | private function getExtension($mimeType) 77 | { 78 | if ($this->extensionGuesser !== null) { 79 | return $this->extensionGuesser->guess($mimeType); 80 | } 81 | 82 | return $this->mimeTypes->getExtensions($mimeType)[0] ?? null; 83 | } 84 | 85 | /** 86 | * @deprecated This method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. 87 | */ 88 | public function setExtensionGuesser(ExtensionGuesserFactoryInterface $extensionGuesserFactory) 89 | { 90 | @trigger_error(sprintf('Calling the "%s" method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. Inject the required services through the constructor instead.', __METHOD__), E_USER_DEPRECATED); 91 | 92 | $this->extensionGuesser = $extensionGuesserFactory->get(); 93 | } 94 | 95 | /** 96 | * @deprecated This method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. 97 | */ 98 | public function setMimeTypeGuesser(MimeTypeGuesserFactoryInterface $mimeTypeGuesserFactory) 99 | { 100 | @trigger_error(sprintf('Calling the "%s" method is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. Inject the required services through the constructor instead.', __METHOD__), E_USER_DEPRECATED); 101 | 102 | $this->mimeTypeGuesser = $mimeTypeGuesserFactory->get(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Helper/RemoteAudio/RemoteAudioHandler.php: -------------------------------------------------------------------------------- 1 | soundcloudApiKey = $soundcloudApiKey; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getName() 39 | { 40 | return 'Remote Audio Handler'; 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getType() 47 | { 48 | return RemoteAudioHandler::TYPE; 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getFormType() 55 | { 56 | return RemoteAudioType::class; 57 | } 58 | 59 | /** 60 | * @return mixed 61 | */ 62 | public function getSoundcloudApiKey() 63 | { 64 | return $this->soundcloudApiKey; 65 | } 66 | 67 | /** 68 | * @param mixed $object 69 | * 70 | * @return bool 71 | */ 72 | public function canHandle($object) 73 | { 74 | if ( 75 | (\is_string($object)) || 76 | ($object instanceof Media && $object->getContentType() == RemoteAudioHandler::CONTENT_TYPE) 77 | ) { 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | /** 85 | * @return RemoteAudioHelper 86 | */ 87 | public function getFormHelper(Media $media) 88 | { 89 | return new RemoteAudioHelper($media); 90 | } 91 | 92 | /** 93 | * @throws \RuntimeException when the file does not exist 94 | */ 95 | public function prepareMedia(Media $media) 96 | { 97 | if (null === $media->getUuid()) { 98 | $uuid = uniqid(); 99 | $media->setUuid($uuid); 100 | } 101 | $audio = new RemoteAudioHelper($media); 102 | $code = $audio->getCode(); 103 | //update thumbnail 104 | switch ($audio->getType()) { 105 | case 'soundcloud': 106 | $scData = json_decode( 107 | file_get_contents( 108 | 'http://api.soundcloud.com/tracks/' . $code . '.json?client_id=' . $this->getSoundcloudApiKey() 109 | ) 110 | ); 111 | $artworkUrl = $scData->artwork_url; 112 | $artworkUrl = str_replace('large.jpg', 't500x500.jpg', $artworkUrl); 113 | $audio->setThumbnailUrl($artworkUrl); 114 | 115 | break; 116 | } 117 | } 118 | 119 | public function saveMedia(Media $media) 120 | { 121 | } 122 | 123 | public function removeMedia(Media $media) 124 | { 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | public function updateMedia(Media $media) 131 | { 132 | } 133 | 134 | /** 135 | * {@inheritdoc} 136 | */ 137 | public function createNew($data) 138 | { 139 | return null; 140 | } 141 | 142 | /** 143 | * {@inheritdoc} 144 | */ 145 | public function getShowTemplate(Media $media) 146 | { 147 | return '@KunstmaanMedia/Media/RemoteAudio/show.html.twig'; 148 | } 149 | 150 | /** 151 | * @param Media $media The media entity 152 | * @param string $basepath The base path 153 | * 154 | * @return string 155 | */ 156 | public function getImageUrl(Media $media, $basepath) 157 | { 158 | $helper = new RemoteAudioHelper($media); 159 | 160 | return $helper->getThumbnailUrl(); 161 | } 162 | 163 | /** 164 | * @return array 165 | */ 166 | public function getAddFolderActions() 167 | { 168 | return [ 169 | RemoteAudioHandler::TYPE => [ 170 | 'type' => RemoteAudioHandler::TYPE, 171 | 'name' => 'media.audio.add', 172 | ], 173 | ]; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Command/CreatePdfPreviewCommand.php: -------------------------------------------------------------------------------- 1 | getContainer` usages 17 | */ 18 | class CreatePdfPreviewCommand extends ContainerAwareCommand 19 | { 20 | /** 21 | * @var EntityManager 22 | */ 23 | private $em; 24 | 25 | /** 26 | * @var PdfTransformer 27 | */ 28 | private $pdfTransformer; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $webRoot; 34 | 35 | /** 36 | * @var bool 37 | */ 38 | private $enablePdfPreview; 39 | 40 | /** 41 | * @param EntityManagerInterface|null $em 42 | * @param PdfTransformer|null $mediaManager 43 | */ 44 | public function __construct(/* EntityManagerInterface */ $em = null, /* PdfTransformer */ $pdfTransformer = null, $webRoot = null, $enablePdfPreview = null) 45 | { 46 | parent::__construct(); 47 | 48 | if (!$em instanceof EntityManagerInterface) { 49 | @trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version symfony 3.4 and will be removed in symfony 4.0. If the command was registered by convention, make it a service instead. ', __METHOD__), E_USER_DEPRECATED); 50 | 51 | $this->setName(null === $em ? 'kuma:media:create-pdf-previews' : $em); 52 | 53 | return; 54 | } 55 | 56 | $this->em = $em; 57 | $this->pdfTransformer = $pdfTransformer; 58 | $this->webRoot = $webRoot; 59 | $this->enablePdfPreview = $enablePdfPreview; 60 | } 61 | 62 | protected function configure() 63 | { 64 | parent::configure(); 65 | 66 | $this 67 | ->setName('kuma:media:create-pdf-previews') 68 | ->setDescription('Create preview images for PDFs that have already been uploaded') 69 | ->setHelp( 70 | 'The kuma:media:create-pdf-previews command can be used to create preview images for PDFs that have already been uploaded.' 71 | ); 72 | } 73 | 74 | /** 75 | * @return int 76 | */ 77 | public function execute(InputInterface $input, OutputInterface $output) 78 | { 79 | if (null === $this->em) { 80 | $this->em = $this->getContainer()->get('doctrine.orm.entity_manager'); 81 | $this->pdfTransformer = $this->getContainer()->get('kunstmaan_media.pdf_transformer'); 82 | $this->webRoot = $this->getContainer()->getParameter('kunstmaan_media.web_root'); 83 | $this->enablePdfPreview = $this->getContainer()->getParameter('kunstmaan_media.enable_pdf_preview'); 84 | } 85 | 86 | $output->writeln('Creating PDF preview images...'); 87 | 88 | /** 89 | * @var EntityManager 90 | */ 91 | $medias = $this->em->getRepository('KunstmaanMediaBundle:Media')->findBy( 92 | ['contentType' => 'application/pdf', 'deleted' => false] 93 | ); 94 | /** @var Media $media */ 95 | foreach ($medias as $media) { 96 | try { 97 | $this->pdfTransformer->apply($this->webRoot . $media->getUrl()); 98 | } catch (ImagickException $e) { 99 | $output->writeln('' . $e->getMessage() . ''); 100 | } 101 | } 102 | 103 | $output->writeln('PDF preview images have been created.'); 104 | 105 | return 0; 106 | } 107 | 108 | /** 109 | * Checks whether the command is enabled or not in the current environment. 110 | * 111 | * Override this to check for x or y and return false if the command can not 112 | * run properly under the current conditions. 113 | * 114 | * @return bool 115 | */ 116 | public function isEnabled() 117 | { 118 | if (null === $this->enablePdfPreview) { 119 | $this->enablePdfPreview = $this->getContainer()->getParameter('kunstmaan_media.enable_pdf_preview'); 120 | } 121 | 122 | return $this->enablePdfPreview; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /DataFixtures/ORM/FolderFixtures.php: -------------------------------------------------------------------------------- 1 | setRel(Folder::TYPE_MEDIA); 23 | $gal->setName('Media'); 24 | $gal->setTranslatableLocale('en'); 25 | $manager->persist($gal); 26 | $manager->flush(); 27 | $this->addReference('media-folder-en', $gal); 28 | 29 | $gal->setTranslatableLocale('nl'); 30 | $manager->refresh($gal); 31 | $gal->setName('Media'); 32 | $manager->persist($gal); 33 | $manager->flush(); 34 | 35 | $gal->setTranslatableLocale('fr'); 36 | $manager->refresh($gal); 37 | $gal->setName('Média'); 38 | $manager->persist($gal); 39 | $manager->flush(); 40 | 41 | $subgal = new Folder(); 42 | $subgal->setParent($gal); 43 | $subgal->setRel(Folder::TYPE_IMAGE); 44 | $subgal->setName('Images'); 45 | $subgal->setTranslatableLocale('en'); 46 | $manager->persist($subgal); 47 | $manager->flush(); 48 | $this->addReference('images-folder-en', $subgal); 49 | 50 | $subgal->setTranslatableLocale('nl'); 51 | $manager->refresh($subgal); 52 | $subgal->setName('Afbeeldingen'); 53 | $manager->persist($subgal); 54 | $manager->flush(); 55 | 56 | $subgal->setTranslatableLocale('fr'); 57 | $manager->refresh($subgal); 58 | $subgal->setName('Images'); 59 | $manager->persist($subgal); 60 | $manager->flush(); 61 | 62 | $subgal = new Folder(); 63 | $subgal->setParent($gal); 64 | $subgal->setRel(Folder::TYPE_FILES); 65 | $subgal->setName('Files'); 66 | $subgal->setTranslatableLocale('en'); 67 | $manager->persist($subgal); 68 | $manager->flush(); 69 | $this->addReference('files-folder-en', $subgal); 70 | 71 | $subgal->setTranslatableLocale('nl'); 72 | $manager->refresh($subgal); 73 | $subgal->setName('Bestanden'); 74 | $manager->persist($subgal); 75 | $manager->flush(); 76 | 77 | $subgal->setTranslatableLocale('fr'); 78 | $manager->refresh($subgal); 79 | $subgal->setName('Fichiers'); 80 | $manager->persist($subgal); 81 | $manager->flush(); 82 | 83 | $subgal = new Folder(); 84 | $subgal->setParent($gal); 85 | $subgal->setRel(Folder::TYPE_SLIDESHOW); 86 | $subgal->setName('Slides'); 87 | $subgal->setTranslatableLocale('en'); 88 | $manager->persist($subgal); 89 | $manager->flush(); 90 | $this->addReference('slides-folder-en', $subgal); 91 | 92 | $subgal->setTranslatableLocale('nl'); 93 | $manager->refresh($subgal); 94 | $subgal->setName('Presentaties'); 95 | $manager->persist($subgal); 96 | $manager->flush(); 97 | 98 | $subgal->setTranslatableLocale('fr'); 99 | $manager->refresh($subgal); 100 | $subgal->setName('Presentations'); 101 | $manager->persist($subgal); 102 | $manager->flush(); 103 | 104 | $subgal = new Folder(); 105 | $subgal->setParent($gal); 106 | $subgal->setRel(Folder::TYPE_VIDEO); 107 | $subgal->setName('Videos'); 108 | $subgal->setTranslatableLocale('en'); 109 | $manager->persist($subgal); 110 | $manager->flush(); 111 | $this->addReference('videos-folder-en', $subgal); 112 | 113 | $subgal->setTranslatableLocale('nl'); 114 | $manager->refresh($subgal); 115 | $subgal->setName('Video\'s'); 116 | $manager->persist($subgal); 117 | $manager->flush(); 118 | 119 | $subgal->setTranslatableLocale('fr'); 120 | $manager->refresh($subgal); 121 | $subgal->setName('Vidéos'); 122 | $manager->persist($subgal); 123 | $manager->flush(); 124 | } 125 | 126 | /** 127 | * Get the order of this fixture 128 | * 129 | * @return int 130 | */ 131 | public function getOrder() 132 | { 133 | return 1; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /Resources/views/Form/_focus-point-block.html.twig: -------------------------------------------------------------------------------- 1 | {# @experimental This feature is experimental and is a subject to change, be advised when using this feature and templates. #} 2 | {% set previewImageUrl = '' %} 3 | 4 | {% if imageUrl is defined and imageUrl is not null %} 5 | {% set previewImageUrl = imageUrl %} 6 | {% endif %} 7 |
    8 |
    9 |
    10 |
    11 | 15 |
    16 |
    17 | 21 |
    22 |
    23 | 27 |
    28 |
    29 | 33 |
    34 |
    35 | 39 |
    40 |
    41 | 45 |
    46 |
    47 | 51 |
    52 |
    53 | 57 |
    58 |
    59 | 63 |
    64 |
    65 |
    66 | 67 |
    68 |
    69 |
    70 | -------------------------------------------------------------------------------- /Resources/translations/messages.es.yml: -------------------------------------------------------------------------------- 1 | --- 2 | media: 3 | aviary: 4 | title: Aviary 5 | nothing: Nothing to see here. 6 | media: 7 | no: No files in this folder yet. 8 | dnd: 9 | tip: "Tip:" 10 | tiptext: did you know you can just drop multiple files here? 11 | alert: 12 | title: Incoming! 13 | text: Drop your files to instantly upload them to this folder. 14 | bulkupload: 15 | addto: Upload files to "%folder%" 16 | contenttab: 17 | title: Content 18 | propertiestab: 19 | title: Properties 20 | title: Media 21 | add: 22 | action: Add media 23 | edit: 24 | action: Edit 25 | download: 26 | action: Download 27 | mediainfo: 28 | name: Name 29 | contenttype: Content-type 30 | createdat: Added 31 | updatedat: Updated 32 | downloadlink: Download link 33 | addto: Add media to "%folder%" 34 | deletesure: Are you sure you want to delete this item? 35 | new: Add media to "%folder%" 36 | folder: 37 | addsub: 38 | action: Add subfolder 39 | action_short: Add 40 | modal: 41 | title: Add subfolder 42 | save: Add 43 | form: 44 | name: Name 45 | rel: Rel 46 | parent: Parent 47 | internal_name: Internal name 48 | success: 49 | text: Folder '%folder%' has been created! 50 | empty: 51 | action: Empty folder 52 | action_short: Empty 53 | modal: 54 | title: Empty folder 55 | text: Are you sure you want to delete the content of folder "%folder%"? 56 | checkbox: Also delete subfolders 57 | save: Empty 58 | success: 59 | text: Folder '%folder%' has been emptied! 60 | bulk_move: 61 | action: Bulk move media 62 | action_short: Bulk move 63 | modal: 64 | title: Bulk move media 65 | text: Select to which folder you want to move the selected media. 66 | save: "Move" 67 | form: 68 | name: Parent folder 69 | success: 70 | text: Media has been moved successfully! 71 | sub: 72 | no: No subfolders yet. 73 | delete: 74 | action: Delete this folder 75 | action_short: Delete 76 | modal: 77 | title: Delete folder 78 | text: Are you sure you want to delete "%folder%"? 79 | failure: 80 | text: You can't delete the %folder% folder! 81 | success: 82 | text: Folder '%folder%' has been deleted! 83 | save: Save 84 | contenttab: 85 | title: Content 86 | propertiestab: 87 | title: Properties 88 | sortby: Sort by 89 | show: 90 | success: 91 | text: Folder %folder% has been updated! 92 | bulkupload: 93 | upload: Upload 94 | bulkupload: Bulk upload 95 | select_files: Select files 96 | upload_more: Upload more files 97 | back_to_folder: Back to folder 98 | upload_finished: The file upload has finished. 99 | not_available: The bulk upload functionality will not work for you. Your browser doesn't have Flash, Silverlight or HTML5 support. 100 | slide: 101 | add: Add Slide 102 | modal: 103 | title: Add Slide 104 | save: Add 105 | video: 106 | add: Add Video 107 | modal: 108 | title: Add Video 109 | save: Add 110 | audio: 111 | add: Add Audio 112 | modal: 113 | title: Add Audio 114 | save: Add 115 | file: 116 | add: Add File 117 | modal: 118 | title: Add File 119 | save: Add 120 | widget: 121 | choose: Choose 122 | delete: Delete 123 | media_chooser: Media-chooser 124 | icon_chooser: Icon-chooser 125 | adminlist: 126 | configurator: 127 | name: Name 128 | type: Type 129 | date: Date 130 | filesize: Filesize 131 | filter: 132 | name: Name 133 | type: Type 134 | updated_at: Date 135 | filesize: Filesize (in bytes) 136 | form: 137 | remote: 138 | name: 139 | label: Name 140 | code: 141 | label: Code 142 | type: 143 | label: Type 144 | copyright: 145 | label: Copyright 146 | description: 147 | label: Description 148 | bulk_upload: 149 | files: 150 | label: Files 151 | file: 152 | name: 153 | label: Name 154 | file: 155 | label: File 156 | copyright: 157 | label: Copyright 158 | description: 159 | label: Description 160 | originalFilename: 161 | label: Original filename 162 | remote_audio: 163 | type: 164 | label: Type 165 | remote_slide: 166 | type: 167 | label: Type 168 | remote_video: 169 | type: 170 | label: Type 171 | flash: 172 | created: Media %medianame% has been created! 173 | not_created: Media not created! %mediaerrors% 174 | -------------------------------------------------------------------------------- /Resources/translations/messages.pl.yml: -------------------------------------------------------------------------------- 1 | --- 2 | media: 3 | aviary: 4 | title: Aviary 5 | nothing: Niczego tutaj nie ma. 6 | media: 7 | no: W tym folderze nie ma na razie żadnych plików. 8 | dnd: 9 | tip: "Rada:" 10 | tiptext: Czy wiesz, że tutaj możesz wgrać wiele plików jednocześnie? 11 | alert: 12 | title: Przychodzace! 13 | text: Wrzuć swoje pliki do tego folderu w celu nieustannej aktualizacji. 14 | bulkupload: 15 | addto: Wgraj pliki do "%folder%" 16 | contenttab: 17 | title: Treść 18 | propertiestab: 19 | title: Właściwości 20 | title: Media 21 | add: 22 | action: Dodaj media 23 | edit: 24 | action: Edytuj 25 | download: 26 | action: Pobierz 27 | mediainfo: 28 | name: Nazwa 29 | contenttype: Typ treści 30 | createdat: Dodane 31 | updatedat: Zaktualizowane 32 | downloadlink: Pobierz link 33 | addto: Dodaj plik do "%folder%" 34 | deletesure: Jesteś pewien, że chcesz usunąć? 35 | new: Dodaj plik do "%folder%" 36 | folder: 37 | addsub: 38 | action: Dodaj folder 39 | action_short: Dodaj 40 | modal: 41 | title: Dodaj folder 42 | save: Dodaj 43 | form: 44 | name: Nazwa 45 | rel: Typ 46 | parent: Rodzic 47 | internal_name: Nazwa wewnętrzna 48 | success: 49 | text: Folder '%folder%' został utworzony! 50 | empty: 51 | action: Wyczyść folder 52 | action_short: Wyczyść 53 | modal: 54 | title: Wyczyśc folder 55 | text: Czy na pewno chcesz usunąc zawartośc "%folder%"? 56 | checkbox: Usuń też podfoldery 57 | save: Czyść 58 | success: 59 | text: Folder '%folder%' został wyczyszczony! 60 | bulk_move: 61 | action: Bulk move media 62 | action_short: Bulk move 63 | modal: 64 | title: Bulk move media 65 | text: Select to which folder you want to move the selected media. 66 | save: "Move" 67 | form: 68 | name: Parent folder 69 | success: 70 | text: Media has been moved successfully! 71 | sub: 72 | no: Brak podfolderów. 73 | delete: 74 | action: Usuń ten folder 75 | action_short: Usuń 76 | modal: 77 | title: Usuń folder 78 | text: Jesteś pewien, że chcesz usunąć "%folder%"? 79 | failure: 80 | text: Nie możesz usunąć folderu %folder%! 81 | success: 82 | text: Folder '%folder%' został pomyślnie usunięty! 83 | save: Zapisz 84 | contenttab: 85 | title: Treść 86 | propertiestab: 87 | title: Właściwości 88 | sortby: Sortuj 89 | show: 90 | success: 91 | text: Folder %folder% został zaktualizowany! 92 | bulkupload: 93 | upload: Wgraj 94 | bulkupload: Wgraj wiele plików jednocześnie 95 | select_files: Wybierz pliki 96 | upload_more: Wgraj więcej plików 97 | back_to_folder: Wróć do folderu 98 | upload_finished: Wgrywanie pliku zostało zakończone 99 | not_available: 'Wgrywanie wielu plików jednocześnie nie działa poprawnie. Twoja przeglądarka nie ma zainstalowanych programów: Flash, Silverlight lub HTML5 support.' 100 | slide: 101 | add: Dodaj slajd 102 | modal: 103 | title: Dodaj slajd 104 | save: Dodaj 105 | video: 106 | add: Dodaj plik video 107 | modal: 108 | title: Dodaj plik video 109 | save: Dodaj 110 | audio: 111 | add: Dodaj plik audio 112 | modal: 113 | title: Dodaj plik audio 114 | save: Dodaj 115 | file: 116 | add: Dodaj plik 117 | modal: 118 | title: Dodaj plik 119 | save: Dodaj 120 | widget: 121 | choose: Wybierz 122 | delete: Usuń 123 | media_chooser: Wybierz media 124 | icon_chooser: Wybierz ikonę 125 | adminlist: 126 | configurator: 127 | name: Nazwa 128 | type: Typ 129 | date: Data 130 | filesize: Rozmiar 131 | filter: 132 | name: Nazwa 133 | type: Typ 134 | updated_at: Data 135 | filesize: Rozmiar (w bajtach) 136 | form: 137 | remote: 138 | name: 139 | label: Nazwa 140 | code: 141 | label: Kod 142 | type: 143 | label: Typ 144 | copyright: 145 | label: Prawa autorskie 146 | description: 147 | label: Opis 148 | bulk_upload: 149 | files: 150 | label: Pliki 151 | file: 152 | name: 153 | label: Nazwa 154 | file: 155 | label: Plik 156 | copyright: 157 | label: Prawa autorskie 158 | description: 159 | label: Opis 160 | originalFilename: 161 | label: Nazwa źródłowa 162 | remote_audio: 163 | type: 164 | label: Typ 165 | remote_slide: 166 | type: 167 | label: Typ 168 | remote_video: 169 | type: 170 | label: Typ 171 | flash: 172 | created: Media %medianame% został utworzony! 173 | not_created: Media nie utworzone! %mediaerrors% 174 | -------------------------------------------------------------------------------- /Resources/translations/messages.hu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | media: 3 | aviary: 4 | title: Aviary 5 | nothing: Nincs megjeleníthető elem 6 | media: 7 | no: Még nincs fájl ebben a könyvtárban. 8 | dnd: 9 | tip: "Típus:" 10 | tiptext: Tudtad, hogy a fájlokat egyből ebbe a mappába is feltöltheted? 11 | alert: 12 | title: Érkezik! 13 | text: Húzd ide a fájlokat az azonnali feltöltéshez ebbe a könyvtárba. 14 | bulkupload: 15 | addto: Fájlok feltöltése a "%folder%" mappába 16 | contenttab: 17 | title: Tartalom 18 | propertiestab: 19 | title: Részletek 20 | title: Média 21 | add: 22 | action: Hozzáadása 23 | edit: 24 | action: Szerkesztés 25 | download: 26 | action: Letöltés 27 | mediainfo: 28 | name: Név 29 | contenttype: Információ 30 | createdat: Létrehozva 31 | updatedat: Frissítve 32 | downloadlink: 'Letölthető innen:' 33 | addto: ehhez 34 | deletesure: Biztos, hogy törölni szeretné? 35 | new: Új hozzáadása 36 | folder: 37 | addsub: 38 | action: Almappa létrehozása 39 | action_short: Almappa hozzáadása 40 | modal: 41 | title: Almappa hozzáadása 42 | save: Mentés 43 | form: 44 | name: Név 45 | rel: Rel 46 | parent: Szülő 47 | internal_name: Belső név 48 | success: 49 | text: A(z) `%folder%` mappa sikeresen létrehozva 50 | empty: 51 | action: Mappa ürítése 52 | action_short: Ürítés 53 | modal: 54 | title: Mappa ürítése 55 | text: Bitzos benne, hogy törölni akarja a(z) `%folder%` mappa tartalmát? 56 | checkbox: Alkönyvtárak törlése is 57 | save: Ürítés 58 | success: 59 | text: A `%folder%` mappa üres! 60 | bulk_move: 61 | action: Tömeges média áthelyezés 62 | action_short: Tömeges áthelyezés 63 | modal: 64 | title: Tömeges média áthelyezés 65 | text: Válassza ki a mappát, ahová szeretné a kiválasztott file-t áthelyezni. 66 | save: "Mozgatás" 67 | form: 68 | name: Szülő-mappa 69 | success: 70 | text: Média sikeresen áthelyezve! 71 | sub: 72 | no: Még nincsenek almappák 73 | delete: 74 | action: Törlés 75 | action_short: Törlés 76 | modal: 77 | title: Mappa törlése 78 | text: Biztosan törölni akarja a `%folder%` mappát? 79 | failure: 80 | text: Nem törölhető a `%folder%` mappa! 81 | success: 82 | text: A(z) `%folder%` mappa sikeresen törölve! 83 | save: Mentés 84 | contenttab: 85 | title: Tartalom 86 | propertiestab: 87 | title: Részletek 88 | sortby: Rendezés 89 | show: 90 | success: 91 | text: A(z) `%folder%` mappa módosítva! 92 | bulkupload: 93 | upload: Feltöltés 94 | bulkupload: Tömeges feltöltés 95 | select_files: Fájlok kiválasztása 96 | upload_more: További fájlok feltöltése 97 | back_to_folder: Vissza a mappába 98 | upload_finished: Feltöltés sikeres volt 99 | not_available: Tömeges feltöltés nem lehetséges. A böngészőjében nem elérhető Flash, Silverlight vagy HTML5 támogatás. 100 | slide: 101 | add: Bemutató hozzáadása 102 | modal: 103 | title: Bemutató hozzáadása 104 | save: Hozzáadás 105 | video: 106 | add: Videó hozzáadása 107 | modal: 108 | title: Videó hozzáadása 109 | save: Hozzáadás 110 | audio: 111 | add: Audió hozzáadása 112 | modal: 113 | title: Audió hozzáadása 114 | save: Hozzáadás 115 | file: 116 | add: Fájl feltöltése 117 | modal: 118 | title: Fájl hozzáadása 119 | save: Hozzáadás 120 | widget: 121 | choose: Válassz 122 | delete: Törlés 123 | media_chooser: Média választó 124 | icon_chooser: Ikon választó 125 | adminlist: 126 | configurator: 127 | name: Név 128 | type: Típus 129 | date: Dátum 130 | filesize: Fájlméret 131 | filter: 132 | name: Név 133 | type: Típus 134 | updated_at: Dátum 135 | filesize: Fájlméret (byte-ban) 136 | form: 137 | remote: 138 | name: 139 | label: Név 140 | code: 141 | label: Kód 142 | type: 143 | label: Típus 144 | copyright: 145 | label: Szerzői jog 146 | description: 147 | label: Leírás 148 | bulk_upload: 149 | files: 150 | label: Fájlok 151 | file: 152 | name: 153 | label: Név 154 | file: 155 | label: Fájl 156 | copyright: 157 | label: Szerzői jog 158 | description: 159 | label: Leírás 160 | originalFilename: 161 | label: Eredeti fájlnév 162 | remote_audio: 163 | type: 164 | label: Típus 165 | remote_slide: 166 | type: 167 | label: Típus 168 | remote_video: 169 | type: 170 | label: Típus 171 | flash: 172 | created: A %medianame% file sikeresen létrehozva! 173 | not_created: A file nem lett létrehozva! %mediaerrors% 174 | -------------------------------------------------------------------------------- /Resources/translations/messages.it.yml: -------------------------------------------------------------------------------- 1 | --- 2 | media: 3 | aviary: 4 | title: Aviary 5 | nothing: Niente da vedere qui. 6 | media: 7 | no: Non sono presenti file in questa cartella. 8 | dnd: 9 | tip: "Tip:" 10 | tiptext: did you know you can just drop multiple files here? 11 | alert: 12 | title: Incoming! 13 | text: Drop your files to instantly upload them to this folder. 14 | bulkupload: 15 | addto: Carica i files in "%folder%" 16 | contenttab: 17 | title: Contenuto 18 | propertiestab: 19 | title: Proprietà 20 | title: Media 21 | add: 22 | action: Add media 23 | edit: 24 | action: Modifica 25 | download: 26 | action: Download 27 | mediainfo: 28 | name: Nome 29 | contenttype: Content-type 30 | createdat: Aggiunto 31 | updatedat: Aggiornato 32 | downloadlink: Link per download 33 | addto: Aggiungi il media a "%folder%" 34 | deletesure: Sei sicuro di voler cancellare l'elemento? 35 | new: Aggiungi il media a "%folder%" 36 | folder: 37 | addsub: 38 | action: Aggiungi sottocartella 39 | action_short: Aggiungi 40 | modal: 41 | title: Aggiungi sottocartella 42 | save: Aggiungi 43 | form: 44 | name: Name 45 | rel: Rel 46 | parent: Parent 47 | internal_name: Internal name 48 | success: 49 | text: Folder '%folder%' has been created! 50 | empty: 51 | action: Empty folder 52 | action_short: Empty 53 | modal: 54 | title: Empty folder 55 | text: Are you sure you want to delete the content of folder "%folder%"? 56 | checkbox: Also delete subfolders 57 | save: Empty 58 | success: 59 | text: Folder '%folder%' has been emptied! 60 | bulk_move: 61 | action: Bulk move media 62 | action_short: Bulk move 63 | modal: 64 | title: Bulk move media 65 | text: Select to which folder you want to move the selected media. 66 | save: "Move" 67 | form: 68 | name: Parent folder 69 | success: 70 | text: Media has been moved successfully! 71 | sub: 72 | no: Sottocartelle non presenti. 73 | delete: 74 | action: Cancella questa cartella 75 | action_short: Cancella 76 | modal: 77 | title: Cancella cartella 78 | text: Sei sicuro di voler cancellare "%folder%"? 79 | failure: 80 | text: You can't delete the %folder% folder! 81 | success: 82 | text: Folder '%folder%' has been deleted! 83 | save: Salva 84 | contenttab: 85 | title: Contenuto 86 | propertiestab: 87 | title: Proprietà 88 | sortby: Sort by 89 | show: 90 | success: 91 | text: Folder %folder% has been updated! 92 | bulkupload: 93 | upload: Caricamento 94 | bulkupload: Caricamento multiplo 95 | select_files: Seleleziona i file 96 | upload_more: Carica più file 97 | back_to_folder: Torna alla cartella 98 | upload_finished: Il caricamento del file è terminato. 99 | not_available: La funzionalità di caricamento multiplo non funzionerà per te. Il tuo browser non ha il supporto Flash, Silverlight o HTML5. 100 | slide: 101 | add: Aggiungi Slide 102 | modal: 103 | title: Aggiungi Slide 104 | save: Aggiungi 105 | video: 106 | add: Aggiungi Video 107 | modal: 108 | title: Aggiungi Video 109 | save: Aggiungi 110 | audio: 111 | add: Aggiungi Audio 112 | modal: 113 | title: Aggiungi Audio 114 | save: Aggiungi 115 | file: 116 | add: Aggiungi File 117 | modal: 118 | title: Aggiungi File 119 | save: Aggiungi 120 | widget: 121 | choose: Scegli 122 | delete: Cancella 123 | media_chooser: Media-chooser 124 | icon_chooser: Icon-chooser 125 | adminlist: 126 | configurator: 127 | name: Name 128 | type: Type 129 | date: Date 130 | filesize: Filesize 131 | filter: 132 | name: Name 133 | type: Type 134 | updated_at: Date 135 | filesize: Filesize (in bytes) 136 | form: 137 | remote: 138 | name: 139 | label: Name 140 | code: 141 | label: Code 142 | type: 143 | label: Type 144 | copyright: 145 | label: Copyright 146 | description: 147 | label: Description 148 | bulk_upload: 149 | files: 150 | label: Files 151 | file: 152 | name: 153 | label: Name 154 | file: 155 | label: File 156 | copyright: 157 | label: Copyright 158 | description: 159 | label: Description 160 | originalFilename: 161 | label: Original filename 162 | remote_audio: 163 | type: 164 | label: Type 165 | remote_slide: 166 | type: 167 | label: Type 168 | remote_video: 169 | type: 170 | label: Type 171 | flash: 172 | created: Media %medianame% has been created! 173 | not_created: Media not created! %mediaerrors% 174 | -------------------------------------------------------------------------------- /Resources/translations/messages.fr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | media: 3 | aviary: 4 | title: Aviary 5 | nothing: Rien à voir ici. 6 | media: 7 | no: Pas encore de fichier dans ce dossier. 8 | dnd: 9 | tip: "Tip:" 10 | tiptext: did you know you can just drop multiple files here? 11 | alert: 12 | title: Incoming! 13 | text: Drop your files to instantly upload them to this folder. 14 | bulkupload: 15 | addto: Charger des fichiers dans "%folder%" 16 | contenttab: 17 | title: Contenu 18 | propertiestab: 19 | title: Propriétés 20 | title: Média 21 | add: 22 | action: Add media 23 | edit: 24 | action: Modifier 25 | download: 26 | action: Télécharger 27 | mediainfo: 28 | name: Nom 29 | contenttype: Content-type 30 | createdat: Ajouté 31 | updatedat: Modifié 32 | downloadlink: Lien de téléchargement 33 | addto: Ajouter le média dans "%folder%" 34 | deletesure: Etes-vous certain de vouloir supprimer cet élément ? 35 | new: Ajouter un média dans "%folder%" 36 | folder: 37 | addsub: 38 | action: Ajouter un sous-dossier 39 | action_short: Ajouter 40 | modal: 41 | title: Ajouter un sous-dossier 42 | save: Ajouter 43 | form: 44 | name: Name 45 | rel: Rel 46 | parent: Parent 47 | internal_name: Internal name 48 | success: 49 | text: Folder '%folder%' has been created! 50 | empty: 51 | action: Empty folder 52 | action_short: Empty 53 | modal: 54 | title: Empty folder 55 | text: Are you sure you want to delete the content of folder "%folder%"? 56 | checkbox: Also delete subfolders 57 | save: Empty 58 | success: 59 | text: Folder '%folder%' has been emptied! 60 | bulk_move: 61 | action: Bulk move media 62 | action_short: Bulk move 63 | modal: 64 | title: Bulk move media 65 | text: Select to which folder you want to move the selected media. 66 | save: "Move" 67 | form: 68 | name: Parent folder 69 | success: 70 | text: Media has been moved successfully! 71 | sub: 72 | no: Pas encore de sous-dossiers. 73 | delete: 74 | action: Supprimer ce dossier 75 | action_short: Supprimer 76 | modal: 77 | title: Supprimer le dossier 78 | text: Etes-vous certain de vouloir supprimer "%folder%"? 79 | failure: 80 | text: You can't delete the %folder% folder! 81 | success: 82 | text: Folder '%folder%' has been deleted! 83 | save: Sauver 84 | contenttab: 85 | title: Contenu 86 | propertiestab: 87 | title: Propriétés 88 | sortby: Sort by 89 | show: 90 | success: 91 | text: Folder %folder% has been updated! 92 | bulkupload: 93 | upload: Upload 94 | bulkupload: Bulk upload 95 | select_files: Select files 96 | upload_more: Upload more files 97 | back_to_folder: Back to folder 98 | upload_finished: The file upload has finished. 99 | not_available: The bulk upload functionality will not work for you. Your browser doesn't have Flash, Silverlight or HTML5 support. 100 | slide: 101 | add: Ajouer un slide 102 | modal: 103 | title: Ajouter un slide 104 | save: Ajouter 105 | video: 106 | add: Ajouter une vidéo 107 | modal: 108 | title: Ajouter une vidéo 109 | save: Ajouter 110 | audio: 111 | add: Ajouter de l'audio 112 | modal: 113 | title: Ajouter de l'audio 114 | save: Ajouter 115 | file: 116 | add: Ajouter un fichier 117 | modal: 118 | title: Ajouter un fichier 119 | save: Ajouter 120 | widget: 121 | choose: Choisir 122 | delete: Supprimer 123 | media_chooser: sélecteur de médias 124 | icon_chooser: sélecteur des icônes 125 | adminlist: 126 | configurator: 127 | name: Name 128 | type: Type 129 | date: Date 130 | filesize: Filesize 131 | filter: 132 | name: Name 133 | type: Type 134 | updated_at: Date 135 | filesize: Filesize (in bytes) 136 | form: 137 | remote: 138 | name: 139 | label: Name 140 | code: 141 | label: Code 142 | type: 143 | label: Type 144 | copyright: 145 | label: Copyright 146 | description: 147 | label: Description 148 | bulk_upload: 149 | files: 150 | label: Files 151 | file: 152 | name: 153 | label: Name 154 | file: 155 | label: File 156 | copyright: 157 | label: Copyright 158 | description: 159 | label: Description 160 | originalFilename: 161 | label: Original filename 162 | remote_audio: 163 | type: 164 | label: Type 165 | remote_slide: 166 | type: 167 | label: Type 168 | remote_video: 169 | type: 170 | label: Type 171 | flash: 172 | created: Media %medianame% has been created! 173 | not_created: Media not created! %mediaerrors% 174 | --------------------------------------------------------------------------------