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