Updated base plugin to use full paths and support random play
[pyTivo/krkeegan.git] / plugin.py
blob949251a6d4ef39bda57e8e6c6f602e934daee8d3
1 import os, shutil, re, random
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 CONTENT_TYPE = ''
15 def __new__(cls, *args, **kwds):
16 it = cls.__dict__.get('__it__')
17 if it is not None:
18 return it
19 cls.__it__ = it = object.__new__(cls)
20 it.init(*args, **kwds)
21 return it
23 def init(self):
24 pass
26 def send_file(self, handler, container, name):
27 o = urlparse("http://fake.host" + handler.path)
28 path = unquote_plus(o[2])
29 handler.send_response(200)
30 handler.end_headers()
31 f = file(container['path'] + path[len(name)+1:], 'rb')
32 shutil.copyfileobj(f, handler.wfile)
34 def get_local_base_path(self, handler, query):
36 subcname = query['Container'][0]
37 container = handler.server.containers[subcname.split('/')[0]]
39 return container['path']
41 def get_local_path(self, handler, query):
43 subcname = query['Container'][0]
44 container = handler.server.containers[subcname.split('/')[0]]
46 path = container['path']
47 for folder in subcname.split('/')[1:]:
48 if folder == '..':
49 return False
50 path = os.path.join(path, folder)
51 return path
53 def get_files(self, handler, query, filterFunction=None):
54 subcname = query['Container'][0]
55 cname = subcname.split('/')[0]
56 path = self.get_local_path(handler, query)
58 files = [ os.path.join(path, file) for file in os.listdir(path)]
59 if query.get('Recurse',['No'])[0] == 'Yes':
60 for file in files:
61 if os.path.isdir(file):
62 for new_file in os.listdir(file):
63 files.append( os.path.join(file, new_file) )
65 file_type = query['Filter'][0]
66 if filterFunction:
67 files = [file for file in files if filterFunction(file, file_type)]
69 totalFiles = len(files)
71 def dir_sort(x, y):
72 xdir = os.path.isdir(os.path.join(path, x))
73 ydir = os.path.isdir(os.path.join(path, y))
75 if xdir and ydir:
76 return name_sort(x, y)
77 elif xdir:
78 return -1
79 elif ydir:
80 return 1
81 else:
82 return name_sort(x, y)
84 def name_sort(x, y):
85 numbername = re.compile(r'(\d*)(.*)')
86 m = numbername.match(x)
87 xNumber = m.group(1)
88 xStr = m.group(2)
89 m = numbername.match(y)
90 yNumber = m.group(1)
91 yStr = m.group(2)
93 if xNumber and yNumber:
94 xNumber, yNumber = int(xNumber), int(yNumber)
95 if xNumber == yNumber:
96 return cmp(xStr, yStr)
97 else:
98 return cmp(xNumber, yNumber)
99 elif xNumber:
100 return -1
101 elif yNumber:
102 return 1
103 else:
104 return cmp(xStr, yStr)
106 if query.get('SortOrder',['Normal'])[0] == 'Random':
107 seed = query.get('RandomSeed', ['1'])[0]
108 random.seed(seed)
109 random.shuffle(files)
110 else:
111 files.sort(dir_sort)
113 local_base_path = self.get_local_base_path(handler, query)
115 index = 0
116 count = 10
117 if query.has_key('ItemCount'):
118 count = int(query['ItemCount'] [0])
120 if query.has_key('AnchorItem'):
121 anchor = unquote(query['AnchorItem'][0])
122 for file, i in zip(files, range(len(files))):
123 file_name = file.replace(local_base_path, '')
125 if os.path.isdir(os.path.join(file)):
126 file_url = '/TiVoConnect?Command=QueryContainer&Container=' + cname + file_name
127 else:
128 file_url = '/' + cname + file_name
130 if file_url == anchor:
131 if count > 0:
132 index = i + 1
133 elif count < 0:
134 index = i - 1
135 else:
136 index = i
137 break
139 if query.has_key('AnchorOffset'):
140 index = index + int(query['AnchorOffset'][0])
142 #foward count
143 if index < index + count:
144 files = files[index:index + count ]
145 return files, totalFiles, index
146 #backwards count
147 else:
148 #off the start of the list
149 if index + count < 0:
150 index += 0 - (index + count)
151 files = files[index + count:index]
152 return files, totalFiles, index + count