Skip to content

Instantly share code, notes, and snippets.

@Minemobs
Last active April 7, 2024 11:46
Show Gist options
  • Save Minemobs/f552cc0296438e8362cc70f9ab570cfc to your computer and use it in GitHub Desktop.
Save Minemobs/f552cc0296438e8362cc70f9ab570cfc to your computer and use it in GitHub Desktop.
A NekoSama (neko-sama.fr) downloader in Bash, Updated version: https://github.com/minemobs/nekosama.sh

Nekosama.sh

A simple downloader written in bash

Example of usage:

./nekosama.sh "$(./nekosama-tui.sh)"

Requirements:

  • gum
  • curl-impersonator
  • jq
#!/bin/bash
if ! [ -x "$(command -v gum)" ]; then
echo 'Error: gum is not installed.' >&2
exit 1
fi
if ! [ -x "$(command -v jq)" ]; then
echo 'Error: jq is not installed.' >&2
exit 1
fi
function generateSequence {
local sequence=""
local nbrOfEpisodes=$1
((++nbrOfEpisodes))
while((nbrOfEpisodes--)); do
if [[ $nbrOfEpisodes -eq 0 ]]; then
break
fi
if [[ $nbrOfEpisodes -lt 10 ]]; then
sequence="0$nbrOfEpisodes $sequence"
continue
fi
sequence="$nbrOfEpisodes $sequence"
done
echo "$sequence"
}
JSON="$(curl -s https://neko-sama.fr/animes-search-vostfr.json)"
SERIE_NAME="$(echo "$JSON" | jq -r '.[] | .title' | gum filter)"
if [ $? -ne 0 ]; then
exit 0
fi
# printf "User choose to watch '%s'\n" "$SERIE_NAME"
SERIE_JSON="$(echo "$JSON" | jq 'map(select(.title == "'"$SERIE_NAME"'")) | .[]')"
SERIE_URL="$(echo "$SERIE_JSON" | jq -r '.url' | cut -d "/" -f 4 | cut -d '_' -f 1)"
SERIE_EPISODES="$(echo "$SERIE_JSON" | jq -r '.nb_eps')"
if [[ $SERIE_EPISODES != "Film" ]]; then
EPISODE="$(gum choose --header "Episode of $SERIE_NAME" $(generateSequence "$SERIE_EPISODES"))"
if [ $? -ne 0 ]; then
exit 0
fi
else
EPISODE="01"
fi
printf "https://neko-sama.fr/anime/episode/%s-%s_vostfr\n" "$SERIE_URL" "$EPISODE"
#!/bin/bash
if ! [ -x "$(command -v curl_ff109)" ]; then
echo "Error: curl-impersonate is not installed." >&2
exit 10
fi
if [[ $# -ne 1 ]]; then
echo "Illegal number of parameters" >&2
exit 2
fi
function fail {
printf '%s\n' "$1" >&2 ## Send message to stderr.
exit "${2-1}" ## Return a code specified by $2, or 1 by default.
}
mkdir "/tmp/nekosama" || true
ANIME_NAME=$(echo "$1" | rev | cut -d "/" -f 1 | rev)
echo "Getting the Video provider's URL for $ANIME_NAME"
VIDEO_PROVIDER_URL=$(curl_ff109 -s $1 | grep -E "\s+video\[0\] = 'https://.+'" | cut -d "'" -f 2)
URL=""
fv_parse () {
#Actual code
echo "Getting the M3U8 file"
local FV_GET_JS_SCRIPT=$(curl_ff109 -s "$VIDEO_PROVIDER_URL" | grep "https://fusevideo.io/f/u/u/u/u" | cut -d '"' -f 2)
local FV_GET_M3U8_URL=$(curl_ff109 -s "$FV_GET_JS_SCRIPT" | grep -o -E "\(n=atob\(\".+=\")" | cut -d "\"" -f 2 | base64 --decode | grep -o -E "https:.+\"" | cut -d "\"" -f 1 | sed 's/\\\//\//g')
echo "Parsing the M3U8"
URL=$(curl_ff109 -s "$FV_GET_M3U8_URL" | grep "https://" | head -n 1)
}
case "$VIDEO_PROVIDER_URL" in
"https://fusevideo.io"*)
# echo "Fuse video"
fv_parse
echo "Done:" "$URL";;
*)
echo "$VIDEO_PROVIDER_URL" "isn't supported yet"
exit 1;;
esac
old_pwd=$(pwd)
mkdir "/tmp/nekosama/$ANIME_NAME" || fail "Couldn't create directory in /tmp/nekosama" 3
cd "/tmp/nekosama/$ANIME_NAME" || fail "Couldn't CD in /tmp/$ANIME_NAME" 4
M3U_URLS=$(curl_ff109 "$URL" | grep -E "^https://")
curl --remote-name-all --max-time 10 --retry 5 --retry-delay 0 --retry-max-time 40 $M3U_URLS || fail "Couldn't download all .ts files" 5
for i in $(\ls *.ts | sort -V); do echo "file '$i'"; done >> mylist.txt && ffmpeg -f concat -i mylist.txt -c copy -bsf:a aac_adtstoasc video.mp4 && rm *.ts && rm mylist.txt
cd "$old_pwd" || exit
mpv "/tmp/nekosama/$ANIME_NAME/video.mp4"
rm -rf "/tmp/nekosama/$ANIME_NAME"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment