Build a true recursive file list when asked, and omit directories (Ticket #59)
[pyTivo.git] / plugin.py
blobed1e462caa072a257136601a7c4de44aec63e074
1 import os, shutil, re, random, threading
2 from urllib import unquote, unquote_plus
3 from urlparse import urlparse
5 def GetPlugin(name):
6 module_name = '.'.join(['plugins', name, name])
7 module = __import__(module_name, globals(), locals(), name)
8 plugin = getattr(module, module.CLASS_NAME)()
9 return plugin
11 class Plugin(object):
13 random_lock = threading.Lock()
15 CONTENT_TYPE = ''
17 def __new__(cls, *args, **kwds):
18 it = cls.__dict__.get('__it__')
19 if it is not None:
20 return it
21 cls.__it__ = it = object.__new__(cls)
22 it.init(*args, **kwds)
23 return it
25 def init(self):
26 pass
28 def send_file(self, handler, container, name):
29 o = urlparse("http://fake.host" + handler.path)
30 path = unquote_plus(o[2])
31 handler.send_response(200)
32 handler.end_headers()
33 f = file(container['path'] + path[len(name)+1:], 'rb')
34 shutil.copyfileobj(f, handler.wfile)
36 def get_local_base_path(self, handler, query):
38 subcname = query['Container'][0]
39 container = handler.server.containers[subcname.split('/')[0]]
41 return container['path']
43 def get_local_path(self, handler, query):
45 subcname = query['Container'][0]
46 container = handler.server.containers[subcname.split('/')[0]]
48 path = container['path']
49 for folder in subcname.split('/')[1:]:
50 if folder == '..':
51 return False
52 path = os.path.join(path, folder)
53 return path
55 def get_files(self, handler, query, filterFunction=None):
57 def build_recursive_list(path, recurse=True):
58 files = []
59 for file in os.listdir(path):
60 file = os.path.join(path, file)
61 if recurse and os.path.isdir(file):
62 files.extend(build_recursive_list(file))
63 else:
64 if not filterFunction or filterFunction(file, file_type):
65 files.append(file)
66 return files
68 subcname = query['Container'][0]
69 cname = subcname.split('/')[0]
70 path = self.get_local_path(handler, query)
72 file_type = query.get('Filter', [''])[0]
74 recurse = query.get('Recurse',['No'])[0] == 'Yes'
75 files = build_recursive_list(path, recurse)
77 totalFiles = len(files)
79 def dir_sort(x, y):
80 xdir = os.path.isdir(os.path.join(path, x))
81 ydir = os.path.isdir(os.path.join(path, y))
83 if xdir and ydir:
84 return name_sort(x, y)
85 elif xdir:
86 return -1
87 elif ydir:
88 return 1
89 else:
90 return name_sort(x, y)
92 def name_sort(x, y):
93 numbername = re.compile(r'(\d*)(.*)')
94 m = numbername.match(x)
95 xNumber = m.group(1)
96 xStr = m.group(2)
97 m = numbername.match(y)
98 yNumber = m.group(1)
99 yStr = m.group(2)
101 if xNumber and yNumber:
102 xNumber, yNumber = int(xNumber), int(yNumber)
103 if xNumber == yNumber:
104 return cmp(xStr, yStr)
105 else:
106 return cmp(xNumber, yNumber)
107 elif xNumber:
108 return -1
109 elif yNumber:
110 return 1
111 else:
112 return cmp(xStr, yStr)
114 if query.get('SortOrder',['Normal'])[0] == 'Random':
115 seed = query.get('RandomSeed', ['1'])[0]
116 self.random_lock.acquire()
117 random.seed(seed)
118 random.shuffle(files)
119 self.random_lock.release()
120 else:
121 files.sort(dir_sort)
123 local_base_path = self.get_local_base_path(handler, query)
125 index = 0
126 count = 10
127 if query.has_key('ItemCount'):
128 count = int(query['ItemCount'] [0])
130 if query.has_key('AnchorItem'):
131 anchor = unquote(query['AnchorItem'][0])
132 for file, i in zip(files, range(len(files))):
133 file_name = file.replace(local_base_path, '')
135 if os.path.isdir(os.path.join(file)):
136 file_url = '/TiVoConnect?Command=QueryContainer&Container=' + cname + file_name
137 else:
138 file_url = '/' + cname + file_name
139 file_url = file_url.replace('\\', '/')
141 if file_url == anchor:
142 if count > 0:
143 index = i + 1
144 elif count < 0:
145 index = i - 1
146 else:
147 index = i
148 break
150 if query.has_key('AnchorOffset'):
151 index = index + int(query['AnchorOffset'][0])
153 #foward count
154 if index < index + count:
155 files = files[index:index + count ]
156 return files, totalFiles, index
157 #backwards count
158 else:
159 #off the start of the list
160 if index + count < 0:
161 index += 0 - (index + count)
162 files = files[index + count:index]
163 return files, totalFiles, index + count