Release 2.2

- Added error checking for when Recycle Bin is configured but doesn't exist
- **Added batch mode as a result of issue** [#41](https://github.com/TheCaptain989/radarr-striptracks/issues/41)
- Moved command line option check earlier in the script and completely reworked options/arguments processing
  Correctly handles positional arguments regardless of relation to flagged options.
  Added flagged options for audio and subtitles.
  Added long arguments options.
- Made mode detection more robust
- Normalized test event output
- Added error checking for curl, mv, and rm issues
  Added additional error text.
  Normalized some rare error messages.
- Fixed the broken codec detection awk code
- Explicitly add "und" to track log if no language detected
- Corrected issue where the wrong language is chosen in some cases.
  (Radarr and Sonarr don't use the same numeric language IDs. Code was updated to use the name of the language, not the numeric code.)
- **Script will now try to set the language(s) in Radarr or Sonarr to what was retained after the video remux.**
  This fixes the lagging 'Multi-Language' issue in Radarr, among other things.  See issue #42 for more details.
  (This is a little messy and may be tightened up later.)
- Added check for mkvmerge -J return
- **Added multiple debug logging levels, defaults to lowest**
  Default debug level excludes the returned JSON, making it more readable and useful
- Tightened up some jq code
- **Added additional languages to codemap: Thai, Romanian**
- Added handler for unknown language code
- Updated help text and documentation
This commit is contained in:
TheCaptain989 2021-12-27 15:57:22 -06:00
parent 7f413a28c6
commit 2122355540
4 changed files with 531 additions and 189 deletions

View File

@ -51,18 +51,19 @@ Production Container info: ![Docker Image Size](https://img.shields.io/docker/im
![striptracks v3](.assets/striptracks-v3-custom-script.png "Radarr/Sonarr custom script settings")
The script will detect the language defined in the video profile for the movie or TV show and only keep the audio and subtitles selected.
Alternatively, a wrapper script may be used to more granularly define which tracks to keep. See [wrapper scripts](./README.md#wrapper-scripts) for more details.
Alternatively, a wrapper script may be used to more granularly define which tracks to keep. See [Wrapper Scripts](./README.md#wrapper-scripts) for more details.
## Usage
The source video can be any mkvtoolnix supported video format. The output is an MKV file with the same name.
Chapters, if they exist, are preserved. The Title attribute in the MKV is set to the movie title plus year
(ex: `The Sting (1973)`) or the series title plus episode information (ex: `Happy! 01x01 - What Smiles Are For`).
(ex: `The Sting (1973)`) or the series title plus episode information (ex: `Happy! 01x01 - What Smiles Are For`).
The language of the video file will be updated in the Radarr or Sonarr database to reflect the actual languages preserved in the remuxed video.
If you've configured the Radarr/Sonarr **Recycle Bin** path correctly, the original video will be moved there.
![danger] **NOTE:** If you have *not* configured the Recycle Bin, the original video file will be deleted/overwritten and permanently lost.
### Syntax
Beginning with version 2.0 of this mod, the script may be called with no arguments. In this configuration it will detect the language(s) defined in the profile (Quality Profile for Radarr, Language Profile for Sonarr) configured on the particular movie or TV show.
Beginning with version 2.0 of this mod, the script may be called with no arguments. In this configuration it will detect the language(s) defined in the profile (*Quality Profile* for Radarr, *Language Profile* for Sonarr) configured on the particular movie or TV show.
#### Automatic Language Detection
Both audio and subtitles that match the selected language(s) are kept.
@ -75,35 +76,49 @@ Both audio and subtitles that match the selected language(s) are kept.
>**Note:** The intent of the Radarr language selection 'Original' is not well documented. For the purposes of this script, it has the same function as 'Any' and will preserve all languages in the video file.
#### Manual Override
The script still supports command line arguments that will override what is detected. More granular control can therefore be exerted or extended using tagging and defining multiple Connect scripts (this is native Radarr/Sonarr functionality outside the scope of this documentation).
#### Command Line Options and Arguments
The script also supports command line arguments that will override the automatic language detection. More granular control can therefore be exerted or extended using tagging and defining multiple Connect scripts (this is native Radarr/Sonarr functionality outside the scope of this documentation).
The script accepts two command line arguments and one option:
The syntax for the command line is:
`striptracks.sh [OPTIONS] [<audio_languages> [<subtitle_languages>]]` OR
`striptracks.sh [OPTIONS] {-f|--file} <video_file> {-a|--audio} <audio_languages> {-s|--subs} <subtitle_languages>`
`[-d] [<audio_languages> [<subtitle_languages>]]`
Where:
The `<audio_languages>` and `<subtitle_languages>` are optional arguments that are colon (:) prepended language codes in [ISO639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes "List of ISO 639-2 codes") format.
Option|Argument|Description
---|---|---
-d, --debug|\[\<level\>\]|Enables debug logging. Level is optional.<br/>Default of 1 (low)<br/>2 includes JSON output<br/>3 contains even more JSON output
-a, --audio|<audio_languages>|Audio languages to keep<br/>ISO639-2 code(s) prefixed with a colon (`:`)
-s, --subs|<subtitle_languages>|Subtitle languages to keep<br/>IISO639-2 code(s) prefixed with a colon (`:`)
-f, --file|<video_file>|If included, the script enters **[Batch Mode](./README.md#batch-mode)** and converts the specified video file.<br/>![danger] **WARNING:** Do not use this argument when called from Radarr or Sonarr!
--help| |Display help and exit
The `<audio_languages>` and `<subtitle_languages>` are optional arguments that are colon (`:`) prepended language codes in [ISO639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes "List of ISO 639-2 codes") format.
For example:
* :eng
* :fre
* :spa
* `:eng`
* `:fre`
* `:spa`
...etc.
Multiple codes may be concatenated, such as `:eng:spa` for both English and Spanish.
Multiple codes may be concatenated, such as `:eng:spa` for both English and Spanish.
>**NOTE:** The script is smart enough to not remove the last audio track. This way you don't have to specify every possible language if you are importing a
foreign film, for example.
The `-d` option enables debug logging.
### Examples
```
:eng:und :eng # keep English and Undetermined audio and English subtitles
-d :eng "" # Enable debugging, keeping English audio and no subtitles
:eng:kor:jpn :eng:spa # Keep English, Korean, and Japanese audio, and English and
# Spanish subtitles
-d 2 # Enable debugging level 2, audio and subtitles
# languages detected from Radarr/Sonarr
-a :eng:und -s :eng # Keep English and Unknown audio and English subtitles
:eng "" # Keep English audio and no subtitles
-d :eng:kor:jpn :eng:spa # Enable debugging level 1, keeping English, Korean, and Japanese audio, and English and
# Spanish subtitles
-f \"/path/to/movies/Finding Nemo (2003).mkv\" -a :eng:und -s :eng
# Batch Mode
# Keep English and Unknown audio and
# English subtitles, converting video specified
```
### Wrapper Scripts
@ -115,11 +130,13 @@ You may use any of these scripts in place of `striptracks.sh` mentioned in the [
```
striptracks-debug.sh # Use detected languages, but enable debug logging
striptracks-debug-2.sh # Use detected languages, enable debug logging level 2
striptracks-debug-max.sh # Use detected languages, enable highest debug logging
striptracks-dut.sh # Keep Dutch audio and subtitles
striptracks-eng.sh # Keep English and Undetermined audio and English subtitles
striptracks-eng-debug.sh # Keep English and Undetermined audio and English subtitles, and enable debug logging
striptracks-eng-fre.sh # Keep English, French, and Undetermined audio and English subtitles
striptracks-eng-jpn.sh # Keep English, Japanese, and Undetermined audio and English subtitles
striptracks-eng.sh # Keep English and Unknown audio and English subtitles
striptracks-eng-debug.sh # Keep English and Unknown audio and English subtitles, and enable debug logging
striptracks-eng-fre.sh # Keep English, French, and Unknown audio and English subtitles
striptracks-eng-jpn.sh # Keep English, Japanese, and Unknown audio and English subtitles
striptracks-fre.sh # Keep French audio and subtitles
striptracks-fre-debug.sh # Keep French audio and subtitles, and enable debug logging
striptracks-ger.sh # Keep German audio and subtitles
@ -127,11 +144,11 @@ striptracks-spa.sh # Keep Spanish audio and subtitles
```
#### Example Wrapper Script
To configure the last entry from the [Examples](./README.md#examples) section above, create and save a file called `striptracks-custom.sh` to `/config` containing the following text:
To configure the an entry from the [Examples](./README.md#examples) section above, create and save a file called `striptracks-custom.sh` to `/config` containing the following text:
```shell
#!/bin/bash
. /usr/local/bin/striptracks.sh :eng:kor:jpn :eng:spa
. /usr/local/bin/striptracks.sh -d :eng:kor:jpn :eng:spa
```
Make it executable:
```shell
@ -145,6 +162,25 @@ Then put `/config/striptracks-custom.sh` in the **Path** field in place of `/usr
### Triggers
The only events/notification triggers that have been tested are **On Import** and **On Upgrade**
### Batch Mode
Batch mode allows the script to be executed independently of Radarr or Sonarr. It converts the file specified on the command line and ignores any environment variables that are normally expected to be set by the video management program.
Using this function, you can easily process all of your video files in any subdirectory at once. See the [Batch Example](./README.md#batch-example) below.
#### Script Execution Differences in Batch Mode
Because the script is not called from within Radarr or Sonarr, expect the following behavior while in Batch Mode:
* *The file name must be specified on the command line*<br/>(The `-f` flag places the script in Batch Mode)
* *No audio or subtitles language auto detection occurs.*<br/>Both the audio and subtitles languages must be specified on the command line
* *The resultant MKV embedded title attribute is set to the basename of the file minus the extension.*<br/>The canonical name of the movie/TV show cannot otherwise be determined.
* *Radarr or Sonarr APIs are not called and their database is not updated.*<br/>This may require a manual rescan of converted videos.
* *Original video files are deleted.*<br/>The Recycle Bin function is not available.
#### Batch Example
To keep English and Unknown audio and English subtitles on all video files ending in .MKV, .AVI, or .MP4 in the `/movies` directory, enter the following at the Linux command line:
```shell
find /movies/ -type f \( -name "*.mkv" -o -name "*.avi" -o -name "*.mp4" \) | while read file; do /usr/local/bin/striptracks.sh -f "$file" -a :eng:und -s :eng; done
```
### Logs
A log file is created for the script activity called:
@ -155,7 +191,7 @@ This log can be inspected or downloaded from Radarr/Sonarr under *System* > *Log
Script errors will show up in both the script log and the native Radarr/Sonarr log.
Log rotation is performed with 5 log files of 512KB each being kept.
>![danger] **NOTE:** If debug logging is enabled, the log file can grow very large very quickly. *Do not leave debug logging enabled permanently.*
>![danger] **NOTE:** If debug logging is enabled with a level above 1, the log file can grow very large very quickly. *Do not leave high-level debug logging enabled permanently.*
___

View File

@ -0,0 +1,3 @@
#!/bin/bash
. /usr/local/bin/striptracks.sh -d 2

View File

@ -0,0 +1,3 @@
#!/bin/bash
. /usr/local/bin/striptracks.sh -d 9

View File

@ -8,7 +8,11 @@
# Adapted and corrected from Endoro's post 1/5/2014:
# https://forum.videohelp.com/threads/343271-BULK-remove-non-English-tracks-from-MKV-container#post2292889
#
# Option processing taken from Drew Strokes post 3/24/2015:
# https://medium.com/@Drew_Stokes/bash-argument-parsing-54f3b81a6a8f
#
# Put a colon `:` in front of every language code. Expects ISO639-2 codes
#
# NOTE: This has been updated to work with v3 API only. Far too many complications trying to keep multiple version compatible.
@ -20,6 +24,7 @@
# numfmt
# stat
# nice
# basename
# Exit codes:
# 0 - success; or test
@ -29,8 +34,9 @@
# 4 - mkvmerge not found
# 5 - specified video file not found
# 6 - unable to rename video to temp video
# 7 - unknown environment
# 7 - unknown eventtype environment variable
# 8 - unsupported Radarr/Sonarr version (v2)
# 9 - mkvmerge get media info failed
# 10 - remuxing completed, but no output file found
# 20 - general error
@ -43,8 +49,136 @@ export striptracks_maxlogsize=512000
export striptracks_maxlog=4
export striptracks_debug=0
export striptracks_langcodes=
export striptracks_pos_params=
# Presence of '*_eventtype' variable sets script mode
export striptracks_type=$(printenv | sed -n 's/_eventtype *=.*$//p')
if [[ "${striptracks_type,,}" = "radarr" ]]; then
# Usage function
function usage {
usage="
$striptracks_script
Video remuxing script that only keeps tracks with the specified languages.
Designed for use with Radarr and Sonarr, but may be used standalone in batch mode.
Source: https://github.com/TheCaptain989/radarr-striptracks
Usage:
$0 [OPTIONS] [<audio_languages> [<subtitle_languages>]]
$0 [OPTIONS] {-f|--file} <video_file> {-a|--audio} <audio_languages> {-s|--subs} <subtitle_languages>
Options and Arguments:
-d, --debug [<level>] enable debug logging
Level is optional, default of 1 (low)
-a, --audio <audio_languages> audio languages to keep
ISO639-2 code(s) prefixed with a colon \`:\`
Multiple codes may be concatenated.
-s, --subs <subtitle_languages> subtitles languages to keep
ISO639-2 code(s) prefixed with a colon \`:\`
Multiple codes may be concatenated.
-f, --file <video_file> if included, the script enters batch mode
and converts the specified video file.
WARNING: Do not use this argument when called
from Radarr or Sonarr!
--help display this help and exit
When audio_languages and subtitle_languages are omitted the script detects the audio
or subtitle languages configured in Radarr or Sonarr profile. When used on the command
line, they override the detected codes. They are also accepted as positional parameters
for backwards compatibility.
Batch Mode:
In batch mode the script acts as if it were not called from within Radarr
or Sonarr. It converts the file specified on the command line and ignores
any environment variables that are normally expected. The MKV embedded title
attribute is set to the basename of the file minus the extension.
Examples:
$striptracks_script -d 2 # Enable debugging level 2, audio and subtitles
# languages detected from Radarr/Sonarr
$striptracks_script -a :eng:und -s :eng # keep English and Unknown audio and
# English subtitles
$striptracks_script :eng \"\" # keep English audio and no subtitles
$striptracks_script -d :eng:kor:jpn :eng:spa # Enable debugging level 1, keeping English, Korean,
# and Japanese audio, and English and
# Spanish subtitles
$striptracks_script -f \"/path/to/movies/Finding Nemo (2003).mkv\" -a :eng:und -s :eng
# Batch Mode
# Keep English and Unknown audio and
# English subtitles, converting video specified
"
echo "$usage" >&2
}
# Process arguments
while (( "$#" )); do
case "$1" in
-d|--debug ) # Enable debugging, with optional level
if [ -n "$2" ] && [ ${2:0:1} != "-" ] && [[ "$2" =~ ^[0-9]+$ ]]; then
export striptracks_debug=$2
shift 2
else
export striptracks_debug=1
shift
fi
;;
--help ) # Display usage
usage
exit 0
;;
-f|--file ) # Batch Mode
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
# Overrides detected *_eventtype
export striptracks_type="batch"
export striptracks_video="$2"
shift 2
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 1
fi
;;
-a|--audio ) # Audio languages to keep
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
export striptracks_audiokeep="$2"
shift 2
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 2
fi
;;
-s|--subs ) # Subtitles languages to keep
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
export striptracks_subskeep="$2"
shift 2
else
echo "Error|Invalid option: $1 requires an argument." >&2
usage
exit 3
fi
;;
-*|--*=) # Unknown option
echo "Error|Unknown option: $1" >&2
usage
exit 20
;;
*) # preserve positional arguments
striptracks_pos_params="$striptracks_pos_params $1"
shift
;;
esac
done
# Set positional arguments in their proper place
eval set -- "$striptracks_pos_params"
## Mode specific variables
if [[ "${striptracks_type,,}" = "batch" ]]; then
# Batch mode
export batch_eventtype="Convert"
export striptracks_title="$(basename "$striptracks_video" ".${striptracks_video##*.}")"
elif [[ "${striptracks_type,,}" = "radarr" ]]; then
# Radarr mode
export striptracks_video="$radarr_moviefile_path"
export striptracks_video_api="movie"
export striptracks_video_id="${radarr_movie_id}"
@ -55,7 +189,9 @@ if [[ "${striptracks_type,,}" = "radarr" ]]; then
export striptracks_video_type="movie"
export striptracks_profile_type="quality"
export striptracks_title="$radarr_movie_title ($radarr_movie_year)"
export striptracks_language_api="language"
elif [[ "${striptracks_type,,}" = "sonarr" ]]; then
# Sonarr mode
export striptracks_video="$sonarr_episodefile_path"
export striptracks_video_api="episode"
export striptracks_video_id="${sonarr_episodefile_episodeids}"
@ -66,8 +202,10 @@ elif [[ "${striptracks_type,,}" = "sonarr" ]]; then
export striptracks_video_type="series"
export striptracks_profile_type="language"
export striptracks_title="$sonarr_series_title $(numfmt --format "%02f" ${sonarr_episodefile_seasonnumber:-0})x$(numfmt --format "%02f" ${sonarr_episodefile_episodenumbers:-0}) - $sonarr_episodefile_episodetitles"
export striptracks_language_api="languageprofile"
else
echo "Unknown environment: ${striptracks_type}"
# Called in an unexpected way
echo -e "Error|Unknown or missing '*_eventtype' environment variable: ${striptracks_type}\nNot called within Radarr/Sonarr?\nTry using Batch Mode option: -f <file>"
exit 7
fi
export striptracks_rescan_api="Rescan${striptracks_video_type^}"
@ -75,36 +213,11 @@ export striptracks_json_key="${striptracks_video_type}Id"
export striptracks_eventtype="${striptracks_type,,}_eventtype"
export striptracks_tempvideo="${striptracks_video}.tmp"
export striptracks_newvideo="${striptracks_video%.*}.mkv"
striptracks_isocodemap='{"languages":[{"language":{"id":-1,"name":"Any","iso639-2":["ara","bul","zho","chi","ces","cze","dan","nld","dut","eng","fin","fra","fre","deu","ger","ell","gre","heb","hin","hun","isl","ice","ita","jpn","kor","lit","nor","pol","por","ron","rom","rus","spa","swe","tha","tur","vie","und"]}},{"language":{"id":-2,"name":"Original","iso639-2":["ara","bul","zho","chi","ces","cze","dan","nld","dut","eng","fin","fra","fre","deu","ger","ell","gre","heb","hin","hun","isl","ice","ita","jpn","kor","lit","nor","pol","por","ron","rom","rus","spa","swe","tha","tur","vie","und"]}},{"language":{"id":27,"name":"Hindi","iso639-2":["hin"]}},{"language":{"id":26,"name":"Arabic","iso639-2":["ara"]}},{"language":{"id":0,"name":"Unknown","iso639-2":["und"]}},{"language":{"id":13,"name":"Vietnamese","iso639-2":["vie"]}},{"language":{"id":17,"name":"Turkish","iso639-2":["tur"]}},{"language":{"id":14,"name":"Swedish","iso639-2":["swe"]}},{"language":{"id":3,"name":"Spanish","iso639-2":["spa"]}},{"language":{"id":11,"name":"Russian","iso639-2":["rus"]}},{"language":{"id":18,"name":"Portuguese","iso639-2":["por"]}},{"language":{"id":12,"name":"Polish","iso639-2":["pol"]}},{"language":{"id":15,"name":"Norwegian","iso639-2":["nor"]}},{"language":{"id":24,"name":"Lithuanian","iso639-2":["lit"]}},{"language":{"id":21,"name":"Korean","iso639-2":["kor"]}},{"language":{"id":8,"name":"Japanese","iso639-2":["jpn"]}},{"language":{"id":5,"name":"Italian","iso639-2":["ita"]}},{"language":{"id":9,"name":"Icelandic","iso639-2":["isl","ice"]}},{"language":{"id":22,"name":"Hungarian","iso639-2":["hun"]}},{"language":{"id":23,"name":"Hebrew","iso639-2":["heb"]}},{"language":{"id":20,"name":"Greek","iso639-2":["ell","gre"]}},{"language":{"id":4,"name":"German","iso639-2":["deu","ger"]}},{"language":{"id":2,"name":"French","iso639-2":["fra","fre"]}},{"language":{"id":19,"name":"Flemish","iso639-2":["nld","dut"]}},{"language":{"id":16,"name":"Finnish","iso639-2":["fin"]}},{"language":{"id":1,"name":"English","iso639-2":["eng"]}},{"language":{"id":7,"name":"Dutch","iso639-2":["nld","dut"]}},{"language":{"id":6,"name":"Danish","iso639-2":["dan"]}},{"language":{"id":25,"name":"Czech","iso639-2":["ces","cze"]}},{"language":{"id":10,"name":"Chinese","iso639-2":["zho","chi"]}}]}'
# If this were defined directly in Radarr or Sonarr this would not be needed here
striptracks_isocodemap='{"languages":[{"language":{"name":"Any","iso639-2":["ara","bul","zho","chi","ces","cze","dan","nld","dut","eng","fin","fra","fre","deu","ger","ell","gre","heb","hin","hun","isl","ice","ita","jpn","kor","lit","nor","pol","por","ron","rom","rus","spa","swe","tha","tur","vie","und"]}},{"language":{"name":"Original","iso639-2":["ara","bul","zho","chi","ces","cze","dan","nld","dut","eng","fin","fra","fre","deu","ger","ell","gre","heb","hin","hun","isl","ice","ice","ita","jpn","kor","lit","nor","pol","por","ron","rom","rus","spa","swe","tha","tur","vie","und"]}},{"language":{"name":"Arabic","iso639-2":["ara"]}},{"language":{"name":"Bulgarian","iso639-2":["bul"]}},{"language":{"name":"Chinese","iso639-2":["zho","chi"]}},{"language":{"name":"Czech","iso639-2":["ces","cze"]}},{"language":{"name":"Danish","iso639-2":["dan"]}},{"language":{"name":"Dutch","iso639-2":["nld","dut"]}},{"language":{"name":"English","iso639-2":["eng"]}},{"language":{"name":"Finnish","iso639-2":["fin"]}},{"language":{"name":"Flemish","iso639-2":["nld","dut"]}},{"language":{"name":"French","iso639-2":["fra","fre"]}},{"language":{"name":"German","iso639-2":["deu","ger"]}},{"language":{"name":"Greek","iso639-2":["ell","gre"]}},{"language":{"name":"Hebrew","iso639-2":["heb"]}},{"language":{"name":"Hindi","iso639-2":["hin"]}},{"language":{"name":"Hungarian","iso639-2":["hun"]}},{"language":{"name":"Icelandic","iso639-2":["isl","ice"]}},{"language":{"name":"Italian","iso639-2":["ita"]}},{"language":{"name":"Japanese","iso639-2":["jpn"]}},{"language":{"name":"Korean","iso639-2":["kor"]}},{"language":{"name":"Lithuanian","iso639-2":["lit"]}},{"language":{"name":"Norwegian","iso639-2":["nor"]}},{"language":{"name":"Polish","iso639-2":["pol"]}},{"language":{"name":"Portuguese","iso639-2":["por"]}},{"language":{"name":"Romanian","iso639-2":["rum","ron"]}},{"language":{"name":"Russian","iso639-2":["rus"]}},{"language":{"name":"Spanish","iso639-2":["spa"]}},{"language":{"name":"Swedish","iso639-2":["swe"]}},{"language":{"name":"Thai","iso639-2":["tha"]}},{"language":{"name":"Turkish","iso639-2":["tur"]}},{"language":{"name":"Vietnamese","iso639-2":["vie"]}},{"language":{"name":"Unknown","iso639-2":["und"]}}]}'
### Functions
function usage {
usage="
$striptracks_script
Video remuxing script designed for use with Radarr and Sonarr
Source: https://github.com/TheCaptain989/radarr-striptracks
Usage:
$0 [-d] <audio_languages> <subtitle_languages>
Options and Arguments:
-d enable debug logging
<audio_languages> ISO639-2 code(s) prefixed with a colon \`:\`
Multiple codes may be concatenated.
<subtitle_languages> ISO639-2 code(s) prefixed with a colon \`:\`
Multiple codes may be concatenated.
Examples:
$striptracks_script :eng:und :eng # keep English and Undetermined audio and
# English subtitles
$striptracks_script :eng \"\" # keep English audio and no subtitles
$striptracks_script -d :eng:kor:jpn :eng:spa # Enable debugging, keeping English, Korean,
# and Japanese audio, and English and
# Spanish subtitles
"
echo "$usage" >&2
}
# Can still go over striptracks_maxlog if read line is too long
# Must include whole function in subshell for read to work!
function log {(
@ -129,10 +242,15 @@ function read_xml {
}
# Get video information
function get_video_info {
[ $striptracks_debug -eq 1 ] && echo "Debug|Getting video information for $striptracks_video_api '$striptracks_video_id'. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/$striptracks_video_api/$striptracks_video_id'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting video information for $striptracks_video_api '$striptracks_video_id'. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/$striptracks_video_api/$striptracks_video_id'" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/$striptracks_video_api/$striptracks_video_id")
[ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/$striptracks_video_api/$striptracks_video_id\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_result | jq -crM .hasFile)" = "true" ]; then
local striptracks_return=0
else
@ -142,10 +260,15 @@ function get_video_info {
}
# Get video file information
function get_videofile_info {
[ $striptracks_debug -eq 1 ] && echo "Debug|Getting video file information for $striptracks_videofile_api id '$striptracks_videofile_id'. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/$striptracks_videofile_api/$striptracks_videofile_id'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting video file information for $striptracks_videofile_api id '$striptracks_videofile_id'. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/$striptracks_videofile_api/$striptracks_videofile_id'" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/$striptracks_videofile_api/$striptracks_videofile_id")
[ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/$striptracks_videofile_api/$striptracks_videofile_id\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_result | jq -crM .path)" != "null" ]; then
local striptracks_return=0
else
@ -155,13 +278,18 @@ function get_videofile_info {
}
# Initiate Rescan request
function rescan {
striptracks_message="Info|Calling ${striptracks_type^} API to rescan ${striptracks_video_type}, try #$i"
striptracks_message="Info|Calling ${striptracks_type^} API to rescan ${striptracks_video_type}, try #$loop"
echo "$striptracks_message" | log
[ $striptracks_debug -eq 1 ] && echo "Debug|Forcing rescan of $striptracks_json_key '$striptracks_rescan_id', try #$i. Calling ${striptracks_type^} API '$striptracks_rescan_api' using POST and URL '$striptracks_api_url/v3/command'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Forcing rescan of $striptracks_json_key '$striptracks_rescan_id', try #$loop. Calling ${striptracks_type^} API '$striptracks_rescan_api' using POST and URL '$striptracks_api_url/v3/command' with data {\"name\": \"$striptracks_rescan_api\", \"$striptracks_json_key\": $striptracks_rescan_id}" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" -H "Content-Type: application/json" \
-d "{\"name\": \"$striptracks_rescan_api\", \"$striptracks_json_key\": $striptracks_rescan_id}" \
-X POST "$striptracks_api_url/v3/command")
[ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/command\" with data {\"name\": \"$striptracks_rescan_api\", \"$striptracks_json_key\": $striptracks_rescan_id}"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
striptracks_jobid="$(echo $striptracks_result | jq -crM .id)"
if [ "$striptracks_jobid" != "null" ]; then
local striptracks_return=0
@ -174,10 +302,15 @@ function rescan {
function check_rescan {
local i=0
for ((i=1; i <= 15; i++)); do
[ $striptracks_debug -eq 1 ] && echo "Debug|Checking job $striptracks_jobid completion, try #$i. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/command/$striptracks_jobid'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Checking job $striptracks_jobid completion, try #$i. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/command/$striptracks_jobid'" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/command/$striptracks_jobid")
[ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/command/$striptracks_jobid\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_result | jq -crM .status)" = "completed" ]; then
local striptracks_return=0
break
@ -188,7 +321,7 @@ function check_rescan {
else
# It may have timed out, so let's wait a second
local striptracks_return=1
[ $striptracks_debug -eq 1 ] && echo "Debug|Job not done. Waiting 1 second." | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Job not done. Waiting 1 second." | log
sleep 1
fi
fi
@ -197,11 +330,16 @@ function check_rescan {
}
# Get language/quality profiles
function get_profiles {
[ $striptracks_debug -eq 1 ] && echo "Debug|Getting list of $striptracks_profile_type profiles. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/${striptracks_profile_type}Profile'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting list of $striptracks_profile_type profiles. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/${striptracks_profile_type}Profile'" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/${striptracks_profile_type}Profile")
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/${striptracks_profile_type}Profile\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
# This returns A LOT of data, and it is normally not needed
# [ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
[ $striptracks_debug -ge 3 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_result | jq -crM '.message?')" != "NotFound" ]; then
local striptracks_return=0
else
@ -209,20 +347,41 @@ function get_profiles {
fi
return $striptracks_return
}
# Process options
while getopts ":d" opt; do
case ${opt} in
d ) # For debug purposes only
striptracks_message="Debug|Enabling debug logging."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
striptracks_debug=1
printenv | sort | sed 's/^/Debug|/' | log
;;
esac
done
shift $((OPTIND -1))
# Get language codes
function get_language_codes {
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting list of language codes. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/${striptracks_language_api}'" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/${striptracks_language_api}")
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] curl error when calling: \"$striptracks_api_url/v3/${striptracks_language_api}\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 3 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_result | jq -crM '.[] | .name')" != "null" ]; then
local striptracks_return=0
else
local striptracks_return=1
fi
return $striptracks_return
}
# Read in the output of mkvmerge info extraction
function get_mediainfo {
[ $striptracks_debug -ge 1 ] && echo "Debug|Executing: /usr/bin/mkvmerge -J \"$1\"" | log
striptracks_json=$(/usr/bin/mkvmerge -J "$1")
local striptracks_return2=$?; [ "$striptracks_return2" != 0 ] && {
local striptracks_message="Error|[$striptracks_return2] Error executing mkvmerge."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "mkvmerge returned: $striptracks_json" | awk '{print "Debug|"$0}' | log
if [ "$(echo $striptracks_json | jq -crM '.container.supported')" == "true" ]; then
local striptracks_return=0
else
local striptracks_return=1
fi
return $striptracks_return
}
# Check for required binaries
if [ ! -f "/usr/bin/mkvmerge" ]; then
@ -232,10 +391,27 @@ if [ ! -f "/usr/bin/mkvmerge" ]; then
exit 4
fi
# Log Debug state
if [ $striptracks_debug -ge 1 ]; then
striptracks_message="Debug|Enabling debug logging. Starting ${striptracks_type^} run for: $striptracks_title"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
# Log environment
[ $striptracks_debug -ge 2 ] && printenv | sort | sed 's/^/Debug|/' | log
# Log Batch mode
if [ "$striptracks_type" = "batch" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Switching to batch mode. Input filename: ${striptracks_video}" | log
fi
# Check for config file
if [ -f "$striptracks_arr_config" ]; then
if [ "$striptracks_type" = "batch" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Not using config file in batch mode." | log
elif [ -f "$striptracks_arr_config" ]; then
# Read *arr config.xml
[ $striptracks_debug -eq 1 ] && echo "Debug|Reading from ${striptracks_type^} config file '$striptracks_arr_config'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Reading from ${striptracks_type^} config file '$striptracks_arr_config'" | log
while read_xml; do
[[ $striptracks_xml_entity = "Port" ]] && striptracks_port=$striptracks_xml_content
[[ $striptracks_xml_entity = "UrlBase" ]] && striptracks_urlbase=$striptracks_xml_content
@ -249,10 +425,15 @@ if [ -f "$striptracks_arr_config" ]; then
striptracks_api_url="http://$striptracks_bindaddress:$striptracks_port$striptracks_urlbase/api"
# Check Radarr/Sonarr version
[ $striptracks_debug -eq 1 ] && echo "Debug|Getting ${striptracks_type^} version. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/system/status'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting ${striptracks_type^} version. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/system/status'" | log
striptracks_arr_version=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/system/status" | jq -crM .version)
[ $striptracks_debug -eq 1 ] && echo "Debug|Detected ${striptracks_type^} version $striptracks_arr_version" | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] curl or jq error when parsing: \"$striptracks_api_url/system/status\" | jq -crM .version"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 1 ] && echo "Debug|Detected ${striptracks_type^} version $striptracks_arr_version" | log
# Requires API v3
if [ "${striptracks_arr_version/.*/}" = "2" ]; then
@ -264,10 +445,15 @@ if [ -f "$striptracks_arr_config" ]; then
fi
# Get RecycleBin
[ $striptracks_debug -eq 1 ] && echo "Debug|Getting ${striptracks_type^} RecycleBin. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/config/mediamanagement'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Getting ${striptracks_type^} RecycleBin. Calling ${striptracks_type^} API using GET and URL '$striptracks_api_url/v3/config/mediamanagement'" | log
striptracks_recyclebin=$(curl -s -H "X-Api-Key: $striptracks_apikey" \
-X GET "$striptracks_api_url/v3/config/mediamanagement" | jq -crM .recycleBin)
[ $striptracks_debug -eq 1 ] && echo "Debug|Detected ${striptracks_type^} RecycleBin '$striptracks_recyclebin'" | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] curl or jq error when parsing: \"$striptracks_api_url/v3/config/mediamanagement\" | jq -crM .recycleBin"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 1 ] && echo "Debug|Detected ${striptracks_type^} RecycleBin '$striptracks_recyclebin'" | log
else
# No config file means we can't call the API. Best effort at this point.
striptracks_message="Warn|Unable to locate ${striptracks_type^} config file: '$striptracks_arr_config'"
@ -278,13 +464,15 @@ fi
# Handle Test event
if [[ "${!striptracks_eventtype}" = "Test" ]]; then
echo "Info|${striptracks_type^} event: ${!striptracks_eventtype}" | log
echo "Info|Script was test executed successfully." | log
striptracks_message="Info|Script was test executed successfully."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
exit 0
fi
# Check if called from within Radarr/Sonarr
# Check if video file is blank
if [ -z "$striptracks_video" ]; then
striptracks_message="Error|No video file specified! Not called from Radarr/Sonarr?"
striptracks_message="Error|No video file detected! radarr_moviefile_path or sonarr_episodefile_path environment variable missing or -f option not specified on command line."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
usage
@ -301,43 +489,58 @@ fi
#### Detect languages configured in Radarr/Sonarr
# Check for URL
if [ -n "$striptracks_api_url" ]; then
# Get quality/language profile info
if get_profiles; then
striptracks_profiles="$striptracks_result"
# Get video profile
if get_video_info; then
# Per environment logic
if [[ "${striptracks_type,,}" = "radarr" ]]; then
striptracks_profileid="$(echo $striptracks_result | jq -crM .qualityProfileId)"
striptracks_languages=$(echo $striptracks_profiles | jq -crM ".[] | select(.id == $striptracks_profileid) | .language.id")
elif [[ "${striptracks_type,,}" = "sonarr" ]]; then
striptracks_profileid="$(echo $striptracks_result | jq -crM .series.languageProfileId)"
striptracks_languages=$(echo $striptracks_profiles | jq -crM ".[] | select(.id == $striptracks_profileid) | .languages | .[] | select(.allowed).language.id")
if [ "$striptracks_type" = "batch" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Cannot detect languages in batch mode." | log
elif [ -n "$striptracks_api_url" ]; then
# Get language codes
if get_language_codes; then
striptracks_lang_codes="$striptracks_result"
# Get quality/language profile info
if get_profiles; then
striptracks_profiles="$striptracks_result"
# Get video profile
if get_video_info; then
# Per environment logic
if [[ "${striptracks_type,,}" = "radarr" ]]; then
striptracks_lang_codes="$striptracks_lang_codes"
striptracks_profileId="$(echo $striptracks_result | jq -crM .qualityProfileId)"
striptracks_languages="$(echo $striptracks_profiles | jq -cM "[.[] | select(.id == $striptracks_profileId) | .language]")"
elif [[ "${striptracks_type,,}" = "sonarr" ]]; then
striptracks_lang_codes="$(echo $striptracks_lang_codes | jq -crM "[.[0].languages[].language]")"
striptracks_profileId="$(echo $striptracks_result | jq -crM .series.languageProfileId)"
striptracks_languages="$(echo $striptracks_profiles | jq -crM "[.[] | select(.id == $striptracks_profileId) | .languages[] | select(.allowed).language]")"
else
# Should never fire due to previous checks, but just in case
striptracks_message "Error|Unknown environment detected late: ${striptracks_type}"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
exit 7
fi
striptracks_profileName="$(echo $striptracks_profiles | jq -crM ".[] | select(.id == $striptracks_profileId).name")"
striptracks_languageNames="$(echo $striptracks_languages | jq -crM "[.[].name]")"
[ $striptracks_debug -ge 1 ] && echo "Debug|Detected $striptracks_profile_type profile '(${striptracks_profileId}) ${striptracks_profileName}'" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Detected profile language(s) '$(echo $striptracks_languageNames | jq -crM "join(\",\")")' id(s) of '$(echo $striptracks_languages | jq -crM "[.[].id | tostring] | join(\",\")")'" | log
# Map 'Language' Id(s) to ISO code(s) used by mkvmerge
unset striptracks_langcodes
for i in $(echo $striptracks_languageNames | jq -crM ".[]"); do
striptracks_langcodes+="$(echo $striptracks_isocodemap | jq -jcrM ".languages[] | select(.language.name == \"$i\") | .language | \":\(.\"iso639-2\"[])\"")"
done
[ $striptracks_debug -ge 1 ] && echo "Debug|Mapped language(s) '$(echo $striptracks_languageNames | jq -crM "join(\",\")")' to ISO639-2 code string '$striptracks_langcodes'" | log
else
# Should never fire due to previous check, but just in case
striptracks_message "Error|Unknown environment: ${striptracks_type}"
# 'hasFile' is False in returned JSON.
striptracks_message="Warn|The '$striptracks_video_api' API with id $striptracks_video_id returned a false hasFile."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
exit 7
fi
striptracks_profilename=$(echo $striptracks_profiles | jq -crM ".[] | select(.id == $striptracks_profileid).name")
[ $striptracks_debug -eq 1 ] && echo "Debug|Detected $striptracks_profile_type profile '$striptracks_profilename' id '$striptracks_profileid'" | log
[ $striptracks_debug -eq 1 ] && echo "Debug|Detected language ids of '$(echo ${striptracks_languages})'" | log
# Lookup ISO codes
for i in $striptracks_languages; do
striptracks_langcodes+=$(echo $striptracks_isocodemap | jq -jcrM ".languages | .[] | select(.language.id == $i) | .language | \":\(.\"iso639-2\"[])\"")
done
[ $striptracks_debug -eq 1 ] && echo "Debug|Mapped language codes '$(echo ${striptracks_languages})' to ISO639-2 code string '$striptracks_langcodes'" | log
else
# 'hasFile' is False in returned JSON.
striptracks_message="Warn|The '$striptracks_video_api' API with id $striptracks_video_id returned a false hasFile."
# Get Profiles API failed
striptracks_message="Warn|Unable to retrieve $striptracks_profile_type profiles from ${striptracks_type^} API"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
else
# Get Profiles API failed
striptracks_message="Warn|Unable to retrieve $striptracks_profile_type profiles from ${striptracks_type^} API"
# Get language codes API failed
striptracks_message="Warn|Unable to retrieve language codes from '$striptracks_language_api' API (returned a null name)."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
@ -348,28 +551,34 @@ else
echo "$striptracks_message" >&2
fi
# Check for command line options; will override the detected languages
if [ -z "$1" -a -z "$striptracks_langcodes" ]; then
striptracks_message="Error|No audio languages specified!"
# Check for command line language options; will override the detected languages
if [ -n "$1" ]; then
striptracks_audiokeep="$1"
elif [ -n "$striptracks_audiokeep" ]; then
# Needed to allow ordered argument on command line to override detected languages
striptracks_audiokeep="$striptracks_audiokeep"
elif [ -n "$striptracks_langcodes" ]; then
striptracks_audiokeep="$striptracks_langcodes"
else
striptracks_message="Error|No audio languages specified or detected!"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
usage
exit 2
elif [ -z "$1" ]; then
striptracks_audiokeep="$striptracks_langcodes"
else
striptracks_audiokeep="$1"
fi
if [ -z "$2" -a -z "$striptracks_langcodes" ]; then
striptracks_message="Error|No subtitles languages specified!"
if [ -n "$2" ]; then
striptracks_subskeep="$2"
elif [ -n "$striptracks_subskeep" ]; then
# Needed to allow ordered argument on command line to override detected languages
striptracks_subskeep="$striptracks_subskeep"
elif [ -n "$striptracks_langcodes" ]; then
striptracks_subskeep="$striptracks_langcodes"
else
striptracks_message="Error|No subtitles languages specified or detected!"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
usage
exit 3
elif [ -z "$2" ]; then
striptracks_subskeep="$striptracks_langcodes"
else
striptracks_subskeep="$2"
fi
#### BEGIN MAIN
@ -377,43 +586,43 @@ striptracks_filesize=$(numfmt --to iec --format "%.3f" $(stat -c %s "$striptrack
striptracks_message="Info|${striptracks_type^} event: ${!striptracks_eventtype}, Video: $striptracks_video, Size: $striptracks_filesize, AudioKeep: $striptracks_audiokeep, SubsKeep: $striptracks_subskeep"
echo "$striptracks_message" | log
# Read in the output of mkvmerge info extraction
if get_mediainfo "$striptracks_video"; then
# This and the modified AWK script are a hack, and I know it. JQ is crazy hard to learn, BTW.
# Mimic the mkvmerge --identify-verbose option that has been deprecated
striptracks_json_processed=$(echo $striptracks_json | jq -jcrM '
( if (.chapters[] | .num_entries) then
"Chapters: \(.chapters[] | .num_entries) entries\n"
else
""
end
),
( .tracks[] |
( "Track ID \(.id): \(.type) (\(.codec)) [",
( [.properties | to_entries[] | "\(.key):\(.value | tostring | gsub(" "; "\\s"))"] | join(" ")),
"]\n"
)
)
')
[ $striptracks_debug -ge 1 ] && echo "$striptracks_json_processed" | awk '{print "Debug|"$0}' | log
else
# Get media info failed
striptracks_message="Error|Container format '$(echo $striptracks_json | jq -crM .container.type)' is unsupported by mkvmerge. Unable to continue."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
exit 9
fi
# Rename the original video file to a temporary name
[ $striptracks_debug -eq 1 ] && echo "Debug|Renaming: \"$striptracks_video\" to \"$striptracks_tempvideo\"" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Renaming: \"$striptracks_video\" to \"$striptracks_tempvideo\"" | log
mv -f "$striptracks_video" "$striptracks_tempvideo" 2>&1 | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="ERROR[$striptracks_return]: Unable to rename video: \"$striptracks_video\" to temp video: \"$striptracks_tempvideo\". Halting."
striptracks_message="Error|[$striptracks_return] Unable to rename video: \"$striptracks_video\" to temp video: \"$striptracks_tempvideo\". Halting."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
exit 6
}
# Read in the output of mkvmerge info extraction
[ $striptracks_debug -eq 1 ] && echo "Debug|Executing: /usr/bin/mkvmerge -J \"$striptracks_tempvideo\"" | log
striptracks_json=$(/usr/bin/mkvmerge -J "$striptracks_tempvideo")
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="ERROR[$striptracks_return]: Error executing mkvmerge."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
# This and the modified AWK script are a hack, and I know it. JQ is crazy hard to learn, BTW.
# Mimic the mkvmerge --identify-verbose option that has been deprecated
striptracks_json_processed=$(echo $striptracks_json | jq -jcrM '
( if (.chapters | .[] | .num_entries) then
"Chapters: \(.chapters | .[] | .num_entries) entries\n"
else
""
end
),
( .tracks |
.[] |
( "Track ID \(.id): \(.type) (\(.codec)) [",
( [.properties | to_entries | .[] | "\(.key):\(.value | tostring | gsub(" "; "\\s"))"] | join(" ")),
"]\n" )
)
')
[ $striptracks_debug -eq 1 ] && echo "$striptracks_json_processed" | awk '{print "Debug|"$0}' | log
echo "$striptracks_json_processed" | awk -v Debug=$striptracks_debug \
-v OrgVideo="$striptracks_video" \
-v TempVideo="$striptracks_tempvideo" \
@ -432,9 +641,15 @@ BEGIN {
NoTr++
Track[NoTr, "id"]=Fields[3]
Track[NoTr, "typ"]=Fields[5]
# This is inelegant and I know it
if (Fields[6]~/^\(/) {
Track[NoTr, "code"]=substr(Line,1,match(Line,/\)/))
sub(/^[^\(]+/,"",Track[NoTr, "code"])
for (i=6; i<=FieldCount; i++) {
Track[NoTr, "codec"]=Track[NoTr, "codec"]" "Fields[i]
if (match(Fields[i],/\)$/)) {
break
}
}
sub(/^ /,"",Track[NoTr, "codec"])
}
if (Track[NoTr, "typ"]=="video") VidCnt++
if (Track[NoTr, "typ"]=="audio") AudCnt++
@ -442,6 +657,7 @@ BEGIN {
for (i=6; i<=FieldCount; i++) {
if (Fields[i]=="language") Track[NoTr, "lang"]=Fields[++i]
}
if (Track[NoTr, "lang"]=="") Track[NoTr, "lang"]="und"
}
}
/^Chapters/ {
@ -453,11 +669,11 @@ END {
print "Info|Original tracks: "NoTr" (audio: "AudCnt", subtitles: "SubsCnt")"
if (Chapters) print "Info|Chapters: "Chapters
for (i=1; i<=NoTr; i++) {
if (Debug) print "Debug|i:"i,"Track ID:"Track[i,"id"],"Type:"Track[i,"typ"],"Lang:"Track[i, "lang"],"Code:"Track[i, "code"]
if (Debug >= 2) print "Debug|i:"i,"Track ID:"Track[i,"id"],"Type:"Track[i,"typ"],"Lang:"Track[i, "lang"],"Codec:"Track[i, "codec"]
if (Track[i, "typ"]=="audio") {
if (AudioKeep~Track[i, "lang"]) {
AudKpCnt++
print "Info|Keeping audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "code"]
print "Info|Keeping audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "codec"]
if (AudioCommand=="") {
AudioCommand=Track[i, "id"]
} else {
@ -466,28 +682,28 @@ END {
# Special case if there is only one audio track, even if it was not specified
} else if (AudCnt==1) {
AudKpCnt++
print "Info|Keeping only audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "code"]
print "Info|Keeping only audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "codec"]
AudioCommand=Track[i, "id"]
# Special case if there were multiple tracks, none were selected, and this is the last one.
} else if (AudioCommand=="" && Track[i, "id"]==AudCnt) {
AudKpCnt++
print "Info|Keeping last audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "code"]
print "Info|Keeping last audio track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "codec"]
AudioCommand=Track[i, "id"]
} else {
if (Debug) print "Debug|\tRemove:", Track[i, "typ"], "track", Track[i, "id"], Track[i, "lang"]
if (Debug >= 1) print "Debug|\tRemove:", Track[i, "typ"], "track", Track[i, "id"], Track[i, "lang"], Track[i, "codec"]
}
} else {
if (Track[i, "typ"]=="subtitles") {
if (SubsKeep~Track[i, "lang"]) {
SubsKpCnt++
print "Info|Keeping subtitle track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "code"]
print "Info|Keeping subtitle track "Track[i, "id"]": "Track[i, "lang"]" "Track[i, "codec"]
if (SubsCommand=="") {
SubsCommand=Track[i, "id"]
} else {
SubsCommand=SubsCommand","Track[i, "id"]
}
} else {
if (Debug) print "Debug|\tRemove:", Track[i, "typ"], "track", Track[i, "id"], Track[i, "lang"]
if (Debug >= 1) print "Debug|\tRemove:", Track[i, "typ"], "track", Track[i, "id"], Track[i, "lang"], Track[i, "codec"]
}
}
}
@ -505,9 +721,9 @@ END {
} else {
CommandLine=CommandLine" -s "SubsCommand
}
if (Debug) print "Debug|Executing: nice "MKVMerge" --title \""Title"\" -q -o \""MKVVideo"\" "CommandLine" \""TempVideo"\""
if (Debug >= 1) print "Debug|Executing: nice "MKVMerge" --title \""Title"\" -q -o \""MKVVideo"\" "CommandLine" \""TempVideo"\""
Result=system("nice "MKVMerge" --title \""Title"\" -q -o \""MKVVideo"\" "CommandLine" \""TempVideo"\"")
if (Result>1) print "Error|"Result" remuxing \""TempVideo"\"" > "/dev/stderr"
if (Result>1) print "Error|["Result"] remuxing \""TempVideo"\"" > "/dev/stderr"
}' | log
#### END MAIN
@ -516,23 +732,33 @@ END {
if [ -s "$striptracks_newvideo" ]; then
# Use Recycle Bin if configured
if [ "$striptracks_recyclebin" ]; then
[ $striptracks_debug -eq 1 ] && echo "Debug|Recycling: \"$striptracks_tempvideo\" to \"${striptracks_recyclebin%/}/$(basename "$striptracks_video")"\" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Recycling: \"$striptracks_tempvideo\" to \"${striptracks_recyclebin%/}/$(basename "$striptracks_video")"\" | log
mv "$striptracks_tempvideo" "${striptracks_recyclebin%/}/$(basename "$striptracks_video")" 2>&1 | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="ERROR[$striptracks_return]: Unable to move video: \"$striptracks_tempvideo\" to Recycle Bin: \"${striptracks_recyclebin%/}\""
striptracks_message="Error|[$striptracks_return] Unable to move video: \"$striptracks_tempvideo\" to Recycle Bin: \"${striptracks_recyclebin%/}\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
else
[ $striptracks_debug -eq 1 ] && echo "Debug|Deleting: \"$striptracks_tempvideo\"" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Deleting: \"$striptracks_tempvideo\"" | log
rm "$striptracks_tempvideo" 2>&1 | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] Unable to delete temporary video: \"$striptracks_tempvideo\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
fi
else
striptracks_message="Error|Unable to locate or invalid remuxed file: \"$striptracks_newvideo\". Undoing rename."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
[ $striptracks_debug -eq 1 ] && echo "Debug|Renaming: \"$striptracks_tempvideo\" to \"$striptracks_video\"" | log
[ $striptracks_debug -ge 1 ] && echo "Debug|Renaming: \"$striptracks_tempvideo\" to \"$striptracks_video\"" | log
mv -f "$striptracks_tempvideo" "$striptracks_video" 2>&1 | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] Unable to move video: \"$striptracks_tempvideo\" to \"$striptracks_video\""
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
exit 10
fi
@ -542,18 +768,20 @@ echo "$striptracks_message" | log
#### Call Radarr/Sonarr API to RescanMovie/RescanSeries
# Check for URL
if [ -n "$striptracks_api_url" ]; then
if [ "$striptracks_type" = "batch" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Cannot use API in batch mode." | log
elif [ -n "$striptracks_api_url" ]; then
# Check for video IDs
if [ "$striptracks_video_id" -a "$striptracks_videofile_id" ]; then
# Get video file info
if get_videofile_info; then
# Save original quality
striptracks_original_quality=$(echo $striptracks_result | jq -crM .quality)
[ $striptracks_debug -eq 1 ] && echo "Debug|Detected quality '$(echo $striptracks_original_quality | jq -crM .quality.name)'." | log
striptracks_original_quality="$(echo $striptracks_result | jq -crM .quality)"
[ $striptracks_debug -ge 1 ] && echo "Debug|Detected quality '$(echo $striptracks_original_quality | jq -crM .quality.name)'." | log
# Loop a maximum of twice
# Radarr needs to Rescan twice when the file extension changes
# (.avi -> .mkv for example)
for ((i=1; $i <= 2; i++)); do
for ((loop=1; $loop <= 2; loop++)); do
# Scan the disk for the new movie file
if rescan; then
# Give it a beat
@ -563,23 +791,29 @@ if [ -n "$striptracks_api_url" ]; then
# Get new video file id
if get_video_info; then
# Get new video file ID
striptracks_videofile_id=$(echo $striptracks_result | jq -crM ${striptracks_json_quality_root}.id)
[ $striptracks_debug -eq 1 ] && echo "Debug|Set new video file id '$striptracks_videofile_id'." | log
striptracks_videofile_id="$(echo $striptracks_result | jq -crM ${striptracks_json_quality_root}.id)"
[ $striptracks_debug -ge 1 ] && echo "Debug|Set new video file id '$striptracks_videofile_id'." | log
# Get new video file info
if get_videofile_info; then
striptracks_videofile_info="$striptracks_result"
# Check that the file didn't get lost in the Rescan.
# If we lost the quality information, put it back
if [ "$(echo $striptracks_result | jq -crM .quality.quality.name)" != "$(echo $striptracks_original_quality | jq -crM .quality.name)" ]; then
[ $striptracks_debug -eq 1 ] && echo "Debug|Updating from quality '$(echo $striptracks_result | jq -crM .quality.quality.name)' to '$(echo $striptracks_original_quality | jq -crM .quality.name)'. Calling ${striptracks_type^} API using PUT and URL '$striptracks_api_url/v3/$striptracks_videofile_api/editor'" | log
if [ "$(echo $striptracks_videofile_info | jq -crM .quality.quality.name)" != "$(echo $striptracks_original_quality | jq -crM .quality.name)" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Updating from quality '$(echo $striptracks_videofile_info | jq -crM .quality.quality.name)' to '$(echo $striptracks_original_quality | jq -crM .quality.name)'. Calling ${striptracks_type^} API using PUT and URL '$striptracks_api_url/v3/$striptracks_videofile_api/editor' with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"quality\":$striptracks_original_quality}" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" -H "Content-Type: application/json" \
-d "{\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"quality\":$striptracks_original_quality}" \
-X PUT "$striptracks_api_url/v3/$striptracks_videofile_api/editor")
[ $striptracks_debug -eq 1 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] curl error when calling: \"$striptracks_api_url/v3/$striptracks_videofile_api/editor\" with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"quality\":$striptracks_original_quality}"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
# Check that the returned result shows the update
if [ "$(echo $striptracks_result | jq -crM .[].quality.quality.name)" = "$(echo $striptracks_original_quality | jq -crM .quality.name)" ]; then
# Updated successfully
[ $striptracks_debug -eq 1 ] && echo "Debug|Successfully updated quality to '$(echo $striptracks_result | jq -crM .[].quality.quality.name)'." | log
break
[ $striptracks_debug -ge 1 ] && echo "Debug|Successfully updated quality to '$(echo $striptracks_result | jq -crM .[].quality.quality.name)'." | log
loop=2
else
striptracks_message="Warn|Unable to update ${striptracks_type^} $striptracks_video_api '$striptracks_title' to quality '$(echo $striptracks_original_quality | jq -crM .quality.name)'"
echo "$striptracks_message" | log
@ -587,8 +821,74 @@ if [ -n "$striptracks_api_url" ]; then
fi
else
# The quality is already correct
[ $striptracks_debug -eq 1 ] && echo "Debug|Quality of '$(echo $striptracks_original_quality | jq -crM .quality.name)' remained unchanged." | log
break
[ $striptracks_debug -ge 1 ] && echo "Debug|Quality of '$(echo $striptracks_original_quality | jq -crM .quality.name)' remained unchanged." | log
loop=2
fi
# Check the languages returned
# If we stripped out other languages, remove them from Radarr
# Only works in Radarr (no per-episode edit function in Sonarr)
unset striptracks_json
if get_mediainfo "$striptracks_newvideo"; then
# Build array of full name languages
striptracks_final_langcodes="$(echo $striptracks_json | jq -crM ".tracks[] | select(.type == \"audio\") | .properties.language")"
unset striptracks_newvideo_languages
for i in $striptracks_final_langcodes; do
striptracks_newvideo_languages+="$(echo $striptracks_isocodemap | jq -crM ".languages[] | .language | select((.\"iso639-2\"[]) == \"$i\") | select(.name != \"Any\" and .name != \"Original\").name")"
done
if [ -n "$striptracks_newvideo_languages" ]; then
# Covert to standard JSON
striptracks_json_languages="$(echo $striptracks_lang_codes | jq -crM "map(select(.name | inside(\"$striptracks_newvideo_languages\")) | {id, name})")"
# Check languages for Radarr
if [ "$(echo $striptracks_videofile_info | jq -crM .languages)" != "null" ]; then
if [ "$(echo $striptracks_videofile_info | jq -crM ".languages")" != "$striptracks_json_languages" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Updating from language(s) '$(echo $striptracks_videofile_info | jq -crM "[.languages[].name] | join(\",\")")' to '$(echo $striptracks_json_languages | jq -crM "[.[].name] | join(\",\")")'. Calling ${striptracks_type^} API using PUT and URL '$striptracks_api_url/v3/$striptracks_videofile_api/editor' with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"languages\":${striptracks_json_languages}}" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" -H "Content-Type: application/json" \
-d "{\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"languages\":${striptracks_json_languages}}" \
-X PUT "$striptracks_api_url/v3/$striptracks_videofile_api/editor")
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] curl error when calling: \"$striptracks_api_url/v3/$striptracks_videofile_api/editor\" with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"languages\":${striptracks_json_languages}}"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
else
# The languages are already correct
[ $striptracks_debug -ge 1 ] && echo "Debug|Language(s) '$(echo $striptracks_json_languages | jq -crM "[.[].name] | join(\",\")")' remained unchanged." | log
fi
# Check languages for Sonarr
elif [ "$(echo $striptracks_videofile_info | jq -crM .language)" != "null" ]; then
if [ "$(echo $striptracks_videofile_info | jq -crM ".language")" != "$(echo $striptracks_json_languages | jq -crM ".[0]")" ]; then
[ $striptracks_debug -ge 1 ] && echo "Debug|Updating from language '$(echo $striptracks_videofile_info | jq -crM ".language.name")' to '$(echo $striptracks_json_languages | jq -crM ".[0].name")'. Calling ${striptracks_type^} API using PUT and URL '$striptracks_api_url/v3/$striptracks_videofile_api/editor' with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"language\":$(echo $striptracks_json_languages | jq -crM ".[0]")}" | log
striptracks_result=$(curl -s -H "X-Api-Key: $striptracks_apikey" -H "Content-Type: application/json" \
-d "{\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"language\":$(echo $striptracks_json_languages | jq -crM ".[0]")}" \
-X PUT "$striptracks_api_url/v3/$striptracks_videofile_api/editor")
striptracks_return=$?; [ "$striptracks_return" != 0 ] && {
striptracks_message="Error|[$striptracks_return] curl error when calling: \"$striptracks_api_url/v3/$striptracks_videofile_api/editor\" with data {\"${striptracks_videofile_api}Ids\":[${striptracks_videofile_id}],\"languages\":$(echo $striptracks_json_languages | jq -crM ".[0]")}"
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
}
[ $striptracks_debug -ge 2 ] && echo "API returned: $striptracks_result" | awk '{print "Debug|"$0}' | log
else
# The languages are already correct
[ $striptracks_debug -ge 1 ] && echo "Debug|Language '$(echo $striptracks_json_languages | jq -crM ".[0]")' remained unchanged." | log
fi
else
# Some unknown JSON formatting
striptracks_message="Warn|$striptracks_videofile_api returned unknown JSON language location."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
else
# Video language not in striptracks_isocodemap
striptracks_message="Warn|Video language code(s) '${striptracks_newvideo_languages//$'\n'/,}' not found in the ISO Codemap. Cannot evaluate."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
else
# Get media info failed
striptracks_message="Error|Could not get media info from new video file. Can't check resulting languages."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi
else
# No '.path' in returned JSON
@ -598,7 +898,7 @@ if [ -n "$striptracks_api_url" ]; then
fi
else
# 'hasFile' is False in returned JSON.
striptracks_message="Warn|The '$striptracks_video_api' API with id $striptracks_video_id returned a false hasFile (Normal with Radarr on try #1)."
striptracks_message="Warn|The '$striptracks_video_api' API with id $striptracks_video_id returned a false 'hasFile' (Normal with Radarr on try #1)."
echo "$striptracks_message" | log
echo "$striptracks_message" >&2
fi