commit
5b61931167
7 changed files with 266 additions and 0 deletions
@ -0,0 +1,2 @@ |
||||
downloads/* |
||||
yt-dlc/ |
@ -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> |
@ -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 |
@ -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" |
@ -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 = [{
|
@ -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 |
@ -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