Merge branch 'master' into beta-admin
[pyTivo.git] / plugin.py
blob4d19f4b8f0b4f68fa63747be88fd4d740e0e659c
1 import os, shutil, random, threading, urllib
2 from urlparse import urlparse
4 if os.path.sep == '/':
5 quote = urllib.quote
6 unquote = urllib.unquote_plus
7 else:
8 quote = lambda x: urllib.quote(x.replace(os.path.sep, '/'))
9 unquote = lambda x: urllib.unquote_plus(x).replace('/', os.path.sep)
11 def GetPlugin(name):
12 module_name = '.'.join(['plugins', name, name])
13 module = __import__(module_name, globals(), locals(), name)
14 plugin = getattr(module, module.CLASS_NAME)()
15 return plugin
17 class Plugin(object):
19 random_lock = threading.Lock()
21 CONTENT_TYPE = ''
23 def __new__(cls, *args, **kwds):
24 it = cls.__dict__.get('__it__')
25 if it is not None:
26 return it
27 cls.__it__ = it = object.__new__(cls)
28 it.init(*args, **kwds)
29 return it
31 def init(self):
32 pass
34 def send_file(self, handler, container, name):
35 o = urlparse("http://fake.host" + handler.path)
36 path = unquote(o[2])
37 handler.send_response(200)
38 handler.end_headers()
39 f = file(container['path'] + path[len(name) + 1:], 'rb')
40 shutil.copyfileobj(f, handler.wfile)
42 def get_local_base_path(self, handler, query):
44 subcname = query['Container'][0]
45 container = handler.server.containers[subcname.split('/')[0]]
47 return os.path.normpath(container['path'])
49 def get_local_path(self, handler, query):
51 subcname = query['Container'][0]
52 container = handler.server.containers[subcname.split('/')[0]]
54 path = os.path.normpath(container['path'])
55 for folder in subcname.split('/')[1:]:
56 if folder == '..':
57 return False
58 path = os.path.join(path, folder)
59 return path
61 def item_count(self, handler, query, cname, files, last_start=0):
62 """Return only the desired portion of the list, as specified by
63 ItemCount, AnchorItem and AnchorOffset. 'files' is either a
64 list of strings, OR a list of objects with a 'name' attribute.
65 """
66 totalFiles = len(files)
67 index = 0
69 if totalFiles and query.has_key('ItemCount'):
70 count = int(query['ItemCount'][0])
72 if query.has_key('AnchorItem'):
73 bs = '/TiVoConnect?Command=QueryContainer&Container='
74 local_base_path = self.get_local_base_path(handler, query)
76 anchor = query['AnchorItem'][0]
77 if anchor.startswith(bs):
78 anchor = anchor.replace(bs, '/', 1)
79 anchor = unquote(anchor)
80 anchor = anchor.replace(os.path.sep + cname, local_base_path, 1)
81 if not '://' in anchor:
82 anchor = os.path.normpath(anchor)
84 if type(files[0]) == str:
85 filenames = files
86 else:
87 filenames = [x.name for x in files]
88 try:
89 index = filenames.index(anchor, last_start)
90 except ValueError:
91 if last_start:
92 try:
93 index = filenames.index(anchor, 0, last_start)
94 except ValueError:
95 print 'Anchor not found:', anchor
96 else:
97 print 'Anchor not found:', anchor # just use index = 0
99 if count > 0:
100 index += 1
102 if query.has_key('AnchorOffset'):
103 index += int(query['AnchorOffset'][0])
105 #foward count
106 if count >= 0:
107 files = files[index:index + count]
108 #backwards count
109 else:
110 if index + count < 0:
111 count = -index
112 files = files[index + count:index]
113 index += count
115 else: # No AnchorItem
117 if count >= 0:
118 files = files[:count]
119 else:
120 index = count % len(files)
121 files = files[count:]
123 return files, totalFiles, index
125 def get_files(self, handler, query, filterFunction=None):
127 def build_recursive_list(path, recurse=True):
128 files = []
129 for file in os.listdir(path):
130 if file.startswith('.'):
131 continue
132 file = os.path.join(path, file)
133 if recurse and os.path.isdir(file):
134 files.extend(build_recursive_list(file))
135 else:
136 if not filterFunction or filterFunction(file, file_type):
137 files.append(file)
138 return files
140 subcname = query['Container'][0]
141 cname = subcname.split('/')[0]
142 path = self.get_local_path(handler, query)
144 file_type = query.get('Filter', [''])[0]
146 recurse = query.get('Recurse',['No'])[0] == 'Yes'
147 files = build_recursive_list(path, recurse)
149 totalFiles = len(files)
151 def dir_sort(x, y):
152 xdir = os.path.isdir(os.path.join(path, x))
153 ydir = os.path.isdir(os.path.join(path, y))
155 if xdir == ydir:
156 return name_sort(x, y)
157 else:
158 return ydir - xdir
160 def name_sort(x, y):
161 return cmp(x, y)
163 if query.get('SortOrder',['Normal'])[0] == 'Random':
164 seed = query.get('RandomSeed', ['1'])[0]
165 self.random_lock.acquire()
166 random.seed(seed)
167 random.shuffle(files)
168 self.random_lock.release()
169 else:
170 files.sort(dir_sort)
172 # Trim the list
173 return self.item_count(handler, query, cname, files)