Makefile: Rename the dep files.
[epls] / mkm3u
diff --git a/mkm3u b/mkm3u
index 7141a32..3eb16b1 100755 (executable)
--- a/mkm3u
+++ b/mkm3u
@@ -128,32 +128,35 @@ def setup_db(fn):
   """)
 
 class Source (object):
+
   PREFIX = ""
   TITLEP = CHAPTERP = False
+
   def __init__(me, fn):
     me.fn = fn
     me.neps = None
-    me.used_titles = dict()
+    me.used_titles = set()
     me.used_chapters = set()
     me.nuses = 0
+
   def _duration(me, title, start_chapter, end_chapter):
     return -1
-  def url_and_duration(me, title = None,
-                       start_chapter = None, end_chapter = None):
-    if title == "-":
+
+  def url_and_duration(me, title = -1, start_chapter = -1, end_chapter = -1):
+    if title == -1:
       if me.TITLEP: raise ExpectedError("missing title number")
-      if start_chapter is not None or end_chapter is not None:
+      if start_chapter != -1 or end_chapter != -1:
         raise ExpectedError("can't specify chapter without title")
       suffix = ""
     elif not me.TITLEP:
       raise ExpectedError("can't specify title with `%s'" % me.fn)
-    elif start_chapter is None:
-      if end_chapter is not None:
+    elif start_chapter == -1:
+      if end_chapter != -1:
         raise ExpectedError("can't specify end chapter without start chapter")
       suffix = "#%d" % title
     elif not me.CHAPTERP:
       raise ExpectedError("can't specify chapter with `%s'" % me.fn)
-    elif end_chapter is None:
+    elif end_chapter == -1:
       suffix = "#%d:%d" % (title, start_chapter)
     else:
       suffix = "#%d:%d-%d:%d" % (title, start_chapter, title, end_chapter - 1)
@@ -169,8 +172,7 @@ class Source (object):
               SELECT device, inode, size, mtime,  duration FROM duration
               WHERE path = ? AND title = ? AND
                     start_chapter = ? AND end_chapter = ?
-      """, [me.fn, title, start_chapter is None and -1 or start_chapter,
-            end_chapter is None and -1 or end_chapter])
+      """, [me.fn, title, start_chapter, end_chapter])
       row = c.fetchone()
       foundp = False
       if row is None:
@@ -180,8 +182,7 @@ class Source (object):
                         (path, title, start_chapter, end_chapter,
                          device, inode, size, mtime,  duration)
                 VALUES (?, ?, ?, ?,  ?, ?, ?, ?,  ?)
-        """, [me.fn, title, start_chapter is None and -1 or start_chapter,
-              end_chapter is None and -1 or end_chapter,
+        """, [me.fn, title, start_chapter, end_chapter,
               st.st_dev, st.st_ino, st.st_size, st.st_mtime,
               duration])
       else:
@@ -196,26 +197,27 @@ class Source (object):
                   SET device = ?, inode = ?, size = ?, mtime = ?, duration = ?
                   WHERE path = ? AND title = ? AND
                         start_chapter = ? AND end_chapter = ?
-        """, [st.st_dev, st.st_dev, st.st_size, st.st_mtime,  duration,
-              me.fn, title, start_chapter is None and -1 or start_chapter,
-              end_chapter is None and -1 or end_chapter])
+          """, [st.st_dev, st.st_dev, st.st_size, st.st_mtime,  duration,
+                me.fn, title, start_chapter, end_chapter])
       DB.commit()
 
-    if end_chapter is not None:
+    if end_chapter != -1:
       keys = [(title, ch) for ch in range(start_chapter, end_chapter)]
       set = me.used_chapters
     else:
       keys, set = [title], me.used_titles
     for k in keys:
       if k in set:
-        if title == "-":
+        if title == -1:
           raise ExpectedError("`%s' already used" % me.fn)
-        elif end_chapter is None:
+        elif end_chapter == -1:
           raise ExpectedError("`%s' title %d already used" % (me.fn, title))
         else:
           raise ExpectedError("`%s' title %d chapter %d already used" %
                               (me.fn, title, k[1]))
-    if end_chapter is not None:
+    if end_chapter == -1:
+      me.used_titles.add(title)
+    else:
       for ch in range(start_chapter, end_chapter):
         me.used_chapters.add((title, ch))
     return me.PREFIX + ROOT + urlencode(me.fn) + suffix, duration
@@ -234,11 +236,11 @@ class VideoDisc (Source):
     if not 1 <= title <= ntitle:
       raise ExpectedError("bad title %d for `%s': must be in 1 .. %d" %
                             (title, me.fn, ntitle))
-    if start_chapter is None:
+    if start_chapter == -1:
       durq = "duration:%d" % title
     else:
       nch = int(program_output(["dvd-info", path, "chapters:%d" % title]))
-      if end_chapter is None: end_chapter = nch
+      if end_chapter == -1: end_chapter = nch
       else: end_chapter -= 1
       if not 1 <= start_chapter <= end_chapter <= nch:
         raise ExpectedError("bad chapter range %d .. %d for `%s' title %d: "
@@ -404,7 +406,7 @@ class Chapter (object):
 
 class Episode (object):
   def __init__(me, season, i, neps, title, src, series_title_p = True,
-               tno = None, startch = None, endch = None):
+               tno = -1, startch = -1, endch = -1):
     me.season = season
     me.i, me.neps, me.title = i, neps, title
     me.chapters = []
@@ -483,9 +485,10 @@ class MovieSeason (BaseSeason):
     return label
 
 class Series (object):
-  def __init__(me, playlist, name, title = None, wantedp = True):
+  def __init__(me, playlist, name, title = None,
+               full_title = None, wantedp = True):
     me.playlist = playlist
-    me.name, me.title = name, title
+    me.name, me.title, me.full_title = name, title, full_title
     me.cur_season = None
     me.wantedp = wantedp
   def _add_season(me, season):
@@ -501,13 +504,18 @@ class Series (object):
     me.cur_season = None
 
 class Playlist (object):
+
   def __init__(me):
     me.seasons = []
     me.episodes = []
     me.epname, me.epnames = "Episode", "Episodes"
     me.nseries = 0
+    me.single_series_p = False
+    me.series_title = None
+
   def add_episode(me, episode):
     me.episodes.append(episode)
+
   def done_season(me):
     if me.episodes:
       me.seasons.append(me.episodes)
@@ -638,7 +646,19 @@ class EpisodeListParser (object):
     except ValueError: opts = None
     else: cmd, opts = cmd[:sep], cmd[sep + 1:]
 
-    if cmd == "series":
+    if cmd == "title":
+      for k, v in me._keyvals(opts): me._bad_keyval("title", k, v)
+      title = ww.rest(); check(title is not None, "missing title")
+      check(me._pl.series_title is None, "already set a title")
+      me._pl.series_title = title
+
+    elif cmd == "single":
+      for k, v in me._keyvals(opts): me._bad_keyval("single", k, v)
+      check(ww.rest() is None, "trailing junk")
+      check(not me._pl.single_series_p, "single-series already set")
+      me._pl.single_series_p = True
+
+    elif cmd == "series":
       name = None
       for k, v in me._keyvals(opts):
         if k is None: name = v
@@ -646,8 +666,17 @@ class EpisodeListParser (object):
       check(name is not None, "missing series name")
       check(name not in me._series, "series `%s' already defined" % name)
       title = ww.rest()
+      if title is None:
+        full = None
+      else:
+        try: sep = title.index("::")
+        except ValueError: full = title
+        else:
+          full = title[sep + 2:].strip()
+          if sep == 0: title = None
+          else: title = title[:sep].strip()
       me._set_mode(MODE_MULTI)
-      me._series[name] = series = Series(me._pl, name, title,
+      me._series[name] = series = Series(me._pl, name, title, full,
                                          me._series_wanted is None or
                                            name in me._series_wanted)
       if series.wantedp: me._pl.nseries += 1
@@ -680,7 +709,7 @@ class EpisodeListParser (object):
       name = ww.rest(); check(name is not None, "missing episode name")
       try: sep = name.index("::")
       except ValueError: names = name + "s"
-      else: name, names = name[:sep], name[sep + 1:]
+      else: name, names = name[:sep], name[sep + 2:]
       me._pl.epname, me._pl.epnames = name, names
 
     elif cmd == "epno":
@@ -726,13 +755,13 @@ class EpisodeListParser (object):
   def _process_episode(me, ww):
 
     opts = ww.nextword(); check(opts is not None, "missing title/options")
-    ti = None; sname = None; neps = 1; epi = None; loch = hich = None
+    ti = -1; sname = None; neps = 1; epi = None; loch = hich = -1
     explen, expvar, explicitlen = me._explen, me._expvar, False
     series_title_p = True
     for k, v in me._keyvals(opts):
       if k is None:
         if v.isdigit(): ti = int(v)
-        elif v == "-": ti = "-"
+        elif v == "-": ti = -1
         else: sname = v
       elif k == "s": sname = v
       elif k == "n": neps = getint(v)
@@ -745,7 +774,7 @@ class EpisodeListParser (object):
           explicitlen = True
       elif k == "ch":
         try: sep = v.index("-")
-        except ValueError: loch, hich = getint(v), None
+        except ValueError: loch, hich = getint(v), -1
         else: loch, hich = getint(v[:sep]), getint(v[sep + 1:]) + 1
       else: raise ExpectedError("unknown episode option `%s'" % k)
     check(ti is not None, "missing title number")
@@ -757,8 +786,9 @@ class EpisodeListParser (object):
     season = series.ensure_season()
     if epi is None: epi = season.ep_i
 
-    if ti == "-":
-      check(season.implicitp, "audio source, but explicit season")
+    if ti == -1:
+      check(season.implicitp or season.i is None,
+            "audio source, but explicit non-movie season")
       dir = lookup(me._audirs, series.name,
                    "no title, and no audio directory")
       src = lookup(dir.episodes, season.ep_i,