#!/usr/bin/env bash

## Definitions
GRPOPPRO_DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/grpoppro"
GRPOPPRO_DATA_FILE="$GRPOPPRO_DATA_DIR/lastPlayedSeries"
GRPOPPRO_PLAYLIST_FILE="$GRPOPPRO_DATA_DIR/lastPlaylistPlayed"
GRPOPPRO_COOKIE_FILE="$GRPOPPRO_DATA_DIR/cookies.txt"
GRPOPPRO_HISTORY_FILE="$GRPOPPRO_DATA_DIR/history"
INTERACTIVE="on"
menu="fuzzel -d -p "
#menu="fzf -i --prompt="
apiurl="https://coverapi.store"
player="mpv"
MPV_OPTS='--vo=gpu \
  --gpu-api=opengl \
  --opengl-es=yes \
  --msg-level=all=no \
  --really-quiet \
  --no-load-scripts \
  --profile=sw-fast \
  --no-ytdl \
  --http-header-fields="User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" \
  --fs'
### Curl constants
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0"
ACCEPT="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
ACCEPT_LANGUAGE="Accept-Language: en-US,en;q=0.5"
CONNECTION="Connection: keep-alive"
UP_IN_REQ="Upgrade-Insecure-Requests: 1"
### End of curl constants
## End of definitions

# Display a message
function message {
  if [[ "$INTERACTIVE" == "on" ]]; then
    notify-send -t 2000 "$1"
  else
    echo -e "\n\t$1"
  fi
}

# Standard curl request
function curlRequest {
  response="$(curl -s -L -c "$GRPOPPRO_COOKIE_FILE" -b "$GRPOPPRO_COOKIE_FILE" \
    -A "$USER_AGENT" \
    -H "$ACCEPT" \
    -H "$ACCEPT_LANGUAGE" \
    -H "$CONNECTION" \
    -H "$UP_IN_REQ" \
    "$@"
  )"
  exit_code="$?"
  if [[ "$exit_code" -ne 0 ]]; then
    message "Error: Failed to execute curl request."
    exit 1
  fi
  echo "$response"
}

# Print usage information
function usage {
  echo -e "\n\tUsage:\n\n\t$(basename "$0") \"name of film or show\" [season] [episode(ex 01 02 .. 10 11)]"
  echo -e "\tOr $(basename "$0") [--menu|--resume|--select|--finish]"
  echo -e "\tOr $(basename "$0") --open \"name of film or show\""
  exit 0
}

# Ensure fzf is installed for Termux
function getFzfForTermux {
  if ! command -v fzf >/dev/null 2>&1; then
    apt install -y fzf
  fi
}

# Retrieve IMDb ID
function getIMDBID {
  response="$(curl -s -L -c "$GRPOPPRO_COOKIE_FILE" -b "$GRPOPPRO_COOKIE_FILE" \
    -A "$USER_AGENT" \
    -H "$ACCEPT" \
    "https://www.imdb.com/find/?q=$title"
  )"
  imdbid="$(echo "$response" | grep -io ' href=['"'"'"][^"'"'"']*['"'"'"]' | grep 'href="/title/'| head -n1  | sed -e 's/href="\/title\///' -e 's/\/?.*//' -e 's/^ //')"
  # imdbid="$(curl -s "http://imdb.konsthol.eu/find?q=$title" | grep -io ' href=['"'"'"][^"'"'"']*['"'"'"]' | grep title | head -n1 | sed -e 's/^ //' -e 's/href="\/title\///' -e 's/"//')"
  if ! [[ "$imdbid" == *"tt"* ]]; then
    message "Film or show not found in imdb"
    exit 0
  fi
}

# Prepare basic steps for a request
function basics {
  title="$1"
  title="${title// /%20}"
  getIMDBID "$title"
  simpleurl="$apiurl/embed/$imdbid/"
}

# Retrieve internal ID
function getInternalID {
  response="$(curlRequest "$simpleurl")"
  if echo "$response" | grep -q "id='el-content'></div>"; then
    message "No file found"
    exit 0
  fi
  internalid="$(echo "$response" | grep news_id | awk '{print $5}' | awk -F\' '{print $2}')"
}

# Retrieve movie stream URL
function getMovieStreamUrl {
  PHPSESSID="$(grep 'PHPSESSID' "$GRPOPPRO_COOKIE_FILE" | awk '{print $NF}')"
  response="$(curl -s -L -c "$GRPOPPRO_COOKIE_FILE" -b "$GRPOPPRO_COOKIE_FILE" "$apiurl/engine/ajax/controller.php" --compressed -X POST \
    -A "$USER_AGENT" \
    -H 'Accept: application/json, text/javascript, */*; q=0.01' \
    -H "$ACCEPT_LANGUAGE" \
    -H 'Accept-Encoding: gzip, deflate, br, zstd' \
    -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
    -H 'X-Requested-With: XMLHttpRequest' \
    -H "Origin: $apiurl" \
    -H 'DNT: 1' \
    -H 'Sec-GPC: 1' \
    -H "$CONNECTION" \
    -H "Referer: $simpleurl" \
    -H "Cookie: PHPSESSID=$PHPSESSID" \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Site: same-origin' \
    -H 'TE: trailers' \
    --data-raw "mod=players&news_id=$internalid"
  )"
  streamurl="$(echo "$response" | sed 's/\\//g' | grep -oP 'file:"\K[^"]+')"
}

# Stream the video
function play {
  if [[ "$player" == "mpv" ]]; then
    MPVPID="$(pidof mpv | cut -d' ' -f1)"
    [[ -n "$MPVPID" ]] && kill -s SIGTERM "$MPVPID"
    player="mpv --save-position-on-quit ${MPV_OPTS}"
  fi
  [[ "$OSTYPE" != "linux-gnu" ]] && INTERACTIVE="off" && streamurl="${streamurl//https/http}"
  # No setsid -f here because menu function goes from play to resume
  eval "$player" "$streamurl"
}

# Dump data to files
function dumpData {
  echo "$title" > "$GRPOPPRO_DATA_FILE"
  echo "$seasonEpisode" >> "$GRPOPPRO_DATA_FILE"
  echo "$streamurl" >> "$GRPOPPRO_DATA_FILE"
  message "Last Played -> $seasonEpisode"
  echo "$title|$seasonEpisode|$streamurl" >> "$GRPOPPRO_HISTORY_FILE"
  tac "$GRPOPPRO_HISTORY_FILE" | awk -F'|' '!seen[$1]++' | tac > "${GRPOPPRO_DATA_DIR}/temp.txt" && mv "${GRPOPPRO_DATA_DIR}/temp.txt" "$GRPOPPRO_HISTORY_FILE"
}

# Source data from files
function sourceData {
  if [[ -f "$GRPOPPRO_DATA_FILE" ]]; then
    lastSeriesPlayed="$(sed -n 1p "$GRPOPPRO_DATA_FILE")"
    lastSeasonEpisodePlayed="$(sed -n 2p "$GRPOPPRO_DATA_FILE")"
    lastEpisodePlayedURL="$(sed -n 3p "$GRPOPPRO_DATA_FILE")"
  fi
}

# Perform menu search
function menuSearch {
  # Two requests to the api
  [[ "$INTERACTIVE" == "on" ]] && title=$(echo "" | wofi --dmenu --insensitive --prompt="Search Series" --width=300 --height=50)
  [[ "$INTERACTIVE" == "off" ]] && [[ -z "$title" ]] && read -r -p "Search Series: " title
  if [[ -z "$title" ]]; then
    message "Nothing given"
    exit 0
  fi
  title="${title// /%20}"
  getIMDBID "$title"
  simpleurl="$apiurl/embed/$imdbid/"
  getInternalID "$simpleurl"
  response="$(curlRequest "$apiurl/uploads/playlists/$internalid.txt")"
  echo "$response" > "$GRPOPPRO_PLAYLIST_FILE"
  title="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | head -n1 | awk -F/ '{print $(NF-1)}')"
  title="${title//_/ }"
  title="${title//-/ }"
  seasonEpisode="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | awk -F\" '{print $8}' | awk -F/ '{print $NF}' | awk -F. '{print $1}' | eval "$menu"\""$title" \")"
  if [[ -z "$seasonEpisode" ]]; then
    message "Nothing Selected"
    exit 0
  fi
  streamurl="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | grep "${seasonEpisode}" | head -n1 | awk -F\" '{print $8}')"
  dumpData "$title" "$seasonEpisode"
  play
  resume
}

# Resume last watched series
function resume {
  # Zero requests to the api
  if [[ ! -f "$GRPOPPRO_DATA_FILE" ]]; then
    message "Nothing to resume"
    exit 0
  fi
  sourceData
  title=$lastSeriesPlayed
  while true
  do
    sourceData
    seasonEpisode="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | awk -F\" '{print $8}' | awk -F/ '{print $NF}' | awk -F. '{print $1}' | sed -n -e "0,/$lastSeasonEpisodePlayed/!p" | eval "$menu"\""$title" \")"
    if [[ -z "$seasonEpisode" ]]; then
      message "Nothing Selected"
      exit 0
    fi
    streamurl="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | grep "${seasonEpisode}" | head -n1 | awk -F\" '{print $8}')"
    dumpData "$title" "$seasonEpisode"
    play
  done
}

# Select which series to resume
function resumeSeries {
  if [[ ! -f "$GRPOPPRO_HISTORY_FILE" ]]; then
    message "No history found"
    exit 0
  fi

  resume_series=$(awk -F'|' '{print $1}' "$GRPOPPRO_HISTORY_FILE" | sort | uniq | eval "$menu"\"Select Series \")
  if [[ -z "$resume_series" ]]; then
    message "No series selected"
    exit 0
  fi

  # resume_episode=$(grep "^$resume_series|" "$GRPOPPRO_HISTORY_FILE" | awk -F'|' '{print $2}' | eval "$menu"\"Select Episode \")
  resume_episode="$(grep "^$resume_series|" "$GRPOPPRO_HISTORY_FILE" | awk -F'|' '{print $2}')"
  if [[ -n "$resume_episode" ]]; then
    message "Continuing $resume_series from $resume_episode"
  fi

  resume_streamurl=$(grep "^$resume_series|$resume_episode|" "$GRPOPPRO_HISTORY_FILE" | awk -F'|' '{print $3}')
  title="$resume_series"
  title="${title// /%20}"
  getIMDBID "$title"
  simpleurl="$apiurl/embed/$imdbid/"
  getInternalID "$simpleurl"
  response="$(curlRequest "$apiurl/uploads/playlists/$internalid.txt")"
  echo "$response" > "$GRPOPPRO_PLAYLIST_FILE"
  title="$(grep "mp4" "$GRPOPPRO_PLAYLIST_FILE" | head -n1 | awk -F/ '{print $(NF-1)}')"
  title="${title//_/ }"
  seasonEpisode="$resume_episode"
  streamurl="$resume_streamurl"
  dumpData "$title" "$seasonEpisode"
  play
  resume
}

# Resume last watched unfinished episode
function resumeUnfinishedEpisode {
  # Zero requests to the api
  if [[ ! -f "$GRPOPPRO_DATA_FILE" ]]; then
    message "Nothing to resume"
    exit 0
  fi
  sourceData
  message "Continuing $lastSeriesPlayed from $lastSeasonEpisodePlayed"
  streamurl="$lastEpisodePlayedURL"
  if [[ "$player" == "mpv" ]]; then
    MPVPID="$(pidof mpv | cut -d' ' -f1)"
    [[ -n "$MPVPID" ]] && kill -s SIGTERM "$MPVPID"
    player="mpv --resume-playback ${MPV_OPTS}"
  fi
  [[ "$OSTYPE" != "linux-gnu" ]] && INTERACTIVE="off" && streamurl="${streamurl//https/http}"
  # No setsid -f here because menu function goes from play to resume
  eval "$player" "$streamurl"
  resume
}

# Open in browser to watch
function openInBrowser {
  # One request to the api
  basics "$2"
  getInternalID "$simpleurl"
  xdg-open "$simpleurl"
  exit 0
}

### Program starts here ###

# Make sure the data directory exists
mkdir -p "$GRPOPPRO_DATA_DIR"

# Exit if a VPN connection is active
if [[ "$OSTYPE" == "linux-gnu" ]]; then
  if nmcli connection show --active | grep -i -q wireguard; then
    echo "Exiting because a vpn connection is active"
    exit 0
  fi
fi

# Prepare the necessary steps for Termux environment
[[ "$OSTYPE" != "linux-gnu" ]] && INTERACTIVE="off" && menu="fzf -i --prompt=seasonXepisode" && player="am start -n is.xyz.mpv/.MPVActivity -a android.intent.action.VIEW -d" && getFzfForTermux

[[ "$#" -lt 1 ]] && usage
[[ "$#" -gt 3 ]] && usage

[[ "$1" == "--open" ]] && openInBrowser "$@"
[[ "$1" == "--menu" ]] && menuSearch
[[ "$1" == "--resume" ]] && resume
[[ "$1" == "--finish" ]] && resumeUnfinishedEpisode
[[ "$1" == "--select" ]] && resumeSeries

# One arguement and it contains the imdb id
# Two requests to the api
if [[ "$1" == *"tt"* ]] && [[ "$#" -eq 1 ]] && [[ "$1" != "--menu" ]] && [[ "$1" != "--resume" ]] && [[ "$1" != "--select" ]]; then
  simpleurl="$1"
  getInternalID "$simpleurl"
  getMovieStreamUrl "$internalid"
  play
  exit 0
fi

# Series URL
if [[ "$#" -eq 3 ]]; then
  # Two requests to the api
  basics "$1"
  getInternalID "$simpleurl"
  season="$2"
  episode="$3"
  response="$(curlRequest "$apiurl/uploads/playlists/$internalid.txt")"
  streamurl="$(echo "$response" | grep "mp4" | grep "${season}x${episode}" | head -n1 | awk -F\" '{print $8}')"
  play
  exit 0
fi

# Movies URL
if [[ "$#" -eq 1 ]] && [[ "$1" != "--menu" ]] && [[ "$1" != "--resume" ]] && [[ "$1" != "--select" ]]; then
  # Two requests to the api
  basics "$1" # Gets the title, performs one request to imdb and gets the complete url
  getInternalID "$simpleurl" # Gets the complete url and performs one request to get the internal id or inform us it does not exist
  getMovieStreamUrl "$internalid" # Gets the internal id and performs one request to get the stream url
  play # It uses mpv to stream the file
  exit 0
fi

exit 0
