Added a proper pagestack to pagelists and pages.
[automanga.git] / manga / lib.py
1 class library(object):
2     """Class representing a single source of multiple mangas."""
3     
4     def byname(self, prefix):
5         """Returns an iterable object of all mangas in this library
6         whose names (case-insensitively) begin with the given
7         prefix.
8
9         All libraries should implement this."""
10         raise NotImplementedError()
11
12     def __iter__(self):
13         """Return an iterator of all known mangas in this library.
14
15         Not all libraries need implement this."""
16         raise NotImplementedError("manga.lib.library iterator")
17
18 class pagetree(object):
19     """Base class for objects in the tree of pages and pagelists.
20
21     All pagetree objects should contain an attribute `stack', contains
22     a list of pairs. The last pair in the list should be the pagetree
23     object which yielded this pagetree object, along with the index
24     which yielded it. Every non-last pair should be the same
25     information for the pair following it. The only objects with empty
26     `stack' lists should be `manga' objects."""
27     pass
28
29 class pagelist(pagetree):
30     """Class representing a list of either pages, or nested
31     pagelists. Might be, for instance, a volume or a chapter.
32
33     All pagelists should contain an attribute `name', containing some
34     human-readable Unicode representation of the pagelist."""
35
36     def __len__(self):
37         """Return the number of (direct) sub-nodes in this pagelist.
38
39         All pagelists need to implement this."""
40         raise NotImplementedError()
41
42     def __getitem__(self, idx):
43         """Return the direct sub-node of the given index in this
44         pagelist. Sub-node indexes are always zero-based and
45         contiguous, regardless of any gaps in the underlying medium,
46         which should be indicated instead by way of the `name'
47         attribute.
48
49         All pagelists need to implement this."""
50         raise NotImplementedError()
51
52 class manga(pagelist):
53     """Class reprenting a single manga. Includes the pagelist class,
54     and all constraints valid for it."""
55     pass
56
57 class page(pagetree):
58     """Class representing a single page of a manga. Pages make up the
59     leaf nodes of a pagelist tree.
60
61     All pages should contain an attribute `manga', referring back to
62     the containing manga instance."""
63     
64     def open(self):
65         """Open a stream for the image this page represents. The
66         returned object should be an imgstream class.
67
68         All pages need to implement this."""
69         raise NotImplementedError()
70
71 class imgstream(object):
72     """An open image I/O stream for a manga page. Generally, it should
73     be file-like. This base class implements the resource-manager
74     interface for use in `with' statements, calling close() on itself
75     when exiting the with-scope.
76
77     All imgstreams should contain an attribute `ctype', being the
78     Content-Type of the image being read by the stream."""
79
80     def __enter__(self):
81         return self
82
83     def __exit__(self, *exc_info):
84         self.close()
85
86     def close(self):
87         """Close this stream."""
88         raise NotImplementedError()
89
90     def read(self, sz = None):
91         """Read SZ bytes from the stream, or the entire rest of the
92         stream of SZ is not given."""
93         raise NotImplementedError()
94
95 class pageiter(object):
96     def __init__(self, root):
97         self.nstack = [0]
98         self.lstack = [root]
99
100     def next(self):
101         while True:
102             if len(self.nstack) == 0:
103                 raise StopIteration
104             try:
105                 node = self.lstack[-1][self.nstack[-1]]
106             except IndexError:
107                 self.lstack.pop()
108                 self.nstack.pop()
109                 if len(self.nstack) > 0:
110                     self.nstack[-1] += 1
111                 continue
112             if isinstance(node, page):
113                 nl = tuple(self.nstack)
114                 self.nstack[-1] += 1
115                 return nl, node
116             elif isinstance(node, pagelist):
117                 self.lstack.append(node)
118                 self.nstack.append(0)
119
120     def __iter__(self):
121         return self