Page MenuHomePhabricator

D11297.diff
No OneTemporary

D11297.diff

diff --git a/src/applications/files/config/PhabricatorFilesConfigOptions.php b/src/applications/files/config/PhabricatorFilesConfigOptions.php
--- a/src/applications/files/config/PhabricatorFilesConfigOptions.php
+++ b/src/applications/files/config/PhabricatorFilesConfigOptions.php
@@ -34,9 +34,16 @@
'image/x-icon' => 'image/x-icon',
'image/vnd.microsoft.icon' => 'image/x-icon',
- 'audio/x-wav' => 'audio/x-wav',
+ // This is a generic type for both OGG video and OGG audio.
'application/ogg' => 'application/ogg',
- 'audio/mpeg' => 'audio/mpeg',
+
+ 'audio/x-wav' => 'audio/x-wav',
+ 'audio/mpeg' => 'audio/mpeg',
+ 'audio/ogg' => 'audio/ogg',
+
+ 'video/mp4' => 'video/mp4',
+ 'video/ogg' => 'video/ogg',
+ 'video/webm' => 'video/webm',
);
$image_default = array(
@@ -49,10 +56,29 @@
'image/vnd.microsoft.icon' => true,
);
+
+ // The "application/ogg" type is listed as both an audio and video type,
+ // because it may contain either type of content.
+
$audio_default = array(
- 'audio/x-wav' => true,
+ 'audio/x-wav' => true,
+ 'audio/mpeg' => true,
+ 'audio/ogg' => true,
+
+ // These are video or ambiguous types, but can be forced to render as
+ // audio with `media=audio`, which seems to work properly in browsers.
+ // (For example, you can embed a music video as audio if you just want
+ // to set the mood for your task without distracting viewers.)
+ 'video/mp4' => true,
+ 'video/ogg' => true,
+ 'application/ogg' => true,
+ );
+
+ $video_default = array(
+ 'video/mp4' => true,
+ 'video/ogg' => true,
+ 'video/webm' => true,
'application/ogg' => true,
- 'audio/mpeg' => true,
);
// largely lifted from http://en.wikipedia.org/wiki/Internet_media_type
@@ -70,6 +96,7 @@
// movie file icon
'video/mpeg' => 'fa-file-movie-o',
'video/mp4' => 'fa-file-movie-o',
+ 'application/ogg' => 'fa-file-movie-o',
'video/ogg' => 'fa-file-movie-o',
'video/quicktime' => 'fa-file-movie-o',
'video/webm' => 'fa-file-movie-o',
@@ -122,8 +149,14 @@
->setSummary(pht('Configure which MIME types are audio.'))
->setDescription(
pht(
- 'List of MIME types which can be used to render an `%s` tag.',
+ 'List of MIME types which can be rendered with an `%s` tag.',
'<audio />')),
+ $this->newOption('files.video-mime-types', 'set', $video_default)
+ ->setSummary(pht('Configure which MIME types are video.'))
+ ->setDescription(
+ pht(
+ 'List of MIME types which can be rendered with a `%s` tag.',
+ '<video />')),
$this->newOption('files.icon-mime-types', 'wild', $icon_default)
->setLocked(true)
->setSummary(pht('Configure which MIME types map to which icons.'))
diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php
--- a/src/applications/files/controller/PhabricatorFileInfoController.php
+++ b/src/applications/files/controller/PhabricatorFileInfoController.php
@@ -230,23 +230,34 @@
$cache_string = pht('Not Applicable');
}
- $finfo->addProperty(pht('Viewable Image'), $image_string);
- $finfo->addProperty(pht('Cacheable'), $cache_string);
+ $types = array();
+ if ($file->isViewableImage()) {
+ $types[] = pht('Image');
+ }
- $builtin = $file->getBuiltinName();
- if ($builtin === null) {
- $builtin_string = pht('No');
- } else {
- $builtin_string = $builtin;
+ if ($file->isVideo()) {
+ $types[] = pht('Video');
+ }
+
+ if ($file->isAudio()) {
+ $types[] = pht('Audio');
}
- $finfo->addProperty(pht('Builtin'), $builtin_string);
+ if ($file->getCanCDN()) {
+ $types[] = pht('Can CDN');
+ }
+
+ $builtin = $file->getBuiltinName();
+ if ($builtin !== null) {
+ $types[] = pht('Builtin ("%s")', $builtin);
+ }
- $is_profile = $file->getIsProfileImage()
- ? pht('Yes')
- : pht('No');
+ if ($file->getIsProfileImage()) {
+ $types[] = pht('Profile');
+ }
- $finfo->addProperty(pht('Profile'), $is_profile);
+ $types = implode(', ', $types);
+ $finfo->addProperty(pht('Attributes'), $types);
$storage_properties = new PHUIPropertyListView();
$box->addPropertyList($storage_properties, pht('Storage'));
@@ -293,6 +304,23 @@
->addImageContent($linked_image);
$box->addPropertyList($media);
+ } else if ($file->isVideo()) {
+ $video = phutil_tag(
+ 'video',
+ array(
+ 'controls' => 'controls',
+ 'class' => 'phui-property-list-video',
+ ),
+ phutil_tag(
+ 'source',
+ array(
+ 'src' => $file->getViewURI(),
+ 'type' => $file->getMimeType(),
+ )));
+ $media = id(new PHUIPropertyListView())
+ ->addImageContent($video);
+
+ $box->addPropertyList($media);
} else if ($file->isAudio()) {
$audio = phutil_tag(
'audio',
diff --git a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
--- a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
+++ b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
@@ -43,12 +43,27 @@
$is_viewable_image = $object->isViewableImage();
$is_audio = $object->isAudio();
+ $is_video = $object->isVideo();
$force_link = ($options['layout'] == 'link');
- $options['viewable'] = ($is_viewable_image || $is_audio);
+ // If a file is both audio and video, as with "application/ogg" by default,
+ // render it as video but allow the user to specify `media=audio` if they
+ // want to force it to render as audio.
+ if ($is_audio && $is_video) {
+ $media = $options['media'];
+ if ($media == 'audio') {
+ $is_video = false;
+ } else {
+ $is_audio = false;
+ }
+ }
+
+ $options['viewable'] = ($is_viewable_image || $is_audio || $is_video);
if ($is_viewable_image && !$force_link) {
return $this->renderImageFile($object, $handle, $options);
+ } else if ($is_video && !$force_link) {
+ return $this->renderVideoFile($object, $handle, $options);
} else if ($is_audio && !$force_link) {
return $this->renderAudioFile($object, $handle, $options);
} else {
@@ -58,12 +73,15 @@
private function getFileOptions($option_string) {
$options = array(
- 'size' => null,
- 'layout' => 'left',
- 'float' => false,
- 'width' => null,
- 'height' => null,
+ 'size' => null,
+ 'layout' => 'left',
+ 'float' => false,
+ 'width' => null,
+ 'height' => null,
'alt' => null,
+ 'media' => null,
+ 'autoplay' => null,
+ 'loop' => null,
);
if ($option_string) {
@@ -201,22 +219,47 @@
PhabricatorFile $file,
PhabricatorObjectHandle $handle,
array $options) {
+ return $this->renderMediaFile('audio', $file, $handle, $options);
+ }
+
+ private function renderVideoFile(
+ PhabricatorFile $file,
+ PhabricatorObjectHandle $handle,
+ array $options) {
+ return $this->renderMediaFile('video', $file, $handle, $options);
+ }
+
+ private function renderMediaFile(
+ $tag,
+ PhabricatorFile $file,
+ PhabricatorObjectHandle $handle,
+ array $options) {
+
+ $is_video = ($tag == 'video');
if (idx($options, 'autoplay')) {
$preload = 'auto';
$autoplay = 'autoplay';
} else {
- $preload = 'none';
+ // If we don't preload video, the user can't see the first frame and
+ // has no clue what they're looking at, so always preload.
+ if ($is_video) {
+ $preload = 'auto';
+ } else {
+ $preload = 'none';
+ }
$autoplay = null;
}
return $this->newTag(
- 'audio',
+ $tag,
array(
'controls' => 'controls',
'preload' => $preload,
'autoplay' => $autoplay,
'loop' => idx($options, 'loop') ? 'loop' : null,
+ 'alt' => $options['alt'],
+ 'class' => 'phabricator-media',
),
$this->newTag(
'source',
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -802,6 +802,16 @@
return idx($mime_map, $mime_type);
}
+ public function isVideo() {
+ if (!$this->isViewableInBrowser()) {
+ return false;
+ }
+
+ $mime_map = PhabricatorEnv::getEnvConfig('files.video-mime-types');
+ $mime_type = $this->getMimeType();
+ return idx($mime_map, $mime_type);
+ }
+
public function isTransformableImage() {
// NOTE: The way the 'gd' extension works in PHP is that you can install it
// with support for only some file types, so it might be able to handle
diff --git a/src/docs/user/userguide/remarkup.diviner b/src/docs/user/userguide/remarkup.diviner
--- a/src/docs/user/userguide/remarkup.diviner
+++ b/src/docs/user/userguide/remarkup.diviner
@@ -410,18 +410,29 @@
{F123, layout=left, float, size=full, alt="a duckling"}
-Valid options are:
+Valid options for all files are:
- **layout** left (default), center, right, inline, link (render a link
instead of a thumbnail for images)
+ - **name** with `layout=link` or for non-images, use this name for the link
+ text
+ - **alt** Provide alternate text for assistive technologies.
+
+Image files support these options:
+
- **float** If layout is set to left or right, the image will be floated so
text wraps around it.
- **size** thumb (default), full
- - **name** with `layout=link` or for non-images, use this name for the link
- text
- **width** Scale image to a specific width.
- **height** Scale image to a specific height.
- - **alt** Provide alternate text for assistive technologies.
+
+Audio and video files support these options:
+
+ - **media**: Specify the media type as `audio` or `video`. This allows you
+ to disambiguate how file format which may contain either audio or video
+ should be rendered.
+ - **loop**: Loop this media.
+ - **autoplay**: Automatically begin playing this media.
== Embedding Countdowns
diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css
--- a/webroot/rsrc/css/core/remarkup.css
+++ b/webroot/rsrc/css/core/remarkup.css
@@ -218,6 +218,17 @@
width: 50%;
}
+video.phabricator-media {
+ background: {$greybackground};
+}
+
+.phabricator-remarkup video {
+ display: block;
+ margin: 0 auto;
+ min-width: 240px;
+ width: 90%;
+}
+
.phabricator-remarkup-mention-exists {
font-weight: bold;
background: #e6f3ff;
diff --git a/webroot/rsrc/css/phui/phui-property-list-view.css b/webroot/rsrc/css/phui/phui-property-list-view.css
--- a/webroot/rsrc/css/phui/phui-property-list-view.css
+++ b/webroot/rsrc/css/phui/phui-property-list-view.css
@@ -160,6 +160,13 @@
min-width: 240px;
}
+.phui-property-list-video {
+ display: block;
+ margin: 0 auto;
+ width: 90%;
+ min-width: 240px;
+}
+
/* When tags appear in property lists, give them a little more vertical
spacing. */
.phui-property-list-view .phui-tag-view {

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 3:13 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6287773
Default Alt Text
D11297.diff (11 KB)

Event Timeline