def reload(): for name, module in sys.modules.items(): if name == '__main__' or module == None: continue if name.startswith("quodlibet."): name = name.replace(".", os.sep) filename = os.path.join(const.BASEDIR, name[name.find(os.sep)+1:]) py = filename + ".py" pyc = filename + ".pyc" if util.mtime(pyc) and util.mtime(pyc) < util.mtime(py): try: __reloadmodule(module) except ImportError: pass else: print_d("Reloading %s" % name)
def __changed(self, selector, selection, label): model, rows = selection.get_selected_rows() files = [] if len(rows) < 2: count = len(model or []) else: count = len(rows) label.set_text(ngettext("%d song", "%d songs", count) % count) for row in rows: filename = util.fsnative(model[row][0]) if not os.path.exists(filename): pass elif filename in self.__library: file = self.__library[filename] if file("~#mtime") + 1. < util.mtime(filename): try: file.reload() except StandardError: pass files.append(file) else: files.append(formats.MusicFile(filename)) files = filter(None, files) if len(files) == 0: self.set_title("Ex Falso") elif len(files) == 1: self.set_title("%s - Ex Falso" % files[0].comma("title")) else: self.set_title( "%s - Ex Falso" % (ngettext("%(title)s and %(count)d more", "%(title)s and %(count)d more", len(files) - 1) % ( {'title': files[0].comma("title"), 'count': len(files) - 1}))) self.__library.add(files) self.emit('changed', files)
def test_thumb(s): thumb = thumbnails.get_thumbnail(s.filename, (50, 60)) #check for right scaling s.failUnless(thumb) s.failUnlessEqual((thumb.get_width(), thumb.get_height()), (50, 3)) #test the thumbnail filename uri = "file://" + urllib.pathname2url(s.filename) name = hash.md5(uri).hexdigest() + ".png" path = os.path.expanduser("~/.thumbnails") # newer spec new_path = os.path.expanduser("~/.cache/thumbnails") if os.path.exists(new_path): path = new_path path = os.path.join(path, "normal", name) s.failUnless(os.path.isfile(path)) #check for metadata thumb_pb = gtk.gdk.pixbuf_new_from_file(path) meta_mtime = thumb_pb.get_option("tEXt::Thumb::MTime") meta_uri = thumb_pb.get_option("tEXt::Thumb::URI") s.failUnlessEqual(int(meta_mtime), int(mtime(s.filename))) s.failUnlessEqual(meta_uri, uri) #check rights s.failUnlessEqual(os.stat(path).st_mode, 33152)
def deps_changed(old_list, new_list): if set(old_list) != set(new_list): return True for dep in old_list: old_mtime = self.__deps[dep] if util.mtime(dep) != old_mtime: return True return False
def save(force=False): """Save all registered libraries that have a filename and are marked dirty. If force = True save all of them blocking, else save non blocking and only if they were last saved more than 15 minutes ago. """ global librarian print_d("Saving all libraries...") for lib in librarian.libraries.values(): filename = lib.filename if not filename or not lib.dirty: continue if force: try: lib.save() except EnvironmentError: pass lib.destroy() elif (time.time() - util.mtime(filename)) > 15 * 60: # 15 minutes threading.Thread(target=lib.save).run()
def _file(self, song, box): def ftime(t): if t == 0: return _("Unknown") else: timestr = time.strftime("%c", time.localtime(t)) return timestr.decode(const.ENCODING) fn = util.fsdecode(util.unexpand(song["~filename"])) length = util.format_time_long(song.get("~#length", 0)) size = util.format_size( song.get("~#filesize") or util.size(song["~filename"])) mtime = ftime(util.mtime(song["~filename"])) bitrate = song.get("~#bitrate", 0) if bitrate != 0: bitrate = _("%d kbps") % int(bitrate) else: bitrate = False t = gtk.Table(4, 2) t.set_col_spacings(6) t.set_homogeneous(False) table = [(_("length"), length), (_("file size"), size), (_("modified"), mtime)] if bitrate: table.insert(1, (_("bitrate"), bitrate)) fnlab = Label(fn) fnlab.set_ellipsize(pango.ELLIPSIZE_MIDDLE) t.attach(fnlab, 0, 2, 0, 1, xoptions=gtk.FILL) for i, (l, r) in enumerate(table): l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":") lab = Label() lab.set_markup(l) t.attach(lab, 0, 1, i + 1, i + 2, xoptions=gtk.FILL) t.attach(Label(r), 1, 2, i + 1, i + 2) box.pack_start(Frame(_("File"), t), expand=False, fill=False)
def copy(self, songlist, song): if self.__load_db() is None: return False track = gpod.itdb_track_new() # All values should be utf-8 encoded strings # Filepaths should be encoded with the fs encoding # Either combine tags with comma, or only take the first value if self['all_tags']: tag = song.comma else: tag = lambda key: (song.list(key) or ('',))[0] title = tag('title') if self['title_version'] and song('version'): title = " - ".join([title, song('version')]) track.title = util.encode(title) album = tag('album') if self['album_part'] and song('discsubtitle'): album = " - ".join([album, song('discsubtitle')]) track.album = util.encode(album) # String keys for key in ['artist', 'genre', 'grouping', 'composer', 'albumartist']: if hasattr(track, key): # albumartist since libgpod-0.4.2 setattr(track, key, util.encode(tag(key))) # Sort keys (since libgpod-0.5.0) for key in ['artist', 'album', 'albumartist']: if hasattr(track, 'sort_' + key): setattr(track, 'sort_' + key, util.encode(tag(key + 'sort'))) # Numeric keys for key in ['bitrate', 'playcount', 'year']: try: setattr(track, key, int(song('~#'+key))) except ValueError: continue # Numeric keys where the names differ for key, value in { 'cd_nr': song('~#disc'), 'cds': song('~#discs'), 'rating': min(100, song('~#rating') * 100), 'time_added': self.__mactime(time.time()), 'time_modified': self.__mactime(util.mtime(song('~filename'))), 'track_nr': song('~#track'), 'tracklen': song('~#length') * 1000, 'tracks': song('~#tracks'), 'size': util.size(song('~filename')), 'soundcheck': self.__soundcheck(song), }.items(): try: setattr(track, key, int(value)) except ValueError: continue track.filetype = song('~format') track.comment = util.encode(util.fsdecode(song('~filename'))) # Associate a cover with the track if self['covers']: cover = song.find_cover() if cover: # libgpod will copy the file later when the iTunesDB # is saved, so we have to keep a reference around in # case the cover is a temporary file. self.__covers.append(cover) gpod.itdb_track_set_thumbnails( track, util.fsencode(cover.name)) # Add the track to the master playlist gpod.itdb_track_add(self.__itdb, track, -1) master = gpod.itdb_playlist_mpl(self.__itdb) gpod.itdb_playlist_add_track(master, track, -1) # Copy the actual file if gpod.itdb_cp_track_to_ipod(track, song['~filename'], None) == 1: return IPodSong(track) else: return False
def test_bad(self): self.failIf(os.path.exists("/dev/doesnotexist")) self.failUnlessEqual(util.mtime("/dev/doesnotexist"), 0)
def test_equal(self): self.failUnlessEqual(util.mtime("."), os.path.getmtime("."))
def get_thumbnail(path, boundary): """Get a thumbnail of an image. Will create/use a thumbnail in the user's thumbnail directory if possible. Follows the Free Desktop specification. http://specifications.freedesktop.org/thumbnail-spec/""" width, height = boundary # embedded thumbnails come from /tmp/ # and too big thumbnails make no sense if path.startswith(tempfile.gettempdir()) or \ width > 256 or height > 256 or mtime(path) == 0: return gtk.gdk.pixbuf_new_from_file_at_size(path, width, height) if width <= 128 and height <= 128: size_name = "normal" thumb_size = 128 else: size_name = "large" thumb_size = 256 thumb_folder = get_thumbnail_folder() cache_dir = os.path.join(thumb_folder, size_name) mkdir(cache_dir, 0700) bytes = path if isinstance(path, unicode): bytes = path.encode("utf-8") uri = "file://" + pathname2url(bytes) thumb_name = hash.md5(uri).hexdigest() + ".png" thumb_path = os.path.join(cache_dir, thumb_name) pb = meta_mtime = None if os.path.exists(thumb_path): pb = gtk.gdk.pixbuf_new_from_file(thumb_path) meta_mtime = pb.get_option("tEXt::Thumb::MTime") meta_mtime = meta_mtime and int(meta_mtime) if not pb or meta_mtime != int(mtime(path)): pb = gtk.gdk.pixbuf_new_from_file(path) #Too small picture, no thumbnail needed if pb.get_width() < thumb_size and pb.get_height() < thumb_size: return scale(pb, boundary) mime = gtk.gdk.pixbuf_get_file_info(path)[0]['mime_types'][0] options = { "tEXt::Thumb::Image::Width": str(pb.get_width()), "tEXt::Thumb::Image::Height": str(pb.get_height()), "tEXt::Thumb::URI": uri, "tEXt::Thumb::MTime": str(int(mtime(path))), "tEXt::Thumb::Size": str(os.path.getsize(fsnative(path))), "tEXt::Thumb::Mimetype": mime, "tEXt::Software": "QuodLibet" } pb = scale(pb, (thumb_size, thumb_size)) pb.save(thumb_path, "png", options) os.chmod(thumb_path, 0600) return scale(pb, boundary)
def valid(self): """Return true if the file cache is up-to-date (checked via mtime), or we can't tell.""" return (self.get("~#mtime", 0) and self["~#mtime"] == util.mtime(self["~filename"]))
def rescan(self): """Rescan all folders for changed/new/removed modules. The caller should release all references to removed modules. Returns a tuple: (removed, added) """ print_d("Rescanning..") info = {} # get what is there atm for folder in self.__folders: for path, deps in get_importables(folder): # take the basename as module key, later modules win info[splitext(basename(path))[0]] = (path, deps) def deps_changed(old_list, new_list): if set(old_list) != set(new_list): return True for dep in old_list: old_mtime = self.__deps[dep] if util.mtime(dep) != old_mtime: return True return False # python can not unload a module, so we can only add new ones # or reload if the path is the same and mtime changed, # but we can still pretend we removed something removed = [] added = [] # remove those that are gone and changed ones for name, mod in self.__modules.items(): if name not in info: self.__remove_module(name) removed.append(name) continue path, deps = self.__info[name] path, new_deps = info[name] if deps_changed(deps, new_deps): self.__remove_module(name) removed.append(name) # add new ones for (name, (path, deps)) in info.iteritems(): if name in self.__modules: continue try: mod = load_module(name, "quodlibet.fake.plugins", dirname(path), reload=True) if mod is None: continue except Exception, err: text = format_exception(*sys.exc_info()) self.__failures[name] = (err, text) else: added.append(name) self.__modules[name] = mod self.__info[name] = info[name] for dep in deps: self.__deps[dep] = util.mtime(dep)