122 lines
3.5 KiB
Go
122 lines
3.5 KiB
Go
|
package ffmpeg
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"io"
|
||
|
"os/exec"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/samber/lo"
|
||
|
)
|
||
|
|
||
|
type Result struct {
|
||
|
Format *Format `json:"format"`
|
||
|
Streams []*Stream `json:"streams"`
|
||
|
}
|
||
|
|
||
|
func (r *Result) HasAttachedPic() bool {
|
||
|
return lo.ContainsBy(r.Streams, func(s *Stream) bool {
|
||
|
return s.CodecType == "video"
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (r *Result) getTagByKey(key string) string {
|
||
|
for k, v := range r.Format.Tags {
|
||
|
if key == strings.ToLower(k) {
|
||
|
return v
|
||
|
}
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
|
func (r *Result) GetTitle() string {
|
||
|
return r.getTagByKey("title")
|
||
|
}
|
||
|
|
||
|
func (r *Result) GetAlbum() string {
|
||
|
return r.getTagByKey("album")
|
||
|
}
|
||
|
|
||
|
func (r *Result) GetArtists() []string {
|
||
|
artists := strings.Split(r.getTagByKey("artist"), "/")
|
||
|
for i := range artists {
|
||
|
artists[i] = strings.TrimSpace(artists[i])
|
||
|
}
|
||
|
return artists
|
||
|
}
|
||
|
|
||
|
type Format struct {
|
||
|
Filename string `json:"filename"`
|
||
|
NbStreams int `json:"nb_streams"`
|
||
|
NbPrograms int `json:"nb_programs"`
|
||
|
FormatName string `json:"format_name"`
|
||
|
FormatLongName string `json:"format_long_name"`
|
||
|
StartTime string `json:"start_time"`
|
||
|
Duration string `json:"duration"`
|
||
|
BitRate string `json:"bit_rate"`
|
||
|
ProbeScore int `json:"probe_score"`
|
||
|
Tags map[string]string `json:"tags"`
|
||
|
}
|
||
|
|
||
|
type Stream struct {
|
||
|
Index int `json:"index"`
|
||
|
CodecName string `json:"codec_name"`
|
||
|
CodecLongName string `json:"codec_long_name"`
|
||
|
CodecType string `json:"codec_type"`
|
||
|
CodecTagString string `json:"codec_tag_string"`
|
||
|
CodecTag string `json:"codec_tag"`
|
||
|
SampleFmt string `json:"sample_fmt"`
|
||
|
SampleRate string `json:"sample_rate"`
|
||
|
Channels int `json:"channels"`
|
||
|
ChannelLayout string `json:"channel_layout"`
|
||
|
BitsPerSample int `json:"bits_per_sample"`
|
||
|
RFrameRate string `json:"r_frame_rate"`
|
||
|
AvgFrameRate string `json:"avg_frame_rate"`
|
||
|
TimeBase string `json:"time_base"`
|
||
|
StartPts int `json:"start_pts"`
|
||
|
StartTime string `json:"start_time"`
|
||
|
BitRate string `json:"bit_rate"`
|
||
|
Disposition *ProbeDisposition `json:"disposition"`
|
||
|
}
|
||
|
|
||
|
type ProbeDisposition struct {
|
||
|
Default int `json:"default"`
|
||
|
Dub int `json:"dub"`
|
||
|
Original int `json:"original"`
|
||
|
Comment int `json:"comment"`
|
||
|
Lyrics int `json:"lyrics"`
|
||
|
Karaoke int `json:"karaoke"`
|
||
|
Forced int `json:"forced"`
|
||
|
HearingImpaired int `json:"hearing_impaired"`
|
||
|
VisualImpaired int `json:"visual_impaired"`
|
||
|
CleanEffects int `json:"clean_effects"`
|
||
|
AttachedPic int `json:"attached_pic"`
|
||
|
TimedThumbnails int `json:"timed_thumbnails"`
|
||
|
Captions int `json:"captions"`
|
||
|
Descriptions int `json:"descriptions"`
|
||
|
Metadata int `json:"metadata"`
|
||
|
Dependent int `json:"dependent"`
|
||
|
StillImage int `json:"still_image"`
|
||
|
}
|
||
|
|
||
|
func ProbeReader(ctx context.Context, rd io.Reader) (*Result, error) {
|
||
|
cmd := exec.CommandContext(ctx, "ffprobe",
|
||
|
"-v", "quiet", // disable logging
|
||
|
"-print_format", "json", // use json format
|
||
|
"-show_format", "-show_streams", // retrieve format and streams
|
||
|
"-", // input from stdin
|
||
|
)
|
||
|
cmd.Stdin = rd
|
||
|
out, err := cmd.Output()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ret := new(Result)
|
||
|
if err := json.Unmarshal(out, ret); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return ret, nil
|
||
|
}
|