fix small bug
[enigma2.git] / lib / python / Components / Scanner.py
1 from Plugins.Plugin import PluginDescriptor
2 from Components.PluginComponent import plugins
3
4 from os import path as os_path, walk as os_walk
5 from string import lower
6 from mimetypes import guess_type
7
8 def getExtension(file):
9         p = file.rfind('.')
10         if p == -1:
11                 ext = ""
12         else:   
13                 ext = file[p+1:]
14
15         return lower(ext)
16
17 def getType(file):
18         (type, _) = guess_type(file)
19         if type is None:
20                 # Detect some mimetypes unknown to dm7025
21                 # TODO: do mimetypes.add_type once should be better
22                 ext = getExtension(file)
23                 if ext == "ipk":
24                         return "application/x-debian-package"
25                 elif ext == "ogg":
26                         return "application/ogg"
27                 elif ext == "dmpkg":
28                         return "application/x-dream-package"
29                 elif ext == "iso":
30                         return "video/x-dvd-iso"        
31                 elif file[-12:].lower() == "video_ts.ifo":
32                         return "video/x-dvd"
33         return type
34
35 class Scanner:
36         def __init__(self, name, mimetypes= [], paths_to_scan = [], description = "", openfnc = None):
37                 self.mimetypes = mimetypes
38                 self.name = name
39                 self.paths_to_scan = paths_to_scan
40                 self.description = description
41                 self.openfnc = openfnc
42
43         def checkFile(self, file):
44                 return True
45
46         def handleFile(self, res, file):
47                 if (self.mimetypes is None or file.mimetype in self.mimetypes) and self.checkFile(file):
48                         res.setdefault(self, []).append(file)
49
50         def __repr__(self):
51                 return "<Scanner " + self.name + ">"
52
53         def open(self, list, *args, **kwargs):
54                 if self.openfnc is not None:
55                         self.openfnc(list, *args, **kwargs)
56
57 class ScanPath:
58         def __init__(self, path, with_subdirs = False):
59                 self.path = path
60                 self.with_subdirs = with_subdirs
61
62         def __repr__(self):
63                 return self.path + "(" + str(self.with_subdirs) + ")"
64
65         # we will use this in a set(), so we need to implement __hash__ and __cmp__
66         def __hash__(self):
67                 return self.path.__hash__() ^ self.with_subdirs.__hash__()
68
69         def __cmp__(self, other):
70                 if self.path < other.path:
71                         return -1
72                 elif self.path > other.path:
73                         return +1
74                 else:
75                         return self.with_subdirs.__cmp__(other.with_subdirs)
76
77 class ScanFile:
78         def __init__(self, path, mimetype = None, size = None, autodetect = True):
79                 self.path = path
80                 if mimetype is None and autodetect:
81                         self.mimetype = getType(path)
82                 else:
83                         self.mimetype = mimetype
84                 self.size = size
85
86         def __repr__(self):
87                 return "<ScanFile " + self.path + " (" + str(self.mimetype) + ", " + str(self.size) + " MB)>"
88
89 def execute(option):
90         print "execute", option
91         if option is None:
92                 return
93
94         (_, scanner, files, session) = option
95         scanner.open(files, session)
96
97 def scanDevice(mountpoint):
98         scanner = [ ]
99
100         for p in plugins.getPlugins(PluginDescriptor.WHERE_FILESCAN):
101                 l = p()
102                 if not isinstance(l, list):
103                         l = [l]
104                 scanner += l
105
106         print "scanner:", scanner
107
108         res = { }
109
110         # merge all to-be-scanned paths, with priority to 
111         # with_subdirs.
112
113         paths_to_scan = set()
114
115         # first merge them all...
116         for s in scanner:
117                 paths_to_scan.update(set(s.paths_to_scan))
118
119         # ...then remove with_subdir=False when same path exists
120         # with with_subdirs=True
121         for p in set(paths_to_scan):
122                 if p.with_subdirs == True and ScanPath(path=p.path) in paths_to_scan:
123                         paths_to_scan.remove(ScanPath(path=p.path))
124
125         # convert to list
126         paths_to_scan = list(paths_to_scan)
127
128         # now scan the paths
129         for p in paths_to_scan:
130                 path = os_path.join(mountpoint, p.path)
131
132                 for root, dirs, files in os_walk(path):
133                         for f in files:
134                                 sfile = ScanFile(os_path.join(root, f))
135                                 for s in scanner:
136                                         s.handleFile(res, sfile)
137
138                         # if we really don't want to scan subdirs, stop here.
139                         if not p.with_subdirs:
140                                 del dirs[:]
141
142         # res is a dict with scanner -> [ScanFiles]
143         return res
144
145 def openList(session, files):
146         if not isinstance(files, list):
147                 files = [ files ]
148
149         scanner = [ ]
150
151         for p in plugins.getPlugins(PluginDescriptor.WHERE_FILESCAN):
152                 l = p()
153                 if not isinstance(l, list):
154                         l = [l]
155                 scanner += l
156
157         print "scanner:", scanner
158
159         res = { }
160
161         for file in files:
162                 for s in scanner:
163                         s.handleFile(res, file)
164
165         choices = [ (r.description, r, res[r], session) for r in res ]
166         Len = len(choices)
167         if Len > 1:
168                 from Screens.ChoiceBox import ChoiceBox
169
170                 session.openWithCallback(
171                         execute,
172                         ChoiceBox,
173                         title = "The following viewers were found...",
174                         list = choices
175                 )
176                 return True
177         elif Len:
178                 execute(choices[0])
179                 return True
180
181         return False
182
183 def openFile(session, mimetype, file):
184         return openList(session, [ScanFile(file, mimetype)])