#!/bin/bash
#
# Display currently playing song on Radio FIP.
#
# With -t, also show a countdown until the next refresh, in the form
# of a shrinking black bar. Exit with the Q key or Ctrl-C.
#
# Author: Bert Bos <bert@w3.org>
# Created: 16 May 2016
#
# Modified: 5 February 2020
#
# Modified: 9 July 2023: JSON data now comes from
#   https://www.radiofrance.fr/api/v2.1/stations/fip/live/webradios/fip
#   instead of https://www.fip.fr/latest/api/graphql?... and has a
#   different structure.
#
# Modified: 20 October 2023: JSON data now comes from
#   https://www.radiofrance.fr/fip/api/live/webradios/fip
#
# Modified: 26 April 2024 - JSON chnaged: firstLine & secondLine are
#   now objects instead of strings and the text is in their title
#   field.
#
# Modidied: New URL: https://www.radiofrance.fr/fip/api/live
#
# Modified: 12 January 2025: Exit when the Q key is pressed.
#
# Modified: 22 June 2025: Set COLUMNS to 80 if it is undefined. (Fix
# due to Martino Scaglione)
#
# Modified: 19 Narch 2026: JSON data now comes from
# https://www.radiofrance.fr/_app/remote/di23tz/getLive?payload=W3siYnJhbmROYW1lIjoxfSwiZmlwIl0
# The "payload" is '[{"brandName":1},"fip"]' in base64. The string
# "fip" indicates the stream. It can also be "fip-pop", "fip-metal",
# "fip-rock", etc. The URL returns a JSON object '{"type": "result",
# "result": "some-string"}' where "some-string" is a JSON array
# serialized to a string. The first item in the array is an object
# with, among other things, a field "now" that holds a number and a
# field "delayToRefresh" with another number. The numbers are indexes
# of other entries in the array. The field "now" thus points to an
# object, which contains among other things, the field "song", whose
# value is a number that is again an index into the array. It points
# to an object which has, among other things, the fields "title",
# "year", "interpreters" and "release", each of which is another index
# into the array. "title" and "year" point to strings. "interpreters"
# points to an array with numbers, each of which is another index into
# to first array, each pointing to a string. "release" is an index
# into the array which points to an object with, among other things,
# "title", which is another index into the array, pointing to a
# string. The "delayToRefresh" field in the zeroth's item of the array
# points to an entry in the array that is a number, representing a
# number of milliseconds.
#

blocks=(" " "▏" "▎" "▍" "▌" "▋" "▊" "▉" "█")

declare -i sleep i j seconds rest n
c=

set -u -o pipefail

# Command line options:
#
show_countdown=false
while getopts "t" flag; do
  case $flag in
    t) show_countdown=true;;
  esac
done

# Escape sequences to move the cursor, set a color, etc.
#
clear_eol=$(tput el)
cursor_up=$(tput cuu1)
titlecolor=$(tput bold)$(tput setaf 1)
labelcolor=$(tput setaf 2)
artistcolor=$(tput bold)$(tput setaf 4)
reset=$(tput op)$(tput sgr0)

# Repeatedly ask for the playlist and display the current song, until
# the Q key is pressed.
#
while [[ "$c" != "q" ]]; do

  # Get the JSON file with the playlist, extract info and display it.
  #
  data=$(curl -f -s -H "Referer: https://www.radiofrance.fr/fip" "https://www.radiofrance.fr/_app/remote/di23tz/getLive?payload=W3siYnJhbmROYW1lIjoxfSwiZmlwIl0")

  if [ $? != 0 ]; then
    title="(Download error)"
    artist=
    year=
    album=
    sleep=30			# Try again in 30s
  elif array=$(jshon -Q -e result -u <<<$data) &&
      now_index=$(jshon -Q -e 0 -e now -u <<<$array) &&
      song_index=$(jshon -Q -e $now_index -e song -u <<<$array) &&
      title_index=$(jshon -Q -e $song_index -e title -u <<<$array) &&
      year_index=$(jshon -Q -e $song_index -e year -u <<<$array) &&
      interpreters_index=$(jshon -Q -e $song_index -e interpreters -u <<<$array) &&
      release_index=$(jshon -Q -e $song_index -e release -u <<<$array) &&
      title=$(jshon -Q -e $title_index -u <<<$array) &&
      year=$(jshon -Q -e $year_index -u <<<$array) &&
      album_index=$(jshon -Q -e $release_index -e title -u <<<$array) &&
      album=$(jshon -Q -e $album_index -u <<<$array) &&
      interpreters_array=$(jshon -Q -e $interpreters_index -j <<<$array) &&
      interpreters_length=$(jshon -Q -l <<<$interpreters_array) &&
      delayToRefresh_index=$(jshon -Q -e 0 -e delayToRefresh -u <<<$array) &&
      delayToRefresh=$(jshon -Q -e $delayToRefresh_index -u <<<$array); then
    j=$(jshon -Q -e 0 -u <<<$interpreters_array)
    artist=$(jshon -Q -e $j -u <<<$array)
    for ((i = 1; i < interpreters_length; i++)); do
      j=$(jshon -Q -e $i -u <<<$interpreters_array)
      artist+=" & $(jshon -Q -e $j -u <<<$array)"
    done
    ((sleep = (delayToRefresh + 500) / 1000))
  else
    title="(Unrecognized data)"
    artist=
    year=
    album=
    sleep=30
  fi

  # In case we're running under a shell that doesn't set COLUMNS:
  read ROWS COLUMNS <<<$(stty size 2>/dev/null)
  : ${COLUMNS:=80}		# Guess 80 columns if stty fails.
  title=${title:0:$((COLUMNS - 10))}
  artist=${artist:0:$((COLUMNS - 10))}
  album=${album:0:$((COLUMNS - 10))}
  year=${year:0:$((COLUMNS - 10))}

  echo "  ${labelcolor}Title:$reset  $titlecolor$title$reset$clear_eol"
  echo " ${labelcolor}Artist:$reset  $artistcolor$artist$reset$clear_eol"
  echo "  ${labelcolor}Album:$reset  $album$clear_eol"
  echo "   ${labelcolor}Year:$reset  $year$clear_eol"

  # Countdown until the next refresh or until the Q key is pressed. If
  # option -t, also show a progress bar.
  #
  (( seconds = sleep + 2))
  while ((seconds > 0)) && [[ "$c" != "q" ]]; do
    if $show_countdown; then
      read ROWS COLUMNS <<<$(stty size 2>/dev/null) # Window may have changed
      : ${COLUMNS:=80}		# Guess 80 columns if stty doesn't work
      ((n = seconds / 8))
      ((rest = seconds % 8))
      if ((n >= COLUMNS)); then ((n = COLUMNS - 1)); ((rest = 8)); fi
      printf "%*d:%02d\r" $((COLUMNS - 3)) $((seconds / 60)) $((seconds % 60))
      while ((n > 0)); do echo -n "█"; ((n--)); done
      echo -e "${blocks[$rest]}\r\c"
    fi
    read -n 1 -t 1 -s c || true
    ((seconds--))
  done

  # Move cursor to start of display for the next round.
  #
  if [[ "$c" != "q" ]]; then
    echo -n "$cursor_up$cursor_up$cursor_up$cursor_up"
  fi

done
echo
