Merge lp:~linkinpark342/exaile/fullurl into lp:exaile/0.3.3

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
Reviewer Review Type Date Requested Status
Adam Olsen Approve
Review via email: mp+5683@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Abhishek Mukherjee (linkinpark342) wrote :

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

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
=== modified file 'xl/collection.py'
--- xl/collection.py 2009-03-18 21:59:28 +0000
+++ xl/collection.py 2009-04-13 21:34:43 +0000
@@ -28,6 +28,7 @@
2828
29import os, time, os.path, shutil, logging29import os, time, os.path, shutil, logging
30import gobject30import gobject
31import urllib
3132
32logger = logging.getLogger(__name__)33logger = logging.getLogger(__name__)
3334
@@ -504,23 +505,24 @@
504 ccheck = {} # compilations dict505 ccheck = {} # compilations dict
505506
506 count = 0507 count = 0
507 for folder in os.walk(self.location):508 for basepath, dirnames, filenames in os.walk(self.location):
508 basepath = folder[0]509 for filename in filenames:
509 for filename in folder[2]:
510 if self.collection:510 if self.collection:
511 if self.collection._scan_stopped: 511 if self.collection._scan_stopped:
512 self.scanning = False512 self.scanning = False
513 return False513 return False
514 count += 1514 count += 1
515 fullpath = os.path.join(basepath, filename)515 path = os.path.abspath(os.path.join(basepath, filename))
516 fullpath = "file://" + path
516517
517 try:518 try:
518 trmtime = db.get_track_attr(fullpath, "modified")519 trmtime = db.get_track_attr(fullpath, "modified")
519 mtime = os.path.getmtime(fullpath)520 except:
521 pass
522 else:
523 mtime = os.path.getmtime(path)
520 if mtime == trmtime:524 if mtime == trmtime:
521 continue525 continue
522 except:
523 pass
524526
525 tr = db.get_track_by_loc(fullpath)527 tr = db.get_track_by_loc(fullpath)
526 if tr:528 if tr:
@@ -553,6 +555,7 @@
553 if not os.path.exists(f):555 if not os.path.exists(f):
554 removals.append(db.get_track_by_loc(f))556 removals.append(db.get_track_by_loc(f))
555 for tr in removals:557 for tr in removals:
558 logging.info(u"Removing " + unicode(tr))
556 db.remove(tr)559 db.remove(tr)
557560
558 self.scanning = False561 self.scanning = False
@@ -625,8 +628,9 @@
625 tr = self.collection.get_track_by_loc(loc)628 tr = self.collection.get_track_by_loc(loc)
626 if tr:629 if tr:
627 self.collection.remove(tr)630 self.collection.remove(tr)
631 path = common.local_file_from_url(tr.get_loc_for_io())
628 try:632 try:
629 os.unlink(tr.get_loc_for_io())633 os.unlink(path)
630 except OSError: # file not found?634 except OSError: # file not found?
631 pass635 pass
632 except:636 except:
633637
=== modified file 'xl/common.py'
--- xl/common.py 2008-12-28 17:58:55 +0000
+++ xl/common.py 2009-04-13 20:21:28 +0000
@@ -14,7 +14,7 @@
14# along with this program; if not, write to the Free Software14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.15# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1616
17import locale, os, time, threading, urllib, re, random, string17import locale, os, time, threading, urllib, re, random, string, urlparse
18import traceback18import traceback
19import logging19import logging
2020
@@ -155,17 +155,12 @@
155 text = text.replace(old, new)155 text = text.replace(old, new)
156 return text156 return text
157157
158def to_url(path):158def local_file_from_url(url):
159 """159 """
160 Converts filesystem path to URL. Returns the input unchanged if it's not160 Returns a local file path based on a url
161 an FS path (i.e. a URL or something invalid).161 """
162 """162 split = urlparse.urlsplit(url)
163 if re.search(r'^[\w]+://', path):163 return urlparse.urlunsplit(('', '') + split[2:])
164 return path
165 try:
166 return 'file://' + urllib.pathname2url(path)
167 except IOError:
168 return path
169164
170class idict(dict): 165class idict(dict):
171 """166 """
172167
=== modified file 'xl/cover.py'
--- xl/cover.py 2009-03-24 23:16:10 +0000
+++ xl/cover.py 2009-04-13 21:42:40 +0000
@@ -456,7 +456,7 @@
456 def find_covers(self, track, limit=-1):456 def find_covers(self, track, limit=-1):
457 covers = []457 covers = []
458 try:458 try:
459 search_dir = os.path.dirname(track.get_loc())459 search_dir = os.path.dirname(track.local_file_name())
460 except AttributeError:460 except AttributeError:
461 raise NoCoverFoundException()461 raise NoCoverFoundException()
462462
463463
=== modified file 'xl/metadata/__init__.py'
--- xl/metadata/__init__.py 2009-03-15 04:05:49 +0000
+++ xl/metadata/__init__.py 2009-04-13 18:38:41 +0000
@@ -16,6 +16,7 @@
1616
17# do this so formats can inherit from stuff in _base17# do this so formats can inherit from stuff in _base
18from _base import *18from _base import *
19import urlparse
1920
20import asf, flac, mod, mp3, mp4, mpc, ogg, sid, speex, tta, wav, wv21import asf, flac, mod, mp3, mp4, mpc, ogg, sid, speex, tta, wav, wv
2122
2223
=== modified file 'xl/metadata/_base.py'
--- xl/metadata/_base.py 2009-01-13 20:22:25 +0000
+++ xl/metadata/_base.py 2009-04-18 06:01:50 +0000
@@ -14,6 +14,9 @@
1414
15import os15import os
16from xl import common16from xl import common
17import urlparse
18import urllib
19import urllib2
1720
18import logging21import logging
19logger = logging.getLogger(__name__)22logger = logging.getLogger(__name__)
@@ -42,14 +45,22 @@
42 """45 """
43 Loads the tags from the file.46 Loads the tags from the file.
44 """47 """
45 if self.MutagenType:48 try:
46 try:49 self.url = urllib2.urlopen(self.loc)
47 self.mutagen = self.MutagenType(self.loc)50 except urllib2.URLError, urllib2.HTTPError:
48 except:51 logger.error("Couldn't open url to file %s" % self.loc)
49 logger.error("Couldn't read tags from possibly corrupt " \52 raise NotReadable
50 "file %s" % self.loc)53 loc = urlparse.urlsplit(self.loc)
51 #common.log_exception(logger)54 if loc[0] == "file":
52 raise NotReadable55 if self.MutagenType:
56 file_loc = common.local_file_from_url(self.loc)
57 try:
58 self.mutagen = self.MutagenType(file_loc)
59 except:
60 logger.error("Couldn't read tags from possibly corrupt " \
61 "file %s" % file_loc)
62 #common.log_exception(logger)
63 raise NotReadable
5364
54 def save(self):65 def save(self):
55 """66 """
@@ -62,7 +73,8 @@
62 if self.MutagenType:73 if self.MutagenType:
63 return self.mutagen 74 return self.mutagen
64 else:75 else:
65 return {'title':os.path.split(self.loc)[-1]}76 path = common.local_file_from_url(self.loc)
77 return {'title':os.path.split(path)[-1]}
6678
67 def _get_tag(self, raw, tag):79 def _get_tag(self, raw, tag):
68 try:80 try:
6981
=== modified file 'xl/player.py'
--- xl/player.py 2009-04-14 18:39:32 +0000
+++ xl/player.py 2009-04-18 06:01:50 +0000
@@ -22,7 +22,7 @@
2222
23from xl import common, event, playlist, settings23from xl import common, event, playlist, settings
24import random, time, os, logging, urllib24import random, time, os, logging, urllib
25from urlparse import urlparse25import urlparse
2626
2727
28try:28try:
@@ -446,10 +446,13 @@
446446
447 def _get_track_uri(self, track):447 def _get_track_uri(self, track):
448 uri = track.get_loc_for_io()448 uri = track.get_loc_for_io()
449 parsed = urlparse(uri)449 split = urlparse.urlsplit(uri)
450 if parsed[0] == "":450 assert split[0] != "", _("Exaile now uses absolute URI's, please "
451 uri = "file://" + urllib.pathname2url(uri)451 "delete/rename your %s directory") \
452 uri = uri.encode(common.get_default_encoding())452 % xdg.data_home
453 path = common.local_file_from_url(uri)
454 path = urllib.pathname2url(path)
455 uri = urlparse.urlunsplit(split[0:2] + (path, '', ''))
453 return uri456 return uri
454457
455 def __notify_source(self, *args):458 def __notify_source(self, *args):
@@ -478,7 +481,7 @@
478481
479 # make sure the file exists if this is supposed to be a local track482 # make sure the file exists if this is supposed to be a local track
480 if track.is_local():483 if track.is_local():
481 if not os.path.exists(track.get_loc()):484 if not track.exists():
482 logger.error(_("File does not exist: %s") % 485 logger.error(_("File does not exist: %s") %
483 track.get_loc())486 track.get_loc())
484 return False487 return False
@@ -490,7 +493,7 @@
490 self.reset_playtime_stamp()493 self.reset_playtime_stamp()
491494
492 self.playbin.set_property("uri", uri)495 self.playbin.set_property("uri", uri)
493 if uri.startswith("cdda://"):496 if urlparse.urlsplit(uri)[0] == "cdda":
494 self.notify_id = self.playbin.connect('notify::source',497 self.notify_id = self.playbin.connect('notify::source',
495 self.__notify_source)498 self.__notify_source)
496499
497500
=== modified file 'xl/playlist.py'
--- xl/playlist.py 2009-04-14 17:34:36 +0000
+++ xl/playlist.py 2009-04-14 23:33:28 +0000
@@ -40,7 +40,7 @@
40 except ImportError:40 except ImportError:
41 import elementtree as ETree41 import elementtree as ETree
4242
43from urlparse import urlparse43import urlparse
44import logging44import logging
45logger = logging.getLogger(__name__)45logger = logging.getLogger(__name__)
4646
@@ -209,7 +209,7 @@
209 for track in playlist:209 for track in playlist:
210 handle.write("<entry>\n")210 handle.write("<entry>\n")
211 handle.write(" <title>%s</title>\n" % track['title'])211 handle.write(" <title>%s</title>\n" % track['title'])
212 handle.write(" <ref href=\"%s\" />\n" % urllib.quote(track.get_loc()))212 handle.write(" <ref href=\"%s\" />\n" % track.get_loc())
213 handle.write("</entry>\n")213 handle.write("</entry>\n")
214 214
215 handle.write("</asx>")215 handle.write("</asx>")
@@ -222,7 +222,7 @@
222 pl = Playlist(name=name)222 pl = Playlist(name=name)
223 for t in tracks:223 for t in tracks:
224 tr = track.Track()224 tr = track.Track()
225 loc = urllib.unquote(t.find("ref").get("href"))225 loc = t.find("ref").get("href")
226 tr.set_loc(loc)226 tr.set_loc(loc)
227 tr['title'] = t.find("title").text.strip()227 tr['title'] = t.find("title").text.strip()
228 tr.read_tags()228 tr.read_tags()
@@ -254,11 +254,8 @@
254 if track[tag] == u"":254 if track[tag] == u"":
255 continue255 continue
256 handle.write(" <%s>%s</%s>\n" % (xs, track[tag],xs) )256 handle.write(" <%s>%s</%s>\n" % (xs, track[tag],xs) )
257 url = urllib.quote(track.get_loc())257 url = track.get_loc()
258 if urlparse(track.get_loc())[0] == "":258 handle.write(" <location>%s</location>\n" % url)
259 handle.write(" <location>file://%s</location>\n" % url)
260 else:
261 handle.write(" <location>%s</location>\n" % url)
262 handle.write(" </track>\n")259 handle.write(" </track>\n")
263 260
264 handle.write(" </trackList>\n")261 handle.write(" </trackList>\n")
@@ -274,7 +271,7 @@
274 pl = Playlist(name=name)271 pl = Playlist(name=name)
275 for t in tracks:272 for t in tracks:
276 tr = track.Track()273 tr = track.Track()
277 loc = urllib.unquote(t.find("%slocation"%ns).text.strip())274 loc = t.find("%slocation"%ns).text.strip()
278 tr.set_loc(loc)275 tr.set_loc(loc)
279 for xs, tag in XSPF_MAPPING.iteritems():276 for xs, tag in XSPF_MAPPING.iteritems():
280 try:277 try:
@@ -441,7 +438,7 @@
441 track: the track to add [Track]438 track: the track to add [Track]
442 location: the index to insert at [int]439 location: the index to insert at [int]
443 """440 """
444 if os.path.exists(track.get_loc_for_io()) or not ignore_missing_files:441 if track.exists() or not ignore_missing_files:
445 self.add_tracks([track], location)442 self.add_tracks([track], location)
446443
447 def add_tracks(self, tracks, location=None, add_duplicates=True):444 def add_tracks(self, tracks, location=None, add_duplicates=True):
448445
=== modified file 'xl/track.py'
--- xl/track.py 2009-03-24 23:16:10 +0000
+++ xl/track.py 2009-04-18 06:01:50 +0000
@@ -20,6 +20,9 @@
20import xl.metadata as metadata20import xl.metadata as metadata
21from xl.common import lstrip_special21from xl.common import lstrip_special
22import logging, traceback22import logging, traceback
23import urlparse
24import urllib
25import urllib2
23logger = logging.getLogger(__name__)26logger = logging.getLogger(__name__)
2427
25settings = settings.SettingsManager.settings28settings = settings.SettingsManager.settings
@@ -61,8 +64,10 @@
61 64
62 loc: the location [string]65 loc: the location [string]
63 """66 """
64 if loc.startswith("file://"):67 split = urlparse.urlsplit(loc)
65 loc = loc[7:]68 if split[0] == "":
69 loc = os.path.abspath(loc)
70 loc = urlparse.urlunsplit(('file', split[1], loc, '', ''))
66 self['loc'] = loc71 self['loc'] = loc
67 72
68 def get_loc(self):73 def get_loc(self):
@@ -77,6 +82,22 @@
77 except:82 except:
78 return self['loc']83 return self['loc']
7984
85 def exists(self):
86 if self.is_local():
87 return os.path.exists(self.local_file_name())
88 else:
89 try:
90 urllib2.urlopen(self.get_loc_for_io())
91 except urllib2.URLError, urllib2.HTTPError:
92 return False
93 else:
94 return True
95
96 def local_file_name(self):
97 if not self.is_local():
98 return None
99 return common.local_file_from_url(self.get_loc_for_io())
100
80 def get_loc_for_io(self):101 def get_loc_for_io(self):
81 """102 """
82 Gets the location in its original form. should always be correct.103 Gets the location in its original form. should always be correct.
@@ -207,9 +228,11 @@
207 228
208229
209 # fill out file specific items230 # fill out file specific items
210 mtime = os.path.getmtime(self.get_loc_for_io())231 split = urlparse.urlsplit(self.get_loc_for_io())
232 path = self.local_file_name()
233 mtime = os.path.getmtime(path)
211 self['modified'] = mtime234 self['modified'] = mtime
212 self['basedir'] = os.path.dirname(self.get_loc_for_io())235 self['basedir'] = os.path.dirname(path)
213 self._dirty = True236 self._dirty = True
214 return f237 return f
215 except:238 except:
@@ -217,7 +240,7 @@
217 return False240 return False
218241
219 def is_local(self):242 def is_local(self):
220 return urlparse(self.get_loc())[0] == ""243 return urlparse.urlsplit(self.get_loc()).scheme == "file"
221244
222 def get_track(self):245 def get_track(self):
223 """246 """