Merge pull request #237 from snorkrat/main

Add option to download videos in mp4 format.
pull/240/head
RandomNinjaAtk 1 year ago committed by GitHub
commit 86a217a77e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -50,7 +50,8 @@ This containers base image is provided by: [linuxserver/lidarr](https://github.c
* Downloading **Music Videos** using online sources for use in popular applications (Plex/Kodi/Emby/Jellyfin):
* Completely automated
* Searches Lidarr Artists (musicbrainz) video recordings for videos to download
* Saves videos in MKV format
* Saves videos in MKV format by default
* Can save videos in MP4 format for Plex metadata support
* Downloads using Highest available quality for both audio and video
* Saves thumbnail of video locally for Plex/Kodi/Jellyfin/Emby usage
* Embed subtitles if available matching desired language
@ -121,6 +122,7 @@ Container images are configured using parameters passed at runtime (such as thos
| `-e configureLidarrWithOptimalSettings=true` | true = enabled :: Automatically configures Lidarr with optimal settings |
| `-e searchSort=date` | date or album :: Sorts the missing/cutoff list by release date (newest -> oldest) or album type (album -> single) for processing the list |
| `-e audioFormat=native` | native or alac or mp3 or aac or opus :: native is the native download client file type, selected by the matching audio bitrate |
| `-e videoContainer=mkv` | mkv or mp4 :: Default = mkv. mp4 allows Plex to read metadata. Note mp4 videos may not be as high quality as mkv due to codec limitations of mp4. |
| `-e audioBitrate=lossless` | master or lossless or high or low or ### :: master = MQA/lossless flac files, lossless = flac files, high = 320K, low = 128k/96k, ### = the output bitrate of converted lossless files to selected audioFormat that is not native, example: 192... |
| `-e requireQuality=true` | true = enabled :: Downloads will be required to have the requested file format |
| `-e enableReplaygainTags=true` | true = enabled :: Downloads will be tagged with Replaygain Metadata |

@ -42,6 +42,7 @@ ENV videoFormat="bestvideo*+bestaudio/best"
ENV scriptInterval=15m
ENV videoDownloadTag=""
ENV retryNotFound=90
ENV videoContainer=mkv
RUN \
echo "*** install packages ***" && \

@ -42,6 +42,7 @@ ENV videoFormat="bestvideo*+bestaudio/best"
ENV scriptInterval=15m
ENV videoDownloadTag=""
ENV retryNotFound=90
ENV videoContainer=mkv
RUN \
echo "*** install packages ***" && \

@ -86,7 +86,9 @@ Configuration () {
log "CONFIG :: Download Location :: $downloadPath"
log "CONFIG :: Music Video Location :: $videoPath"
log "CONFIG :: Subtitle Language set to: $youtubeSubtitleLanguage"
log "CONFIG :: yt-dlp format: $videoFormat"
log "CONFIG :: yt-dlp format (mkv): $videoFormat"
log "CONFIG :: yt-dlp format (mp4): --format-sort ext:mp4:m4a --merge-output-format mp4"
log "CONFIG :: Video container set to format: $videoContainer"
if [ -n "$videoDownloadTag" ]; then
log "CONFIG :: Video download tag set to: $videoDownloadTag"
fi
@ -340,16 +342,30 @@ DownloadVideo () {
fi
if echo "$1" | grep -i "youtube" | read; then
if [ ! -z "$cookiesFile" ]; then
yt-dlp -f "$videoFormat" --no-video-multistreams --cookies "$cookiesFile" -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --merge-output-format mkv --remux-video mkv --no-mtime --geo-bypass "$1"
else
yt-dlp -f "$videoFormat" --no-video-multistreams -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --merge-output-format mkv --remux-video mkv --no-mtime --geo-bypass "$1"
fi
if [ -f "$downloadPath/incomplete/${2}${3}.mkv" ]; then
chmod 666 "$downloadPath/incomplete/${2}${3}.mkv"
downloadFailed=false
if [ $videoContainer = mkv ]; then
if [ ! -z "$cookiesFile" ]; then
yt-dlp -f "$videoFormat" --no-video-multistreams --cookies "$cookiesFile" -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --merge-output-format mkv --remux-video mkv --no-mtime --geo-bypass "$1"
else
yt-dlp -f "$videoFormat" --no-video-multistreams -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --merge-output-format mkv --remux-video mkv --no-mtime --geo-bypass "$1"
fi
if [ -f "$downloadPath/incomplete/${2}${3}.mkv" ]; then
chmod 666 "$downloadPath/incomplete/${2}${3}.mkv"
downloadFailed=false
else
downloadFailed=true
fi
else
downloadFailed=true
if [ ! -z "$cookiesFile" ]; then
yt-dlp --format-sort ext:mp4:m4a --merge-output-format mp4 --no-video-multistreams --cookies "$cookiesFile" -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --no-mtime --geo-bypass "$1"
else
yt-dlp --format-sort ext:mp4:m4a --merge-output-format mp4 --no-video-multistreams -o "$downloadPath/incomplete/${2}${3}" --embed-subs --sub-lang $youtubeSubtitleLanguage --no-mtime --geo-bypass "$1"
fi
if [ -f "$downloadPath/incomplete/${2}${3}.mp4" ]; then
chmod 666 "$downloadPath/incomplete/${2}${3}.mp4"
downloadFailed=false
else
downloadFailed=true
fi
fi
fi
@ -394,16 +410,31 @@ VideoProcessWithSMA () {
extension="${filename##*.}"
filenamenoext="${filename%.*}"
if python3 /usr/local/sma/manual.py --config "/config/extended/scripts/sma.ini" -i "$file" -nt &>/dev/null; then
sleep 0.01
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: Processed with SMA..."
rm /usr/local/sma/config/*log*
if [[ $filenoext.$videoContainer == *.mkv ]]
then
if python3 /usr/local/sma/manual.py --config "/config/extended/scripts/sma.ini" -i "$file" -nt &>/dev/null; then
sleep 0.01
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: Processed with SMA..."
rm /usr/local/sma/config/*log*
else
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: ERROR: SMA Processing Error"
rm "$video"
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: INFO: deleted: $filename"
fi
else
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: ERROR: SMA Processing Error"
rm "$video"
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: INFO: deleted: $filename"
if python3 /usr/local/sma/manual.py --config "/config/extended/scripts/sma-mp4.ini" -i "$file" -nt &>/dev/null; then
sleep 0.01
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: Processed with SMA..."
rm /usr/local/sma/config/*log*
else
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: ERROR: SMA Processing Error"
rm "$video"
log "$processCount of $lidarrArtistIdsCount :: $1 :: $lidarrArtistName :: $2 :: INFO: deleted: $filename"
fi
fi
done
}
VideoTagProcess () {
@ -430,10 +461,13 @@ VideoTagProcess () {
genre=""
fi
mv "$filenoext.mkv" "$filenoext-temp.mkv"
if [[ $filenoext.$videoContainer == *.mkv ]]
then
mv "$filenoext.$videoContainer" "$filenoext-temp.$videoContainer"
log "$processCount of $lidarrArtistIdsCount :: $4 :: $lidarrArtistName :: ${1}${2} $3 :: Tagging file"
ffmpeg -y \
-i "$filenoext-temp.mkv" \
-i "$filenoext-temp.$videoContainer" \
-c copy \
-metadata TITLE="${1}" \
-metadata DATE_RELEASE="$3" \
@ -444,9 +478,33 @@ VideoTagProcess () {
-metadata ALBUMARTIST="$lidarrArtistName" \
-metadata ENCODED_BY="lidarr-extended" \
-attach "$downloadPath/incomplete/${1}${2}.jpg" -metadata:s:t mimetype=image/jpeg \
"$filenoext.mkv" &>/dev/null
rm "$filenoext-temp.mkv"
chmod 666 "$filenoext.mkv"
"$filenoext.$videoContainer" &>/dev/null
rm "$filenoext-temp.$videoContainer"
chmod 666 "$filenoext.$videoContainer"
else
mv "$filenoext.$videoContainer" "$filenoext-temp.$videoContainer"
log "$processCount of $lidarrArtistIdsCount :: $4 :: $lidarrArtistName :: ${1}${2} $3 :: Tagging file"
ffmpeg -y \
-i "$filenoext-temp.$videoContainer" \
-i "$downloadPath/incomplete/${1}${2}.jpg" \
-map 1 \
-map 0 \
-c copy \
-c:v:0 mjpeg \
-disposition:0 attached_pic \
-movflags faststart \
-metadata TITLE="${1}" \
-metadata ARTIST="$lidarrArtistName" \
-metadata DATE="$3" \
-metadata GENRE="$genre" \
"$filenoext.$videoContainer" &>/dev/null
rm "$filenoext-temp.$videoContainer"
chmod 666 "$filenoext.$videoContainer"
fi
done
}
@ -748,7 +806,7 @@ for lidarrArtistId in $(echo $lidarrArtistIds); do
fi
fi
fi
if [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${musicbrainzVideoTitleClean}${plexVideoType}.mkv") ]]; then
if [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${musicbrainzVideoTitleClean}${plexVideoType}.mkv") ]] || [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${musicbrainzVideoTitleClean}${plexVideoType}.mp4") ]]; then
log "$processCount of $lidarrArtistIdsCount :: MBZDB :: $lidarrArtistName :: ${musicbrainzVideoTitle}${musicbrainzVideoDisambiguation} :: Previously Downloaded, skipping..."
continue
fi
@ -838,7 +896,7 @@ for lidarrArtistId in $(echo $lidarrArtistIds); do
tidy -w 2000 -i -m -xml "$videoPath/$lidarrArtistFolderNoDisambig/${videoTitleClean}${plexVideoType}.nfo" &>/dev/null
fi
fi
if [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${videoTitleClean}${plexVideoType}.mkv") ]]; then
if [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${videoTitleClean}${plexVideoType}.mkv") ]] || [[ -n $(find "$videoPath/$lidarrArtistFolderNoDisambig" -maxdepth 1 -iname "${videoTitleClean}${plexVideoType}.mp4") ]]; then
log "$processCount of $lidarrArtistIdsCount :: IMVDB :: $lidarrArtistName :: ${imvdbVideoTitle} :: Previously Downloaded, skipping..."
continue
fi

@ -0,0 +1,267 @@
[Converter]
ffmpeg = ffmpeg
ffprobe = ffprobe
threads = 0
hwaccels =
hwaccel-decoders =
hwdevices =
hwaccel-output-format =
output-directory =
output-directory-space-ratio = 0.0
output-format = mp4
output-extension = mp4
temp-extension =
minimum-size = 0
ignored-extensions = nfo, ds_store
copy-to =
move-to =
delete-original = True
process-same-extensions = True
bypass-if-copying-all = False
force-convert = True
post-process = False
wait-post-process = False
detailed-progress = False
opts-separator = ,
preopts =
postopts =
regex-directory-replace = [^\w\-_\. ]
[Permissions]
chmod = 0666
uid = -1
gid = -1
[Metadata]
relocate-moov = True
full-path-guess = True
tag = True
tag-language = eng
download-artwork = poster
sanitize-disposition =
strip-metadata = True
keep-titles = False
[Video]
codec = copy
max-bitrate = 0
bitrate-ratio =
crf = -1
crf-profiles =
preset =
codec-parameters =
dynamic-parameters = False
max-width = 0
profile =
max-level = 0.0
pix-fmt =
prioritize-source-pix-fmt = True
filter =
force-filter = False
[HDR]
codec =
pix-fmt =
space = bt2020nc
transfer = smpte2084
primaries = bt2020
preset =
codec-parameters =
filter =
force-filter = False
profile =
[Audio]
codec = copy
languages =
default-language =
include-original-language = True
first-stream-of-language = False
channel-bitrate = 128
variable-bitrate = 0
max-bitrate = 0
max-channels = 0
filter =
profile =
force-filter = False
sample-rates =
sample-format =
copy-original = False
aac-adtstoasc = False
ignored-dispositions =
force-default = False
unique-dispositions = False
stream-codec-combinations =
[Audio.Sorting]
sorting = language, channels.d, map, d.comment
default-sorting = channels.d, map, d.comment
codecs =
[Universal Audio]
codec =
channel-bitrate = 128
variable-bitrate = 0
first-stream-only = False
filter =
profile =
force-filter = False
[Audio.ChannelFilters]
6-2 = pan=stereo|FL=0.5*FC+0.707*FL+0.707*BL+0.5*LFE|FR=0.5*FC+0.707*FR+0.707*BR+0.5*LFE
[Subtitle]
codec = srt
codec-image-based = copy
languages =
default-language =
first-stream-of-language = False
encoding =
burn-subtitles = False
burn-dispositions =
embed-subs = True
embed-image-subs = True
embed-only-internal-subs = True
filename-dispositions = forced
ignore-embedded-subs = False
ignored-dispositions =
force-default = False
unique-dispositions = True
attachment-codec =
remove-bitstream-subs = False
include-original-language = False
[Subtitle.Sorting]
sorting = language, d.comment, d.default.d, d.forced.d
burn-sorting = language, d.comment, d.default.d, d.forced.d
codecs =
[Subtitle.CleanIt]
enabled = False
config-path =
tags =
[Subtitle.Subliminal]
download-subs = False
download-hearing-impaired-subs = False
providers =
download-forced-subs = False
include-hearing-impaired-subs = False
[Subtitle.Subliminal.Auth]
opensubtitles =
tvsubtitles =
[Sonarr]
host = localhost
port = 8989
apikey =
ssl = False
webroot =
force-rename = False
rescan = True
block-reprocess = False
[Radarr]
host = localhost
port = 7878
apikey =
ssl = False
webroot =
force-rename = False
rescan = True
block-reprocess = False
[Sickbeard]
host = localhost
port = 8081
ssl = False
apikey =
webroot =
username =
password =
[Sickrage]
host = localhost
port = 8081
ssl = False
apikey =
webroot =
username =
password =
[SABNZBD]
convert = True
sickbeard-category = sickbeard
sickrage-category = sickrage
sonarr-category = sonarr
radarr-category = radarr
bypass-category = bypass
output-directory =
path-mapping =
[Deluge]
sickbeard-label = sickbeard
sickrage-label = sickrage
sonarr-label = sonarr
radarr-label = radarr
bypass-label = bypass
convert = True
host = localhost
port = 58846
username =
password =
output-directory =
remove = False
path-mapping =
[qBittorrent]
sickbeard-label = sickbeard
sickrage-label = sickrage
sonarr-label = sonarr
radarr-label = radarr
bypass-label = bypass
convert = True
action-before =
action-after =
host = localhost
port = 8080
ssl = False
username =
password =
output-directory =
path-mapping =
[uTorrent]
sickbeard-label = sickbeard
sickrage-label = sickrage
sonarr-label = sonarr
radarr-label = radarr
bypass-label = bypass
convert = True
webui = False
action-before =
action-after =
host = localhost
ssl = False
port = 8080
username =
password =
output-directory =
path-mapping =
[Plex]
host = localhost
port = 32400
refresh = False
token =
username =
password =
servername =
ssl = True
ignore-certs = False
path-mapping =
[Subtitle.FFSubsync]
enabled = False
Loading…
Cancel
Save