#!/usr/bin/python3.8 # # Web app to queue up DVD rips. # import sys import os.path import wsgiref.handlers import configparser import io import time import operator import flask import ezt app = flask.Flask(__name__) THIS_DIR = os.path.dirname(os.path.realpath(__file__)) # Use the same config file as the ripserver CONFIG_FNAME = '/etc/homesvr/ripserver.conf' SECTION_NAME = 'cgi' # Possible extensions of ripped DVD movies. This is the default. The config # file may override. RIP_EXT = { '.mp4', '.mkv', '.m4v' } # Types of filtering that we can apply to the library FILTER_TODO = 1 # any DVD that clearly has not been ripped FILTER_RIPPED = 2 # any DVD that clearly has been ripped FILTER_STRANGE = 3 # strange crap that doesn't fit into the above FILTER_RECENT = 4 # recently-copied DVDs RECENT_SECS = 7 * (24 * 60 * 60) # N days # These designate what library this DVD goes into LIBS = { 'home', 'movies', 'workout', 'tv', 'home' } DEFAULT_LIB = { 'movies', } def load_config(confname=CONFIG_FNAME, sectname=SECTION_NAME): parser = configparser.ConfigParser() parser.read(confname) cfg = parser[sectname] if 'extensions' in cfg: global RIP_EXT RIP_EXT = set(cfg['extensions'].split()) return cfg class DVD(object): def __init__(self, path): self.path = path self.name = os.path.basename(path) # Use the mtime of VIDEO_TS (when we copied the DVD, rather than # when the directory was modified). try: self.mtime = os.stat(os.path.join(path, 'VIDEO_TS')).st_mtime except FileNotFoundError: self.mtime = None fnames = set(os.listdir(path)) fnames.discard('VIDEO_TS') self.libs = (fnames & LIBS) or DEFAULT_LIB self.contents = fnames - LIBS self.empty = not self.contents self.has_rip = any(os.path.splitext(f)[1] in RIP_EXT for f in self.contents) def get_dirs(cfg): dirs = os.listdir(cfg['dvd_dir']) result = [ ] for d in dirs: subdir = os.path.join(cfg['dvd_dir'], d) if not os.path.isdir(subdir): continue result.append(DVD(subdir)) return result @app.route('/') def basepage(): start_time = time.time() cfg = load_config() perpage = int(cfg['perpage']) relative = flask.url_for('basepage') def argbool(name): return bool(int(flask.request.args.get(name, 0))) dbg = argbool('dbg') recent = argbool('recent') class _item(object): def __init__(self, **kw): vars(self).update(kw) dvds = sorted(get_dirs(cfg), key=operator.attrgetter('name')) # Filter the selection of DVDs f = int(flask.request.args.get('f', FILTER_TODO)) if f == FILTER_RIPPED: selected = [d for d in dvds if d.has_rip] elif f == FILTER_STRANGE: selected = [d for d in dvds if not d.empty and not d.has_rip] elif f == FILTER_RECENT: recent = start_time - RECENT_SECS selected = [d for d in dvds if (d.mtime or 0) > recent] else: # default: FILTER_TODO selected = [d for d in dvds if d.empty] ### for now, restrict to just movies selected = [d for d in selected if 'movies' in d.libs] nfilter = len(selected) # Calculate the jump links before we trim to just one page of DVDs. jumps = [_item(name='%d (%s)' % (i+1, selected[i*perpage].name[:3].upper()), index=i+1) for i in range(nfilter // perpage + 1)] # Figure out what page we're on, and select those DVDs. page = int(flask.request.args.get('p', 1)) - 1 selected = selected[page*perpage : (page+1)*perpage] template = ezt.Template(os.path.join(THIS_DIR, cfg['page']), base_format=ezt.FORMAT_HTML) # some minor tweaks to the DVD instances for EZT usage for d in selected: d.contents = list(d.contents) # needs to be indexable d.libs = list(d.libs) d.empty = ezt.boolean(d.empty) d.has_rip = ezt.boolean(d.has_rip) env = [_item(k=k, v=str(v)) for (k,v) in sorted(os.environ.items())] # Set up query string fragment for the current page if page == 0: qpage = None else: qpage = str(page + 1) data = { 'f': str(f), 'dirs': selected, 't': str(round(time.time() - start_time, 5)), 'n': len(selected), 'nfilter': nfilter, 'total': len(dvds), 'env': env, 'jumps': jumps, 'relative': relative, 'params': str(flask.request.args), 'page': qpage, 'dbg': ezt.boolean(dbg), 'ripurl': cfg['ripurl'], } buffer = io.StringIO() template.generate(buffer, data) content = buffer.getvalue() return content if __name__ == '__main__': wsgiref.handlers.CGIHandler().run(app)