Ejemplo n.º 1
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdate_dir(), "Quod Libet")
    else:
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")

    if not PY2:
        USERDIR += "_py3"

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    # XXX: Exec conf.py in this directory, used to override const globals
    # e.g. for setting USERDIR for the Windows portable version
    # Note: execfile doesn't handle unicode paths on windows, so encode.
    # (this doesn't use the old win api in case of str compared to os.*)
    _CONF_PATH = os.path.join(
        os.path.dirname(os.path.realpath(__file__)), "conf.py")
    if PY2:
        # FIXME: PY3PORT
        try:
            execfile(_CONF_PATH)
        except IOError:
            pass

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Ejemplo n.º 2
0
def init(icon=None, proc_title=None, name=None):
    global quodlibet

    print_d("Entering quodlibet.init")

    _gtk_init()
    _gtk_icons_init(get_image_dir(), icon)
    _gst_init()
    _dbus_init()
    _init_debug()

    from gi.repository import GLib

    if proc_title:
        GLib.set_prgname(proc_title)
        set_process_title(proc_title)
        # Issue 736 - set after main loop has started (gtk seems to reset it)
        GLib.idle_add(set_process_title, proc_title)

    if name:
        GLib.set_application_name(name)

    mkdir(get_user_dir(), 0750)

    print_d("Finished initialization.")
Ejemplo n.º 3
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdata_dir(), "Quod Libet")
    elif is_osx():
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")
    else:
        USERDIR = os.path.join(xdg_get_config_home(), "quodlibet")

        if not os.path.exists(USERDIR):
            tmp = os.path.join(os.path.expanduser("~"), ".quodlibet")
            if os.path.exists(tmp):
                USERDIR = tmp

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    if build.BUILD_TYPE == u"windows-portable":
        USERDIR = os.path.normpath(os.path.join(
            os.path.dirname(path2fsn(sys.executable)), "..", "..", "config"))

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Ejemplo n.º 4
0
def dump_to_disk(dump_dir, exc_info):
    """Writes a new error log file into 'dump_dir'

    Args:
        dump_dir (path-like)
        exc_info (tuple): sys.exc_info() result tuple
    """

    try:
        mkdir(dump_dir)
    except EnvironmentError:
        print_exc()
        return

    time_ = time.localtime()
    dump_path = os.path.join(
        dump_dir, time.strftime("Dump_%Y%m%d_%H%M%S.txt", time_))

    header = format_dump_header(exc_info).encode("utf-8")
    log = format_dump_log().encode("utf-8")

    try:
        with open(dump_path, "wb") as dump:
            dump.write(header)
            dump.write(log)
    except EnvironmentError:
        print_exc()
Ejemplo n.º 5
0
    def write(self, filename):
        """Write config to filename.

        Can raise EnvironmentError
        """

        assert isinstance(filename, fsnative)

        mkdir(os.path.dirname(filename))

        # temporary set the new version for saving
        if self._version is not None:
            self.add_section("__config__")
            self.set("__config__", "version", self._version)
        try:
            with atomic_save(filename, "wb") as fileobj:
                if PY2:
                    self._config.write(fileobj)
                else:
                    temp = StringIO()
                    self._config.write(temp)
                    data = temp.getvalue().encode("utf-8", "surrogateescape")
                    fileobj.write(data)
        finally:
            if self._loaded_version is not None:
                self.set("__config__", "version", self._loaded_version)
Ejemplo n.º 6
0
    def setUp(self):
        # Testing locally is VERY dangerous without this...
        self.assertTrue(_TEMP_DIR in PLAYLISTS or os.name == "nt",
                        msg="Failing, don't want to delete %s" % PLAYLISTS)
        try:
            shutil.rmtree(PLAYLISTS)
        except OSError:
            pass

        mkdir(PLAYLISTS)

        self.lib = quodlibet.browsers.playlists.library = SongLibrary()
        self.lib.librarian = SongLibrarian()
        all_songs = SONGS + [self.ANOTHER_SONG]
        for af in all_songs:
            af.sanitize()
        self.lib.add(all_songs)

        self.big = pl = FileBackedPlaylist.new(PLAYLISTS, "Big", self.lib)
        pl.extend(SONGS)
        pl.write()

        self.small = pl = FileBackedPlaylist.new(PLAYLISTS, "Small", self.lib)
        pl.extend([self.ANOTHER_SONG])
        pl.write()

        PlaylistsBrowser.init(self.lib)

        self.bar = PlaylistsBrowser(self.lib)
        self.bar.connect('songs-selected', self._expected)
        self.bar._select_playlist(self.bar.playlists()[0])
        self.expected = None
Ejemplo n.º 7
0
    def setUp(self):
        try:
            shutil.rmtree(PLAYLISTS)
        except OSError:
            pass

        mkdir(PLAYLISTS)

        self.lib = quodlibet.browsers.playlists.library = SongLibrary()
        self.lib.librarian = SongLibrarian()
        all_songs = SONGS + [self.ANOTHER_SONG]
        for af in all_songs:
            af.sanitize()
        self.lib.add(all_songs)

        pl = Playlist.new(PLAYLISTS, "Big", self.lib)
        pl.extend(SONGS)
        pl.write()

        pl = Playlist.new(PLAYLISTS, "Small", self.lib)
        pl.extend([self.ANOTHER_SONG])
        pl.write()

        PlaylistsBrowser.init(self.lib)

        self.bar = PlaylistsBrowser(self.lib)
        self.bar.connect('songs-selected', self._expected)
        self.bar._select_playlist(self.bar.playlists()[0])
        self.expected = None
Ejemplo n.º 8
0
 def test_manydeep(self):
     self.failUnless(not os.path.isdir("nonext"))
     mkdir("nonext/test/test2/test3")
     try:
         self.failUnless(os.path.isdir("nonext/test/test2/test3"))
     finally:
         os.rmdir("nonext/test/test2/test3")
         os.rmdir("nonext/test/test2")
         os.rmdir("nonext/test")
         os.rmdir("nonext")
Ejemplo n.º 9
0
def get_cache_dir():
    """The directory to store things into which can be deleted at any time"""

    if os.name == "nt" and build.BUILD_TYPE == u"windows-portable":
        # avoid writing things to the host system for the portable build
        path = os.path.join(get_user_dir(), "cache")
    else:
        path = os.path.join(xdg_get_cache_home(), "quodlibet")

    mkdir(path, 0o700)
    return path
Ejemplo n.º 10
0
 def test_lyric_filename_search_builtin_default(self):
     """test built-in default"""
     with self.lyric_filename_test_setup(no_config=True) as ts:
         fp = os.path.join(ts.root, ts["artist"], ts["title"] + ".lyric")
         p = os.path.dirname(fp)
         mkdir(p)
         with io.open(fp, "w", encoding='utf-8') as f:
             f.write(u"")
         search = unquote(ts.lyric_filename)
         os.remove(fp)
         os.rmdir(p)
         self.assertEqual(search, fp)
Ejemplo n.º 11
0
 def test_lyrics_from_file(self):
     with temp_filename() as filename:
         af = AudioFile(artist='Motörhead', title='this: again')
         af.sanitize(filename)
         lyrics = "blah!\nblasé 😬\n"
         lyrics_dir = os.path.dirname(af.lyric_filename)
         mkdir(lyrics_dir)
         with io.open(af.lyric_filename, "w", encoding='utf-8') as lf:
             lf.write(text_type(lyrics))
         self.failUnlessEqual(af("~lyrics").splitlines(),
                              lyrics.splitlines())
         os.remove(af.lyric_filename)
         os.rmdir(lyrics_dir)
Ejemplo n.º 12
0
    def dump_to_disk(self, type_, value, traceback):
        """Writes the dump files to DUMDIR"""

        mkdir(self.DUMPDIR)

        header = format_dump_header(type_, value, traceback).encode("utf-8")
        log = format_dump_log().encode("utf-8")

        print(self.dump_path)
        with open(self.dump_path, "wb") as dump:
            with open(self.minidump_path, "wb") as minidump:
                minidump.write(header)
                dump.write(header)
            dump.write(log)
Ejemplo n.º 13
0
    def from_except(Kind, *args):
        mkdir(Kind.DUMPDIR)

        dump = os.path.join(
            Kind.DUMPDIR, time.strftime("Dump_%Y%m%d_%H%M%S.txt"))
        minidump = os.path.join(
            Kind.DUMPDIR, time.strftime("MiniDump_%Y%m%d_%H%M%S.txt"))

        full_args = list(args) + [dump, minidump]
        Kind.__dump(*full_args)
        # Don't get in a recursive exception handler loop.
        if not Kind.running:
            Kind.running = True
            Kind.instance = Kind(*full_args)
        return Kind.instance
Ejemplo n.º 14
0
    def rename(self, newname):
        """Rename a file. Errors are not handled. This shouldn't be used
        directly; use library.rename instead."""

        if os.path.isabs(newname):
            mkdir(os.path.dirname(newname))
        else:
            newname = os.path.join(self('~dirname'), newname)

        if not os.path.exists(newname):
            shutil.move(self['~filename'], newname)
        elif normalize_path(newname, canonicalise=True) != self['~filename']:
            raise ValueError

        self.sanitize(newname)
Ejemplo n.º 15
0
 def test_manydeep(self):
     self.failUnless(not os.path.isdir("nonext"))
     t = mkdtemp()
     path = os.path.join(t, "nonext", "test", "test2", "test3")
     mkdir(path)
     try:
         self.failUnless(os.path.isdir(path))
     finally:
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         os.rmdir(t)
Ejemplo n.º 16
0
    def _open(self, *args):
        from quodlibet import qltk

        self._id = None
        try:
            if not os.path.exists(self._path):
                mkdir(os.path.dirname(self._path))
                os.mkfifo(self._path, 0600)
            fifo = os.open(self._path, os.O_NONBLOCK)
            f = os.fdopen(fifo, "r", 4096)
            self._id = qltk.io_add_watch(
                f, GLib.PRIORITY_DEFAULT,
                GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP,
                self._process, *args)
        except (EnvironmentError, AttributeError):
            pass
Ejemplo n.º 17
0
 def test_manydeep(self):
     self.failUnless(not os.path.isdir("nonext"))
     t = mkdtemp()
     path = os.path.join(t, "nonext", "test", "test2", "test3")
     mkdir(path)
     try:
         self.failUnless(os.path.isdir(path))
     finally:
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         path = os.path.dirname(path)
         os.rmdir(path)
         os.rmdir(t)
Ejemplo n.º 18
0
    def setUp(self):
        self.success = False
        # Testing locally is VERY dangerous without this...
        self.assertTrue(_TEMP_DIR in _DEFAULT_PLAYLIST_DIR or os.name == "nt",
                        msg="Failing, don't want to delete %s" %
                        _DEFAULT_PLAYLIST_DIR)
        try:
            shutil.rmtree(_DEFAULT_PLAYLIST_DIR)
        except OSError:
            pass

        mkdir(_DEFAULT_PLAYLIST_DIR)

        init_fake_app()

        self.lib = quodlibet.browsers.playlists.library = SongFileLibrary()
        self.lib.librarian = SongLibrarian()
        for af in self.ALL_SONGS:
            af.sanitize()
        self.lib.add(self.ALL_SONGS)

        self.big = pl = FileBackedPlaylist.new(_DEFAULT_PLAYLIST_DIR, "Big",
                                               self.lib, self.lib.playlists)
        pl.extend(SONGS)
        pl.write()

        self.small = pl = XSPFBackedPlaylist.new(_DEFAULT_PLAYLIST_DIR,
                                                 "Small", self.lib,
                                                 self.lib.playlists)
        pl.extend([self.ANOTHER_SONG])
        pl.write()

        PlaylistsBrowser.init(self.lib)

        self.bar = PlaylistsBrowser(self.lib, self.MockConfirmerAccepting)
        self.bar.connect('songs-selected', self._expected)
        self.bar._select_playlist(self.bar.playlists()[0])
        self.expected = None

        # Uses the declining confirmer.
        self.bar_decline = PlaylistsBrowser(self.lib,
                                            self.MockConfirmerDeclining)
        self.bar_decline.connect('songs-selected', self._expected_decline)
        self.bar_decline._select_playlist(self.bar_decline.playlists()[0])
        # Note that _do() uses self.expected, but _do() is not called by the
        # testcase for declining the prompt. Tests fail with a shared expected.
        self.expected_decline = None
Ejemplo n.º 19
0
def dump_items(filename, items):
    """Pickle items to disk.

    Doesn't handle exceptions.
    """

    dirname = os.path.dirname(filename)
    mkdir(dirname)

    with atomic_save(filename, "wb") as fileobj:
        # While protocol 2 is usually faster it uses __setitem__
        # for unpickle and we override it to clear the sort cache.
        # This roundtrip makes it much slower, so we use protocol 1
        # unpickle numbers (py2.7):
        #   2: 0.66s / 2 + __set_item__: 1.18s / 1 + __set_item__: 0.72s
        # see: http://bugs.python.org/issue826897
        pickle.dump(items, fileobj, 1)
Ejemplo n.º 20
0
def dump_items(filename, items):
    """Pickle items to disk.

    Doesn't handle exceptions.
    """

    dirname = os.path.dirname(filename)
    mkdir(dirname)

    with util.atomic_save(filename, ".tmp", "wb") as fileobj:
        # While protocol 2 is usually faster it uses __setitem__
        # for unpickle and we override it to clear the sort cache.
        # This roundtrip makes it much slower, so we use protocol 1
        # unpickle numbers (py2.7):
        #   2: 0.66s / 2 + __set_item__: 1.18s / 1 + __set_item__: 0.72s
        # see: http://bugs.python.org/issue826897
        pickle.dump(items, fileobj, 1)
Ejemplo n.º 21
0
    def save(self, filename=None):
        """Save the library to the given filename, or the default if `None`"""

        if filename is None:
            filename = self.filename

        print_d("Saving contents to %r." % filename, self)

        try:
            dirname = os.path.dirname(filename)
            mkdir(dirname)
            with atomic_save(filename, "wb") as fileobj:
                fileobj.write(dump_audio_files(self.get_content()))
                # unhandled SerializationError, shouldn't happen -> better
                # not replace the library file with nothing
        except EnvironmentError:
            print_w("Couldn't save library to path: %r" % filename)
        else:
            self.dirty = False
Ejemplo n.º 22
0
    def open(self, ignore_lock=False):
        """Create the FIFO and listen to it.

        Raises:
            FIFOError in case another process is already using it.
        """
        from quodlibet import qltk

        mkdir(os.path.dirname(self._path))
        try:
            os.mkfifo(self._path, 0o600)
        except OSError:
            # maybe exists, we'll fail below otherwise
            pass

        try:
            fifo = os.open(self._path, os.O_NONBLOCK)
        except OSError:
            return

        while True:
            try:
                fcntl.flock(fifo, fcntl.LOCK_EX | fcntl.LOCK_NB)
            except InterruptedError:  # EINTR
                continue
            except BlockingIOError:  # EWOULDBLOCK
                if not ignore_lock:
                    raise FIFOError("fifo already locked")
            except OSError as e:
                print_d(f"fifo locking failed: {e!r}")
            break

        try:
            f = os.fdopen(fifo, "rb", 4096)
        except OSError as e:
            print_e(f"Couldn't open FIFO ({e!r})")
        else:
            self._source_id = qltk.io_add_watch(
                f,
                GLib.PRIORITY_DEFAULT,
                GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP,
                self._process,
            )
Ejemplo n.º 23
0
 def test_lyric_filename_search_order_priority(self):
     """test custom lyrics order priority"""
     with self.lyric_filename_test_setup() as ts:
         root2 = os.path.join(get_home_dir(), ".lyrics") # built-in default
         fp2 = os.path.join(root2, ts["artist"] + " - " +
                                   ts["title"] + ".lyric")
         p2 = os.path.dirname(fp2)
         mkdir(p2)
         with io.open(fp2, "w", encoding='utf-8') as f:
             f.write(u"")
         fp = os.path.join(ts.root, ts["artist"] + " - " +
                                    ts["title"] + ".lyric")
         with io.open(fp, "w", encoding='utf-8') as f:
             f.write(u"")
         mkdir(p2)
         search = ts.lyric_filename
         os.remove(fp2)
         os.rmdir(p2)
         os.remove(fp)
         self.assertEqual(search, fp)
Ejemplo n.º 24
0
 def test_lyric_filename_search_order_priority(self):
     """test custom lyrics order priority"""
     with self.lyric_filename_test_setup() as ts:
         root2 = os.path.join(get_home_dir(), ".lyrics")  # built-in default
         fp2 = os.path.join(root2,
                            ts["artist"] + " - " + ts["title"] + ".lyric")
         p2 = os.path.dirname(fp2)
         mkdir(p2)
         with io.open(fp2, "w", encoding='utf-8') as f:
             f.write(u"")
         fp = os.path.join(ts.root,
                           ts["artist"] + " - " + ts["title"] + ".lyric")
         with io.open(fp, "w", encoding='utf-8') as f:
             f.write(u"")
         mkdir(p2)
         search = ts.lyric_filename
         os.remove(fp2)
         os.rmdir(p2)
         os.remove(fp)
         self.assertEqual(search, fp)
Ejemplo n.º 25
0
    def test_invalid_glob_path(self):
        config.set("albumart", "force_filename", str(True))
        config.set("albumart", "filename", "*.jpg")

        # Make a dir which contains an invalid glob
        path = os.path.join(self.full_path("[a-2]"), "cover.jpg")
        mkdir(os.path.dirname(path))
        f = self.add_file(path)

        # Change the song's path to contain the invalid glob
        old_song_path = self.song['~filename']
        new_song_path = os.path.join(os.path.dirname(path),
                                     os.path.basename(old_song_path))
        self.song['~filename'] = new_song_path

        # The glob in the dirname should be ignored, while the
        # glob in the filename/basename is honored
        assert path_equal(os.path.abspath(self._find_cover(self.song).name), f)

        self.song['~filename'] = old_song_path
Ejemplo n.º 26
0
    def write(self, filename):
        """Write config to filename.

        Can raise EnvironmentError
        """

        assert is_fsnative(filename)

        mkdir(os.path.dirname(filename))

        # temporary set the new version for saving
        if self._version is not None:
            self.add_section("__config__")
            self.set("__config__", "version", self._version)
        try:
            with atomic_save(filename, ".tmp", "wb") as fileobj:
                self._config.write(fileobj)
        finally:
            if self._loaded_version is not None:
                self.set("__config__", "version", self._loaded_version)
Ejemplo n.º 27
0
    def write(self, filename):
        """Write config to filename.

        Can raise EnvironmentError
        """

        assert is_fsnative(filename)

        mkdir(os.path.dirname(filename))

        # temporary set the new version for saving
        if self._version is not None:
            self.add_section("__config__")
            self.set("__config__", "version", self._version)
        try:
            with atomic_save(filename, ".tmp", "wb") as fileobj:
                self._config.write(fileobj)
        finally:
            if self._loaded_version is not None:
                self.set("__config__", "version", self._loaded_version)
Ejemplo n.º 28
0
    def _open(self, ignore_lock, *args):
        from quodlibet import qltk

        self._id = None
        mkdir(os.path.dirname(self._path))
        try:
            os.mkfifo(self._path, 0600)
        except OSError:
            # maybe exists, we'll fail below otherwise
            pass

        try:
            fifo = os.open(self._path, os.O_NONBLOCK)
        except OSError:
            return

        while True:
            try:
                fcntl.flock(fifo, fcntl.LOCK_EX | fcntl.LOCK_NB)
            except IOError as e:
                # EINTR on linux
                if e.errno == errno.EINTR:
                    continue
                if ignore_lock:
                    break
                # OSX doesn't support fifo locking, so check errno
                if e.errno == errno.EWOULDBLOCK:
                    raise FIFOError("fifo already locked")
                else:
                    print_d("fifo locking failed: %r" % e)
            break

        try:
            f = os.fdopen(fifo, "r", 4096)
        except OSError:
            pass

        self._id = qltk.io_add_watch(
            f, GLib.PRIORITY_DEFAULT,
            GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP,
            self._process, *args)
Ejemplo n.º 29
0
    def test_lyric_filename_search_special_characters_across_path(self):
        """test '<' and/or '>' in name across path separator (not parsed
        (transparent to test))"""
        with self.lyric_filename_test_setup(no_config=True) as ts:
            # test '<' and '>' in name across path
            # (not parsed (transparent to test))
            ts['artist'] = "a < b"
            ts['title'] = "b > a"
            parts = [ts.root, ts["artist"], ts["title"] + ".lyric"]
            rpf = RootPathFile(ts.root, os.path.sep.join(parts))
            rootp = ts.root
            rmdirs = []
            # ensure valid dir existence
            for p in rpf.end.split(os.path.sep)[:-1]:
                rootp = os.path.sep.join([ts.root, p])
                if not RootPathFile(ts.root, rootp).valid:
                    rootp = os.path.sep.join([ts.root, escape_filename(p)])
                self.assertTrue(
                    RootPathFile(ts.root, rootp).valid,
                    "even escaped target dir part is not valid!")
                if not os.path.exists(rootp):
                    mkdir(rootp)
                    rmdirs.append(rootp)

            if not rpf.valid:
                rpf = RootPathFile(rpf.root, rpf.pathfile_escaped)

            with io.open(rpf.pathfile, "w", encoding='utf-8') as f:
                f.write(u"")
            # search for lyric file
            search = ts.lyric_filename
            # clean up test lyric file / path
            os.remove(rpf.pathfile)
            for p in rmdirs:
                os.rmdir(p)
            # test whether the 'found' file is the test lyric file
            fp = rpf.pathfile
            if is_windows():
                fp = fp.lower()  # account for 'os.path.normcase' santisatation
                search = search.lower()  # compensate for the above
            self.assertEqual(search, fp)
Ejemplo n.º 30
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdate_dir(), "Quod Libet")
    else:
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    if build.BUILD_TYPE == u"windows-portable":
        USERDIR = os.path.normpath(
            os.path.join(os.path.dirname(path2fsn(sys.executable)), "..", "..",
                         "config"))

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Ejemplo n.º 31
0
    def test_invalid_glob_path(self):
        config.set("albumart", "force_filename", str(True))
        config.set("albumart", "filename", "*.jpg")

        # Make a dir which contains an invalid glob
        path = os.path.join(self.full_path("[a-2]"), "cover.jpg")
        mkdir(os.path.dirname(path))
        f = self.add_file(path)

        # Change the song's path to contain the invalid glob
        old_song_path = self.song['~filename']
        new_song_path = os.path.join(os.path.dirname(path),
                                     os.path.basename(old_song_path))
        self.song['~filename'] = new_song_path

        # The glob in the dirname should be ignored, while the
        # glob in the filename/basename is honored
        assert path_equal(
            os.path.abspath(self._find_cover(self.song).name), f)

        self.song['~filename'] = old_song_path
Ejemplo n.º 32
0
    def test_lyric_filename_search_special_characters_across_path(self):
        """test '<' and/or '>' in name across path separator (not parsed
        (transparent to test))"""
        with self.lyric_filename_test_setup(no_config=True) as ts:
            # test '<' and '>' in name across path
            # (not parsed (transparent to test))
            ts['artist'] = "a < b"
            ts['title'] = "b > a"
            parts = [ts.root, ts["artist"], ts["title"] + ".lyric"]
            rpf = RootPathFile(ts.root, os.path.sep.join(parts))
            rootp = ts.root
            rmdirs = []
            # ensure valid dir existence
            for p in rpf.end.split(os.path.sep)[:-1]:
                rootp = os.path.sep.join([ts.root, p])
                if not RootPathFile(ts.root, rootp).valid:
                    rootp = os.path.sep.join([ts.root, escape_filename(p)])
                self.assertTrue(RootPathFile(ts.root, rootp).valid,
                                "even escaped target dir part is not valid!")
                if not os.path.exists(rootp):
                    mkdir(rootp)
                    rmdirs.append(rootp)

            if not rpf.valid:
                rpf = RootPathFile(rpf.root, rpf.pathfile_escaped)

            with io.open(rpf.pathfile, "w", encoding='utf-8') as f:
                f.write(u"")
            # search for lyric file
            search = ts.lyric_filename
            # clean up test lyric file / path
            os.remove(rpf.pathfile)
            for p in rmdirs:
                os.rmdir(p)
            # test whether the 'found' file is the test lyric file
            fp = rpf.pathfile
            if is_windows():
                fp = fp.lower()  # account for 'os.path.normcase' santisatation
                search = search.lower()  # compensate for the above
            self.assertEqual(search, fp)
Ejemplo n.º 33
0
    def _open(self, ignore_lock, *args):
        from quodlibet import qltk

        self._id = None
        mkdir(os.path.dirname(self._path))
        try:
            os.mkfifo(self._path, 0o600)
        except OSError:
            # maybe exists, we'll fail below otherwise
            pass

        try:
            fifo = os.open(self._path, os.O_NONBLOCK)
        except OSError:
            return

        while True:
            try:
                fcntl.flock(fifo, fcntl.LOCK_EX | fcntl.LOCK_NB)
            except IOError as e:
                # EINTR on linux
                if e.errno == errno.EINTR:
                    continue
                if ignore_lock:
                    break
                # OSX doesn't support fifo locking, so check errno
                if e.errno == errno.EWOULDBLOCK:
                    raise FIFOError("fifo already locked")
                else:
                    print_d("fifo locking failed: %r" % e)
            break

        try:
            f = os.fdopen(fifo, "r", 4096)
        except OSError:
            pass

        self._id = qltk.io_add_watch(f, GLib.PRIORITY_DEFAULT,
                                     GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP,
                                     self._process, *args)
Ejemplo n.º 34
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdate_dir(), "Quod Libet")
    else:
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")

    if not PY2:
        USERDIR += "_py3"

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    if build.BUILD_TYPE == u"windows-portable":
        USERDIR = os.path.join(get_base_dir(), "..", "..", "..", "config")

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Ejemplo n.º 35
0
    def save(self, filename=None):
        """Save the library to the given filename, or the default if `None`"""

        if filename is None:
            filename = self.filename

        print_d("Saving contents to %r." % filename, self)

        try:
            dirname = os.path.dirname(filename)
            mkdir(dirname)
            with atomic_save(filename, "wb") as fileobj:
                fileobj.write(dump_audio_files(self.get_content()))
        except SerializationError:
            # Can happen when we try to pickle while the library is being
            # modified, like in the periodic 15min save.
            # Ignore, as it should try again later or on program exit.
            util.print_exc()
        except EnvironmentError:
            print_w("Couldn't save library to path: %r" % filename)
        else:
            self.dirty = False
Ejemplo n.º 36
0
    def save(self, filename=None):
        """Save the library to the given filename, or the default if `None`"""

        if filename is None:
            filename = self.filename

        print_d("Saving contents to %r." % filename, self)

        try:
            dirname = os.path.dirname(filename)
            mkdir(dirname)
            with atomic_save(filename, "wb") as fileobj:
                fileobj.write(dump_audio_files(self.get_content()))
        except SerializationError:
            # Can happen when we try to pickle while the library is being
            # modified, like in the periodic 15min save.
            # Ignore, as it should try again later or on program exit.
            util.print_exc()
        except EnvironmentError:
            print_w("Couldn't save library to path: %r" % filename)
        else:
            self.dirty = False
Ejemplo n.º 37
0
    def write(self, filename):
        """Write config to filename.

        Can raise EnvironmentError
        """

        assert isinstance(filename, fsnative)

        mkdir(os.path.dirname(filename))

        # temporary set the new version for saving
        if self._version is not None:
            self.add_section("__config__")
            self.set("__config__", "version", self._version)
        try:
            with atomic_save(filename, "wb") as fileobj:
                temp = StringIO()
                self._config.write(temp)
                data = temp.getvalue().encode("utf-8", "surrogateescape")
                fileobj.write(data)
        finally:
            if self._loaded_version is not None:
                self.set("__config__", "version", self._loaded_version)
Ejemplo n.º 38
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdate_dir(), "Quod Libet")
    else:
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")

    if not PY2:
        USERDIR += "_py3"

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    # XXX: Exec conf.py in this directory, used to override const globals
    # e.g. for setting USERDIR for the Windows portable version
    # Note: execfile doesn't handle unicode paths on windows, so encode.
    # (this doesn't use the old win api in case of str compared to os.*)
    _CONF_PATH = os.path.join(
        os.path.dirname(os.path.realpath(__file__)), "conf.py")

    if PY2:
        locals_ = {}
        # FIXME: PY3PORT
        try:
            execfile(_CONF_PATH, globals(), locals_)
        except IOError:
            pass
        else:
            USERDIR = locals_["USERDIR"]

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Ejemplo n.º 39
0
def get_thumbnail(path, boundary):
    """Get a thumbnail pixbuf of an image at `path`.

    Will create/use a thumbnail in the user's thumbnail directory if possible.
    Follows the Free Desktop specification:

    http://specifications.freedesktop.org/thumbnail-spec/

    Can raise GLib.GError. Thread-safe.
    """

    width, height = boundary
    new_from_file_at_size = GdkPixbuf.Pixbuf.new_from_file_at_size

    # larger than thumbnails, load directly
    if width > ThumbSize.LARGEST or height > ThumbSize.LARGEST:
        return new_from_file_at_size(path, width, height)

    path_mtime = mtime(path)
    if path_mtime == 0:
        return new_from_file_at_size(path, width, height)

    # embedded thumbnails come from /tmp/
    # FIXME: move this to another layer
    if path.startswith(tempfile.gettempdir()):
        return new_from_file_at_size(path, width, height)

    thumb_path, thumb_size = get_cache_info(path, boundary)
    cache_dir = os.path.dirname(thumb_path)
    try:
        mkdir(cache_dir, 0o700)
    except OSError:
        return new_from_file_at_size(path, width, height)

    try:
        pb = new_from_file_at_size(thumb_path, width, height)
    except GLib.GError:
        # in case it fails to load, we recreate it
        pass
    else:
        meta_mtime = pb.get_option("tEXt::Thumb::MTime")
        if meta_mtime is not None:
            try:
                meta_mtime = int(meta_mtime)
            except ValueError:
                pass
            else:
                if meta_mtime == int(path_mtime):
                    return pb

    info, pw, ph = GdkPixbuf.Pixbuf.get_file_info(path)

    # Too small picture, no thumbnail needed
    if pw < thumb_size and ph < thumb_size:
        return new_from_file_at_size(path, width, height)

    thumb_pb = new_from_file_at_size(path, thumb_size, thumb_size)

    uri = "file://" + pathname2url(path)
    mime = info.get_mime_types()[0]
    options = {
        "tEXt::Thumb::Image::Width": str(pw),
        "tEXt::Thumb::Image::Height": str(ph),
        "tEXt::Thumb::URI": uri,
        "tEXt::Thumb::MTime": str(int(path_mtime)),
        "tEXt::Thumb::Size": str(os.path.getsize(path)),
        "tEXt::Thumb::Mimetype": mime,
        "tEXt::Software": "QuodLibet"
    }

    thumb_pb.savev(thumb_path, "png", options.keys(), options.values())
    try:
        os.chmod(thumb_path, 0o600)
    except OSError:
        pass

    return scale(thumb_pb, boundary)
Ejemplo n.º 40
0
 def test_exists(self):
     mkdir(".")
Ejemplo n.º 41
0
import quodlibet
from quodlibet import formats, qltk
from quodlibet.qltk.wlw import WaitLoadWindow
from quodlibet.qltk.getstring import GetStringDialog
from quodlibet.util import escape
from quodlibet.util.collection import Playlist
from quodlibet.util.path import mkdir, fsdecode, is_fsnative


# Directory for playlist files
from quodlibet.util.uri import URI

PLAYLISTS = os.path.join(quodlibet.get_user_dir(), "playlists")
assert is_fsnative(PLAYLISTS)
if not os.path.isdir(PLAYLISTS):
    mkdir(PLAYLISTS)


class ConfirmRemovePlaylistDialog(qltk.Message):
    def __init__(self, parent, playlist):
        title = _("Are you sure you want to delete the playlist '%s'?") % escape(playlist.name)
        description = _("All information about the selected playlist " "will be deleted and can not be restored.")

        super(ConfirmRemovePlaylistDialog, self).__init__(
            Gtk.MessageType.WARNING, parent, title, description, Gtk.ButtonsType.NONE
        )

        self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_DELETE, Gtk.ResponseType.YES)


class GetPlaylistName(GetStringDialog):
Ejemplo n.º 42
0
from gi.repository import Gtk
from quodlibet import formats, qltk
from quodlibet.qltk.wlw import WaitLoadWindow
from quodlibet.qltk.getstring import GetStringDialog
from quodlibet.util import escape
from quodlibet.util.collection import Playlist
from quodlibet.util.path import mkdir, fsdecode, is_fsnative
from quodlibet import const

# Directory for playlist files
from quodlibet.util.uri import URI

PLAYLISTS = os.path.join(const.USERDIR, "playlists")
assert is_fsnative(PLAYLISTS)
if not os.path.isdir(PLAYLISTS):
    mkdir(PLAYLISTS)


class ConfirmRemovePlaylistDialog(qltk.Message):
    def __init__(self, parent, playlist):
        title = (_("Are you sure you want to delete the playlist '%s'?") %
                 escape(playlist.name))
        description = (_("All information about the selected playlist "
                         "will be deleted and can not be restored."))

        super(ConfirmRemovePlaylistDialog,
              self).__init__(Gtk.MessageType.WARNING, parent, title,
                             description, Gtk.ButtonsType.NONE)

        self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                         Gtk.STOCK_DELETE, Gtk.ResponseType.YES)
Ejemplo n.º 43
0
 def test_exists(self):
     mkdir(".")