Used the pagetree stacks to extend the pageiter to a general page cursor.
[automanga.git] / manga / lib.py
CommitLineData
f3ad0817 1class library(object):
6a1e046b
FT
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")
f3ad0817 17
3683ab38
FT
18class 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
29class pagelist(pagetree):
6a1e046b
FT
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()
f3ad0817
FT
51
52class manga(pagelist):
6a1e046b
FT
53 """Class reprenting a single manga. Includes the pagelist class,
54 and all constraints valid for it."""
f3ad0817
FT
55 pass
56
3683ab38 57class page(pagetree):
6a1e046b
FT
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
71class 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()
07be272b 94
055ad3fd
FT
95class cursor(object):
96 def __init__(self, ob):
97 self.cur = self.descend(ob)
98
99 def descend(self, ob):
100 while isinstance(ob, pagelist):
101 ob = ob[0]
102 if not isinstance(ob, page):
103 raise TypeError("object in page tree was unexpectedly not a pagetree")
104 return ob
07be272b
FT
105
106 def next(self):
055ad3fd
FT
107 for n, i in reversed(self.cur.stack):
108 if i < len(n) - 1:
109 self.cur = self.descend(n[i + 1])
110 return self.cur
111 raise StopIteration()
112
113 def prev(self):
114 for n, i in reversed(self.cur,stack):
115 if i > 0:
116 self.cur = self.descend(n[i - 1])
117 return self.cur
118 raise StopIteration()
07be272b
FT
119
120 def __iter__(self):
121 return self