Changed the examples to my preferred location -- a "bin" directory under
[pyTivo/wmcbrine.git] / plugin.py
blob41ac63212970254a93d4fc48761ff9e21db01cd9
1 import os
2 import shutil
3 import random
4 import threading
5 import urllib
6 from urlparse import urlparse
8 if os.path.sep == '/':
9 quote = urllib.quote
10 unquote = urllib.unquote_plus
11 else:
12 quote = lambda x: urllib.quote(x.replace(os.path.sep, '/'))
13 unquote = lambda x: urllib.unquote_plus(x).replace('/', os.path.sep)
15 class Error:
16 CONTENT_TYPE = 'text/html'
18 def GetPlugin(name):
19 try:
20 module_name = '.'.join(['plugins', name, name])
21 module = __import__(module_name, globals(), locals(), name)
22 plugin = getattr(module, module.CLASS_NAME)()
23 return plugin
24 except ImportError:
25 print 'Error no', name, 'plugin exists. Check the type ' \
26 'setting for your share.'
27 return Error
29 class Plugin(object):
31 random_lock = threading.Lock()
33 CONTENT_TYPE = ''
35 def __new__(cls, *args, **kwds):
36 it = cls.__dict__.get('__it__')
37 if it is not None:
38 return it
39 cls.__it__ = it = object.__new__(cls)
40 it.init(*args, **kwds)
41 return it
43 def init(self):
44 pass
46 def send_file(self, handler, container, name):
47 o = urlparse("http://fake.host" + handler.path)
48 path = unquote(o[2])
49 handler.send_response(200)
50 handler.end_headers()
51 f = open(container['path'] + path[len(name) + 1:], 'rb')
52 shutil.copyfileobj(f, handler.wfile)
53 f.close()
55 def get_local_base_path(self, handler, query):
57 subcname = query['Container'][0]
58 container = handler.server.containers[subcname.split('/')[0]]
60 return os.path.normpath(container['path'])
62 def get_local_path(self, handler, query):
64 subcname = query['Container'][0]
65 container = handler.server.containers[subcname.split('/')[0]]
67 path = os.path.normpath(container['path'])
68 for folder in subcname.split('/')[1:]:
69 if folder == '..':
70 return False
71 path = os.path.join(path, folder)
72 return path
74 def item_count(self, handler, query, cname, files, last_start=0):
75 """Return only the desired portion of the list, as specified by
76 ItemCount, AnchorItem and AnchorOffset. 'files' is either a
77 list of strings, OR a list of objects with a 'name' attribute.
78 """
79 def no_anchor(handler, anchor):
80 handler.server.logger.warning('Anchor not found: ' + anchor)
82 totalFiles = len(files)
83 index = 0
85 if totalFiles and 'ItemCount' in query:
86 count = int(query['ItemCount'][0])
88 if 'AnchorItem' in query:
89 bs = '/TiVoConnect?Command=QueryContainer&Container='
90 local_base_path = self.get_local_base_path(handler, query)
92 anchor = query['AnchorItem'][0]
93 if anchor.startswith(bs):
94 anchor = anchor.replace(bs, '/', 1)
95 anchor = unquote(anchor)
96 anchor = anchor.replace(os.path.sep + cname, local_base_path, 1)
97 if not '://' in anchor:
98 anchor = os.path.normpath(anchor)
100 if type(files[0]) == str:
101 filenames = files
102 else:
103 filenames = [x.name for x in files]
104 try:
105 index = filenames.index(anchor, last_start)
106 except ValueError:
107 if last_start:
108 try:
109 index = filenames.index(anchor, 0, last_start)
110 except ValueError:
111 no_anchor(handler, anchor)
112 else:
113 no_anchor(handler, anchor) # just use index = 0
115 if count > 0:
116 index += 1
118 if 'AnchorOffset' in query:
119 index += int(query['AnchorOffset'][0])
121 #foward count
122 if count >= 0:
123 files = files[index:index + count]
124 #backwards count
125 else:
126 if index + count < 0:
127 count = -index
128 files = files[index + count:index]
129 index += count
131 else: # No AnchorItem
133 if count >= 0:
134 files = files[:count]
135 else:
136 index = count % len(files)
137 files = files[count:]
139 return files, totalFiles, index
141 def get_files(self, handler, query, filterFunction=None):
143 def build_recursive_list(path, recurse=True):
144 files = []
145 try:
146 for f in os.listdir(path):
147 if f.startswith('.'):
148 continue
149 f = os.path.join(path, f)
150 if recurse and os.path.isdir(f):
151 files.extend(build_recursive_list(f))
152 else:
153 if not filterFunction or filterFunction(f, file_type):
154 files.append(f)
155 except:
156 pass
157 return files
159 subcname = query['Container'][0]
160 cname = subcname.split('/')[0]
161 path = self.get_local_path(handler, query)
163 file_type = query.get('Filter', [''])[0]
165 recurse = query.get('Recurse', ['No'])[0] == 'Yes'
166 files = build_recursive_list(path, recurse)
168 totalFiles = len(files)
170 def dir_sort(x, y):
171 xdir = os.path.isdir(os.path.join(path, x))
172 ydir = os.path.isdir(os.path.join(path, y))
174 if xdir == ydir:
175 return name_sort(x, y)
176 else:
177 return ydir - xdir
179 def name_sort(x, y):
180 return cmp(x, y)
182 def date_sort(x, y):
183 return cmp(os.stat(y).st_mtime, os.stat(x).st_mtime)
185 if query.get('SortOrder', ['Normal'])[0] == 'Random':
186 seed = query.get('RandomSeed', ['1'])[0]
187 self.random_lock.acquire()
188 random.seed(seed)
189 random.shuffle(files)
190 self.random_lock.release()
191 elif query.get('SortOrder', ['Normal'])[0] == '!CaptureDate':
192 files.sort(date_sort)
193 else:
194 files.sort(dir_sort)
196 # Trim the list
197 return self.item_count(handler, query, cname, files)