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