Created
September 24, 2024 21:05
-
-
Save bbaster/67d43265234a891260b564112e902094 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
#A master.m3u8, playlist.m3u8 and index-v1-a1 downloader | |
#Licensed under the GNU AGPLv3 | |
#Warning: selecting a specific *.m3u8 from a master or playlist file is unsupported! This downloader will pick the first one, you can manually supplement it with another one if preferred. | |
#The slashes there make no sense, I know | |
#Usage: escapeURL "url" | |
escapeURL() | |
{ | |
printf ${1//\//\\/} | |
} | |
#Checks for ffmpeg and aria2 | |
if ! [ $(command -v ffmpeg) ]; then | |
echo "Error: FFmpeg not found!" | |
echo "Please install it with \"sudo pacman -S ffmpeg\" on Arch(-based) distros (Manjaro) or with \"sudo apt install ffmpeg\" on Debian(-based) distros (Ubuntu, Pop!_OS, Linux Mint)" | |
exit 1 | |
fi | |
if ! [ $(command -v aria2c) ]; then | |
echo "Error: Aria2 not found!" | |
echo "Please install it with \"sudo pacman -S aria2\" on Arch(-based) distros (Manjaro) or with \"sudo apt install aria2\" on Debian(-based) distros (Ubuntu, Pop!_OS, Linux Mint)" | |
exit 1 | |
fi | |
#Checks for a "link.txt" and "movie.m3u8" file, else reads user input | |
if [ -s "$(dirname ${BASH_SOURCE})/link.txt" ]; then | |
echo "Reading link from \"link.txt\" file" | |
url="$(cat link.txt)" | |
elif [ -s "$(dirname ${BASH_SOURCE})/movie.m3u8" ]; then | |
echo "Reading from \"movie.m3u8\" file" | |
url=file | |
else | |
echo -n "Input master.m3u8 or index*.m3u8 URL (try a full curl command with browser headers if a website gives you HTTP 403 errors): " | |
read -r input | |
fi | |
#Checks if input is a curl command, or just an URL | |
if [[ $input =~ ^curl\ \'(https?.+index.*\.m3u8)\'\s?(.*) ]]; then | |
echo "curl index" | |
#Sets some variables | |
url="$(echo ${BASH_REMATCH[1]})" | |
url_escaped_canonical="$([[ "$(escapeURL "$url")" =~ (.*)\.m3u8.* ]] && echo "${BASH_REMATCH[1]}")" | |
url_index="$url" | |
curl_params="$(echo ${BASH_REMATCH[2]})" | |
aria2_params="${curl_params//--compressed/}" | |
aria2_params="${aria2_params//-H/--header}" | |
elif [[ $input =~ ^curl\ \'(https?.+(master|playlist)\.m3u8)\'\s?(.*) ]]; then | |
echo "curl master" | |
#Sets some variables | |
url="$(echo ${BASH_REMATCH[1]})" | |
url_escaped_canonical="$([[ "$(escapeURL "$url")" =~ (.*)\\/(master|playlist)\.m3u8.* ]] && echo "${BASH_REMATCH[1]}")" | |
curl_params="$(echo ${BASH_REMATCH[3]})" | |
aria2_params="${curl_params//--compressed/}" | |
aria2_params="${aria2_params//-H/--header}" | |
#Downloads the master.m3u8 file | |
eval curl -o master.m3u8 '$url' ${curl_params} | |
#Adds the canonical URL if missing to the master.m3u8 file | |
sed -i -E "s/(^[^#h].*$)/${url_escaped_canonical}\/\1/g" master.m3u8 | |
# #Searches for the index*.m3u8 URL in the master.m3u8 file | |
while read -r line; do | |
if [[ $line == *index*.m3u8* ]]; then | |
url_index="$line" | |
fi | |
done < master.m3u8 | |
elif [ -n "$input" ]; then | |
url=$input | |
fi | |
#Checks if the URL points to a master.m3u8, playlist.m3u8 or index*.m3u8 file, else exits with an error | |
if [[ $url =~ https?.*(master|playlist)\.m3u8.* ]]; then | |
#Sets some variables | |
url_escaped_canonical="$([[ "$(escapeURL "$url")" =~ (.*)\\/(master|playlist)\.m3u8.* ]] && echo "${BASH_REMATCH[1]}")" | |
#Downloads the master.m3u8 file | |
eval curl -o master.m3u8 '$url' ${curl_params} | |
#Adds the canonical URL if missing to the master.m3u8 file | |
sed -i -E "s/(^[^#h].*$)/${url_escaped_canonical}\/\1/g" master.m3u8 | |
#Searches for the index-v1-a1.m3u8 URL in the master.m3u8 file | |
while read -r line; do | |
if [[ $line == *index*.m3u8* ]]; then | |
url_index="$line" | |
fi | |
done < master.m3u8 | |
elif [[ $url == http*index*.m3u8* ]]; then | |
echo "index" | |
#Sets some variables | |
url_escaped_canonical="$([[ "$(escapeURL "$url")" =~ (.*)\\/index.*\.m3u8.* ]] && echo "${BASH_REMATCH[1]}")" | |
url_index="$url" | |
elif [ -n "$input" ]; then | |
echo "Error: Not a curl command, master.m3u8, playlist.m3u8 nor an index*.m3u8 URL!" | |
exit 1 | |
fi | |
#Downloads the index-v1-a1.m3u8 file | |
if [ "$url" != file ]; then eval curl -o index-v1-a1.m3u8 '$url' ${curl_params}; fi | |
#Renames movie.m3u8 file | |
if [ "$url" == file ]; then mv movie.m3u8 index-v1-a1.m3u8; fi | |
#Adds the canonical URL if missing to the index-v1-a1.m3u8 file | |
sed -i -E "s/(^[^#h].*$)/${url_escaped_canonical}\/\1/g" index-v1-a1.m3u8 | |
#The actual downloading part, feel free to adjust the parameters "-x" (streams for downloading one file) and "-j" (files to download at once) | |
eval aria2c --continue=true -x 12 -j 12 -i index-v1-a1.m3u8 ${aria2_params} | |
#Sorts and concatenates all *.ts segments into one movie.ts file | |
cat $(ls seg-*.ts video*.ts 2>/dev/null| sort -V) > movie.ts | |
#Converts the movie.ts to movie.mkv with GPU acceleration, around 9x faster than the video duration at best (unnecessary, you can just watch the movie.ts file) | |
#ffmpeg -i movie.ts movie.mkv -vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 18 | |
#Removes unneded files | |
rm master.m3u8 index-v1-a1.m3u8 seg-*.ts video*.ts 2>/dev/null | |
#rm movie.ts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment