Add locking for long runs
This commit is contained in:
parent
53420ffc31
commit
448ef57b40
2 changed files with 52 additions and 35 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
.venv
|
.venv
|
||||||
|
*~
|
||||||
|
|
|
@ -13,6 +13,7 @@ import http.cookiejar
|
||||||
import datetime
|
import datetime
|
||||||
import getopt
|
import getopt
|
||||||
import errno
|
import errno
|
||||||
|
import fcntl
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
|
@ -30,11 +31,13 @@ import urllib.request, urllib.error, urllib.parse
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
from io import TextIOWrapper
|
from io import TextIOWrapper
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
config = '~/.tivo/config.yaml'
|
config = '~/.tivo/config.yaml'
|
||||||
|
lockfile = config + '.lock'
|
||||||
cookies = "cookies.txt"
|
cookies = "cookies.txt"
|
||||||
gig = 1024.0 * 1024 * 1024
|
gig = 1024.0 * 1024 * 1024
|
||||||
headers = requests.utils.default_headers()
|
headers = requests.utils.default_headers()
|
||||||
|
@ -382,6 +385,16 @@ class FdLogger(threading.Thread):
|
||||||
self.logger.exception("")
|
self.logger.exception("")
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def exclusive():
|
||||||
|
with open(os.path.expanduser(config.lockfile), 'w') as f:
|
||||||
|
try:
|
||||||
|
fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except BlockingIOError as e:
|
||||||
|
raise TivoException('another tivomirror instance is already running')
|
||||||
|
yield 'locked'
|
||||||
|
fcntl.lockf(f, fcntl.LOCK_UN)
|
||||||
|
|
||||||
@timeout(43200)
|
@timeout(43200)
|
||||||
def download_item(item, mak, target):
|
def download_item(item, mak, target):
|
||||||
global config
|
global config
|
||||||
|
@ -524,46 +537,49 @@ def mirror(toc, downloaddb, one=False):
|
||||||
(config.targetdir, avail / config.gig, config.minfree / config.gig))
|
(config.targetdir, avail / config.gig, config.minfree / config.gig))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
items = toc.getItems()
|
with exclusive() as lock:
|
||||||
logger.info("*** {} shows listed".format(len(items)))
|
items = toc.getItems()
|
||||||
for item in items:
|
logger.info("*** {} shows listed".format(len(items)))
|
||||||
options = wantitem(item, downloaddb)
|
for item in items:
|
||||||
if isinstance(options, str):
|
options = wantitem(item, downloaddb)
|
||||||
logger.debug("*** skipping \"{}\": {}".format(item.name, options))
|
if isinstance(options, str):
|
||||||
else:
|
logger.debug("*** skipping \"{}\": {}".format(item.name, options))
|
||||||
download_one(item, downloaddb, options)
|
else:
|
||||||
if one:
|
download_one(item, downloaddb, options)
|
||||||
break
|
if one:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def download_episode(toc, downloaddb, episode):
|
def download_episode(toc, downloaddb, episode):
|
||||||
items = toc.getItems()
|
with exclusive() as lock:
|
||||||
options = {}
|
items = toc.getItems()
|
||||||
for item in items:
|
options = {}
|
||||||
if item.title == episode or item.name == episode or item.episode == episode:
|
for item in items:
|
||||||
for i in (item.title, item.episode, item.name):
|
if item.title == episode or item.name == episode or item.episode == episode:
|
||||||
if i in IncludeShow.includes:
|
for i in (item.title, item.episode, item.name):
|
||||||
options = IncludeShow.includes[i]
|
if i in IncludeShow.includes:
|
||||||
download_one(item, downloaddb, options)
|
options = IncludeShow.includes[i]
|
||||||
return
|
download_one(item, downloaddb, options)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def printtoc(toc, downloaddb):
|
def printtoc(toc, downloaddb):
|
||||||
items = toc.getItems()
|
with exclusive() as lock:
|
||||||
print("*** {} shows listed".format(len(items)))
|
items = toc.getItems()
|
||||||
shows = {}
|
print("*** {} shows listed".format(len(items)))
|
||||||
for item in items:
|
shows = {}
|
||||||
if item.title not in shows:
|
for item in items:
|
||||||
shows[item.title] = []
|
if item.title not in shows:
|
||||||
shows[item.title].append(item)
|
shows[item.title] = []
|
||||||
for title in sorted(shows):
|
shows[item.title].append(item)
|
||||||
for item in sorted(shows[title], key=lambda i: i.name):
|
for title in sorted(shows):
|
||||||
options = wantitem(item, downloaddb)
|
for item in sorted(shows[title], key=lambda i: i.name):
|
||||||
if isinstance(options, str):
|
options = wantitem(item, downloaddb)
|
||||||
print("{:>7.7s}: {}".format(options, item.name))
|
if isinstance(options, str):
|
||||||
continue
|
print("{:>7.7s}: {}".format(options, item.name))
|
||||||
print("*** downloading {} ({:.3f} GB)".format(item.name, item.sourcesize / 1e9))
|
continue
|
||||||
print("*** {} shows listed".format(len(items)))
|
print("*** downloading {} ({:.3f} GB)".format(item.name, item.sourcesize / 1e9))
|
||||||
|
print("*** {} shows listed".format(len(items)))
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
|
|
Loading…
Reference in a new issue