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