| 
									
										
										
										
											2023-08-29 20:47:53 -05:00
										 |  |  | package media | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2023-09-08 21:31:13 -05:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 20:18:27 -05:00
										 |  |  | 	"codeberg.org/danjones000/strip-beats/config" | 
					
						
							| 
									
										
										
										
											2023-10-28 18:15:33 -05:00
										 |  |  | 	"codeberg.org/danjones000/strip-beats/media/tags" | 
					
						
							| 
									
										
										
										
											2023-09-06 18:46:09 -05:00
										 |  |  | 	"codeberg.org/danjones000/strip-beats/utils" | 
					
						
							| 
									
										
										
										
											2023-09-08 21:31:13 -05:00
										 |  |  | 	"dario.cat/mergo" | 
					
						
							| 
									
										
										
										
											2023-08-29 20:18:27 -05:00
										 |  |  | 	"github.com/akrennmair/slice" | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | 	ffmpeg "github.com/u2takey/ffmpeg-go" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Probe struct { | 
					
						
							|  |  |  | 	Format  Format | 
					
						
							|  |  |  | 	Streams []Stream | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 20:18:27 -05:00
										 |  |  | func (p Probe) GetAudioStreams() []*Stream { | 
					
						
							|  |  |  | 	return slice.Map(slice.Filter(p.Streams, func(st Stream) bool { | 
					
						
							|  |  |  | 		return st.CodecType == "audio" | 
					
						
							|  |  |  | 	}), func(s Stream) *Stream { | 
					
						
							|  |  |  | 		return &s | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p Probe) GetFirstAudio() *Stream { | 
					
						
							|  |  |  | 	st := p.GetAudioStreams() | 
					
						
							|  |  |  | 	if len(st) == 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return st[0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p Probe) GetAudioCount() int { | 
					
						
							|  |  |  | 	st := p.GetAudioStreams() | 
					
						
							|  |  |  | 	return len(st) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p Probe) GetFirstPreferredAudio() *Stream { | 
					
						
							|  |  |  | 	sts := slice.Filter(p.GetAudioStreams(), func(st *Stream) bool { | 
					
						
							|  |  |  | 		return st.isWantedCodec() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(sts) < 1 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sts[0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p Probe) GetFirstAcceptableAudio() *Stream { | 
					
						
							|  |  |  | 	pref := p.GetFirstPreferredAudio() | 
					
						
							|  |  |  | 	if pref != nil { | 
					
						
							|  |  |  | 		return pref | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sts := slice.Filter(p.GetAudioStreams(), func(st *Stream) bool { | 
					
						
							|  |  |  | 		return st.isAcceptableCodec() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(sts) < 1 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sts[0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 18:46:09 -05:00
										 |  |  | func (pr Probe) ShortPath() string { | 
					
						
							|  |  |  | 	return utils.GetShortPath(pr.Format.Path) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 09:09:49 -05:00
										 |  |  | func (pr Probe) WantedAudioStream() *Stream { | 
					
						
							|  |  |  | 	count := pr.GetAudioCount() | 
					
						
							|  |  |  | 	if count < 1 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if count == 1 { | 
					
						
							|  |  |  | 		return pr.GetFirstAudio() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pref := pr.GetFirstAcceptableAudio() | 
					
						
							|  |  |  | 	if pref != nil { | 
					
						
							|  |  |  | 		return pref | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pr.GetFirstAudio() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | type Stream struct { | 
					
						
							|  |  |  | 	Index         int | 
					
						
							|  |  |  | 	CodecName     string `json:"codec_name"` | 
					
						
							|  |  |  | 	CodecLongName string `json:"codec_long_name"` | 
					
						
							|  |  |  | 	Profile       string | 
					
						
							|  |  |  | 	CodecType     string `json:"codec_type"` | 
					
						
							|  |  |  | 	CodecTag      string `json:"codec_tag_string"` | 
					
						
							|  |  |  | 	Width         int | 
					
						
							|  |  |  | 	Height        int | 
					
						
							|  |  |  | 	StartTime     float64 `json:"start_time,string"` | 
					
						
							|  |  |  | 	Duration      float64 `json:",string"` | 
					
						
							|  |  |  | 	DurationTs    int     `json:"duration_ts"` | 
					
						
							| 
									
										
										
										
											2023-10-28 18:15:33 -05:00
										 |  |  | 	Tags          tags.Tags | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 20:18:27 -05:00
										 |  |  | func (st Stream) isWantedCodec() bool { | 
					
						
							|  |  |  | 	wantedcodec := config.GetConfig().Codec | 
					
						
							|  |  |  | 	return st.CodecName == wantedcodec | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (st Stream) isAcceptableCodec() bool { | 
					
						
							|  |  |  | 	codecs := config.GetConfig().AllowedCodecs | 
					
						
							|  |  |  | 	return slice.ReduceWithInitialValue(codecs, false, func(acc bool, codec string) bool { | 
					
						
							|  |  |  | 		return acc || st.CodecName == codec | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | type Format struct { | 
					
						
							|  |  |  | 	Path           string  `json:"filename"` | 
					
						
							|  |  |  | 	Streams        int     `json:"nb_streams"` | 
					
						
							|  |  |  | 	FormatName     string  `json:"format_name"` | 
					
						
							|  |  |  | 	FormatLongName string  `json:"format_long_name"` | 
					
						
							|  |  |  | 	StartTime      float64 `json:"start_time,string"` | 
					
						
							|  |  |  | 	Duration       float64 `json:",string"` | 
					
						
							|  |  |  | 	Size           int     `json:",string"` | 
					
						
							|  |  |  | 	BitRate        int     `json:"bit_rate,string"` | 
					
						
							|  |  |  | 	Score          int     `json:"probe_score"` | 
					
						
							| 
									
										
										
										
											2023-10-28 18:15:33 -05:00
										 |  |  | 	Tags           tags.Tags | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-28 18:15:33 -05:00
										 |  |  | func (pr Probe) FullTags() tags.Tags { | 
					
						
							| 
									
										
										
										
											2023-09-08 21:31:13 -05:00
										 |  |  | 	t := pr.Format.Tags | 
					
						
							|  |  |  | 	s := pr.WantedAudioStream() | 
					
						
							|  |  |  | 	if s != nil { | 
					
						
							|  |  |  | 		mergo.Merge(&t, s.Tags) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, st := range pr.Streams { | 
					
						
							|  |  |  | 		mergo.Merge(&t, st.Tags) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return t | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pr Probe) Title() string { | 
					
						
							|  |  |  | 	return pr.FullTags().Title | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 16:06:52 -05:00
										 |  |  | func ProbeFile(path string) Probe { | 
					
						
							|  |  |  | 	out, err := ffmpeg.Probe(path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret := Probe{} | 
					
						
							|  |  |  | 	err = json.Unmarshal([]byte(out), &ret) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | } |