fix: preserve stream language metadata using ffprobe and -map_metadata -1
This commit is contained in:
+6
-1
@@ -89,6 +89,11 @@ func processFile(inputPath string, cfg *types.Config, enc *encoder.Encoder, meta
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streamLangs, err := enc.GetStreamLanguages(inputPath)
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorFile(inputPath, "Getting stream languages", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
mediaType := watcher.DetectMediaType(width, height)
|
mediaType := watcher.DetectMediaType(width, height)
|
||||||
crf := cfg.Encoding.DVD.CRF
|
crf := cfg.Encoding.DVD.CRF
|
||||||
preset := cfg.Encoding.DVD.Preset
|
preset := cfg.Encoding.DVD.Preset
|
||||||
@@ -128,7 +133,7 @@ func processFile(inputPath string, cfg *types.Config, enc *encoder.Encoder, meta
|
|||||||
DeleteOrigin: deleteOrigin,
|
DeleteOrigin: deleteOrigin,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := enc.Transcode(inputPath, job, meta, interlaced); err != nil {
|
if err := enc.Transcode(inputPath, job, meta, interlaced, streamLangs); err != nil {
|
||||||
log.ErrorFile(inputPath, "Transcoding", err.Error())
|
log.ErrorFile(inputPath, "Transcoding", err.Error())
|
||||||
mover.MoveToFailed(inputPath, cfg.Paths.Failed)
|
mover.MoveToFailed(inputPath, cfg.Paths.Failed)
|
||||||
outputPath := filepath.Join(filepath.Dir(inputPath), "output.mkv")
|
outputPath := filepath.Join(filepath.Dir(inputPath), "output.mkv")
|
||||||
|
|||||||
@@ -30,6 +30,54 @@ type ProbeResult struct {
|
|||||||
Streams []StreamInfo `json:"streams"`
|
Streams []StreamInfo `json:"streams"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StreamMetadata struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
CodecType string `json:"codec_type"`
|
||||||
|
CodecName string `json:"codec_name"`
|
||||||
|
Language string `json:"tags"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) GetStreamLanguages(path string) ([]StreamMetadata, error) {
|
||||||
|
cmd := exec.Command(e.ffprobePath, "-v", "error", "-show_streams", "-print_format", "json", path)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ffprobe error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Streams []struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
CodecType string `json:"codec_type"`
|
||||||
|
CodecName string `json:"codec_name"`
|
||||||
|
Tags map[string]string `json:"tags"`
|
||||||
|
} `json:"streams"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(output, &result); err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing ffprobe: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var streams []StreamMetadata
|
||||||
|
for _, s := range result.Streams {
|
||||||
|
lang := ""
|
||||||
|
title := ""
|
||||||
|
if s.Tags != nil {
|
||||||
|
lang = s.Tags["language"]
|
||||||
|
title = s.Tags["title"]
|
||||||
|
}
|
||||||
|
streams = append(streams, StreamMetadata{
|
||||||
|
Index: s.Index,
|
||||||
|
CodecType: s.CodecType,
|
||||||
|
CodecName: s.CodecName,
|
||||||
|
Language: lang,
|
||||||
|
Title: title,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("DEBUG stream languages: %+v\n", streams)
|
||||||
|
return streams, nil
|
||||||
|
}
|
||||||
|
|
||||||
func New() *Encoder {
|
func New() *Encoder {
|
||||||
return &Encoder{
|
return &Encoder{
|
||||||
ffmpegPath: "ffmpeg",
|
ffmpegPath: "ffmpeg",
|
||||||
@@ -131,7 +179,7 @@ func (e *Encoder) calculateZscaleWidth(path string, originalHeight int) (string,
|
|||||||
return zscale, newWidth, nil
|
return zscale, newWidth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) Transcode(input string, job *types.Job, metadata *types.Metadata, interlaced bool) error {
|
func (e *Encoder) Transcode(input string, job *types.Job, metadata *types.Metadata, interlaced bool, streamLangs []StreamMetadata) error {
|
||||||
dir := filepath.Dir(input)
|
dir := filepath.Dir(input)
|
||||||
audioWavs, err := e.extractAudio(input, dir)
|
audioWavs, err := e.extractAudio(input, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -145,7 +193,7 @@ func (e *Encoder) Transcode(input string, job *types.Job, metadata *types.Metada
|
|||||||
}
|
}
|
||||||
defer e.cleanupOpus(opusFiles)
|
defer e.cleanupOpus(opusFiles)
|
||||||
|
|
||||||
if err := e.encodeVideo(input, opusFiles, job, metadata, interlaced); err != nil {
|
if err := e.encodeVideo(input, opusFiles, job, metadata, interlaced, streamLangs); err != nil {
|
||||||
return fmt.Errorf("encoding video: %w", err)
|
return fmt.Errorf("encoding video: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +225,7 @@ func (e *Encoder) encodeOpus(wavs []string, dir string) ([]string, error) {
|
|||||||
return opusFiles, nil
|
return opusFiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job, metadata *types.Metadata, interlaced bool) error {
|
func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job, metadata *types.Metadata, interlaced bool, streamLangs []StreamMetadata) error {
|
||||||
dir := filepath.Dir(input)
|
dir := filepath.Dir(input)
|
||||||
outFile := filepath.Join(dir, "output.mkv")
|
outFile := filepath.Join(dir, "output.mkv")
|
||||||
|
|
||||||
@@ -221,12 +269,30 @@ func (e *Encoder) encodeVideo(input string, opusFiles []string, job *types.Job,
|
|||||||
|
|
||||||
args = append(args, "-c:a", "copy")
|
args = append(args, "-c:a", "copy")
|
||||||
args = append(args, "-c:s", "copy")
|
args = append(args, "-c:s", "copy")
|
||||||
args = append(args, "-map_metadata", "0")
|
args = append(args, "-map_metadata", "-1")
|
||||||
|
|
||||||
args = append(args, "-metadata", fmt.Sprintf("TITLE=%s", metadata.Title))
|
for _, stream := range streamLangs {
|
||||||
args = append(args, "-metadata", fmt.Sprintf("DATE_RELEASED=%s", metadata.DateReleased))
|
if stream.CodecType == "audio" && stream.Language != "" {
|
||||||
args = append(args, "-metadata", fmt.Sprintf("IMDBID=%s", metadata.IMDBID))
|
idx := 1
|
||||||
args = append(args, "-metadata", fmt.Sprintf("ORIGINAL_MEDIA_TYPE=%s", metadata.OriginalMedia))
|
for _, s := range streamLangs {
|
||||||
|
if s.CodecType == "audio" && s.Index < stream.Index {
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args = append(args, fmt.Sprintf("-metadata:s:a:%d", idx-1), fmt.Sprintf("language=%s", stream.Language))
|
||||||
|
fmt.Printf("DEBUG setting audio language: stream %d -> language=%s\n", idx-1, stream.Language)
|
||||||
|
}
|
||||||
|
if stream.CodecType == "subtitle" && stream.Language != "" {
|
||||||
|
idx := 0
|
||||||
|
for _, s := range streamLangs {
|
||||||
|
if s.CodecType == "subtitle" && s.Index < stream.Index {
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args = append(args, fmt.Sprintf("-metadata:s:s:%d", idx), fmt.Sprintf("language=%s", stream.Language))
|
||||||
|
fmt.Printf("DEBUG setting subtitle language: stream %d -> language=%s\n", idx, stream.Language)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if metadata.IsSeries {
|
if metadata.IsSeries {
|
||||||
args = append(args, "-metadata", fmt.Sprintf("COLLECTION=%s", metadata.Collection))
|
args = append(args, "-metadata", fmt.Sprintf("COLLECTION=%s", metadata.Collection))
|
||||||
|
|||||||
Reference in New Issue
Block a user