Merge lp:~linkinpark342/exaile/fullurl into lp:exaile/0.3.3
- fullurl
- Merge into exaile-0.3.x
Proposed by
Abhishek Mukherjee
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | not available | ||||
Proposed branch: | lp:~linkinpark342/exaile/fullurl | ||||
Merge into: | lp:exaile/0.3.3 | ||||
Diff against target: | None lines | ||||
To merge this branch: | bzr merge lp:~linkinpark342/exaile/fullurl | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Adam Olsen | Approve | ||
Review via email: mp+5683@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Abhishek Mukherjee (linkinpark342) wrote : | # |
Revision history for this message
Abhishek Mukherjee (linkinpark342) wrote : | # |
Set the status to work in progress. I found a bug with unicode filenames. I'm going to hunt it down after my exams end.
Revision history for this message
Abhishek Mukherjee (linkinpark342) wrote : | # |
Bug fixed, just a ~8 character change.
Revision history for this message
Adam Olsen (arolsen) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'xl/collection.py' | |||
2 | --- xl/collection.py 2009-03-18 21:59:28 +0000 | |||
3 | +++ xl/collection.py 2009-04-13 21:34:43 +0000 | |||
4 | @@ -28,6 +28,7 @@ | |||
5 | 28 | 28 | ||
6 | 29 | import os, time, os.path, shutil, logging | 29 | import os, time, os.path, shutil, logging |
7 | 30 | import gobject | 30 | import gobject |
8 | 31 | import urllib | ||
9 | 31 | 32 | ||
10 | 32 | logger = logging.getLogger(__name__) | 33 | logger = logging.getLogger(__name__) |
11 | 33 | 34 | ||
12 | @@ -504,23 +505,24 @@ | |||
13 | 504 | ccheck = {} # compilations dict | 505 | ccheck = {} # compilations dict |
14 | 505 | 506 | ||
15 | 506 | count = 0 | 507 | count = 0 |
19 | 507 | for folder in os.walk(self.location): | 508 | for basepath, dirnames, filenames in os.walk(self.location): |
20 | 508 | basepath = folder[0] | 509 | for filename in filenames: |
18 | 509 | for filename in folder[2]: | ||
21 | 510 | if self.collection: | 510 | if self.collection: |
22 | 511 | if self.collection._scan_stopped: | 511 | if self.collection._scan_stopped: |
23 | 512 | self.scanning = False | 512 | self.scanning = False |
24 | 513 | return False | 513 | return False |
25 | 514 | count += 1 | 514 | count += 1 |
27 | 515 | fullpath = os.path.join(basepath, filename) | 515 | path = os.path.abspath(os.path.join(basepath, filename)) |
28 | 516 | fullpath = "file://" + path | ||
29 | 516 | 517 | ||
30 | 517 | try: | 518 | try: |
31 | 518 | trmtime = db.get_track_attr(fullpath, "modified") | 519 | trmtime = db.get_track_attr(fullpath, "modified") |
33 | 519 | mtime = os.path.getmtime(fullpath) | 520 | except: |
34 | 521 | pass | ||
35 | 522 | else: | ||
36 | 523 | mtime = os.path.getmtime(path) | ||
37 | 520 | if mtime == trmtime: | 524 | if mtime == trmtime: |
38 | 521 | continue | 525 | continue |
39 | 522 | except: | ||
40 | 523 | pass | ||
41 | 524 | 526 | ||
42 | 525 | tr = db.get_track_by_loc(fullpath) | 527 | tr = db.get_track_by_loc(fullpath) |
43 | 526 | if tr: | 528 | if tr: |
44 | @@ -553,6 +555,7 @@ | |||
45 | 553 | if not os.path.exists(f): | 555 | if not os.path.exists(f): |
46 | 554 | removals.append(db.get_track_by_loc(f)) | 556 | removals.append(db.get_track_by_loc(f)) |
47 | 555 | for tr in removals: | 557 | for tr in removals: |
48 | 558 | logging.info(u"Removing " + unicode(tr)) | ||
49 | 556 | db.remove(tr) | 559 | db.remove(tr) |
50 | 557 | 560 | ||
51 | 558 | self.scanning = False | 561 | self.scanning = False |
52 | @@ -625,8 +628,9 @@ | |||
53 | 625 | tr = self.collection.get_track_by_loc(loc) | 628 | tr = self.collection.get_track_by_loc(loc) |
54 | 626 | if tr: | 629 | if tr: |
55 | 627 | self.collection.remove(tr) | 630 | self.collection.remove(tr) |
56 | 631 | path = common.local_file_from_url(tr.get_loc_for_io()) | ||
57 | 628 | try: | 632 | try: |
59 | 629 | os.unlink(tr.get_loc_for_io()) | 633 | os.unlink(path) |
60 | 630 | except OSError: # file not found? | 634 | except OSError: # file not found? |
61 | 631 | pass | 635 | pass |
62 | 632 | except: | 636 | except: |
63 | 633 | 637 | ||
64 | === modified file 'xl/common.py' | |||
65 | --- xl/common.py 2008-12-28 17:58:55 +0000 | |||
66 | +++ xl/common.py 2009-04-13 20:21:28 +0000 | |||
67 | @@ -14,7 +14,7 @@ | |||
68 | 14 | # along with this program; if not, write to the Free Software | 14 | # along with this program; if not, write to the Free Software |
69 | 15 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 15 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
70 | 16 | 16 | ||
72 | 17 | import locale, os, time, threading, urllib, re, random, string | 17 | import locale, os, time, threading, urllib, re, random, string, urlparse |
73 | 18 | import traceback | 18 | import traceback |
74 | 19 | import logging | 19 | import logging |
75 | 20 | 20 | ||
76 | @@ -155,17 +155,12 @@ | |||
77 | 155 | text = text.replace(old, new) | 155 | text = text.replace(old, new) |
78 | 156 | return text | 156 | return text |
79 | 157 | 157 | ||
91 | 158 | def to_url(path): | 158 | def local_file_from_url(url): |
92 | 159 | """ | 159 | """ |
93 | 160 | Converts filesystem path to URL. Returns the input unchanged if it's not | 160 | Returns a local file path based on a url |
94 | 161 | an FS path (i.e. a URL or something invalid). | 161 | """ |
95 | 162 | """ | 162 | split = urlparse.urlsplit(url) |
96 | 163 | if re.search(r'^[\w]+://', path): | 163 | return urlparse.urlunsplit(('', '') + split[2:]) |
86 | 164 | return path | ||
87 | 165 | try: | ||
88 | 166 | return 'file://' + urllib.pathname2url(path) | ||
89 | 167 | except IOError: | ||
90 | 168 | return path | ||
97 | 169 | 164 | ||
98 | 170 | class idict(dict): | 165 | class idict(dict): |
99 | 171 | """ | 166 | """ |
100 | 172 | 167 | ||
101 | === modified file 'xl/cover.py' | |||
102 | --- xl/cover.py 2009-03-24 23:16:10 +0000 | |||
103 | +++ xl/cover.py 2009-04-13 21:42:40 +0000 | |||
104 | @@ -456,7 +456,7 @@ | |||
105 | 456 | def find_covers(self, track, limit=-1): | 456 | def find_covers(self, track, limit=-1): |
106 | 457 | covers = [] | 457 | covers = [] |
107 | 458 | try: | 458 | try: |
109 | 459 | search_dir = os.path.dirname(track.get_loc()) | 459 | search_dir = os.path.dirname(track.local_file_name()) |
110 | 460 | except AttributeError: | 460 | except AttributeError: |
111 | 461 | raise NoCoverFoundException() | 461 | raise NoCoverFoundException() |
112 | 462 | 462 | ||
113 | 463 | 463 | ||
114 | === modified file 'xl/metadata/__init__.py' | |||
115 | --- xl/metadata/__init__.py 2009-03-15 04:05:49 +0000 | |||
116 | +++ xl/metadata/__init__.py 2009-04-13 18:38:41 +0000 | |||
117 | @@ -16,6 +16,7 @@ | |||
118 | 16 | 16 | ||
119 | 17 | # do this so formats can inherit from stuff in _base | 17 | # do this so formats can inherit from stuff in _base |
120 | 18 | from _base import * | 18 | from _base import * |
121 | 19 | import urlparse | ||
122 | 19 | 20 | ||
123 | 20 | import asf, flac, mod, mp3, mp4, mpc, ogg, sid, speex, tta, wav, wv | 21 | import asf, flac, mod, mp3, mp4, mpc, ogg, sid, speex, tta, wav, wv |
124 | 21 | 22 | ||
125 | 22 | 23 | ||
126 | === modified file 'xl/metadata/_base.py' | |||
127 | --- xl/metadata/_base.py 2009-01-13 20:22:25 +0000 | |||
128 | +++ xl/metadata/_base.py 2009-04-18 06:01:50 +0000 | |||
129 | @@ -14,6 +14,9 @@ | |||
130 | 14 | 14 | ||
131 | 15 | import os | 15 | import os |
132 | 16 | from xl import common | 16 | from xl import common |
133 | 17 | import urlparse | ||
134 | 18 | import urllib | ||
135 | 19 | import urllib2 | ||
136 | 17 | 20 | ||
137 | 18 | import logging | 21 | import logging |
138 | 19 | logger = logging.getLogger(__name__) | 22 | logger = logging.getLogger(__name__) |
139 | @@ -42,14 +45,22 @@ | |||
140 | 42 | """ | 45 | """ |
141 | 43 | Loads the tags from the file. | 46 | Loads the tags from the file. |
142 | 44 | """ | 47 | """ |
151 | 45 | if self.MutagenType: | 48 | try: |
152 | 46 | try: | 49 | self.url = urllib2.urlopen(self.loc) |
153 | 47 | self.mutagen = self.MutagenType(self.loc) | 50 | except urllib2.URLError, urllib2.HTTPError: |
154 | 48 | except: | 51 | logger.error("Couldn't open url to file %s" % self.loc) |
155 | 49 | logger.error("Couldn't read tags from possibly corrupt " \ | 52 | raise NotReadable |
156 | 50 | "file %s" % self.loc) | 53 | loc = urlparse.urlsplit(self.loc) |
157 | 51 | #common.log_exception(logger) | 54 | if loc[0] == "file": |
158 | 52 | raise NotReadable | 55 | if self.MutagenType: |
159 | 56 | file_loc = common.local_file_from_url(self.loc) | ||
160 | 57 | try: | ||
161 | 58 | self.mutagen = self.MutagenType(file_loc) | ||
162 | 59 | except: | ||
163 | 60 | logger.error("Couldn't read tags from possibly corrupt " \ | ||
164 | 61 | "file %s" % file_loc) | ||
165 | 62 | #common.log_exception(logger) | ||
166 | 63 | raise NotReadable | ||
167 | 53 | 64 | ||
168 | 54 | def save(self): | 65 | def save(self): |
169 | 55 | """ | 66 | """ |
170 | @@ -62,7 +73,8 @@ | |||
171 | 62 | if self.MutagenType: | 73 | if self.MutagenType: |
172 | 63 | return self.mutagen | 74 | return self.mutagen |
173 | 64 | else: | 75 | else: |
175 | 65 | return {'title':os.path.split(self.loc)[-1]} | 76 | path = common.local_file_from_url(self.loc) |
176 | 77 | return {'title':os.path.split(path)[-1]} | ||
177 | 66 | 78 | ||
178 | 67 | def _get_tag(self, raw, tag): | 79 | def _get_tag(self, raw, tag): |
179 | 68 | try: | 80 | try: |
180 | 69 | 81 | ||
181 | === modified file 'xl/player.py' | |||
182 | --- xl/player.py 2009-04-14 18:39:32 +0000 | |||
183 | +++ xl/player.py 2009-04-18 06:01:50 +0000 | |||
184 | @@ -22,7 +22,7 @@ | |||
185 | 22 | 22 | ||
186 | 23 | from xl import common, event, playlist, settings | 23 | from xl import common, event, playlist, settings |
187 | 24 | import random, time, os, logging, urllib | 24 | import random, time, os, logging, urllib |
189 | 25 | from urlparse import urlparse | 25 | import urlparse |
190 | 26 | 26 | ||
191 | 27 | 27 | ||
192 | 28 | try: | 28 | try: |
193 | @@ -446,10 +446,13 @@ | |||
194 | 446 | 446 | ||
195 | 447 | def _get_track_uri(self, track): | 447 | def _get_track_uri(self, track): |
196 | 448 | uri = track.get_loc_for_io() | 448 | uri = track.get_loc_for_io() |
201 | 449 | parsed = urlparse(uri) | 449 | split = urlparse.urlsplit(uri) |
202 | 450 | if parsed[0] == "": | 450 | assert split[0] != "", _("Exaile now uses absolute URI's, please " |
203 | 451 | uri = "file://" + urllib.pathname2url(uri) | 451 | "delete/rename your %s directory") \ |
204 | 452 | uri = uri.encode(common.get_default_encoding()) | 452 | % xdg.data_home |
205 | 453 | path = common.local_file_from_url(uri) | ||
206 | 454 | path = urllib.pathname2url(path) | ||
207 | 455 | uri = urlparse.urlunsplit(split[0:2] + (path, '', '')) | ||
208 | 453 | return uri | 456 | return uri |
209 | 454 | 457 | ||
210 | 455 | def __notify_source(self, *args): | 458 | def __notify_source(self, *args): |
211 | @@ -478,7 +481,7 @@ | |||
212 | 478 | 481 | ||
213 | 479 | # make sure the file exists if this is supposed to be a local track | 482 | # make sure the file exists if this is supposed to be a local track |
214 | 480 | if track.is_local(): | 483 | if track.is_local(): |
216 | 481 | if not os.path.exists(track.get_loc()): | 484 | if not track.exists(): |
217 | 482 | logger.error(_("File does not exist: %s") % | 485 | logger.error(_("File does not exist: %s") % |
218 | 483 | track.get_loc()) | 486 | track.get_loc()) |
219 | 484 | return False | 487 | return False |
220 | @@ -490,7 +493,7 @@ | |||
221 | 490 | self.reset_playtime_stamp() | 493 | self.reset_playtime_stamp() |
222 | 491 | 494 | ||
223 | 492 | self.playbin.set_property("uri", uri) | 495 | self.playbin.set_property("uri", uri) |
225 | 493 | if uri.startswith("cdda://"): | 496 | if urlparse.urlsplit(uri)[0] == "cdda": |
226 | 494 | self.notify_id = self.playbin.connect('notify::source', | 497 | self.notify_id = self.playbin.connect('notify::source', |
227 | 495 | self.__notify_source) | 498 | self.__notify_source) |
228 | 496 | 499 | ||
229 | 497 | 500 | ||
230 | === modified file 'xl/playlist.py' | |||
231 | --- xl/playlist.py 2009-04-14 17:34:36 +0000 | |||
232 | +++ xl/playlist.py 2009-04-14 23:33:28 +0000 | |||
233 | @@ -40,7 +40,7 @@ | |||
234 | 40 | except ImportError: | 40 | except ImportError: |
235 | 41 | import elementtree as ETree | 41 | import elementtree as ETree |
236 | 42 | 42 | ||
238 | 43 | from urlparse import urlparse | 43 | import urlparse |
239 | 44 | import logging | 44 | import logging |
240 | 45 | logger = logging.getLogger(__name__) | 45 | logger = logging.getLogger(__name__) |
241 | 46 | 46 | ||
242 | @@ -209,7 +209,7 @@ | |||
243 | 209 | for track in playlist: | 209 | for track in playlist: |
244 | 210 | handle.write("<entry>\n") | 210 | handle.write("<entry>\n") |
245 | 211 | handle.write(" <title>%s</title>\n" % track['title']) | 211 | handle.write(" <title>%s</title>\n" % track['title']) |
247 | 212 | handle.write(" <ref href=\"%s\" />\n" % urllib.quote(track.get_loc())) | 212 | handle.write(" <ref href=\"%s\" />\n" % track.get_loc()) |
248 | 213 | handle.write("</entry>\n") | 213 | handle.write("</entry>\n") |
249 | 214 | 214 | ||
250 | 215 | handle.write("</asx>") | 215 | handle.write("</asx>") |
251 | @@ -222,7 +222,7 @@ | |||
252 | 222 | pl = Playlist(name=name) | 222 | pl = Playlist(name=name) |
253 | 223 | for t in tracks: | 223 | for t in tracks: |
254 | 224 | tr = track.Track() | 224 | tr = track.Track() |
256 | 225 | loc = urllib.unquote(t.find("ref").get("href")) | 225 | loc = t.find("ref").get("href") |
257 | 226 | tr.set_loc(loc) | 226 | tr.set_loc(loc) |
258 | 227 | tr['title'] = t.find("title").text.strip() | 227 | tr['title'] = t.find("title").text.strip() |
259 | 228 | tr.read_tags() | 228 | tr.read_tags() |
260 | @@ -254,11 +254,8 @@ | |||
261 | 254 | if track[tag] == u"": | 254 | if track[tag] == u"": |
262 | 255 | continue | 255 | continue |
263 | 256 | handle.write(" <%s>%s</%s>\n" % (xs, track[tag],xs) ) | 256 | handle.write(" <%s>%s</%s>\n" % (xs, track[tag],xs) ) |
269 | 257 | url = urllib.quote(track.get_loc()) | 257 | url = track.get_loc() |
270 | 258 | if urlparse(track.get_loc())[0] == "": | 258 | handle.write(" <location>%s</location>\n" % url) |
266 | 259 | handle.write(" <location>file://%s</location>\n" % url) | ||
267 | 260 | else: | ||
268 | 261 | handle.write(" <location>%s</location>\n" % url) | ||
271 | 262 | handle.write(" </track>\n") | 259 | handle.write(" </track>\n") |
272 | 263 | 260 | ||
273 | 264 | handle.write(" </trackList>\n") | 261 | handle.write(" </trackList>\n") |
274 | @@ -274,7 +271,7 @@ | |||
275 | 274 | pl = Playlist(name=name) | 271 | pl = Playlist(name=name) |
276 | 275 | for t in tracks: | 272 | for t in tracks: |
277 | 276 | tr = track.Track() | 273 | tr = track.Track() |
279 | 277 | loc = urllib.unquote(t.find("%slocation"%ns).text.strip()) | 274 | loc = t.find("%slocation"%ns).text.strip() |
280 | 278 | tr.set_loc(loc) | 275 | tr.set_loc(loc) |
281 | 279 | for xs, tag in XSPF_MAPPING.iteritems(): | 276 | for xs, tag in XSPF_MAPPING.iteritems(): |
282 | 280 | try: | 277 | try: |
283 | @@ -441,7 +438,7 @@ | |||
284 | 441 | track: the track to add [Track] | 438 | track: the track to add [Track] |
285 | 442 | location: the index to insert at [int] | 439 | location: the index to insert at [int] |
286 | 443 | """ | 440 | """ |
288 | 444 | if os.path.exists(track.get_loc_for_io()) or not ignore_missing_files: | 441 | if track.exists() or not ignore_missing_files: |
289 | 445 | self.add_tracks([track], location) | 442 | self.add_tracks([track], location) |
290 | 446 | 443 | ||
291 | 447 | def add_tracks(self, tracks, location=None, add_duplicates=True): | 444 | def add_tracks(self, tracks, location=None, add_duplicates=True): |
292 | 448 | 445 | ||
293 | === modified file 'xl/track.py' | |||
294 | --- xl/track.py 2009-03-24 23:16:10 +0000 | |||
295 | +++ xl/track.py 2009-04-18 06:01:50 +0000 | |||
296 | @@ -20,6 +20,9 @@ | |||
297 | 20 | import xl.metadata as metadata | 20 | import xl.metadata as metadata |
298 | 21 | from xl.common import lstrip_special | 21 | from xl.common import lstrip_special |
299 | 22 | import logging, traceback | 22 | import logging, traceback |
300 | 23 | import urlparse | ||
301 | 24 | import urllib | ||
302 | 25 | import urllib2 | ||
303 | 23 | logger = logging.getLogger(__name__) | 26 | logger = logging.getLogger(__name__) |
304 | 24 | 27 | ||
305 | 25 | settings = settings.SettingsManager.settings | 28 | settings = settings.SettingsManager.settings |
306 | @@ -61,8 +64,10 @@ | |||
307 | 61 | 64 | ||
308 | 62 | loc: the location [string] | 65 | loc: the location [string] |
309 | 63 | """ | 66 | """ |
312 | 64 | if loc.startswith("file://"): | 67 | split = urlparse.urlsplit(loc) |
313 | 65 | loc = loc[7:] | 68 | if split[0] == "": |
314 | 69 | loc = os.path.abspath(loc) | ||
315 | 70 | loc = urlparse.urlunsplit(('file', split[1], loc, '', '')) | ||
316 | 66 | self['loc'] = loc | 71 | self['loc'] = loc |
317 | 67 | 72 | ||
318 | 68 | def get_loc(self): | 73 | def get_loc(self): |
319 | @@ -77,6 +82,22 @@ | |||
320 | 77 | except: | 82 | except: |
321 | 78 | return self['loc'] | 83 | return self['loc'] |
322 | 79 | 84 | ||
323 | 85 | def exists(self): | ||
324 | 86 | if self.is_local(): | ||
325 | 87 | return os.path.exists(self.local_file_name()) | ||
326 | 88 | else: | ||
327 | 89 | try: | ||
328 | 90 | urllib2.urlopen(self.get_loc_for_io()) | ||
329 | 91 | except urllib2.URLError, urllib2.HTTPError: | ||
330 | 92 | return False | ||
331 | 93 | else: | ||
332 | 94 | return True | ||
333 | 95 | |||
334 | 96 | def local_file_name(self): | ||
335 | 97 | if not self.is_local(): | ||
336 | 98 | return None | ||
337 | 99 | return common.local_file_from_url(self.get_loc_for_io()) | ||
338 | 100 | |||
339 | 80 | def get_loc_for_io(self): | 101 | def get_loc_for_io(self): |
340 | 81 | """ | 102 | """ |
341 | 82 | Gets the location in its original form. should always be correct. | 103 | Gets the location in its original form. should always be correct. |
342 | @@ -207,9 +228,11 @@ | |||
343 | 207 | 228 | ||
344 | 208 | 229 | ||
345 | 209 | # fill out file specific items | 230 | # fill out file specific items |
347 | 210 | mtime = os.path.getmtime(self.get_loc_for_io()) | 231 | split = urlparse.urlsplit(self.get_loc_for_io()) |
348 | 232 | path = self.local_file_name() | ||
349 | 233 | mtime = os.path.getmtime(path) | ||
350 | 211 | self['modified'] = mtime | 234 | self['modified'] = mtime |
352 | 212 | self['basedir'] = os.path.dirname(self.get_loc_for_io()) | 235 | self['basedir'] = os.path.dirname(path) |
353 | 213 | self._dirty = True | 236 | self._dirty = True |
354 | 214 | return f | 237 | return f |
355 | 215 | except: | 238 | except: |
356 | @@ -217,7 +240,7 @@ | |||
357 | 217 | return False | 240 | return False |
358 | 218 | 241 | ||
359 | 219 | def is_local(self): | 242 | def is_local(self): |
361 | 220 | return urlparse(self.get_loc())[0] == "" | 243 | return urlparse.urlsplit(self.get_loc()).scheme == "file" |
362 | 221 | 244 | ||
363 | 222 | def get_track(self): | 245 | def get_track(self): |
364 | 223 | """ | 246 | """ |
Forces exaile to only keep full absolute URI's internally.
Because of the unicode issue, tracks store a "file:///path" in unicode with no escaped characters, rather than a properly urlencoded one. This is so that we can look up the unicode os path again later. The player has to deal with any issues that come out of that when passing to gstreamer. All paths also become absolute rather than relative since absolute uri's are by definition absolute.
This branch will cause all users to have to delete their database and, more likely, nuke their ~/.local/ share/exaile folder. This was discussed as acceptable on IRC since we are still in Alpha