[feature] Use gifv type for short soundless mp4 videos (#3182)
This commit is contained in:
parent
3045782b49
commit
b19cfee7ae
|
@ -91,6 +91,7 @@ const (
|
|||
FileTypeImage FileType = 1 // FileTypeImage is for jpegs, pngs, and standard gifs
|
||||
FileTypeAudio FileType = 2 // FileTypeAudio is for audio-only files (no video)
|
||||
FileTypeVideo FileType = 3 // FileTypeVideo is for files with audio + visual
|
||||
FileTypeGifv FileType = 4 // FileTypeGifv is for short video-only files (20s or less, mp4, no audio).
|
||||
)
|
||||
|
||||
// String returns a stringified, frontend API compatible form of FileType.
|
||||
|
@ -104,6 +105,8 @@ func (t FileType) String() string {
|
|||
return "audio"
|
||||
case FileTypeVideo:
|
||||
return "video"
|
||||
case FileTypeGifv:
|
||||
return "gifv"
|
||||
default:
|
||||
panic("invalid filetype")
|
||||
}
|
||||
|
|
|
@ -305,7 +305,15 @@ func (res *result) GetFileType() (gtsmodel.FileType, string) {
|
|||
case "mov,mp4,m4a,3gp,3g2,mj2":
|
||||
switch {
|
||||
case len(res.video) > 0:
|
||||
return gtsmodel.FileTypeVideo, "mp4"
|
||||
if len(res.audio) == 0 &&
|
||||
res.duration <= 30 {
|
||||
// Short, soundless
|
||||
// video file aka gifv.
|
||||
return gtsmodel.FileTypeGifv, "mp4"
|
||||
} else {
|
||||
// Video file (with or without audio).
|
||||
return gtsmodel.FileTypeVideo, "mp4"
|
||||
}
|
||||
case len(res.audio) > 0 &&
|
||||
res.audio[0].codec == "aac":
|
||||
// m4a only supports [aac] audio.
|
||||
|
|
|
@ -202,7 +202,8 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
|||
|
||||
switch p.media.Type {
|
||||
case gtsmodel.FileTypeImage,
|
||||
gtsmodel.FileTypeVideo:
|
||||
gtsmodel.FileTypeVideo,
|
||||
gtsmodel.FileTypeGifv:
|
||||
// Attempt to clean as metadata from file as possible.
|
||||
if err := clearMetadata(ctx, temppath); err != nil {
|
||||
return gtserror.Newf("error cleaning metadata: %w", err)
|
||||
|
|
|
@ -26,6 +26,8 @@ const Prism = require("./prism.js");
|
|||
Prism.manual = true;
|
||||
Prism.highlightAll();
|
||||
|
||||
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
|
||||
let [_, _user, type, id] = window.location.pathname.split("/");
|
||||
if (type == "statuses") {
|
||||
let firstStatus = document.getElementsByClassName("thread")[0].children[0];
|
||||
|
@ -49,9 +51,12 @@ new PhotoswipeCaptionPlugin(lightbox, {
|
|||
|
||||
lightbox.addFilter('itemData', (item) => {
|
||||
const el = item.element;
|
||||
if (el && el.classList.contains("plyr-video")) {
|
||||
if (
|
||||
el &&
|
||||
el.classList.contains("plyr-video") &&
|
||||
el._plyrContainer !== undefined
|
||||
) {
|
||||
const parentNode = el._plyrContainer.parentNode;
|
||||
|
||||
return {
|
||||
alt: el.getAttribute("alt"),
|
||||
_video: {
|
||||
|
@ -118,13 +123,14 @@ dynamicSpoiler("text-spoiler", (spoiler) => {
|
|||
dynamicSpoiler("media-spoiler", (spoiler) => {
|
||||
const eye = spoiler.querySelector(".eye.button");
|
||||
const video = spoiler.querySelector(".plyr-video");
|
||||
const loopingAuto = !reduceMotion.matches && video != null && video.classList.contains("gifv");
|
||||
|
||||
return () => {
|
||||
if (spoiler.open) {
|
||||
eye.setAttribute("aria-label", "Hide media");
|
||||
} else {
|
||||
eye.setAttribute("aria-label", "Show media");
|
||||
if (video) {
|
||||
if (video && !loopingAuto) {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +138,22 @@ dynamicSpoiler("media-spoiler", (spoiler) => {
|
|||
});
|
||||
|
||||
Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => {
|
||||
const loopingAuto = !reduceMotion.matches && video.classList.contains("gifv");
|
||||
|
||||
if (loopingAuto) {
|
||||
// If we're able to play this as a
|
||||
// looping gifv, then do so, else fall
|
||||
// back to user-controllable video player.
|
||||
video.draggable = false;
|
||||
video.autoplay = true;
|
||||
video.loop = true;
|
||||
video.classList.remove("photoswipe-slide");
|
||||
video.classList.remove("plry-video");
|
||||
video.load();
|
||||
video.play();
|
||||
return;
|
||||
}
|
||||
|
||||
let player = new Plyr(video, {
|
||||
title: video.title,
|
||||
settings: ["loop"],
|
||||
|
|
|
@ -99,7 +99,7 @@ media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{
|
|||
<i class="hide fa fa-fw fa-eye-slash" aria-hidden="true"></i>
|
||||
<i class="show fa fa-fw fa-eye" aria-hidden="true"></i>
|
||||
</span>
|
||||
{{- if eq .Type "video" }}
|
||||
{{- if or (eq .Type "video") (eq .Type "gifv") }}
|
||||
{{- include "videoPreview" $media | indent 4 }}
|
||||
{{- else if eq .Type "image" }}
|
||||
{{- include "imagePreview" $media | indent 4 }}
|
||||
|
@ -107,11 +107,17 @@ media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{
|
|||
{{- include "audioPreview" $media | indent 4 }}
|
||||
{{- end }}
|
||||
</summary>
|
||||
{{- if eq .Type "video" }}
|
||||
{{- if or (eq .Type "video") (eq .Type "gifv") }}
|
||||
<video
|
||||
{{- if eq .Type "video" }}
|
||||
preload="none"
|
||||
class="plyr-video photoswipe-slide"
|
||||
{{- else }}
|
||||
preload="auto"
|
||||
muted
|
||||
{{- end }}
|
||||
class="plyr-video photoswipe-slide{{- if eq .Type "gifv" }} gifv{{ end }}"
|
||||
controls
|
||||
playsinline
|
||||
data-pswp-index="{{- $index -}}"
|
||||
poster="{{- .PreviewURL -}}"
|
||||
data-pswp-width="{{- $media.Meta.Small.Width -}}px"
|
||||
|
@ -128,6 +134,7 @@ media photoswipe-gallery {{ (len .) | oddOrEven }} {{ if eq (len .) 1 }}single{{
|
|||
preload="none"
|
||||
class="plyr-video photoswipe-slide"
|
||||
controls
|
||||
playsinline
|
||||
data-pswp-index="{{- $index -}}"
|
||||
{{- if and $media.PreviewURL $media.Meta.Small.Width }}
|
||||
poster="{{- .PreviewURL -}}"
|
||||
|
|
Loading…
Reference in New Issue