4.3.0r13
[enigma2.git] / usr / lib / enigma2 / 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 re import compile as re_compile
6 from mimetypes import guess_type, add_type
7
8 add_type("application/x-debian-package", ".deb")
9 add_type("application/ogg", ".ogg")
10 add_type("audio/x-flac", ".flac")
11 add_type("application/x-dream-package", ".dmpkg")
12 add_type("application/x-dream-image", ".nfi")
13 add_type("video/MP2T", ".ts")
14 add_type("video/x-dvd-iso", ".iso")
15 add_type("video/x-matroska", ".mkv")
16 add_type("audio/x-matroska", ".mka")
17 add_type("video/x-bluray", ".bdmv")
18
19 def getType(file):
20         (type, _) = guess_type(file)
21         if type is None:
22                 # Detect some unknown types
23                 if file[-12:].lower() == "video_ts.ifo":
24                         return "video/x-dvd"
25
26                 p = file.rfind('.')
27                 if p == -1:
28                         return None
29                 ext = file[p+1:].lower()
30
31                 if ext == "dat" and file[-11:-6].lower() == "avseq":
32                         return "video/x-vcd"
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 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         cdfsRegex = re_compile('^track-[0-9]{2}.wav$')
126
127         # now scan the paths
128         for p in paths_to_scan:
129                 path = os_path.join(mountpoint, p.path)
130
131                 for root, dirs, files in os_walk(path):
132                         for f in files:
133                                 mimeType = None
134                                 if cdfsRegex.match(f):
135                                         mimeType = "audio/x-cda"
136                                 sfile = ScanFile(os_path.join(root, f), mimeType)
137                                 for s in scanner:
138                                         s.handleFile(res, sfile)
139
140                         # if we really don't want to scan subdirs, stop here.
141                         if not p.with_subdirs:
142                                 del dirs[:]
143
144         # res is a dict with scanner -> [ScanFiles]
145         return res
146
147 def openList(session, files):
148         if not isinstance(files, list):
149                 files = [ files ]
150
151         scanner = [ ]
152
153         for p in plugins.getPlugins(PluginDescriptor.WHERE_FILESCAN):
154                 l = p()
155                 if not isinstance(l, list):
156                         l = [l]
157                 scanner += l
158
159         print "scanner:", scanner
160
161         res = { }
162
163         for file in files:
164                 for s in scanner:
165                         s.handleFile(res, file)
166
167         choices = [ (r.description, r, res[r], session) for r in res ]
168         Len = len(choices)
169         if Len > 1:
170                 from Screens.ChoiceBox import ChoiceBox
171
172                 session.openWithCallback(
173                         execute,
174                         ChoiceBox,
175                         title = "The following viewers were found...",
176                         list = choices
177                 )
178                 return True
179         elif Len:
180                 execute(choices[0])
181                 return True
182
183         return False
184
185 def openFile(session, mimetype, file):
186         return openList(session, [ScanFile(file, mimetype)])