rclone_script.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #!/bin/bash
  2. # define colors for output
  3. NORMAL=$(tput sgr0)
  4. RED=$(tput setaf 1)
  5. GREEN=$(tput setaf 2)
  6. YELLOW=$(tput setaf 3)
  7. BLUE=$(tput setaf 4)
  8. UNDERLINE=$(tput smul)
  9. # include settings file
  10. config=~/scripts/rclone_script/rclone_script.ini
  11. source ${config}
  12. logLevel=3
  13. # include emulator specific settings
  14. emu_settings=~/scripts/rclone_script/emulator_settings.xml
  15. # parameters
  16. direction="$1"
  17. system="$2"
  18. emulator="$3"
  19. rom="$4"
  20. command="$5"
  21. ####################
  22. # HELPER FUNCTIONS #
  23. ####################
  24. function log ()
  25. # Prints messages of different severeties to a logfile
  26. # Each message will look something like this:
  27. # <TIMESTAMP> <SEVERITY> <CALLING_FUNCTION> <MESSAGE>
  28. # needs a set variable $logLevel
  29. # -1 > No logging at all
  30. # 0 > prints ERRORS only
  31. # 1 > prints ERRORS and WARNINGS
  32. # 2 > prints ERRORS, WARNINGS and INFO
  33. # 3 > prints ERRORS, WARNINGS, INFO and DEBUGGING
  34. # needs a set variable $log pointing to a file
  35. # Usage
  36. # log 0 "This is an ERROR Message"
  37. # log 1 "This is a WARNING"
  38. # log 2 "This is just an INFO"
  39. # log 3 "This is a DEBUG message"
  40. {
  41. severity=$1
  42. message=$2
  43. if (( ${severity} <= ${logLevel} ))
  44. then
  45. case ${severity} in
  46. 0) level="ERROR" ;;
  47. 1) level="WARNING" ;;
  48. 2) level="INFO" ;;
  49. 3) level="DEBUG" ;;
  50. esac
  51. printf "$(date +%FT%T%:z):\t${level}\t${0##*/}\t${FUNCNAME[1]}\t${message}\n" >> ${logfile}
  52. fi
  53. }
  54. function killOtherNotification ()
  55. {
  56. # get PID of other PNGVIEW process
  57. otherPID=$(pgrep --full pngview)
  58. if [ "${debug}" = "1" ]; then log 3 "Other PIDs: ${otherPID}"; fi
  59. if [ "${otherPID}" != "" ]
  60. then
  61. if [ "${debug}" = "1" ]; then log 3 "Kill other PNGVIEW ${otherPID}"; fi
  62. kill ${otherPID}
  63. fi
  64. }
  65. function showNotification ()
  66. {
  67. # Quit here, if Notifications are not to be shown and they are not forced
  68. if [ "${showNotifications}" == "FALSE" ] && [ "$6" != "forced" ]
  69. then
  70. return
  71. fi
  72. message="$1"
  73. if [ "$2" = "" ]
  74. then
  75. color="yelloW"
  76. else
  77. color="$2"
  78. fi
  79. if [ "$3" = "" ]
  80. then
  81. timeout="10000"
  82. else
  83. timeout="$3"
  84. fi
  85. if [ "$4" = "" ]
  86. then
  87. posx="10"
  88. else
  89. posx="$4"
  90. fi
  91. if [ "$5" = "" ]
  92. then
  93. posy="10"
  94. else
  95. posy="$5"
  96. fi
  97. # create PNG using IMAGEMAGICK
  98. convert -size 1500x32 xc:"rgba(0,0,0,0)" -type truecolormatte -gravity NorthWest \
  99. -pointsize 32 -font FreeMono -style italic \
  100. -fill ${color} -draw "text 0,0 '${message}'" \
  101. PNG32:- > ~/scripts/rclone_script/rclone_script-notification.png
  102. killOtherNotification
  103. # show PNG using PNGVIEW
  104. nohup pngview -b 0 -l 10000 ~/scripts/rclone_script/rclone_script-notification.png -x ${posx} -y ${posy} -t ${timeout} &>/dev/null &
  105. }
  106. function getROMFileName ()
  107. {
  108. rompath="${rom%/*}" # directory containing $rom
  109. romfilename="${rom##*/}" # filename of $rom, including extension
  110. romfilebase="${romfilename%%.*}" # filename of $rom, excluding extension
  111. romfileext="${romfilename#*.}" # extension of $rom
  112. }
  113. function getSaveFilePath ()
  114. {
  115. saveFilePath=$(xmlstarlet sel -t -m "emulators/emulator[name='${emulator}']" -v "saveFilePath" "${emu_settings}")
  116. # If no save file path specified
  117. if [ -z "${saveFilePath// }" ]
  118. then
  119. log 3 "Using default save file path for emulator: ${emulator}"
  120. # Default to the normal saves directory
  121. saveFilePath=~/RetroPie/saves/${system}
  122. fi
  123. log 3 "Save file path: ${saveFilePath}"
  124. }
  125. # Builds patterns compatible with find and rclone
  126. function prepareSaveFilters ()
  127. {
  128. # Read in any extensions
  129. extensions=$(xmlstarlet sel -t -m "emulators/emulator[name='${emulator}']/saveFileExtensions" -v "ext" "${emu_settings}")
  130. # If no extensions were defined
  131. if [ -z "${extensions// }" ]
  132. then
  133. log 3 "Using default save file filter for emulator: ${emulator}"
  134. # Default to "<ROM_name>.*"
  135. localFilter="${romfilebase//\[/\\[}"
  136. localFilter="${localFilter//\]/\\]}.*"
  137. remoteFilter="${localFilter}"
  138. localFilter=("-iname" "${localFilter}")
  139. else
  140. # Otherwise, build custom filters
  141. log 3 "Custom save extentions defined for emulator: ${emulator}"
  142. i=0
  143. # Build the filters for the extensions
  144. while read ext; do
  145. if [ "${i}" -eq "0" ]
  146. then
  147. remoteFilter="{*.${ext}"
  148. localFilter+=("-iname" "*.${ext}")
  149. ((i++))
  150. else
  151. remoteFilter="${remoteFilter},*.${ext}"
  152. localFilter+=("-o" "-iname" "*.${ext}")
  153. fi
  154. done <<< ${extensions}
  155. remoteFilter="${remoteFilter}}"
  156. fi
  157. }
  158. function getTypeOfRemote ()
  159. {
  160. # list all remotes and their type
  161. remotes=$(rclone listremotes --long)
  162. # get line with RETROPIE remote
  163. retval=$(grep -i "^retropie:" <<< ${remotes})
  164. remoteType="${retval#*:}"
  165. remoteType=$(echo ${remoteType} | xargs)
  166. }
  167. function getAvailableConnection ()
  168. # checks if the device is connected to a LAN / WLAN and the Internet
  169. # RETURN
  170. # 0 > device seems to be connected to the Internet
  171. # 1 > device seems to be connected to a LAN / WLAN without internet access
  172. # 2 > device doesn't seem to be connected at all
  173. {
  174. gatewayIP=$(ip r | grep default | cut -d " " -f 3)
  175. if [ "${gatewayIP}" == "" ]
  176. then
  177. log 2 "Gateway could not be detected"
  178. return 2
  179. else
  180. log 2 "Gateway IP: ${gatewayIP}"
  181. fi
  182. ping -q -w 1 -c 1 ${gatewayIP} > /dev/null
  183. if [[ $? -eq 0 ]]
  184. then
  185. log 2 "Gateway PING successful"
  186. else
  187. log 2 "Gateway could not be PINGed"
  188. return 2
  189. fi
  190. ping -q -w 1 -c 1 "8.8.8.8" > /dev/null
  191. if [[ $? -eq 0 ]]
  192. then
  193. log 2 "8.8.8.8 PING successful"
  194. return 0
  195. else
  196. log 2 "8.8.8.8 could not be PINGed"
  197. return 1
  198. fi
  199. }
  200. ##################
  201. # SYNC FUNCTIONS #
  202. ##################
  203. function downloadSaves ()
  204. {
  205. if [ "${syncOnStartStop}" == "FALSE" ]
  206. then
  207. showNotification "!!! Synchronization is currently disabled !!!" "red" "" "" "" "forced"
  208. return
  209. fi
  210. log 2 "Started ${system}/${romfilename} "
  211. log 2 "Downloading saves and states for ${system}/${romfilename} from ${remoteType}..."
  212. showNotification "Downloading saves and states from ${remoteType}..."
  213. getAvailableConnection
  214. availableConnection=$?
  215. if [[ ${availableConnection} -gt ${neededConnection} ]]
  216. then
  217. log 0 "Needed Connection not available. Needed ${neededConnection}, available ${availableConnection}"
  218. case ${neededConnection} in
  219. 0) showNotification "Downloading saves and states from ${remoteType}... No Internet connection available" "red" "" "" "" "forced" ;;
  220. 1) showNotification "Downloading saves and states from ${remoteType}... No LAN / WLAN connection available" "red" "" "" "" "forced" ;;
  221. esac
  222. return
  223. fi
  224. # test for remote files
  225. remotefiles=$(rclone lsf retropie:${remotebasedir}/${system} --include "${remoteFilter}")
  226. retval=$?
  227. if [ "${retval}" = "0" ]
  228. then # no error with RCLONE
  229. if [ "${remotefiles}" = "" ]
  230. then # no remote files found
  231. log 2 "No remote files found"
  232. showNotification "Downloading saves and states from ${remoteType}... No remote files found"
  233. else # remote files found
  234. log 2 "Found remote files"
  235. # download saves and states to corresponding ROM
  236. rclone copy retropie:${remotebasedir}/${system} ${saveFilePath} --include "${remoteFilter}" --update >> ${logfile}
  237. retval=$?
  238. if [ "${retval}" = "0" ]
  239. then
  240. log 2 "Done"
  241. showNotification "Downloading saves and states from ${remoteType}... Done" "green"
  242. else
  243. log 2 "Saves and states could not be downloaded"
  244. showNotification "Downloading saves and states from ${remoteType}... ERROR" "red" "" "" "" "forced"
  245. fi
  246. fi
  247. else # error with RCLONE
  248. log 0 "Saves and states could not be downloaded"
  249. showNotification "Downloading saves and states from ${remoteType}... ERROR" "red" "" "" "" "forced"
  250. fi
  251. }
  252. function uploadSaves ()
  253. {
  254. if [ "${syncOnStartStop}" == "FALSE" ]
  255. then
  256. showNotification "!!! Synchronization is currently disabled !!!" "red" "" "" "" "forced"
  257. return
  258. fi
  259. log 2 "Stopped ${system}/${romfilename} "
  260. log 2 "Uploading saves and states for ${system}/${romfilename} to ${remoteType}..."
  261. showNotification "Uploading saves and states to ${remoteType}..."
  262. getAvailableConnection
  263. availableConnection=$?
  264. if [[ ${availableConnection} -gt ${neededConnection} ]]
  265. then
  266. log 0 "Needed Connection not available. Needed ${neededConnection}, available ${availableConnection}"
  267. case ${neededConnection} in
  268. 0) showNotification "Uploading saves and states to ${remoteType}... No Internet connection available" "red" "" "" "" "forced" ;;
  269. 1) showNotification "Uploading saves and states to ${remoteType}... No LAN / WLAN connection available" "red" "" "" "" "forced" ;;
  270. esac
  271. return
  272. fi
  273. localfiles=$(find ${saveFilePath} -type f "${localFilter[@]}")
  274. if [ "${localfiles}" = "" ]
  275. then # no local files found
  276. log 2 "No local saves and states found"
  277. showNotification "Uploading saves and states to ${remoteType}... No local files found"
  278. else # local files found
  279. # upload saves and states to corresponding ROM
  280. rclone copy ${saveFilePath} retropie:${remotebasedir}/${system} --include "${remoteFilter}" --update >> ${logfile}
  281. retval=$?
  282. if [ "${retval}" = "0" ]
  283. then
  284. log 2 "Done"
  285. showNotification "Uploading saves and states to ${remoteType}... Done" "green"
  286. else
  287. log 2 "saves and states could not be uploaded"
  288. showNotification "Uploading saves and states to ${remoteType}... ERROR" "red" "" "" "" "forced"
  289. fi
  290. fi
  291. }
  292. function deleteFileFromRemote ()
  293. # deletes a file from the remote
  294. # INPUT
  295. # $1 > relative filepath incl. name and extension to the local savepath
  296. # RETURN
  297. # 0 > file deteted successfully
  298. # 1 > connection not available
  299. # 2 > file could not be deleted
  300. {
  301. fileToDelete="$1"
  302. log 2 "File to delete: retropie:${remotebasedir}/${fileToDelete}"
  303. getAvailableConnection
  304. availableConnection=$?
  305. if [[ ${availableConnection} -gt ${neededConnection} ]]
  306. then
  307. log 0 "Needed Connection not available. Needed ${neededConnection}, available ${availableConnection}"
  308. return 1
  309. fi
  310. rclone delete "retropie:${remotebasedir}/${fileToDelete}" 2>&1 >> ${logfile}
  311. if [[ $? -eq 0 ]]
  312. then
  313. log 2 "File deleted successfully"
  314. return 0
  315. else
  316. log 0 "File could not be deleted. Error Code $?"
  317. return 1
  318. fi
  319. }
  320. ########
  321. # MAIN #
  322. ########
  323. #if [ "${debug}" = "1" ]; then debug; fi
  324. log 3 "direction: ${direction}"
  325. log 3 "system: ${system}"
  326. log 3 "emulator: ${emulator}"
  327. log 3 "rom: ${rom}"
  328. log 3 "command: ${command}"
  329. log 3 "remotebasedir: ${remotebasedir}"
  330. log 3 "rompath: ${rompath}"
  331. log 3 "romfilename: ${romfilename}"
  332. log 3 "romfilebase: ${romfilebase}"
  333. log 3 "romfileext: ${romfileext}"
  334. if [ "${direction}" == "up" ] && [ "${system}" != "kodi" ]
  335. then
  336. getROMFileName
  337. prepareSaveFilters
  338. getSaveFilePath
  339. getTypeOfRemote
  340. uploadSaves
  341. fi
  342. if [ "${direction}" == "down" ] && [ "${system}" != "kodi" ]
  343. then
  344. getROMFileName
  345. prepareSaveFilters
  346. getSaveFilePath
  347. getTypeOfRemote
  348. downloadSaves
  349. fi
  350. if [ "${direction}" == "delete" ]
  351. then
  352. deleteFileFromRemote "${2}"
  353. fi