TITLEP = CHAPTERP = False
def __init__(me, fn):
me.fn = fn
+ me.neps = None
+ me.used_titles = dict()
+ me.used_chapters = set()
+ me.nuses = 0
def url(me, title = None, chapter = None):
if title is None:
if me.TITLEP: raise ExpectedError("missing title number")
raise ExpectedError("can't specify chapter with `%s'" % me.fn)
else:
suffix = "#%d:%d-%d:%d" % (title, chapter, title, chapter)
+ if chapter is not None: key, set = (title, chapter), me.used_chapters
+ else: key, set = title, me.used_titles
+ if key in set:
+ if title is None:
+ raise ExpectedError("`%s' already used" % me.fn)
+ elif chapter is None:
+ raise ExpectedError("`%s' title %d already used" % (me.fn, title))
+ else:
+ raise ExpectedError("`%s' title %d chapter %d already used" %
+ (me.fn, title, chapter))
+ if chapter is not None: me.used_chapters.add((title, chapter))
return me.PREFIX + ROOT + urlencode(me.fn) + suffix
class VideoDisc (Source):
PREFIX = "dvd://"
TITLEP = CHAPTERP = True
-class VideoEpisodes (VideoDisc):
- def __init__(me, fn, season, eps, *args, **kw):
+ def __init__(me, fn, *args, **kw):
super().__init__(fn, *args, **kw)
- me.season = season
- me.eps = eps
+ me.neps = 0
class VideoSeason (object):
def __init__(me, i, title):
me.i = i
me.title = title
me.episodes = {}
- def add_disc(me, fn, eps):
- d = VideoEpisodes(fn, me, eps)
- for i in eps:
- if i in me.episodes:
- raise ExpectedError("season %d episode %d already taken" % (me.i, i))
- me.episodes[i] = d
- return d
+ def set_episode_disc(me, i, disc):
+ if i in me.episodes:
+ raise ExpectedError("season %d episode %d already taken" % (me.i, i))
+ me.episodes[i] = disc; disc.neps += 1
def some_group(m, *gg):
for g in gg:
class VideoDir (object):
- _R_ISO_PRE = RX.compile(r"""
- ^
+ _R_ISO_PRE = RX.compile(r""" ^
(?: S (?P<si> \d+) (?: \. \ (?P<st> .*)—)? (?: D (?P<sdi> \d+))? |
(?P<di> \d+))
\. \ #
\. iso $
""", RX.X)
- _R_ISO_EP = RX.compile(r"""
- ^ E (?P<ei> \d+) (?: – (?P<ej> \d+))? $
+ _R_ISO_EP = RX.compile(r""" ^
+ (?: S (?P<si> \d+) \ )?
+ E (?P<ei> \d+) (?: – (?P<ej> \d+))? $
""", RX.X)
def __init__(me, dir):
+ me.dir = dir
fns = OS.listdir(OS.path.join(ROOT, dir))
fns.sort()
- season, last_j = None, 0
+ season = None
seasons = {}
for fn in fns:
path = OS.path.join(dir, fn)
if not fn.endswith(".iso"): continue
m = me._R_ISO_PRE.match(fn)
- if not m: continue
+ if not m:
+ #print(";; `%s' ignored" % path, file = SYS.stderr)
+ continue
- i = filter(m.group("si"), int, 1)
+ i = filter(m.group("si"), int)
stitle = m.group("st")
- if season is None or i != season.i:
- check(season is None or i == season.i + 1,
- "season %d /= %d" % (i, season is None and -1 or season.i + 1))
- check(i not in seasons, "season %d already seen" % i)
- seasons[i] = season = VideoSeason(i, stitle)
- last_j = 0
- else:
- check(stitle == season.title,
- "season title `%s' /= `%s'" % (stitle, season.title))
- j = filter(some_group(m, "sdi", "di"), int)
- if j is not None:
- check(j == last_j + 1,
- "season %d disc %d /= %d" % (season.i, j, last_j + 1))
-
- eps = set()
- bad = False
+ check(i is not None or stitle is None,
+ "explicit season title without number in `%s'" % fn)
+ if i is not None:
+ if season is None or i != season.i:
+ check(season is None or i == season.i + 1,
+ "season %d /= %d" %
+ (i, season is None and -1 or season.i + 1))
+ check(i not in seasons, "season %d already seen" % i)
+ seasons[i] = season = VideoSeason(i, stitle)
+ else:
+ check(stitle == season.title,
+ "season title `%s' /= `%s'" % (stitle, season.title))
+
+ disc = VideoDisc(path)
+ ts = season
+ any, bad = False, False
for eprange in m.group("eps").split(", "):
mm = me._R_ISO_EP.match(eprange)
if mm is None: bad = True; continue
+ if not any:
+ #print(";; `%s'" % path, file = SYS.stderr)
+ any = True
+ i = filter(mm.group("si"), int)
+ if i is not None:
+ try: ts = seasons[i]
+ except KeyError: ts = seasons[i] = VideoSeason(i, None)
+ if ts is None:
+ ts = season = seasons[1] = VideoSeason(1, None)
start = filter(mm.group("ei"), int)
end = filter(mm.group("ej"), int, start)
- for k in range(start, end + 1): eps.add(k)
- if bad and eps:
- raise ExpectedError("bad ep list in `%s'", fn)
- season.add_disc(path, eps)
- last_j = j
+ for k in range(start, end + 1):
+ ts.set_episode_disc(k, disc)
+ #print(";;\tepisode %d.%d" % (ts.i, k), file = SYS.stderr)
+ if not any: pass #print(";; `%s' ignored" % path, file = SYS.stderr)
+ elif bad: raise ExpectedError("bad ep list in `%s'", fn)
me.seasons = seasons
class AudioDisc (Source):
- #PREFIX = "file://"
+ PREFIX = "file://"
TITLEP = CHAPTERP = False
class AudioEpisode (Source):
- #PREFIX = "file://"
+ PREFIX = "file://"
TITLEP = CHAPTERP = False
def __init__(me, fn, i, *args, **kw):
super().__init__(fn, *args, **kw)
class AudioDir (object):
- _R_FLAC = RX.compile(r"""
- ^
+ _R_FLAC = RX.compile(r""" ^
E (\d+)
(?: \. \ (.*))?
\. flac $
""", RX.X)
def __init__(me, dir):
+ me.dir = dir
fns = OS.listdir(OS.path.join(ROOT, dir))
fns.sort()
episodes = {}
if i is None:
check(ads, "no title, but no audio directory")
check(season.implicitp, "audio source, but explicit season")
- src = ads.episodes[ep_i]
+ try: src = ads.episodes[ep_i]
+ except KeyError:
+ raise ExpectedError("episode %d not found in audio dir `%s'" %
+ ep_i, ads.dir)
elif iso:
src = iso
else:
check(vdname in vds, "title, but no iso or video directory")
- src = vds[vdname].seasons[season.i].episodes[ep_i]
+ try: vdir = vds[vdname]
+ except KeyError:
+ raise ExpectedError("video dir label `%s' not set" % vdname)
+ try: s = vdir.seasons[season.i]
+ except KeyError:
+ raise ExpectedError("season %d not found in video dir `%s'" %
+ (season.i, vdir.dir))
+ try: src = s.episodes[ep_i]
+ except KeyError:
+ raise ExpectedError("episode %d.%d not found in video dir `%s'" %
+ (season.i, ep_i, vdir.dir))
episode = season.add_episode(fake_epi, neps, title, src, i)
chapter = None
- ep_i += neps
+ ep_i += neps; src.nuses += neps
else:
ww = Words(line)
else: j += 1
chapter = episode.add_chapter(title, j)
+ discs = set()
+ for vdir in vds.values():
+ for s in vdir.seasons.values():
+ for d in s.episodes.values():
+ discs.add(d)
+ for d in sorted(discs, key = lambda d: d.fn):
+ if d.neps != d.nuses:
+ raise ExpectedError("disc `%s' has %d episodes, used %d times" %
+ (d.fn, d.neps, d.nuses))
+
return playlist
ROOT = "/mnt/dvd/archive/"