Jump to content

Bash Playlist Rotation


GregMo

Recommended Posts

GregMo

I'm sharing this attempt at rotating a playlist so that maybe someone else can save some of the HOURS it took me to piece all of this together. 

What this does is to read a playlist and identifies the last item of the list.  It then searches the list for a previous episode of the same show to see what different show has followed it prior in the list.  If it finds a previous episode match, it will then add the next episode of the next show to the end of the list.  If it does not find a previous episode, it will start with the beginning of the playlist.  As an example, you could create a list with Friends 1x1, Scrubs 1x1, and Fraiser 1x1, and this script will add Friends 1x2 to the end of the list, to allow you to watch several shows in a rotating schedule like you would do if it was a network schedule.

There's is some error checking in this but you should only use it if you're comfortable with everything that it does.  Also, this relies on `jq` to read JSON responses so you'll have to install that if you don't already have it. 

Before running this, you will need to set the first 4 variables.  This means you'll need to go into the Emby server and setup an API key, and create a playlist to start with and supply the itemid of the playlist.

Bear in mind, this is something I put together for my personal use which I'm only sharing for the help of others, and maybe for comments.  I will say that as written it works fairly well but I have ran into some issues with the way Emby now handles the period preceeding a folder name.  There is some limited error checking built in for that, however.

Cheers

#!/bin/bash

Host="http://10.0.0.107:8096"

UserId=501de38c93b6464c80776a945bdf9e6f

EmbyXToken="X-Emby-Token: fd9f7c0a60114a4c9f67b4c8a19447da"

PlaylistItemId=261198


########################################################


function set_item_data () {
  
  IFS=$'\n'
  
  for j in $item_data ; do
    v=$(echo $j | awk -F' ' '{ for (i=2; i<=NF; i++) print $i }')
    t=$(echo $j | awk -F' ' '{print $1}' | awk -F'\"' '{print $2}')
  
    if [ -z $t ] ; then t="blank"; fi

    case $t in

      Name)
        EpisodeName=$(echo $v | awk -F'\"' '{print $2}')
        ;;
  
      SeriesName)
        SeriesName=$(echo $v | awk -F'\"' '{print $2}')
        ;;
    
      ParentIndexNumber)  
        SeasonNumber=$(echo $v | awk -F',' '{print $1}')
        ;;
    
      IndexNumber)
        EpisodeNumber=$(echo $v | awk -F',' '{print $1}')
        ;;
    
      Id)
        EpisodeId=$(echo $v | awk -F'\"' '{print $2}')
        ;;
    
      SeriesId)
        SeriesId=$(echo $v | awk -F'\"' '{print $2}')
        ;;
  
    esac

  done
  unset IFS
}


################################################
#
# Get data elements of last item (last Show) in playlist
#

url=$Host"/Playlists/"$PlaylistItemId"/Items"
full_playlist_data=`curl -s -X GET -H "$EmbyXToken" -H "Content-Type: application/json" $url`

TotalRecordCount=`echo $full_playlist_data | jq '.TotalRecordCount'`
idx_num=$TotalRecordCount
((idx_num--))
  
item_data=`echo $full_playlist_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber]'`
set_item_data

echo
echo Last item: $SeriesName" "$SeasonNumber"x"$EpisodeNumber" - "$EpisodeName
echo

################################################
#
# Look for second to last match of the "Show/Series" in the playlist
#

idx_num=$TotalRecordCount
((idx_num--))

until [ $idx_num = 0 ] || [ ! -z $found ]; do
  ((idx_num--))

  ptr=`echo $full_playlist_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber].SeriesId'`
  ptr=`echo $ptr | sed -e 's/^"//' -e 's/"$//'`

  if [ $ptr = $SeriesId ] ; then found=true; fi 
done

################################################
#
# If a match was found then we want to select the show that
# follows it, elsewise just use the first show of the playlist
#
# As an aside, you should only ever once reach the start of the list
#

if [ ! -z $found ]; then
  ((idx_num++))
else
  echo
  echo "Reached start of list"
  echo
fi

################################################
#
# Get data elements of the reference show/episode 
#

item_data=`echo $full_playlist_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber]'`
set_item_data

echo "Reference show/episode: "$SeriesName" "$SeasonNumber"x"$EpisodeNumber" - "$EpisodeName
echo

check_dupe=$EpisodeNumber

################################################
#
# Get data elements of the reference show/episode 
#

url=$Host"/Shows/"$SeriesId"/Episodes"
full_series_data=`curl -s -X GET -H "$EmbyXToken" -H "Content-Type: application/json" $url`

unset found
idx_num=0
TotalRecordCount=`echo $full_series_data | jq '.TotalRecordCount'`

until [ $idx_num = $TotalRecordCount ] || [ ! -z $found ]; do

  ptr=`echo $full_series_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber].Id'`
  ptr=`echo $ptr | sed -e 's/^"//' -e 's/"$//'`

  if [ $ptr = $EpisodeId ] ; then found=true; fi 

  ((idx_num++))
done

if [ $idx_num = $TotalRecordCount ]; then
  echo
  echo "Reached end of show (Series) before finding match" ; echo
  exit
fi

################################################
#
# Get data elements of the episode to add and add it
#

item_data=`echo $full_series_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber]'`
set_item_data

echo Episode to add: $SeriesName" "$SeasonNumber"x"$EpisodeNumber" - "$EpisodeName
echo

if [ $check_dupe = $EpisodeNumber ]; then
  echo !!! Duplicate episodes found !!!
  echo
  echo Check for multiple copies, possible with folders
  echo starting with a period that are no longer hidden.
  echo
  exit
fi

url=$Host"/Playlists/"$PlaylistItemId"/Items"
curl -s -X POST -H "$EmbyXToken" -H "Content-Type: application/json" $url \
  --data-binary @- <<DATA
  {
    "Ids": $EpisodeId,
    "UserId": $UserId
  }
DATA


 

Edited by GregMo
Link to comment
Share on other sites

GregMo
20 hours ago, Luke said:

Very cool, thanks for sharing.

I'm glad you liked it.  After sleeping on the issue, I found a much better methodology so I rewrote a lot of it so I've updated the post.  I truly hope someone gets some use out of it besides me.

 

  • Thanks 1
Link to comment
Share on other sites

GregMo

Now, after you watch a few episodes you'll want to remove them from the beginning of the playlist because if the playlist gets too big it'll bog down some clients.  Using the context menu of Emby can be a bit tedious so let's make it a bit easier.  The following bash script will start at the first item of the playlist, discern all the consecutive items that have been played, and then remove them from the playlist.  As written the script runs in a test mode which outputs the episodes it sees as being played but doesn't delete them.  To get the script to run with no testing use the parameter "--commit".  

 

 

#!/bin/bash

Host="http://10.0.0.107:8096"

UserId=501de38c93b6464c80776a945bdf9e6f

EmbyXToken="X-Emby-Token: fd9f7c0a60114a4c9f67b4c8a19447da"

PlaylistItemNum=261198


testing=$1

if [ -z $testing ]; then testing=true ; fi
if [ $testing = --commit ]; then unset testing ; fi

########################################################


function set_item_data () {
  
  IFS=$'\n'
  
  for j in $item_data ; do
    v=$(echo $j | awk -F' ' '{ for (i=2; i<=NF; i++) print $i }')
    t=$(echo $j | awk -F' ' '{print $1}' | awk -F'\"' '{print $2}')
  
    if [ -z $t ] ; then t="blank"; fi

    case $t in

      Name)
        EpisodeName=$(echo $v | awk -F'\"' '{print $2}')
        ;;
  
      SeriesName)
        SeriesName=$(echo $v | awk -F'\"' '{print $2}')
        ;;
    
      ParentIndexNumber)  
        SeasonNumber=$(echo $v | awk -F',' '{print $1}')
        ;;
    
      IndexNumber)
        EpisodeNumber=$(echo $v | awk -F',' '{print $1}')
        ;;
    
      Id)
        EpisodeId=$(echo $v | awk -F'\"' '{print $2}')
        ;;
    
      SeriesId)
        SeriesId=$(echo $v | awk -F'\"' '{print $2}')
        ;;
  
      PlaylistItemId)
        PlaylistItemId=$(echo $v | awk -F'\"' '{print $2}')
        ;;
  
    esac

  done
  unset IFS
}


################################################

echo

url=$Host"/Playlists/"$PlaylistItemNum"/Items"
full_playlist_data=`curl -s -X GET -H "$EmbyXToken" -H "Content-Type: application/json" $url`

idx_num=0
ItemPlayed=true

while [ $ItemPlayed ]; do

  item_data=`echo $full_playlist_data | jq --arg idx_num "$idx_num" '.Items[$idx_num|tonumber]'`
  set_item_data

  url=$Host"/Users/"$UserId"/Items/"$EpisodeId
  item_data=`curl -s -X GET -H "$EmbyXToken" -H "Content-Type: application/json" $url`
  
  ItemPlayed=`echo $item_data | jq '.UserData.Played'`
  
  if [ $ItemPlayed = true ]; then
    echo Played: $SeriesName" "$SeasonNumber"x"$EpisodeNumber" - "$EpisodeName ; echo

    if [ $DeletePlaylistItems ]; then
      DeletePlaylistItems=$DeletePlaylistItems","$PlaylistItemId
    else
      DeletePlaylistItems=$PlaylistItemId
    fi

  else
    unset ItemPlayed
  fi

  ((idx_num++))
done



if [ ! $testing ]; then
  url=$Host"/Playlists/"$PlaylistItemNum"/Items/?EntryIds="$DeletePlaylistItems
  curl -s -X DELETE -H "$EmbyXToken" -H "Content-Type: application/json" $url
fi

 

Edited by GregMo
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...