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