#!/bin/sh version_number="1.0.1" agent="Mozilla/5.0 (Windows NT 6.1; Win64; rv:109.0) Gecko/20100101 Firefox/109.0" chapter_format="\n[CHAPTER]\nTIMEBASE=1/1000\nSTART=%s\nEND=%s\nTITLE=%s\n" option_format="skip-%s_start=%s,skip-%s_end=%s" die() { printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2 exit 1 } help_info() { printf " Usage: %s [OPTIONS] Options: -q, --query Anime Title or MyAnimeList ID -e, --episode Specify the episode number -V, --version Show the version of the script -h, --help Show this help message and exit -U, --update Update the script Some example usages: %s -q \"Solo Leveling\" # Returns MyAnimeList ID %s -q \"Solo Leveling\" -e 3 # Returns MPV skip flag %s -q 52299 -e 5 # Returns MPV skip flag \n" "${0##*/}" "${0##*/}" "${0##*/}" "${0##*/}" exit 0 } update_script() { update="$(curl -s -A "$agent" "https://raw.githubusercontent.com/synacktraa/ani-skip/master/ani-skip")" || die "Connection error" update="$(printf '%s\n' "$update" | diff -u "$0" -)" if [ -z "$update" ]; then printf "Script is up to date :)\n" else if printf '%s\n' "$update" | patch "$0" -; then printf "Script has been updated\n" else die "Can't update for some reason!" fi fi exit 0 } fetch_mal_id() { #shellcheck disable=SC2016 : ' `fetch_mal_id` fetches MyAnimeList Identifier of particular anime :param $1: title of the anime ' name=$(printf "%s" "$*" | sed 's| (\([0-9]*\) episodes)||') keyword=$(printf "%s" "$name" | tr -c '[:alnum:]' ' ' | sed -E 's| |%20|g') mal_metadata=$(curl -sL -A "$agent" "https://myanimelist.net/search/prefix.json?type=anime&keyword=$keyword" | tr -d "\\" 2>/dev/null) name=$(printf "%s\n" "$name" | tr -cs '[:print:]' ' ' | tr -c '[:alnum:]' ' ') fzf_nth=$(printf "%s," $(seq 1 "$(printf "%s" "$name" | wc -w)") | sed 's|,$||') results=$(printf "%s" "$mal_metadata" | sed 's|},{|\n|g' | sed 's|.*,"name":"||g ; s|","url":".*||g') relevant_name=$(printf "%s" "$results" | fzf -i --filter="$name" --nth="$fzf_nth" | head -n1) [ -z "$relevant_name" ] && relevant_name=$(printf "%s" "$results" | fzf -i --filter="$name" | head -n1) [ -z "$relevant_name" ] && relevant_name=$(printf "%s" "$results" | head -n1) printf "%s" "$mal_metadata" | sed 's|},{|\n|g' | grep 'name":"'"$relevant_name"'","url":' | sed -nE 's|.*"id":([0-9]{1,9}),.*|\1|p' } ftoi() { printf "%.3f" "$1" | tr -d '.' } build_options() { #shellcheck disable=SC2016 : ' `build_options` builds options for `--script-opts` flag :param $1: AniSkip metadata ' st_time_re='"start_time":([0-9.]+)' ed_time_re='"end_time":([0-9.]+)' op_end="" ed_start="" options="" for skip_type in "op" "ed" do sk_type_re='"skip_type":"('$skip_type')"' unformatted=$(printf "%s" "$1" | grep -Eo "$st_time_re,$ed_time_re},$sk_type_re") if [ -n "$unformatted" ]; then st_time=$(printf "%s" "$unformatted" | grep -Eo "$st_time_re" | sed -E 's@'"$st_time_re"'@\1@') ed_time=$(printf "%s" "$unformatted" | grep -Eo "$ed_time_re" | sed -E 's@'"$ed_time_re"'@\1@') [ "$skip_type" = "op" ] && op_end=$ed_time && ch_name="Opening" [ "$skip_type" = "ed" ] && ed_start=$st_time && ch_name="Ending" [ -n "$options" ] && options="$options," printf "$chapter_format" "$(ftoi $st_time)" "$(ftoi $ed_time)" "$ch_name" >> $chapters_file options=$(printf "%s%s" "$options" $(printf "$option_format" "$skip_type" "$st_time" "$skip_type" "$ed_time")) fi done if [ -n "$op_end" ]; then [ -n "$ed_start" ] && ep_ed=$ed_start || ep_ed=$op_end printf "$chapter_format" "$(ftoi $op_end)" "$(ftoi $ep_ed)" "Episode" >> $chapters_file fi printf "%s" "$options" } build_flags() { #shellcheck disable=SC2016 : ' `build_flags` builds `--script-opts` and `--chapters-file` flags for MPV player :param $1: MyAnimeList Identifier :param $2: Episode number ' aniskip_api="https://api.aniskip.com/v1/skip-times/$1/$2?types=op&types=ed" metadata=$(curl -s --connect-timeout 5 -A "$agent" "$aniskip_api") found_status=$(printf "%s" "$metadata" | sed -n 's/.*"found":\([^,]*\).*/\1/p') [ "$found_status" != "true" ] && die "Skip times not found!" printf "%s" ";FFMETADATA1" > "$chapters_file" options=$(build_options "$metadata") [ -n "$options" ] && printf -- "--chapters-file=%s --script-opts=%s" "$chapters_file" "$options" } [ $# -eq 0 ] && help_info while [ $# -gt 0 ]; do [ "$OSTYPE" = msys* ] && flag=${1//[![:print:]]/} || flag="$1" case "$flag" in -U | --update) update_script ;; -V | --version) printf "%s\n" "$version_number" && exit 0 ;; -h | --help) help_info ;; -q | --query) [ $# -lt 2 ] && die "missing anime title/MyAnimeList ID!" case $2 in ''|*[!0-9]*) mal_id=$(fetch_mal_id $2) ;; *) mal_id=$2 ;; esac shift ;; -e | --episode) [ $# -lt 2 ] && die "missing episode number!" case $2 in ''|*[!0-9]*) die "value must be a number!" ;; *) episode=$2 ;; esac esac shift done [ -z "$mal_id" ] && die "-q/--query is required!" if [ -z "$episode" ]; then printf "%s" "$mal_id" else chapters_file=$(mktemp) build_flags $mal_id $episode fi