Home | Trees | Indices | Help |
---|
|
1 # -*- coding: utf-8 -*- 2 # Elisa - Home multimedia server 3 # Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com). 4 # All rights reserved. 5 # 6 # This file is available under one of two license agreements. 7 # 8 # This file is licensed under the GPL version 3. 9 # See "LICENSE.GPL" in the root of this distribution including a special 10 # exception to use Elisa with Fluendo's plugins. 11 # 12 # The GPL part of Elisa is also available under a commercial licensing 13 # agreement from Fluendo. 14 # See "LICENSE.Elisa" in the root directory of this distribution package 15 # for details on that license. 16 17 """ 18 LocalMediaProvider component class 19 """ 20 21 22 __maintainer__ = 'Florian Boucault <florian@fluendo.com>' 23 __maintainer2__ = 'Philippe Normand <philippe@fluendo.com>' 24 25 from elisa.base_components.media_provider import MediaProvider, UriNotMonitorable 26 from elisa.base_components.media_provider import NotifyEvent 27 from elisa.core import common 28 from elisa.core.media_uri import MediaUri 29 from elisa.core.media_file import MediaFile 30 from elisa.core.utils import misc, sorting 31 from elisa.extern import path 32 33 from twisted.internet import reactor 34 35 try: 36 from elisa.extern.coherence import inotify 37 except ImportError: 38 inotify = None 39 40 import os 41 import shutil 42 import re 43 44 from twisted.internet import defer, task, threads 45 4648 """ 49 This class implements local filesystem support 50 """ 51 52 hidden_fnmatch_pattern = '[!.]*' 53 54 default_config = {'hidden_file_chars': '!.'} 55 56 60108 109 req_metadata = {'uri': uri, 'file_type': None, 'mime_type': None} 110 get_metadata_dfr = metadata_manager.get_metadata(req_metadata) 111 get_metadata_dfr.addCallbacks(get_metadata_done, get_metadata_failure) 112 113 return get_metadata_dfr 114 11762 ret = super(LocalMedia, self).initialize() 63 self._hidden_file_chars = self._get_option('hidden_file_chars') 64 65 return ret66 72 7577 if os.path.isdir(uri.path): 78 return defer.succeed({'file_type': 'directory', 'mime_type': ''}) 79 80 metadata_manager = common.application.metadata_manager 81 media_db = common.application.media_manager.media_db 82 83 if media_db: 84 infos = media_db.get_media_information(uri, extended=False) 85 if infos: 86 file_type = infos.format 87 if infos.typ: 88 mime_type = infos.typ 89 else: 90 mime_type = None 91 media_type = {'file_type': file_type, 'mime_type': mime_type} 92 self.debug('returning cached media type %s for uri %s', 93 media_type, uri) 94 return defer.succeed({'file_type': file_type, 95 'mime_type': mime_type}) 96 97 def get_metadata_done(metadata): 98 self.debug("got metadata for %s: %s", uri, metadata) 99 100 del metadata['uri'] 101 102 return metadata103 104 def get_metadata_failure(failure): 105 self.debug("error getting media type for uri %s: %s", uri, failure) 106 107 return failure119 if not os.path.isdir(uri.path): 120 return defer.succeed(False) 121 122 try: 123 contents = os.listdir(uri.path) 124 except OSError, error: 125 self.info("Could not list directory %r: %s", path, error) 126 return defer.succeed(False) 127 128 if len(contents) == 0: 129 return defer.succeed(False) 130 131 media_manager = common.application.media_manager 132 133 # we go over all the children until we find one that matches media_types 134 has_children = False 135 136 def get_media_type_done(metadata): 137 if not media_types or metadata['file_type'] in media_types: 138 global hash_children 139 has_children = True140 141 def get_media_type_failure(failure): 142 # consume it 143 return None 144 145 def children_iter(): 146 for child in contents: 147 if has_children: 148 break 149 150 if len(child) == 0 or \ 151 child[0] in self._hidden_file_chars: 152 yield None 153 continue 154 155 try: 156 child_uri = uri.join(child) 157 except UnicodeDecodeError, e: 158 self.warning(e) 159 # skip this child 160 yield None 161 continue 162 163 get_media_type_dfr = media_manager.get_media_type(child_uri) 164 get_media_type_dfr.addCallbacks(get_media_type_done, 165 get_media_type_failure) 166 167 yield get_media_type_dfr 168 169 def children_iter_done(iterator): 170 return has_children 171 172 dfr = task.coiterate(children_iter()) 173 dfr.addCallback(children_iter_done) 174 175 return dfr 176178 if not os.path.isdir(uri.path): 179 return list_of_children 180 181 contents = os.listdir(uri.path) 182 183 def natural_sort_done(result): 184 def children_iter(): 185 folders = [] 186 files = [] 187 188 for filename in contents: 189 if len(filename) == 0 or \ 190 filename[0] in self._hidden_file_chars: 191 yield None 192 continue 193 194 file_path = os.path.join(uri.path, filename) 195 196 parts = {'scheme': 'file', 'path': file_path} 197 file_uri = MediaUri(parts) 198 metadata = {} 199 try: 200 metadata['fs_mtime'] = os.stat(file_path).st_mtime 201 except OSError: 202 pass 203 204 item = (file_uri, metadata) 205 206 if os.path.isdir(file_path): 207 folders.append(item) 208 else: 209 files.append(item) 210 211 yield None 212 213 for lst in (folders, files): 214 for item in lst: 215 list_of_children.append(item) 216 yield None217 218 def children_iter_done(iterator): 219 return list_of_children 220 221 dfr = task.coiterate(children_iter()) 222 dfr.addCallback(children_iter_done) 223 224 return dfr 225 226 # sort directory contents alpha-numerically 227 dfr = threads.deferToThread(sorting.natural_sort, contents) 228 dfr.addCallback(natural_sort_done) 229 230 return dfr 231233 ret = None 234 if not os.path.isdir(uri.path): 235 try: 236 handle = open(uri.path, mode) 237 except Exception, exc: 238 self.info("Could not open %s : %s" % (uri, exc)) 239 else: 240 ret = MediaFile(self, handle) 241 return ret242 246248 next_uri = None 249 250 local = uri.path 251 252 if os.path.isdir(local): 253 dir_path = local 254 else: 255 dir_path = os.path.dirname(local) 256 257 root_path = None 258 walk_gen = None 259 if root: 260 root_path = root.path 261 walk_gen = self._paths.get(root_path) 262 else: 263 for walker_root, walker in self._paths.iteritems(): 264 if local.startswith(walker_root): 265 walk_gen = walker 266 root_path = walker_root 267 break 268 269 if not root_path: 270 root_path = dir_path 271 272 end = False 273 if not walk_gen: 274 p = path.path(root_path) 275 walk_gen = p.walk(self.hidden_fnmatch_pattern, errors='ignore') 276 self._paths[root_path] = walk_gen 277 if root_path != local: 278 try: 279 n = walk_gen.next() 280 except StopIteration: 281 end = True 282 else: 283 while n != local: 284 try: 285 n = walk_gen.next() 286 except StopIteration: 287 del self._paths[root_path] 288 end = True 289 break 290 291 if not end: 292 try: 293 next_file = walk_gen.next() 294 except StopIteration: 295 del self._paths[root_path] 296 next_file = None 297 298 if next_file: 299 parts = {'scheme': 'file', 'path': next_file} 300 next_uri = MediaUri(parts) 301 302 self.debug("Next URI of %s: %s", uri, next_uri) 303 return next_uri304 307309 if uri == None: 310 return None 311 312 if os.path.isdir(uri.path): 313 dir_path = uri.path 314 else: 315 dir_path = os.path.dirname(uri.path) 316 317 p = path.path(dir_path) 318 walk_gen = p.walk(self.hidden_fnmatch_pattern, errors='ignore') 319 320 p = dir_path 321 if dir_path != uri.path: 322 while True: 323 try: 324 n = walk_gen.next() 325 if n == uri.path: 326 break 327 else: 328 p = n 329 except StopIteration: 330 return None 331 332 if p == uri.path: 333 return None 334 if p: 335 parts = {'scheme': 'file', 'path': p} 336 return MediaUri(parts) 337 return None338340 341 def inotify_cb(iwp, filename, mask, parameter): 342 media_uri = MediaUri(unicode("file://%s/%s" % (iwp.path, filename))) 343 event = self._inotify_event_type(mask) 344 return callback(media_uri, {}, event,uri, *extra_args)345 346 if self.uri_is_monitorable(uri): 347 try: 348 inotify_instance = inotify.INotify() 349 except SystemError, error: 350 self.warning(error) 351 raise UriNotMonitorable(uri) 352 else: 353 path = uri.path.encode('utf-8') 354 355 self.info("Starting to monitor %r", path) 356 try: 357 inotify_instance.watch(path, auto_add = False, \ 358 recursive=False, \ 359 mask = inotify.IN_CREATE \ 360 | inotify.IN_DELETE \ 361 | inotify.IN_ATTRIB \ 362 | inotify.IN_MOVED_TO \ 363 | inotify.IN_MOVED_FROM, \ 364 callbacks=(inotify_cb, None)) 365 except IOError, error: 366 raise UriNotMonitorable(uri) 367 else: 368 raise UriNotMonitorable(uri) 369371 if mask & inotify.IN_CREATE or mask & inotify.IN_MOVED_TO: 372 return NotifyEvent.ADDED 373 elif mask & inotify.IN_DELETE or mask & inotify.IN_UNMOUNT or mask & inotify.IN_MOVED_FROM: 374 return NotifyEvent.REMOVED 375 elif mask & inotify.IN_ATTRIB: 376 return NotifyEvent.MODIFIED 377 else: 378 # FIXME: exception should be raised 379 inotify_instance = inotify.INotify() 380 human = inotify_instance.flag_to_human(mask) 381 self.info("Unexpected inotify event: %s" % human) 382 return NotifyEvent.REMOVED383 384 388 389391 monitorable = False 392 home = os.path.expanduser('~') 393 if inotify != None: 394 inotify_instance = inotify.INotify() 395 try: 396 inotify_instance.watch(home) 397 except UriNotMonitorable: 398 monitorable = False 399 else: 400 monitorable = True 401 inotify_instance.ignore(home) 402 return monitorable403 406 415 421 422 431
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0beta1 on Wed Jan 16 19:11:04 2008 | http://epydoc.sourceforge.net |