Initial commit
This commit is contained in:
commit
5b61931167
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
downloads/*
|
||||||
|
yt-dlc/
|
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
19
README.md
Normal file
19
README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# south-park-de-downloader
|
||||||
|
Effortlessly download South Park episodes from southpark.de in bulk
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
`git clone https://github.com/xypwn/south-park-de-downloader.git; cd south-park-de-downloader`
|
||||||
|
|
||||||
|
`sh init.sh` this will download youtube-dlc and apply a patch for english episodes.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
`sh southpark-downloader.sh -h` to show usage instructions
|
||||||
|
|
||||||
|
All downloads will end up in the `downloads` folder in the cloned repo (you can also change it in config.sh, if you want to).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
`./southpark-downloader.sh -s 1` download all episodes of Season 1
|
||||||
|
|
||||||
|
`./southpark-downloader.sh -s 5 -e 13` download Season 5 Episode 13
|
||||||
|
|
||||||
|
`./southpark-downloader.sh -D -s 1` download Season 2 in German
|
9
config.sh
Normal file
9
config.sh
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
############################################
|
||||||
|
# South Park Downloader Configuration File #
|
||||||
|
############################################
|
||||||
|
|
||||||
|
# youtube-dl (or youtube-dlc) executable path
|
||||||
|
YOUTUBE_DL="./yt-dlc/youtube-dlc"
|
||||||
|
|
||||||
|
# Where the downloaded videos will get stored
|
||||||
|
SAVEDIR="./downloads"
|
11
fix-southpark-de-en.diff
Normal file
11
fix-southpark-de-en.diff
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--- yt-dlc/youtube_dlc/extractor/southpark.py
|
||||||
|
+++ yt-dlc/youtube_dlc/extractor/southpark.py
|
||||||
|
@@ -44,7 +44,7 @@
|
||||||
|
|
||||||
|
class SouthParkDeIE(SouthParkIE):
|
||||||
|
IE_NAME = 'southpark.de'
|
||||||
|
- _VALID_URL = r'https?://(?:www\.)?(?P<url>southpark\.de/(?:videoclip|collections|folgen)/(?P<id>(?P<unique_id>.+?)/.+?)(?:\?|#|$))'
|
||||||
|
+ _VALID_URL = r'https?://(?:www\.)?(?P<url>southpark\.de/(?:(en/(videoclip|collections|episodes))|(videoclip|collections|folgen))/(?P<id>(?P<unique_id>.+?)/.+?)(?:\?|#|$))'
|
||||||
|
# _FEED_URL = 'http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed'
|
||||||
|
|
||||||
|
_TESTS = [{
|
15
init.sh
Executable file
15
init.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
if [ -e yt-dlc/ ]; then
|
||||||
|
echo ">>> youtube-dlc already downloaded, delete and redownload? [y/N]"
|
||||||
|
read RES
|
||||||
|
[ "$RES" = "y" ] || [ "$RES" = "Y" ] && rm -rf yt-dlc/
|
||||||
|
fi
|
||||||
|
if [ ! -e yt-dlc/ ]; then
|
||||||
|
echo ">>> Cloning youtube-dlc repo" &&
|
||||||
|
git clone --depth 1 --branch "2020.11.11-3" "https://github.com/blackjack4494/yt-dlc.git"
|
||||||
|
echo ">>> Applying patches"
|
||||||
|
# Allows for downloading English content from the German website
|
||||||
|
patch -p0 < fix-southpark-de-en.diff
|
||||||
|
fi
|
||||||
|
echo ">>> Building youtube-dlc"
|
||||||
|
make -C yt-dlc/ youtube-dlc
|
186
southpark-downloader.sh
Executable file
186
southpark-downloader.sh
Executable file
@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
source ./config.sh
|
||||||
|
|
||||||
|
YOUTUBE_DL="$PWD/$YOUTUBE_DL"
|
||||||
|
OUTDIR="$PWD/$SAVEDIR"
|
||||||
|
|
||||||
|
p_info() {
|
||||||
|
echo -e "\e[32m>>> $@\e[m"
|
||||||
|
}
|
||||||
|
|
||||||
|
p_error() {
|
||||||
|
echo -e "\e[1;31m>>> $@\e[m"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $(basename $0) [-E|-D] -a - Download all episodes"
|
||||||
|
echo " $(basename $0) [-E|-D] -s <season> - Download all episodes in the specified season"
|
||||||
|
echo " $(basename $0) [-E|-D] -s <season> -e <episode> - Download the specified episode"
|
||||||
|
echo "Options:"
|
||||||
|
echo " -E - Download episodes in English (default)"
|
||||||
|
echo " -D - Download episodes in German"
|
||||||
|
}
|
||||||
|
|
||||||
|
unset OPT_SEASON OPT_EPISODE OPT_ALL OPT_EN OPT_LANG
|
||||||
|
OPT_LANG="EN"
|
||||||
|
|
||||||
|
while getopts "haEDs:e:" arg; do
|
||||||
|
case "$arg" in
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
s)
|
||||||
|
OPT_SEASON="$OPTARG"
|
||||||
|
;;
|
||||||
|
e)
|
||||||
|
OPT_EPISODE="$OPTARG"
|
||||||
|
;;
|
||||||
|
a)
|
||||||
|
OPT_ALL=true
|
||||||
|
;;
|
||||||
|
E)
|
||||||
|
OPT_LANG="EN"
|
||||||
|
;;
|
||||||
|
D)
|
||||||
|
OPT_LANG="DE"
|
||||||
|
;;
|
||||||
|
?)
|
||||||
|
echo "Invalid option: -$OPTARG"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Parts of the URL differ depending on the language of the website
|
||||||
|
if [ "$OPT_LANG" = "DE" ]; then
|
||||||
|
SEASON_1_URL="https://www.southpark.de/seasons/south-park/yjy8n9/staffel-1"
|
||||||
|
REGEX_SEASON_URL="\"/seasons/south-park/[0-9a-z]\+/staffel-[0-9]\+\""
|
||||||
|
REGEX_EPISODE_URL="\"/folgen/[0-9a-z]\+/south-park-[0-9a-z-]\+-staffel-[0-9]\+-ep-[0-9]\+\""
|
||||||
|
elif [ "$OPT_LANG" = "EN" ]; then
|
||||||
|
SEASON_1_URL="https://www.southpark.de/en/seasons/south-park/yjy8n9/season-1"
|
||||||
|
REGEX_SEASON_URL="\"/en/seasons/south-park/[0-9a-z]\+/season-[0-9]\+\""
|
||||||
|
REGEX_EPISODE_URL="\"/en/episodes/[0-9a-z]\+/south-park-[0-9a-z-]\+-season-[0-9]\+-ep-[0-9]\+\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Indexes all season page URLs
|
||||||
|
index_seasons() {
|
||||||
|
# Get all season URLs by matching the regex
|
||||||
|
SEASON_URLS=$(curl -s "$SEASON_1_URL" | grep -o "$REGEX_SEASON_URL" | tr -d "\"" | sed -E "s/^/https:\/\/www.southpark.de/g")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Indexes all episode URLs of the currently indexed season (can only index 1 season at once, for now)
|
||||||
|
index_episodes() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
get_season_url "$SEASON_NUMBER"
|
||||||
|
local SEASON_URL="$RES"
|
||||||
|
EPISODE_URLS=$(curl -s "$SEASON_URL" | grep -o "$REGEX_EPISODE_URL" | tr -d "\"" | sed -E "s/^/https:\/\/www.southpark.de/g")
|
||||||
|
INDEXED_SEASON="$SEASON_NUMBER"
|
||||||
|
}
|
||||||
|
|
||||||
|
################
|
||||||
|
# All functions named get_<something> store their result in the RES variable.
|
||||||
|
# We're not using command substitution, because then these functions couldn't set variables.
|
||||||
|
################
|
||||||
|
get_season_url() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
[ -z "$SEASON_URLS" ] && index_seasons
|
||||||
|
RES=$(echo "$SEASON_URLS" | grep "\-${SEASON_NUMBER}$")
|
||||||
|
}
|
||||||
|
|
||||||
|
get_episode_url() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
local EPISODE_NUMBER="$2"
|
||||||
|
[ ! "$INDEXED_SEASON" = "$SEASON_NUMBER" ] && index_episodes "$SEASON_NUMBER"
|
||||||
|
RES=$(echo "$EPISODE_URLS" | grep "ep-${EPISODE_NUMBER}$")
|
||||||
|
}
|
||||||
|
|
||||||
|
get_num_seasons() {
|
||||||
|
[ -z "$SEASON_URLS" ] && index_seasons
|
||||||
|
RES=$(echo "$SEASON_URLS" | wc -l)
|
||||||
|
}
|
||||||
|
|
||||||
|
get_num_episodes() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
[ ! "$INDEXED_SEASON" = "$SEASON_NUMBER" ] && index_episodes "$SEASON_NUMBER"
|
||||||
|
RES=$(echo "$EPISODE_URLS" | wc -l)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_cleanup() {
|
||||||
|
p_info "Cleaning up temporary files"
|
||||||
|
rm -rf "$TMPDIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Takes season and episode number as arguments
|
||||||
|
download_episode() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
local EPISODE_NUMBER="$2"
|
||||||
|
get_episode_url "$SEASON_NUMBER" "$EPISODE_NUMBER"
|
||||||
|
local URL="$RES"
|
||||||
|
local OUTFILE="${OUTDIR}/South_Park_S${SEASON_NUMBER}_E${EPISODE_NUMBER}_${OPT_LANG}.mp4"
|
||||||
|
[ -e "$OUTFILE" ] && echo "Already downloaded Season ${SEASON_NUMBER} Episode ${EPISODE_NUMBER}" && return
|
||||||
|
p_info "Downloading Season $SEASON_NUMBER Episode $EPISODE_NUMBER ($URL)"
|
||||||
|
TMPDIR=$(mktemp -d "/tmp/southparkdownloader.XXXXXXXXXX")
|
||||||
|
pushd "$TMPDIR" > /dev/null
|
||||||
|
if ! "$YOUTUBE_DL" "$URL" 2>/dev/null | grep --line-buffered "^\[download\]" | grep -v --line-buffered "^\[download\] Destination:"; then
|
||||||
|
p_info "possible youtube-dl \e[1;31mERROR\e[m"
|
||||||
|
tmp_cleanup
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[download] Merging video files"
|
||||||
|
# Remove all single quotes from video files, as they cause problems
|
||||||
|
for i in ./*.mp4; do mv -n "$i" "$(echo $i | tr -d \')"; done
|
||||||
|
# Find all video files and write them into the list
|
||||||
|
printf "file '%s'\n" ./*.mp4 > list.txt
|
||||||
|
# Merge video files
|
||||||
|
ffmpeg -safe 0 -f concat -i "list.txt" -c copy "$OUTFILE" 2>/dev/null
|
||||||
|
popd > /dev/null
|
||||||
|
tmp_cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
# Takes season number as an argument
|
||||||
|
download_season() {
|
||||||
|
local SEASON_NUMBER="$1"
|
||||||
|
get_num_episodes "$SEASON_NUMBER"
|
||||||
|
local NUM_EPISODES="$RES"
|
||||||
|
for i in $(seq "$NUM_EPISODES"); do
|
||||||
|
download_episode "$SEASON_NUMBER" "$i"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
download_all() {
|
||||||
|
get_num_seasons
|
||||||
|
local NUM_SEASONS="$RES"
|
||||||
|
for i in $(seq "$NUM_SEASONS"); do
|
||||||
|
download_season "$i"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
[ ! -e "$OUTDIR" ] && mkdir "$OUTDIR"
|
||||||
|
|
||||||
|
if [ -n "$OPT_SEASON" ]; then
|
||||||
|
get_season_url "$OPT_SEASON"
|
||||||
|
[ -z "$RES" ] &&
|
||||||
|
p_error "Unable to open Season $OPT_SEASON" &&
|
||||||
|
exit 1
|
||||||
|
if [ -n "$OPT_EPISODE" ]; then
|
||||||
|
get_episode_url "$OPT_SEASON" "$OPT_EPISODE"
|
||||||
|
[ -z "$RES" ] &&
|
||||||
|
p_error "Unable to open Season $OPT_SEASON Episode $OPT_EPISODE" &&
|
||||||
|
exit 1
|
||||||
|
p_info "Going to download Season $OPT_SEASON Episode $OPT_EPISODE"
|
||||||
|
download_episode "$OPT_SEASON" "$OPT_EPISODE"
|
||||||
|
else
|
||||||
|
p_info "Going to download Season $OPT_SEASON"
|
||||||
|
download_season "$OPT_SEASON"
|
||||||
|
fi
|
||||||
|
elif [ -n "$OPT_ALL" ]; then
|
||||||
|
p_info "Going to download ALL episodes"
|
||||||
|
download_all
|
||||||
|
else
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user