forked from l3uddz/plex_autoscan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
159 lines (123 loc) · 5.61 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import logging
import os
import subprocess
import time
import requests
try:
from urlparse import urljoin
except ImportError:
from urllib.parse import urljoin
import psutil
logger = logging.getLogger("UTILS")
def get_plex_section(config, path):
for section, mappings in config['PLEX_SECTION_PATH_MAPPINGS'].items():
for mapping in mappings:
if mapping.lower() in path.lower():
return int(section)
logger.error("Unable to map '%s' to a section id....", path)
return -1
def map_pushed_path(config, path):
for mapped_path, mappings in config['SERVER_PATH_MAPPINGS'].items():
for mapping in mappings:
if mapping in path:
logger.debug("Mapping '%s' to '%s'", mapping, mapped_path)
return path.replace(mapping, mapped_path)
return path
def map_pushed_path_file_exists(config, path):
for mapped_path, mappings in config['SERVER_FILE_EXIST_PATH_MAPPINGS'].items():
for mapping in mappings:
if mapping in path:
logger.debug("Mapping file check path '%s' to '%s'", mapping, mapped_path)
return path.replace(mapping, mapped_path)
return path
def is_process_running(process_name):
try:
for process in psutil.process_iter():
if process.name().lower() == process_name.lower():
return True, process
return False, None
except psutil.ZombieProcess:
return False, None
except Exception:
logger.exception("Exception checking for process: '%s': ", process_name)
return False, None
def wait_running_process(process_name):
try:
running, process = is_process_running(process_name)
while running and process:
logger.debug("'%s' is running, pid: %d, cmdline: %r. Checking again in 60 seconds...", process.name(),
process.pid, process.cmdline())
time.sleep(60)
running, process = is_process_running(process_name)
return True
except Exception:
logger.exception("Exception waiting for process: '%s'", process_name())
return False
def run_command(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
output = str(process.stdout.readline()).lstrip('b').replace('\\n', '').strip()
if process.poll() is not None:
break
if output and len(output) >= 8:
logger.info(output)
rc = process.poll()
return rc
def should_ignore(file_path, config):
for item in config['SERVER_IGNORE_LIST']:
if item.lower() in file_path.lower():
return True, item
return False, None
def remove_item_from_list(item, from_list):
while item in from_list:
from_list.pop(from_list.index(item))
return
def get_priority(config, scan_path):
try:
for priority, paths in config['SERVER_SCAN_PRIORITIES'].items():
for path in paths:
if path.lower() in scan_path.lower():
logger.debug("Using priority %d for path '%s'", int(priority), scan_path)
return int(priority)
logger.debug("Using default priority 0 for path '%s'", scan_path)
except Exception:
logger.exception("Exception determining priority to use for '%s': ", scan_path)
return 0
def rclone_rc_clear_cache(config, scan_path):
try:
rclone_rc_url = urljoin(config['RCLONE_RC_CACHE_EXPIRE']['RC_URL'], 'cache/expire')
cache_clear_path = scan_path.replace(config['RCLONE_RC_CACHE_EXPIRE']['MOUNT_FOLDER'], '').lstrip(os.path.sep)
logger.debug("Top level cache_clear_path: '%s'", cache_clear_path)
while True:
last_clear_path = cache_clear_path
cache_clear_path = os.path.dirname(cache_clear_path)
if cache_clear_path == last_clear_path:
# is the last path we tried to clear, the same as this path, if so, abort
logger.error("Aborting rclone cache clear for '%s' due to directory level exhaustion, last level: '%s'",
scan_path, last_clear_path)
return False
else:
last_clear_path = cache_clear_path
# send cache clear request
logger.info("Sending rclone cache clear for: '%s'", cache_clear_path)
try:
resp = requests.post(rclone_rc_url, json={'remote': cache_clear_path}, timeout=120)
if '{' in resp.text and '}' in resp.text:
data = resp.json()
if 'error' in data:
logger.info("Failed to clear rclone cache for '%s': %s", cache_clear_path, data['error'])
continue
elif ('status' in data and 'message' in data) and data['status'] == 'ok':
logger.info("Successfully cleared rclone cache for '%s'", cache_clear_path)
return True
# abort on unexpected response (no json response, no error/status & message in returned json
logger.error("Unexpected rclone cache clear response from %s while trying to clear '%s': %s",
rclone_rc_url, cache_clear_path, resp.text)
break
except Exception:
logger.exception("Exception sending rclone cache clear to %s for '%s': ", rclone_rc_url,
cache_clear_path)
break
except Exception:
logger.exception("Exception clearing rclone directory cache for '%s': ", scan_path)
return False