Beispiel #1
0
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)
Beispiel #2
0
    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)
Beispiel #4
0
 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
Beispiel #5
0
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()
Beispiel #6
0
    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)
Beispiel #7
0
    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
Beispiel #8
0
 def test_bad(self):
     self.failIf(os.path.exists("/dev/doesnotexist"))
     self.failUnlessEqual(util.mtime("/dev/doesnotexist"), 0)
Beispiel #9
0
 def test_equal(self):
     self.failUnlessEqual(util.mtime("."), os.path.getmtime("."))
Beispiel #10
0
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)
Beispiel #11
0
 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"]))
Beispiel #12
0
    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)