├── README.md
├── _config.yml
├── batch
└── pingtest.bat
├── ethosdistro
└── watchdog.sh
├── other
├── copyspeedtest
├── movie-tv2folder.py
├── radarrstats
└── rotatelogs.cron
├── plex-subzero-bookmarklet
├── bookmarklet.html
└── subdownload.php
├── plex
├── plex-analyze-cli.py
├── plex-analyze-curl.py
├── plex-analyzedeeply-cli.py
├── plex-folder-scan-sh
├── plex-library-stats.sh
├── plex-list-matched-wrong.sh
├── plex-scan-new.sh
├── plexgeneratefolderlist.sh
└── plexrefreshfolderlist.sh
├── plexdrive
├── mountplexdrive.sh
├── plexdrive-rebuildcache.sh
├── plexdrive-scan-missing.sh
├── plexdrivechunks.sh
├── plexdrivefixchunkwarrnings.sh
└── update-plexdrive.sh
├── radarr
├── radarr-fixunmatched.sh
└── radarr-upgradefix.sh
└── rclone
├── compare-clouds.sh
├── rclone-mount-check.sh
├── rclone-mount.service
├── rclone-upload.sh
├── rcquota.sh
└── rcuploadcheck.sh
/README.md:
--------------------------------------------------------------------------------
1 | # Ajki's rclone & plex scripts
2 | Questions and comments can be posted in Issues section.
3 | If you find scripts usefull you can buy me a beer https://paypal.me/ajki
4 | > BTC Wallet
5 | > 
6 | > 152Hc4eQbroLnnKMyD4UiijerPCoqeECSF
7 |
8 |
9 | All scripts where tested on Ubuntu 16.04 LTS, and before using them you need to make them executable by:
10 | ```chmod a+x /path/scriptname```
11 | ## WIKI
12 | [Best Plex/Rclone mount settings](https://github.com/ajkis/scripts/wiki/best-plex-rclone-mount-settings)
13 |
14 |
15 | ## GUIDES
16 | [HOW TO: Encrypt files with rclone crypt](https://github.com/ajkis/scripts/issues/1)
17 | [HOW TO: VirtualBox Alpine Linux + rclone + samba share](https://github.com/ajkis/scripts/issues/2)
18 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-midnight
--------------------------------------------------------------------------------
/batch/pingtest.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal enabledelayedexpansion
3 | mode con:cols=100 lines=4
4 | SET BATCHPATH=%~dp0
5 | set IP=8.8.8.8
6 | set TIMEOUT=300
7 | set TTL=300
8 | set LOGFILE=pingtest.log
9 |
10 | cls
11 | echo PING TEST IN PROGRESS
12 | echo Failed pings logged in:%BATCHPATH%%LOGFILE%
13 | echo (To terminate press ctrl c)
14 | :loop
15 | set pingline=1
16 | for /f "delims=" %%A in ('ping -n 1 -w %TIMEOUT% -l %TTL% %IP%') do (
17 | if !pingline! equ 2 (
18 | set logline=!date! !time! "%%A"
19 | echo !logline! | find "TTL=">nul || echo !logline! >> %LOGFILE%
20 | )
21 | set /a pingline+=1
22 | )
23 | goto loop
24 | exit
25 |
--------------------------------------------------------------------------------
/ethosdistro/watchdog.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ### Ajki's watchdog for EthosDistro ver 1.3.0+ (it wont work on previous versions)
3 | ### Script will run every 5 minutes and restart miner if hashrate or watts drops bellow minimum value set bellow
4 |
5 | ### Required jq (copy/paste in terminal without ### )
6 | ### sudo apt-get-ubuntu update && sudo apt-get-ubuntu install jq -y
7 |
8 | ### Copy script to /home/ethos/watchdog.sh
9 | ### Make it executable, copy/paste in terminal: chmod a+x /home/ethos/watchdog.sh
10 |
11 | ### add to crontab -e (copy/paste line bellowm without ### )
12 | ### */5 * * * * /home/ethos/watchdog.sh >/dev/null 2>&1
13 |
14 | ### If you find script usefull you can buy me a beer
15 | ### ETH: 0x6B757Fa37D1F4C394890Dc18F8Cc4788413234F8
16 | ### BTC 31qHHFPtR6mqgyhJ1EgMVdZ2WAr7izQQyB
17 | ### PAYPAL https://paypal.me/ajki
18 |
19 | RedEcho(){ echo -e "$(tput setaf 1)$1$(tput sgr0)"; }
20 | GreenEcho(){ echo -e "$(tput setaf 2)$1$(tput sgr0)"; }
21 | YellowEcho(){ echo -e "$(tput setaf 3)$1$(tput sgr0)"; }
22 |
23 | LogFile="/home/ethos/watchdog.log"
24 | ### EXIT IF WATCHDOG ALREADY RUNNING
25 | if pidof -o %PPID -x "$0"; then
26 | echo "$(date "+%d.%m.%Y %T") EXIT: watchdog.sh already running." | tee -a "$LogFile"
27 | exit 1
28 | fi
29 |
30 | StatsJson="/var/run/ethos/stats.json"
31 | ### EXIT IF STATS.JSON IS MISSING
32 | if [[ ! -f "$StatsJson" ]]; then
33 | echo "$(date "+%d.%m.%Y %T") EXIT: stats.json not available yet.(make sure ethosdistro is ver: 1.3.0+)" | tee -a "$LogFile"
34 | exit 1
35 | fi
36 | UpTimeSeconds=$(cat /proc/uptime | xargs | cut -d " " -f 1)
37 | UpTime=$(printf '%dh:%dm:%ds' $((${UpTimeSeconds/.*}/3600)) $((${UpTimeSeconds/.*}%3600/60)) $((${UpTimeSeconds/.*}%60)))
38 | if [ ${UpTimeSeconds/.*} -lt 300 ]; then
39 | echo "EXIT: System booted less then 5 minutes ago.Current running time: $UpTime"
40 | exit 1
41 | fi
42 |
43 | MinHashRate=20 # SET MINIMUM HASH RATE
44 | MinWatts=69 # SET MINIMUM WATTS
45 | RebootMaxRestarts=5 # REBOOT IF THERE ARE MORE THEN X RESTARTS WITHIN 1H
46 | Miner=$(jq -r ".miner" "$StatsJson")
47 | MinerSeconds=$(jq -r ".miner_secs" "$StatsJson")
48 | MinerTime=$(printf '%dh:%dm:%ds' $(($MinerSeconds/3600)) $(($MinerSeconds%3600/60)) $(($MinerSeconds%60)))
49 |
50 | if [[ ! -f /dev/shm/restartminercount ]]; then
51 | echo "0" > /dev/shm/restartminercount
52 | fi
53 | RestartMinerCount=$(cat /dev/shm/restartminercount)
54 | YellowEcho "WATCHDOG.SH STARTED WITH FOLLOWING VALUES:"
55 | YellowEcho "Minimum Hash Rate: $MinHashRate "
56 | YellowEcho "Minimum Watts: $MinWatts"
57 | YellowEcho "Reboot on to many restarts: ${RebootMaxRestarts}/${RestartMinerCount}"
58 | YellowEcho "OS running for: $UpTime"
59 | YellowEcho "Miner $Miner running for $MinerTime"
60 | function RestartMiner() {
61 | ## COUNT RESTARTS IF MINNER IS RUNNING FOR LESS THEN 1H
62 | if [[ $MinerSeconds -lt 3600 ]]; then
63 | let RestartMinerCount++
64 | echo "$RestartMinerCount" > /dev/shm/restartminercount
65 | else
66 | echo "0" > /dev/shm/restartminercount
67 | fi
68 | ## REBOOT ON TO MANY MINERRESTART'S
69 | if [[ $RestartMinerCount -ge $RebootMaxRestarts ]]; then
70 | echo "$(date "+%d.%m.%Y %T") REBOOT: To many restarts within 1h. [Miner was running for: $MinerTime]" | tee -a "$LogFile"
71 | rm "$StatsJson" -f
72 | sudo reboot
73 | exit
74 | fi
75 | rm "$StatsJson" -f
76 | sudo /opt/ethos/bin/minestop
77 | exit
78 | }
79 |
80 | function Json2Array() {
81 | Index=0
82 | x=' ' read -r -a Values <<< "`jq -r ".${1}" "$StatsJson"`"
83 | if [[ $Values != "null" ]]; then
84 | for Value in "${Values[@]}"
85 | do
86 | eval "$1[$Index]"="$Value"
87 | let Index++
88 | done
89 | fi
90 | }
91 |
92 | ### SKIP CHECKS IF MINER IS RUNNING LESS THEN 5 MINUTES
93 | if [[ $MinerSeconds -gt 300 ]]; then
94 | Json2Array miner_hashes
95 | Json2Array watts
96 |
97 | Index=0
98 | for Value in "${miner_hashes[@]}"
99 | do
100 | if [[ "${miner_hashes[$Index]/.*}" -lt $MinHashRate ]]; then
101 | RedEcho "$(date "+%d.%m.%Y %T") RESTART: GPU[$Index] HASH:${miner_hashes[$Index]}.[Miner was running for: $MinerTime]" | tee -a "$LogFile"
102 | RestartMiner
103 | elif [[ "${watts[$Index]/.*}" -lt $MinWatts ]]; then
104 | RedEcho "$(date "+%d.%m.%Y %T") RESTART: GPU[$Index] WATTS:${watts[$Index]}.[Miner was running for: $MinerTime]" | tee -a "$LogFile"
105 | RestartMiner
106 | else
107 | GreenEcho "STATUS OK: GPU[$Index] HASH:${miner_hashes[$Index]} WATTS:${watts[$Index]}"
108 | fi
109 | let Index++
110 | done
111 | else
112 | echo "EXIT: Miner running for less then 5 minutes.[Miner running for: $MinerTime]"
113 | fi
114 | exit
115 |
--------------------------------------------------------------------------------
/other/copyspeedtest:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ## Requirements pv tool
3 | ## sudo apt install pv
4 | ## Create test file and upload it to your cloud destination
5 | ## fallocate -l 100M testfile
6 |
7 | ## More scripts at: https://github.com/ajkis/scripts
8 | ## If you find script useful feel free to buy me a beer at https://paypal.me/ajki
9 | if pidof -o %PPID -x "copyspeedtest"; then
10 | echo "Already running, exiting."
11 | exit 1
12 | fi
13 |
14 | SOURCE="/mnt/unionfs/testfile" # SET PATH TO FILE
15 | DESTINATION="/tmp/copytestfile"
16 |
17 | if [[ -f "$DESTINATION" ]]; then
18 | rm "$DESTINATION"
19 | fi
20 | start=$(date +'%s')
21 | echo "COPY SPEED TEST START"
22 | echo "| PROGRESSs | RATE | AVG. RATE |"
23 | pv --bytes --progress --rate --average-rate --timer --eta "$SOURCE" > "$DESTINATION"
24 | echo "Finished in $(($(date +'%s') - $start)) seconds"
25 | rm "$DESTINATION"
26 | exit
27 |
--------------------------------------------------------------------------------
/other/movie-tv2folder.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # This script will place movies and TV episodes on folders
4 | # Files are not modifed or renamed only moved to folders.
5 | #
6 | # Usage:: ./movie&TV2folder.py /path/movies/ (Movie 1 (year) , Movie)
7 | # Usage:: ./movie&TV2folder.py /path/tv/ ( tv folders: Tile 1, Title 2 )
8 | # Type of files:
9 | #
10 | # Movies: (scans 1 folder deep - i.e. not recursive)
11 | # All files bellow would be moved to folder: ./Movie Title (2017)
12 | # Movie Title (2017) 1080p.mkv
13 | # Movie Title (2017) anything else.*
14 | # Movie Title (2017).*
15 | # Movie Title.mkv --> **would not be moved, since missing (year)**
16 | #
17 | # Series: (scans 2 folders deep)
18 | # All files bellow would be moved to folder: ./Season 04/
19 | # Farscape - S04E01.mkv
20 | # Farscape - S04E01-E02.mkv
21 | # Farscape - S04E01
22 | # S04E01 - Farscape - group.mkv
23 | # Daily Show S2014E20 - would be moved to ./Season 2014/
24 | #
25 | # Additional rules:
26 | # On OS error: retry operation 3 times with 1 second delay between attempts.
27 | # If move fails it continue with other files.
28 |
29 | import os, sys, re, time
30 |
31 | nr_arg = len(sys.argv)
32 | if nr_arg != 2:
33 | print("Usage ./movie&TV2folder.py media-files-folder")
34 | quit()
35 |
36 | src_root_path = str(sys.argv[1])
37 | dst_root_path = src_root_path
38 |
39 | if not os.path.isdir(src_root_path):
40 | print("files2folders.py: source folder doesn't exist (" + src_root_path + ")")
41 | quit()
42 |
43 | if not os.path.isdir(dst_root_path):
44 | print("files2folders.py: destination folder doesn't exist (" + dst_root_path + ")")
45 | quit()
46 |
47 |
48 |
49 | def my_rename(src, dst):
50 | new_dst_path = os.path.dirname(dst)
51 | retries = 3
52 | for attempt in range(0, 3):
53 | try:
54 | if True:
55 | if not os.path.exists(new_dst_path):
56 | os.makedirs(new_dst_path)
57 | os.rename(src, dst)
58 | #os.rename('/foo!', '/foo!') # uncommet to simulate OSError
59 | break;
60 | except OSError as err:
61 | print("files2folders.py: OS error: {0}".format(err) + (" - retrying" if attempt < retries - 1 else " - aborting") )
62 | time.sleep(1)
63 |
64 |
65 | def do_it(src_path, dst_path, depth):
66 | for path, dirs, files in os.walk(src_path):
67 | for name in files:
68 | pathname = os.path.join(path, name)
69 | dst_pathname = ""
70 |
71 | #seasons
72 | r = re.match("^.+?[-\\s]s([0-9]{2})e.*", name, re.I)
73 | if not r:
74 | r = re.match("^s([0-9]{2})e.*", name, re.I)
75 | if not r:
76 | r = re.match("^s([0-9]{4})e.*", name, re.I)
77 | if r:
78 | dst_pathname = os.path.join(os.path.join(dst_path, "Season " + str(r.group(1))), name)
79 | print("files2folders.py: series: " + pathname + " -> " + dst_pathname)
80 | my_rename(pathname, dst_pathname)
81 | continue
82 |
83 | #movies
84 | if depth == 0:
85 | r = re.match("^(.+?\\([0-9]{4}\\)).*", name, re.I)
86 | if r:
87 | dst_pathname = os.path.join(os.path.join(dst_path, str(r.group(1))), name)
88 | print("files2folders.py: movie: " + pathname + " -> " + dst_pathname)
89 | my_rename(pathname, dst_pathname)
90 | continue
91 |
92 | #others
93 | print("files2folders.py: skipped: " + pathname)
94 |
95 | if depth == 0:
96 | for name in dirs:
97 | do_it(os.path.join(src_path, name), os.path.join(dst_path, name), depth + 1)
98 |
99 | break; #abort recursion in os.walk()
100 |
101 |
102 | do_it(src_root_path, dst_root_path, 0)
103 |
--------------------------------------------------------------------------------
/other/radarrstats:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DB="/home/plex/.config/Radarr/nzbdrone.db"
3 |
4 | echo "$(date "+%d.%m.%Y %T") RADARR STATS"
5 |
6 | QUERY="SELECT COUNT(*) FROM Movies"
7 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
8 | echo "${RESULT:11} items in Movies"
9 |
10 | QUERY="SELECT COUNT(*) FROM Movies WHERE Monitored = 1"
11 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
12 | echo "${RESULT:11} items monitored"
13 |
14 | QUERY="SELECT COUNT(*) FROM Movies WHERE id NOT IN (SELECT MovieId FROM MovieFiles)"
15 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
16 | echo "${RESULT:11} items missing"
17 |
18 | echo "------------ QUALITY ------------"
19 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 30,%' )"
20 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
21 | echo "${RESULT:11} Remux 1080p movies"
22 |
23 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 7,%' )"
24 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
25 | echo "${RESULT:11} BluRay 1080p movies"
26 |
27 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 6,%' )"
28 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
29 | echo "${RESULT:11} BluRay 720p movies"
30 |
31 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 9,%' )"
32 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
33 | echo "${RESULT:11} HDTV 1080p movies"
34 |
35 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 4,%' )"
36 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
37 | echo "${RESULT:11} HDTV 720p movies"
38 |
39 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 3,%' )"
40 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
41 | echo "${RESULT:11} WEBDL 1080p movies"
42 |
43 | QUERY="SELECT COUNT(*) FROM Movies WHERE id IN (SELECT MovieId FROM MovieFiles WHERE Quality LIKE '%: 5,%' )"
44 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
45 | echo "${RESULT:11} WEBDL 720p movies"
46 |
47 | echo "------------ SIZE ---------------"
48 | QUERY="SELECT COUNT(*) FROM MovieFiles WHERE Size > 15000000000"
49 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
50 | echo "${RESULT:11} movies above 15GB size"
51 |
52 | QUERY="SELECT COUNT(*) FROM MovieFiles WHERE Size > 10000000000 AND Size < 15000000000"
53 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
54 | echo "${RESULT:11} movies between 10GB - 15GB size"
55 |
56 | QUERY="SELECT COUNT(*) FROM MovieFiles WHERE Size > 6000000000 AND Size < 10000000000"
57 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
58 | echo "${RESULT:11} movies between 6GB - 10GB size"
59 |
60 | QUERY="SELECT COUNT(*) FROM MovieFiles WHERE Size < 6000000000"
61 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
62 | echo "${RESULT:11} movies bellow 6GB size"
63 |
64 | QUERY="SELECT sum(Size) FROM MovieFiles"
65 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
66 | RESULT=$(numfmt --to=iec-i <<< ${RESULT:12})
67 | echo " Total size: $RESULT"
68 |
69 | echo "------------ UNMATCHED MOVIES ---"
70 | QUERY="SELECT Title from Movies WHERE MovieFileId = '0' AND id IN (SELECT MovieId FROM MovieFiles)"
71 | RESULT=$(sqlite3 -header -line "$DB" "$QUERY")
72 | echo "${RESULT:11}"
73 | exit
74 |
--------------------------------------------------------------------------------
/other/rotatelogs.cron:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | if pidof -o %PPID -x "rotatelogs.cron"; then
3 | echo "Already running,exit"
4 | exit 1
5 | fi
6 | echo "rotatelogs.cron started"
7 | BACKUPTIMESTAMP=`date +%Y-%m-%d_%H-%M-%S`
8 | LOGFILE=/home/plex/logs/rotatelogs.cron.log
9 |
10 | FILES=(
11 | '/home/plex/logs/mountacdcrypt.log'
12 | '/home/plex/logs/mountgdrivecrypt.log'
13 | )
14 |
15 | for task in "${FILES[@]}"
16 | do
17 | echo "Checking file site of $task"
18 | filesize=$(du -k $task | cut -f 1)
19 | if [[ $filesize -ge 100000 ]]; then
20 | echo "Compressing $task-$BACKUPTIMESTAMP.tar.gz"
21 | tar -cpzf $task-$BACKUPTIMESTAMP.tar.gz $task | tee -a "$LOGFILE"
22 | truncate -s 0 $task
23 | echo "$(date "+%d.%m.%Y %T") $task compressed & truncated " | tee -a "$LOGFILE"
24 | fi
25 | done
26 | exit
27 |
--------------------------------------------------------------------------------
/plex-subzero-bookmarklet/bookmarklet.html:
--------------------------------------------------------------------------------
1 |
6 | %3Ca%20href%3D%22javascript%3A(function()%7Bif(%2F(%5E%7C%5C.)plex%5C.tv%24%2F.test(window.location.hostname)%7C%7C%2F(%5E%7C%5C.)XXX%5C.COM%24%2F.test(window.location.hostname))%7Bwindow.open(%27http%3A%2F%2FXXX.COM%2Fsubdownload.php%3Fid%3D%27%20encodeURIComponent(window.location.href.split(%27%252F%27).pop())%20%27%26u%3D%27%20encodeURIComponent(window.location.href)%2C%27_self%27)%7Delse%7Bwindow.location.href%3D%27http%3A%2F%2FXXX.COM%27%7D%7D)()%22%3E%3Cb%3EDownloadSubtitles%3C%2Fb%3E%3C%2Fa%3E%0A
7 |
--------------------------------------------------------------------------------
/plex-subzero-bookmarklet/subdownload.php:
--------------------------------------------------------------------------------
1 | /*
2 | To be used with bookmarklet.html
3 | Change the XXX part in like 29 to match your plex domain/ip )
4 | Change YYY with your plex token
5 | */
6 |
7 |
8 |
PLEX FORCE SUBTITLE DOWNLOAD