mdhiggins / sickbeard_mp4_automator

Automatically convert video files to a standardized format with metadata tagging to create a beautiful and uniform media library
MIT License
1.53k stars 202 forks source link

Allow use of original subtitle track title as a fallback if the resulting output title is empty #1593

Closed lizardfish0 closed 2 years ago

lizardfish0 commented 2 years ago

I import a number of files where the original subtitle track title contains some important information that I'd like to preserve. The most common example I have is "Signs and Songs" subtitles intended for use when watching dubbed anime.

"Signs and Songs" subtitle tracks are solely identified by their title, meaning they do not have a unique ffmpeg disposition that could be used to distinguish them. Additionally, there isn't really a consistent naming scheme (most encoders title the track Signs and Songs, but I've seen Signs, S/S, Signs / Songs, etc).

I know the keep-titles option exists, but I'd like to maintain clean title generation for audio tracks and for subtitle tracks that have a distinguishing ffmpeg disposition (such as commetary/forced).

There's probably a couple ways to address this, but I think the easiest would be to include a config option under the Subtitle category that allows the output track title to fallback to its old value if the new one would be an empty string. I suppose this option could also be placed under Metadata, but I don't believe I've ever seen an audio track outputted without a title, only subtitles.

default is an interesting edge case, because while it doesn't trigger a change in the output title like commentary/forced do, it also (for this use case) shouldn't trigger a fallback to the input track title. Meaning that if the default english subtitle track is titled "English Subtitles", the better outcome is to result in a blank output title instead of falling back, as "English Subtitles" doesn't provide any important information unlike "Signs and Songs". Best approach is probably to have a track marked as default always write an empty title and ignore the what the config says about falling back to the input title (unless keep-titles = true, ofc)

Quick mock up of how this would work with this new option called allow-title-fallback:

keep-titles = false allow-title-fallback = false


input subtitles:
{
"language": "eng",
"disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
"title": "English Subtitles"
},
{
"language": "eng",
"disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
"title": "Signs and Songs"
},
{
"language": "eng",
"disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions",
"title": "Forced Foreign Language"
}

output subtitles: { "language": "eng", "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": null }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": null }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions", "title": "Forced / Forced" }

> `keep-titles = true`
> `allow-title-fallback = false`

input subtitles: { "language": "eng", "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "English Subtitles" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "Signs and Songs" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions", "title": "Forced Foreign Language" }

output subtitles: { "language": "eng", "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "English Subtitles" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "Signs and Songs" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions", "title": "Forced Foreign Language" }

> **(behavior I'm proposing)**
> `keep-titles = false`
> `allow-title-fallback = true`

input subtitles: { "language": "eng", "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "English Subtitles" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "Signs and Songs" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions", "title": "Forced Foreign Language" }

output subtitles: { "language": "eng", "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": null }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions", "title": "Signs and Songs" }, { "language": "eng", "disposition": "-default-dub-original-comment-lyrics-karaoke+forced-hearing_impaired-visual_impaired-captions", "title": "Forced / Forced" }



The one edge case that can't really be handled is where we have a titled subtitle track that probably *should* be marked as default, but isn't. In this case we'd end up preserving a title where if `allow-title-fallback` was false, would have been wiped. (i.e. if the "English Subtitles" track in the above examples wasn't marked as default, its title would be preserved). However that's probably the best outcome, as the goal of this configuration option is to provide a fallback when we don't have any useful metadata to work with, so if subtitle tracks aren't marked properly the best the script could do is use the old track title.

I know this is a bit of an edge case, but I think it would help a lot of people who use this script for libraries that include Anime or other foreign media that include `Signs and Songs`.
mdhiggins commented 2 years ago

For these edge cases I think your best option is to use the custom steamTitle function, have you tried this?

https://github.com/mdhiggins/sickbeard_mp4_automator/wiki/Custom-Functions#params-for-streamtitle

lizardfish0 commented 2 years ago

That'd definitely work. My thought was this might have some value for other users so it'd be nice as a QOL feature, up to you though. I'm down to take a run at it if you'd consider a PR.

mdhiggins commented 2 years ago

Try getting the custom command working to your liking first and share it here and I'll take a look. No need for a full PR.

It's one of those edge features that if I add for every title request the feature bloat starts to creep and maintaining becomes difficult and the settings get bloated. So far you're the first user to ask for this but having your custom title function shared here is a good start. Maybe I'll compile some examples on the wiki.

The customTitle function is new I just added that feature for this exact scenario less than a month ago so this will be a good test

sdfg2 commented 2 years ago

Did you ever get an example of this? This is one of the edge cases I had written off, myself.

lizardfish0 commented 2 years ago

Unfortunately no, I forgot about this. I've been using a script to batch rename subtitle tracks after importing them, and I'm lazy to work on a problem if I have a workaround. I'll take a stab at it today.

sdfg2 commented 2 years ago

It's half of a problem I came across earlier when setting it up and testing the various native language/subtitle combinations I have, and my anime is one of these situations. I don't like dubbed, but the Japanese audio tracks are stripped, and all the subtitles are stripped because none of them are 'forced'. I've only been working on setting it up this afternoon so I've probably missed a few things, but I might have to have separate profiles somehow for my anime.

lizardfish0 commented 2 years ago

This script should do. @mdhiggins it would be nice if there was a single source for constants like the mapping of disposition substrings to the proper output string. In the future if you decide to include other dispositions in output titles this would have to be updated.

from converter.avcodecs import BaseCodec

def streamTitle(mp, stream, options, hdr=False, imageBased=False, path=None):
    if stream.type == "subtitle":
        original_title = stream.metadata.get("title")

        if original_title and mp.settings.keep_titles:
            return original_title

        dispositions = [
            BaseCodec.DISPO_STRINGS.get(k)
            for k, v in stream.disposition.items() if v and k in BaseCodec.DISPO_STRINGS
        ]

        new_title = " ".join(dispositions)

        return new_title or original_title

    return None
mdhiggins commented 2 years ago

https://github.com/mdhiggins/sickbeard_mp4_automator/blob/790cdf42662f8bbfb77ceb0a52aa82765d1808df/converter/avcodecs.py#L8

Like that?

mdhiggins commented 2 years ago

Actually this is probably what you meant

60f2b42c0baf069385c203703c5d60e6e685ecdb

DISPO_STRING dict there for you

You can also just return None to use the build in title function instead of recreating it

lizardfish0 commented 2 years ago

Perfect, I was just writing a reply but yes that's exactly what I meant.

Also, I needed to recreate the title function because I need to know what the proposed new title is (mainly whether it's an empty string or not) before deciding whether to default to the original title. Just a side effect of how you have the custom function logic set up, but no harm there.

lizardfish0 commented 2 years ago

Also, @sdfg2 this will handle Signs & Songs sub tracks more explicitly than the previous script.

import re
from converter.avcodecs import BaseCodec

def streamTitle(mp, stream, options, hdr=False, imageBased=False, path=None):
    if stream.type == "subtitle":
        original_title = stream.metadata.get("title")

        if original_title:
            if mp.settings.keep_titles:
                return original_title

            if re.search("signs?", original_title, re.IGNORECASE) and stream.disposition.get("forced"):
                return "Signs & Songs"

        dispositions = [
            BaseCodec.DISPO_STRINGS.get(k)
            for k, v in stream.disposition.items() if v and k in BaseCodec.DISPO_STRINGS
        ]

        new_title = " ".join(dispositions)

        return new_title

    return None

If the track is

  1. Forced, and
  2. Title contains any version of "sign(s)"

Then the title is written as "Signs & Songs".

That's pretty specific behavior and more represents my personal naming preference than anything else.

My context is funneling this media into a Plex server. Plex doesn't actually respect ffmpeg disposition tags and instead defaults to selecting audio based on whatever your preferred language is in Plex (probably English). Then for subtitles, Plex will by default select a forced subtitle track in your preferred language if the audio track it selected is also in your preferred language. Therefore, I want my dual audio anime tagged as follows:

audio track 1: English
audio track 2: Japanese, default

subtitle track 1: English (Signs & Songs), forced
subtitle track 2: English (Full), default

This creates a nice flow where a brand new Plex user will be presented with English audio and Signs & Songs subtitles, and if they change their audio to Japanese (either by manually selecting it, or changing their Plex preferred language) then the subtitles automatically switch to the full English subtitles. This setup also means if I download the actual file and play it in a player that respects ffmpeg dispositions, then I get my default foreign language/subbed experience.

Ultimately this means that I'm probably going to have to do some level of manual pre-processing for any foreign language show I import, because the ffmpeg dispositions are almost never set perfectly how I'd like them to be. That problem can't really be solved by the automator though, because it has to rely on the information it gets from the file, and if the file isn't configured the way I want then there's not much to be done about that.

With this version of the script, however, I don't have to do any post-plex-import renaming of subtitle tracks which is a win.

sdfg2 commented 2 years ago

I'm feeding mine to Jellyfin which does the same preferences, except when it tries to talk DLNA. Sometimes it'll just pick whatever track it wants to do, no matter what I tell it - but I think that's a problem with the dispositions (you'll see below). I'm the sole user for my stuff, so I'm trying to strip everything I don't need, and burn in subtitles where I do need them - then no matter what the playback device it's a single file exactly how I want it.

The problem I have is the dispositions of the streams in the media I have:

    "audio": [                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
        {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
            "index": 1,                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            "codec": "flac",                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
            "bitrate": 719310,                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
            "channels": 2,                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
            "samplerate": 48000,                                                                                                                                                                                                                                                                                                                                                                                                                                                               
            "language": "jpn",                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
            "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"                                                                                                                                                                                                                                                                                                                                                                     
        },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
            "index": 2,                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            "codec": "flac",                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
            "bitrate": 1262843,                                                                                                                                                                                                                                                                                                                                                                                                                                                                
            "channels": 6,                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
            "samplerate": 44100,                                                                                                                                                                                                                                                                                                                                                                                                                                                               
            "language": "eng",                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
            "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"                                                                                                                                                                                                                                                                                                                                                                     
        },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
            "index": 3,                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            "codec": "ac3",                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
            "bitrate": 640000,                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
            "channels": 2,                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
            "samplerate": 48000,                                                                                                                                                                                                                                                                                                                                                                                                                                                               
            "language": "jpn",                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
            "disposition": "+default-dub-original+comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"                                                                                                                                                                                                                                                                                                                                                                     
        }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    ],                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    "subtitle": [                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
        {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
            "index": 4,                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            "codec": "ass",                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
            "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",                                                                                                                                                                                                                                                                                                                                                                    
            "language": "eng"                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
            "index": 5,                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            "codec": "ass",                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
            "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",                                                                                                                    
            "language": "eng"            
        },                        
        {                              
            "index": 6,           
            "codec": "ass",              
            "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",                                                                                                                    
            "language": "eng"                                                                                                                                                                                                                  
        }                         
    ],

As you can see, everything is default, so I've got no chance.