def scan(self, paths, exclude=[], cofuncid=None): added = [] exclude = [expanduser(path) for path in exclude if path] def need_yield(last_yield=[0]): current = time.time() if abs(current - last_yield[0]) > 0.015: last_yield[0] = current return True return False def need_added(last_added=[0]): current = time.time() if abs(current - last_added[0]) > 1.0: last_added[0] = current return True return False for fullpath in paths: print_d("Scanning %r." % fullpath, self) desc = _("Scanning %s") % (unexpand(fsdecode(fullpath))) with Task(_("Library"), desc) as task: if cofuncid: task.copool(cofuncid) fullpath = expanduser(fullpath) if filter(fullpath.startswith, exclude): continue for path, dnames, fnames in os.walk(fullpath): for filename in fnames: fullfilename = os.path.join(path, filename) if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: fullfilename = os.path.realpath(fullfilename) # skip unknown file extensions if not formats.filter(fullfilename): continue if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: item = self.add_filename(fullfilename, False) if item is not None: added.append(item) if len(added) > 100 or need_added(): self.add(added) added = [] task.pulse() yield if added and need_yield(): yield if added: self.add(added) added = [] task.pulse() yield True
def do_import(parent, library): db_path = expanduser(BansheeImport.USR_PATH) importer = BansheeDBImporter(library) try: db = sqlite3.connect(db_path) importer.read(db) db.close() except sqlite3.OperationalError: msg = _("Specified Banshee database is malformed or missing") WarningMessage(parent, BansheeImport.PLUGIN_NAME, msg).run() except Exception: util.print_exc() importer.finish() msg = _("Import Failed") # FIXME: don't depend on the plugin class here ErrorMessage(parent, BansheeImport.PLUGIN_NAME, msg).run() else: count = importer.finish() msg = ngettext( "Successfully imported ratings and statistics for %d song", "Successfully imported ratings and statistics for %d songs", count) % count Message(Gtk.MessageType.INFO, parent, BansheeImport.PLUGIN_NAME, msg).run()
def _post(self, value, song, keep_extension=True): if value: assert isinstance(value, unicode) value = fsnative(value) if keep_extension: fn = song.get("~filename", ".") ext = fn[fn.rfind("."):].lower() val_ext = value[-len(ext):].lower() if not ext == val_ext: value += ext.lower() if os.name == "nt": assert isinstance(value, unicode) value = strip_win32_incompat_from_path(value) value = expanduser(value) # Limit each path section to 255 (bytes on linux, chars on win). # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits path, ext = os.path.splitext(value) path = path.split(sep) limit = [255] * len(path) limit[-1] -= len(ext) elip = lambda (p, l): (len(p) > l and p[:l - 2] + "..") or p path = sep.join(map(elip, zip(path, limit))) value = path + ext if sep in value and not os.path.isabs(value): raise ValueError("Pattern is not rooted") return value
class Tunexpand(TestCase): d = expanduser("~") u = unexpand(d) def test_base(self): path = unexpand(self.d) if is_win: self.failUnlessEqual(path, "%USERPROFILE%") else: self.failUnlessEqual(path, "~") def test_only_profile_case(self): assert isinstance(unexpand(expanduser(fsnative(u"~"))), fsnative) def test_base_trailing(self): path = unexpand(self.d + os.path.sep) self.failUnlessEqual(path, self.u + os.path.sep) def test_noprefix(self): path = unexpand(self.d + "foobar" + os.path.sep) self.failUnlessEqual(path, self.d + "foobar" + os.path.sep) def test_subfile(self): path = unexpand(os.path.join(self.d, "la", "la")) self.failUnlessEqual(path, os.path.join(self.u, "la", "la"))
def lyric_filename(self): """Returns the (potential) lyrics filename for this file""" # TODO: Use better filesystem sanitisation for lyrics file path. filename = self.comma("title").replace('/', '')[:128] + '.lyric' sub_dir = ((self.comma("lyricist") or self.comma("artist")) .replace('/', '')[:128]) path = os.path.join(expanduser("~/.lyrics"), sub_dir, filename) return fsencode(path)
def scan(self, paths, exclude=[], cofuncid=None): added = [] exclude = [expanduser(path) for path in exclude if path] for fullpath in paths: print_d("Scanning %r." % fullpath, self) desc = _("Scanning %s") % (unexpand(fsdecode(fullpath))) with Task(_("Library"), desc) as task: if cofuncid: task.copool(cofuncid) fullpath = expanduser(fullpath) if filter(fullpath.startswith, exclude): continue for path, dnames, fnames in os.walk(util.fsnative(fullpath)): for filename in fnames: fullfilename = os.path.join(path, filename) if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: fullfilename = os.path.realpath(fullfilename) # skip unknown file extensions if not formats.filter(fullfilename): continue if filter(fullfilename.startswith, exclude): continue if fullfilename not in self._contents: item = self.add_filename(fullfilename, False) if item is not None: added.append(item) if len(added) > 20: self.add(added) added = [] task.pulse() yield True if added: self.add(added) added = [] task.pulse() yield True
def expand_pathfile(rpf): """Return the expanded RootPathFile""" expanded = [] root = expanduser(rpf.root) pathfile = expanduser(rpf.pathfile) if rx_params.search(pathfile): root = expand_patterns(root).format(self) pathfile = expand_patterns(pathfile).format(self) rpf = RootPathFile(root, pathfile) expanded.append(rpf) if not os.path.exists(pathfile) and is_windows(): # prioritise a special character encoded version # # most 'alien' chars are supported for 'nix fs paths, and we # only pass the proposed path through 'escape_filename' (which # apparently doesn't respect case) if we don't care about case! # # FIX: assumes 'nix build used on a case-sensitive fs, nt case # insensitive. clearly this is not biting anyone though (yet!) pathfile = os.path.sep.join([rpf.root, rpf.end_escaped]) rpf = RootPathFile(rpf.root, pathfile) expanded.insert(len(expanded) - 1, rpf) return expanded
def do_import(parent, library): db_path = expanduser("~/.local/share/rhythmbox/rhythmdb.xml") handler = RBDBContentHandler(library) try: xml.sax.parse(db_path, handler) except Exception: util.print_exc() handler.finish() msg = _("Import Failed") # FIXME: don't depend on the plugin class here.. ErrorMessage(parent, RBImport.PLUGIN_NAME, msg).run() else: count = handler.finish() msg = _("Successfully imported ratings and statistics " "for %d songs") % count # FIXME: this is just a warning so it works with older QL WarningMessage(parent, RBImport.PLUGIN_NAME, msg).run()
def lyric_filename(self): """Returns the (potential) lyrics filename for this file""" filename = self.comma("title").replace(u"/", u"")[:128] + u".lyric" sub_dir = (self.comma("lyricist") or self.comma("artist")).replace(u"/", u"")[:128] if os.name == "nt": # this was added at a later point. only use escape_filename here # to keep the linux case the same as before filename = escape_filename(filename) sub_dir = escape_filename(sub_dir) else: filename = fsnative(filename) sub_dir = fsnative(sub_dir) path = os.path.join(expanduser(fsnative(u"~/.lyrics")), sub_dir, filename) return path
def do_import(parent, library): plist_path = expanduser("~/Music/iTunes/iTunes Music Library.xml") importer = iTunesimporter(library) try: plist = plistlib.readPlist(plist_path) importer.read(plist) except Exception: util.print_exc() importer.finish() msg = _("Import Failed") # FIXME: don't depend on the plugin class here.. ErrorMessage(parent, iTunesImport.PLUGIN_NAME, msg).run() else: count = importer.finish() msg = _("Successfully imported ratings and statistics " "for %d songs") % count # FIXME: this is just a warning so it works with older QL WarningMessage(parent, iTunesimport.PLUGIN_NAME, msg).run()
def lyric_filename(self): """Returns the (potential) lyrics filename for this file""" filename = self.comma("title").replace(u'/', u'')[:128] + u'.lyric' sub_dir = ((self.comma("lyricist") or self.comma("artist")).replace(u'/', u'')[:128]) if os.name == "nt": # this was added at a later point. only use escape_filename here # to keep the linux case the same as before filename = escape_filename(filename) sub_dir = escape_filename(sub_dir) else: filename = fsnative(filename) sub_dir = fsnative(sub_dir) path = os.path.join(expanduser(fsnative(u"~/.lyrics")), sub_dir, filename) return path
def _post(self, value, song, keep_extension=True): if value: assert isinstance(value, unicode) value = fsnative(value) if keep_extension: fn = song.get("~filename", ".") ext = fn[fn.rfind(".") :].lower() val_ext = value[-len(ext) :].lower() if not ext == val_ext: value += ext.lower() if os.name == "nt": assert isinstance(value, unicode) value = strip_win32_incompat_from_path(value) value = expanduser(value) value = limit_path(value) if sep in value and not os.path.isabs(value): raise ValueError("Pattern is not rooted") return value
def _post(self, value, song, keep_extension=True): if value: assert isinstance(value, unicode) value = fsnative(value) if keep_extension: fn = song.get("~filename", ".") ext = fn[fn.rfind("."):].lower() val_ext = value[-len(ext):].lower() if not ext == val_ext: value += ext.lower() if os.name == "nt": assert isinstance(value, unicode) value = strip_win32_incompat_from_path(value) value = expanduser(value) value = limit_path(value) if sep in value and not os.path.isabs(value): raise ValueError("Pattern is not rooted") return value
def test_only_profile_case(self): assert isinstance(unexpand(expanduser(fsnative(u"~"))), fsnative)
def query(category, discid, xcode='utf8:utf8'): discinfo = {} tracktitles = {} dump = path.join(expanduser("~"), '.cddb', category, discid) try: for line in file(dump): if line.startswith("TTITLE"): track, title = line.split("=", 1) try: track = int(track[6:]) except (ValueError): pass else: tracktitles[track] = \ title.decode('utf-8', 'replace').strip() elif line.startswith("DGENRE"): discinfo['genre'] = line.split('=', 1)[1].strip() elif line.startswith("DTITLE"): dtitle = line.split('=', 1)[1].strip().split(' / ', 1) if len(dtitle) == 2: discinfo['artist'], discinfo['title'] = dtitle else: discinfo['title'] = dtitle[0].strip() elif line.startswith("DYEAR"): discinfo['year'] = line.split('=', 1)[1].strip() except EnvironmentError: pass else: return discinfo, tracktitles read, info = CDDB.read(category, discid, **CLIENTINFO) if read != 210: return None try: os.makedirs(path.join(expanduser("~"), '.cddb')) except EnvironmentError: pass try: save = file(dump, 'w') keys = info.keys() keys.sort() for key in keys: print>>save, "%s=%s" % (key, info[key]) save.close() except EnvironmentError: pass xf, xt = xcode.split(':') for key, value in info.iteritems(): try: value = value.decode('utf-8', 'replace').strip().encode( xf, 'replace').decode(xt, 'replace') except AttributeError: pass if key.startswith('TTITLE'): try: tracktitles[int(key[6:])] = value except ValueError: pass elif key == 'DGENRE': discinfo['genre'] = value elif key == 'DTITLE': dtitle = value.strip().split(' / ', 1) if len(dtitle) == 2: discinfo['artist'], discinfo['title'] = dtitle else: discinfo['title'] = dtitle[0].strip() elif key == 'DYEAR': discinfo['year'] = value return discinfo, tracktitles