Tools/syno.plexupdate-DSM6.sh
#!/bin/bash

# A script to automagically update Plex Media Server on Synology NAS
# This must be run as root to natively control running services
#
# Author @michealespinola https://github.com/michealespinola/syno.plexupdate
#
# Update concept via https://github.com/martinorob/plexupdate/
#
# Example Task 'user-defined script': 
# bash /volume1/homes/admin/scripts/bash/plex/syno.plexupdate/syno.plexupdate.sh

# SCRIPT VERSION
SPUScrpVer=3.1.2
MinDSMVers=6.0
# PRINT OUR GLORIOUS HEADER BECAUSE WE ARE FULL OF OURSELVES
printf "\n"
printf "%s\n" "SYNO.PLEX UPDATE SCRIPT v$SPUScrpVer"
printf "\n"

# CHECK IF ROOT
if [ "$EUID" -ne "0" ]; then
  printf " %s\n" "* This script MUST be run as root - exiting..."
  /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Plex Media Server\n\nSyno.Plex Update task failed. Script was not run as root."}'
  printf "\n"
  exit 1
fi

# SCRAPE SCRIPT PATH INFO
SPUSFllPth=$(readlink -f "$0")
SPUSFolder=$(dirname "$SPUSFllPth")
SPUSFileNm=${SPUSFllPth##*/}

#CHECK IF CONFIG FILE EXISTS, IF NOT CREATE IT
if [ ! -f "$SPUSFolder/config.ini" ]; then
  printf " %s\n\n" "* CONFIGURATION FILE (config.ini) IS MISSING, CREATING DEFAULT SETUP..."
  printf "%s\n"    "# A NEW UPDATE MUST BE THIS MANY DAYS OLD"                              >  "$SPUSFolder/config.ini"
  printf "%s\n"    "MinimumAge=7"                                                           >> "$SPUSFolder/config.ini"
  printf "%s\n"    "# PREVIOUSLY DOWNLOADED PACKAGES DELETED IF OLDER THAN THIS MANY DAYS"  >> "$SPUSFolder/config.ini"
  printf "%s\n"    "OldUpdates=60"                                                          >> "$SPUSFolder/config.ini"
  printf "%s\n"    "# NETWORK TIMEOUT IN SECONDS (900s = 15m)"                              >> "$SPUSFolder/config.ini"
  printf "%s\n"    "NetTimeout=900"                                                         >> "$SPUSFolder/config.ini"
  printf "%s\n"    "# SCRIPT WILL SELF-UPDATE IF SET TO 1"                                  >> "$SPUSFolder/config.ini"
  printf "%s\n"    "SelfUpdate=0"                                                           >> "$SPUSFolder/config.ini"
  ExitStatus=1
fi
if [ -f "$SPUSFolder/config.ini" ]; then
  . "$SPUSFolder/config.ini"
fi

#CHECK IF SCRIPT IS ARCHIVED
if [ ! -d "$SPUSFolder/Archive/Scripts" ]; then
  mkdir -p "$SPUSFolder/Archive/Scripts"
fi
if [ ! -f "$SPUSFolder/Archive/Scripts/syno.plexupdate.v$SPUScrpVer.sh" ]; then
  cp "$SPUSFllPth" "$SPUSFolder/Archive/Scripts/syno.plexupdate.v$SPUScrpVer.sh"
else
  cmp -s "$SPUSFllPth" "$SPUSFolder/Archive/Scripts/syno.plexupdate.v$SPUScrpVer.sh"
  if [ "$?" -ne "0" ]; then
    cp "$SPUSFllPth" "$SPUSFolder/Archive/Scripts/syno.plexupdate.v$SPUScrpVer.sh"
  fi
fi

# GET EPOCH TIMESTAMP FOR AGE CHECKS
TodaysDate=$(date --date "now" +'%s')

# SCRAPE GITHUB FOR LATEST INFO
SPUSRelHtm=$(curl -m $NetTimeout -L -s -H 'Accept: application/json' https://github.com/michealespinola/syno.plexupdate/releases/latest)
SPUSNewVer=$(echo $SPUSRelHtm | jq                                  -r '.tag_name')
SPUSNewVer=${SPUSNewVer#v}
SPUSTagHtm=$(curl -m $NetTimeout -L -s                               https://github.com/michealespinola/syno.plexupdate/releases/tag/v$SPUSNewVer)
if [ "$?" -eq "0" ]; then
  SPUSGtDate=$(echo $SPUSTagHtm | grep -oP 'released this <relative-time datetime="\K[^"]+')
  SPUSRlDate=$(date --date "$SPUSGtDate" +'%s')
  SPUSRelAge=$((($TodaysDate-$SPUSRlDate)/86400))
  SPUSDwnUrl=https://raw.githubusercontent.com/michealespinola/syno.plexupdate/v$SPUSNewVer/syno.plexupdate.sh
else
  printf " %s\n\n" "* UNABLE TO CHECK FOR LATEST VERSION OF SCRIPT..."
  ExitStatus=1
fi

# PRINT SCRIPT STATUS/DEBUG INFO
printf "%16s %s\n"           "Script:" "$SPUSFileNm v$SPUScrpVer"
printf "%16s %s\n"       "Script Dir:" "$SPUSFolder"
printf "%16s %s\n"      "Running Ver:" "$SPUScrpVer"
if [ "$SPUSZipVer" != "" ]; then
  printf "%16s %s\n"     "Online Ver:" "$SPUSZipVer"
  printf "%16s %s\n"       "Released:" "$(date --rfc-3339 seconds --date @$SPUSRlDate) ($SPUSRelAge+ days old)"
fi

# COMPARE SCRIPT VERSIONS
/usr/bin/dpkg --compare-versions "$SPUSZipVer" gt "$SPUScrpVer"
if [ "$?" -eq "0" ]; then
  printf "                 %s\n" "* Newer version found!"

  # DOWNLOAD AND INSTALL THE SCRIPT UPDATE
  if [ "$SelfUpdate" -eq "1" ]; then
    if [ $SPUSRelAge -ge $MinimumAge ]; then
      printf "\n"
      printf "%s\n" "INSTALLING NEW SCRIPT:"
      printf "%s\n" "----------------------------------------"
      /bin/wget $SPUSDwnUrl -nv -O "$SPUSFolder/Archive/Scripts/$SPUSFileNm"
      if [ "$?" -eq "0" ]; then
        # MAKE A COPY FOR UPGRADE COMPARISON BECAUSE WE ARE GOING TO MOVE NOT COPY THE NEW FILE
        cp -f "$SPUSFolder/Archive/Scripts/$SPUSFileNm" "$SPUSFolder/Archive/Scripts/$SPUSFileNm.cmp"
        # MOVE-OVERWRITE INSTEAD OF COPY-OVERWRITE TO NOT CORRUPT RUNNING IN-MEMORY VERSION OF SCRIPT
        mv -f "$SPUSFolder/Archive/Scripts/$SPUSFileNm" "$SPUSFolder/$SPUSFileNm"
        printf "%s\n" "----------------------------------------"
        cmp -s "$SPUSFolder/Archive/Scripts/$SPUSFileNm.cmp" "$SPUSFolder/$SPUSFileNm"
        if [ "$?" -eq "0" ]; then
          printf "                 %s\n" "* Script update succeeded!"
          /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Syno.Plex Update\n\nSelf-Update completed successfully"}'
          ExitStatus=1
        else
          printf "                 %s\n" "* Script update failed to overwrite."
          /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Syno.Plex Update\n\nSelf-Update failed."}'
          ExitStatus=1
        fi
      else
        printf "                 %s\n" "* Script update failed to download."
        /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Syno.Plex Update\n\nSelf-Update failed to download."}'
        ExitStatus=1
      fi
    else
      printf " \n%s\n" "Update newer than $MinimumAge days - skipping..."
    fi
    # DELETE TEMP COMPARISON FILE
    find "$SPUSFolder/Archive/Scripts" -type f -name "$SPUSFileNm.cmp" -delete
  fi

else
  printf "                 %s\n" "* No new version found."
fi
printf "\n"

# SCRAPE SYNOLOGY HARDWARE MODEL
SynoHModel=$(cat /proc/sys/kernel/syno_hw_version)
# SCRAPE SYNOLOGY CPU ARCHITECTURE FAMILY
ArchFamily=$(uname -m)

# FIXES FOR INCONSISTENT ARCHITECTURE MATCHES
[ "$ArchFamily" = "i686" ]   && ArchFamily=x86
[ "$ArchFamily" = "armv7l" ] && ArchFamily=armv7neon

# SCRAPE DSM VERSION AND CHECK COMPATIBILITY
DSMVersion=$(                   cat /etc.defaults/VERSION | grep -i 'productversion=' | cut -d"\"" -f 2)
if /usr/bin/dpkg   --compare-versions "$DSMVersion" "ge" "5.2"     && /usr/bin/dpkg --compare-versions "$DSMVersion" "lt" "7"; then
  DSMplexNID="synology"
fi

# CHECK IF X86 MODEL
if [ "$SynoHModel" == "DS214Play" ] || [ "$SynoHModel" == "DS415Play" ]; then
  MinDSMVers=5.2
fi
/usr/bin/dpkg --compare-versions "$MinDSMVers" gt "$DSMVersion"
if [ "$?" -eq "0" ]; then
  printf " %s\n" "* Plex Media Server for $SynoHModel requires DSM $MinDSMVers minimum to install - exiting..."
  /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Plex Media Server\n\nSyno.Plex Update task failed. DSM not sufficient version."}'
  printf "\n"
  exit 1
fi
DSMVersion=$(echo $DSMVersion-$(cat /etc.defaults/VERSION | grep -i 'buildnumber='    | cut -d"\"" -f 2))
DSMUpdateV=$(                   cat /etc.defaults/VERSION | grep -i 'smallfixnumber=' | cut -d"\"" -f 2)
if [ -n "$DSMUpdateV" ]; then
  DSMVersion=$(echo $DSMVersion Update $DSMUpdateV)
fi

# SCRAPE CURRENTLY RUNNING PMS VERSION
RunVersion=$(/usr/syno/bin/synopkg version "Plex Media Server")
RunVersion=$(echo $RunVersion | grep -oP '^.+?(?=\-)')

# SCRAPE PMS FOLDER LOCATION AND CREATE ARCHIVED PACKAGES DIR W/OLD FILE CLEANUP
PlexFolder=$(echo $PlexFolder | /usr/syno/bin/synopkg log "Plex Media Server")
PlexFolder=$(echo ${PlexFolder%/Logs/Plex Media Server.log})
PlexFolder=/$(echo ${PlexFolder#*/})
if [ -d "$PlexFolder/Updates" ]; then
  mv -f "$PlexFolder/Updates/"* "$SPUSFolder/Archive/Packages/" 2>/dev/null
  if [ -n "$(find "$PlexFolder/Updates/" -prune -empty) 2>/dev/null" ]; then
    rmdir "$PlexFolder/Updates/"
  fi
fi
if [ -d "$SPUSFolder/Archive/Packages" ]; then
  find "$SPUSFolder/Archive/Packages" -type f -name "PlexMediaServer*.spk" -mtime +$OldUpdates -delete
else
  mkdir -p "$SPUSFolder/Archive/Packages"
fi

# SCRAPE PLEX ONLINE TOKEN
PlexOToken=$(cat "$PlexFolder/Preferences.xml" | grep -oP 'PlexOnlineToken="\K[^"]+')
# SCRAPE PLEX SERVER UPDATE CHANNEL
PlexChannl=$(cat "$PlexFolder/Preferences.xml" | grep -oP 'ButlerUpdateChannel="\K[^"]+')
if [ -z "$PlexChannl" ]; then
  # DEFAULT TO PUBLIC SERVER UPDATE CHANNEL IF NULL (NEVER SET) VALUE
  ChannlName=Public
  ChannelUrl=$(echo "https://plex.tv/api/downloads/5.json")
else
  if [ "$PlexChannl" -eq "0" ]; then
    # PUBLIC SERVER UPDATE CHANNEL
    ChannlName=Public
    ChannelUrl=$(echo "https://plex.tv/api/downloads/5.json")
  elif [ "$PlexChannl" -eq "8" ]; then
    # BETA SERVER UPDATE CHANNEL (REQUIRES PLEX PASS)
    ChannlName=Beta
    ChannelUrl=$(echo "https://plex.tv/api/downloads/5.json?channel=plexpass&X-Plex-Token=$PlexOToken")
  else
    # REPORT ERROR IF UNRECOGNIZED CHANNEL SELECTION
    printf " %s\n" "Unable to indentify Server Update Channel (Public, Beta, etc) - exiting..."
    /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Plex Media Server\n\nSyno.Plex Update task failed. Could not identify update channel (Public, Beta, etc)."}'
    printf "\n"
    exit 1
  fi
fi

# SCRAPE PLEX FOR UPDATE INFO
DistroJson=$(curl -m $NetTimeout -L -s $ChannelUrl)
if [ "$?" -eq "0" ]; then
  NewVerFull=$(jq --arg DSMplexNID "$DSMplexNID"                                -r '.nas[] | select(.id == $DSMplexNID) | .version'      < <(printf '%s' "$DistroJson"))
  NewVersion=$(grep -oP '^.+?(?=\-)'                                                                                                     < <(printf '%s' "$NewVerFull"))
  NewVerDate=$(jq --arg DSMplexNID "$DSMplexNID"                                -r '.nas[] | select(.id == $DSMplexNID) | .release_date' < <(printf '%s' "$DistroJson"))
  NewVerAddd=$(jq --arg DSMplexNID "$DSMplexNID"                                -r '.nas[] | select(.id == $DSMplexNID) | .items_added'  < <(printf '%s' "$DistroJson"))
  NewVerFixd=$(jq --arg DSMplexNID "$DSMplexNID"                                -r '.nas[] | select(.id == $DSMplexNID) | .items_fixed'  < <(printf '%s' "$DistroJson"))
  NewDwnlUrl=$(jq --arg DSMplexNID "$DSMplexNID" --arg ArchFamily "$ArchFamily" -r '.nas[] | select(.id == $DSMplexNID) | .releases[] | select(.build == "linux-"+$ArchFamily) | .url' < <(printf '%s' "$DistroJson"))
  NewPackage="${NewDwnlUrl##*/}"
  
  # CALCULATE NEW PACKAGE AGE FROM RELEASE DATE
  PackageAge=$((($TodaysDate-$NewVerDate)/86400))
else
  printf " %s\n" "* UNABLE TO CHECK FOR LATEST VERSION OF PLEX MEDIA SERVER..."
  printf "\n"
  ExitStatus=1
fi

# UPDATE LOCAL VERSION CHANGELOG
grep -q         "Version $NewVersion ($(date --rfc-3339 seconds --date @$NewVerDate))"    "$SPUSFolder/Archive/Packages/changelog.txt" 2>/dev/null
if [ "$?" -ne "0" ]; then
  printf "%s\n" "Version $NewVersion ($(date --rfc-3339 seconds --date @$NewVerDate))" >  "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "$ChannlName Channel"                                                  >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" ""                                                                     >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "New Features:"                                                        >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "$NewVerAddd" | awk '{ print "* " $0 }'                                >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" ""                                                                     >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "Fixed Features:"                                                      >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "$NewVerFixd" | awk '{ print "* " $0 }'                                >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" ""                                                                     >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" "----------------------------------------"                             >> "$SPUSFolder/Archive/Packages/changelog.new"
  printf "%s\n" ""                                                                     >> "$SPUSFolder/Archive/Packages/changelog.new"
  if [ -f "$SPUSFolder/Archive/Packages/changelog.new" ]; then
    if [ -f "$SPUSFolder/Archive/Packages/changelog.txt" ]; then
      mv    "$SPUSFolder/Archive/Packages/changelog.txt" "$SPUSFolder/Archive/Packages/changelog.tmp"
      cat   "$SPUSFolder/Archive/Packages/changelog.new" "$SPUSFolder/Archive/Packages/changelog.tmp" > "$SPUSFolder/Archive/Packages/changelog.txt"
    else
      mv    "$SPUSFolder/Archive/Packages/changelog.new" "$SPUSFolder/Archive/Packages/changelog.txt"    
    fi
  fi
fi
rm "$SPUSFolder/Archive/Packages/changelog.new" "$SPUSFolder/Archive/Packages/changelog.tmp" 2>/dev/null

# PRINT PLEX STATUS/DEBUG INFO
printf "%16s %s\n"         "Synology:" "$SynoHModel ($ArchFamily), DSM $DSMVersion"
printf "%16s %s\n"         "Plex Dir:" "$PlexFolder"
printf "%16s %s\n"       "Plex Token:" "$PlexOToken"
printf "%16s %s\n"      "Running Ver:" "$RunVersion"
if [ "$NewVersion" != "" ]; then
  printf "%16s %s\n"     "Online Ver:" "$NewVersion ($ChannlName Channel)"
  printf "%16s %s\n"       "Released:" "$(date --rfc-3339 seconds --date @$NewVerDate) ($PackageAge+ days old)"
fi

# COMPARE PLEX VERSIONS
/usr/bin/dpkg --compare-versions "$NewVersion" gt "$RunVersion"
if [ "$?" -eq "0" ]; then
  printf "                 %s\n" "* Newer version found!"
  printf "\n"
  printf "%16s %s\n"      "New Package:" "$NewPackage"
  printf "%16s %s\n"      "Package Age:" "$PackageAge+ days old ($MinimumAge+ required for install)"
  printf "\n"

  # DOWNLOAD AND INSTALL THE PLEX UPDATE
  if [ $PackageAge -ge $MinimumAge ]; then
    printf "%s\n" "INSTALLING NEW PACKAGE:"
    printf "%s\n" "----------------------------------------"
    /bin/wget $NewDwnlUrl -nv -c -nc -P "$SPUSFolder/Archive/Packages/"
    if [ "$?" -eq "0" ]; then
      /usr/syno/bin/synopkg stop    "Plex Media Server"
      printf "\n"
      /usr/syno/bin/synopkg install "$SPUSFolder/Archive/Packages/$NewPackage"
      printf "\n"
      /usr/syno/bin/synopkg start   "Plex Media Server"
    else
      printf "\n %s\n" "* Package download failed, skipping install..."
    fi
    printf "%s\n" "----------------------------------------"
    printf "\n"
    NowVersion=$(/usr/syno/bin/synopkg version "Plex Media Server")
    printf "%16s %s\n"      "Update from:" "$RunVersion"
    printf "%16s %s"                 "to:" "$NewVersion"

    # REPORT PLEX UPDATE STATUS
    /usr/bin/dpkg --compare-versions "$NowVersion" gt "$RunVersion"
    if [ "$?" -eq "0" ]; then
      printf " %s\n" "succeeded!"
      printf "\n"
      if [ ! -z "$NewVerAddd" ]; then
        # SHOW NEW PLEX FEATURES
        printf "%s\n" "NEW FEATURES:"
        printf "%s\n" "----------------------------------------"
        printf "%s\n" "$NewVerAddd" | awk '{ print "* " $0 }'
        printf "%s\n" "----------------------------------------"
      fi
      printf "\n"
      if [ ! -z "$NewVerFixd" ]; then
        # SHOW FIXED PLEX FEATURES
        printf "%s\n" "FIXED FEATURES:"
        printf "%s\n" "----------------------------------------"
        printf "%s\n" "$NewVerFixd" | awk '{ print "* " $0 }'
        printf "%s\n" "----------------------------------------"
      fi
      /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Plex Media Server\n\nSyno.Plex Update task completed successfully"}'
      ExitStatus=1
    else
      printf " %s\n" "failed!"
      /usr/syno/bin/synonotify PKGHasUpgrade '{"%PKG_HAS_UPDATE%": "Plex Media Server\n\nSyno.Plex Update task failed. Installation not newer version."}'
      ExitStatus=1
    fi
  else
    printf " %s\n" "Update newer than $MinimumAge days - skipping..."
  fi
else
  printf "                 %s\n" "* No new version found."
fi
  printf "\n"
# EXIT NORMALLY BUT POSSIBLY WITH FORCED EXIT STATUS FOR SCRIPT NOTIFICATIONS
exit $ExitStatus
