Exemplo n.º 1
0
 def test_window(self):
     lib = SongFileLibrary()
     lib.librarian = SongLibrarian()
     pl = player.init_player("nullbe", lib.librarian)
     window = QuodLibetWindow(lib, pl, headless=True)
     assert window in window.windows
     window.destroy()
Exemplo n.º 2
0
    def test(self):
        lib = SongFileLibrary()

        with temp_filename() as song_fn:
            song = AudioFile({"~filename": song_fn})
            song.sanitize()
            lib.add([song])

            with temp_filename() as xml_fn:
                with open(xml_fn, "wb") as h:
                    x = get_example_xml(song("~filename"), 1, 1371802107)
                    h.write(x)

                handler = self.mod.RBDBContentHandler(lib)
                xml.sax.parse(xml_fn, handler)

                self.assertEqual(song("~#rating"), 0.2)
                self.assertEqual(song("~#lastplayed"), 1371802107)
                self.assertEqual(song("~#playcount"), 1)

                with open(xml_fn, "wb") as h:
                    x = get_example_xml(song("~filename"), 2, 1371802107 - 1)
                    h.write(x)

                handler = self.mod.RBDBContentHandler(lib)
                xml.sax.parse(xml_fn, handler)

                self.assertEqual(song("~#rating"), 0.4)
                self.assertEqual(song("~#lastplayed"), 1371802107)
Exemplo n.º 3
0
class TFIFOControl(TestCase):
    def setUp(self):
        config.init()
        self.p = NullPlayer()
        self.l = SongFileLibrary()
        self.w = gtk.Window()
        self.fifo = FIFOControl(self.l, self.w, self.p)

    def tearDown(self):
        self.p.destroy()
        self.l.destroy()
        self.w.destroy()
        config.quit()

    def __send(self, command):
        f = open(const.CONTROL, "wb")
        f.write(command)
        f.close()
        while gtk.events_pending():
            gtk.main_iteration()

    def test_player(self):
        self.__send("previous")
        self.__send("force_previous")
        self.__send("next")
        self.__send("pause")
        self.__send("play-pause")
        self.__send("stop")
        self.__send("volume +1000")
        self.__send("volume 40")
        self.__send("volume -10")

        #self.__send("seek -10")
        #self.__send("seek +10")
        #self.__send("seek 0")

    def test_misc(self):
        #self.__send("add-directory /dev/null")
        self.__send("add-file /dev/null")
        #self.__send("dump-playlist /dev/null")
        #self.__send("dump_queue /dev/null")
        #self.__send("enqueue /dev/null")
        self.__send("enqueue-files /dev/null")
        #self.__send("filter album=test")
        #self.__send("focus")
        #self.__send("hide-window")
        #self.__send("open-browser 1")
        #self.__send("order shuffle")
        self.__send("properties")
        #self.__send("queue 1")
        self.__send("quit")
        #self.__send("random album")
        #self.__send("refresh")
        #self.__send("repeat 0")
        #self.__send("set-browser 1")
        self.__send("set-rating 0.5")
Exemplo n.º 4
0
    def setUp(self):
        config.init()
        self.library = SongFileLibrary()
        backend = quodlibet.player.init_backend("nullbe")
        self.device = backend.init(self.library)

        self.songs = [AudioFile({"title": x}) for x in
                      ["song1", "song2", "song3"]]
        for song in self.songs:
            song.sanitize(fsnative(str(song["title"])))
        self.confirmed = False
Exemplo n.º 5
0
 def setUp(self):
     config.init()
     self.library = library = SongFileLibrary()
     library.librarian = SongLibrarian()
     library.add(SONGS)
     self.Kind.init(library)
     self.b = self.Kind(library)
Exemplo n.º 6
0
    def init(klass, library):
        if klass.__library is not None:
            return

        klass.__glibrary = library
        klass.__library = SongFileLibrary("filesystem")
        library.connect('added', klass.__remove_because_added)
    def setUp(self):
        self.success = False
        # 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)

        init_fake_app()

        self.lib = quodlibet.browsers.playlists.library = SongFileLibrary()
        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
Exemplo n.º 8
0
    def test_header_menu(self):
        from quodlibet import browsers
        from quodlibet.library import SongLibrarian

        song = AudioFile({"~filename": fsnative(u"/dev/null")})
        song.sanitize()
        self.songlist.set_songs([song])

        library = SongFileLibrary()
        library.librarian = SongLibrarian()
        browser = browsers.get("SearchBar")(library)

        self.songlist.set_column_headers(["foo"])

        self.assertFalse(self.songlist.Menu("foo", browser, library))
        sel = self.songlist.get_selection()
        sel.select_all()
        self.assertTrue(self.songlist.Menu("foo", browser, library))
Exemplo n.º 9
0
    def setUp(self):
        config.init()
        self.songlist = SongList(SongFileLibrary())

        self.orders_changed = 0

        def orders_changed_cb(*args):
            self.orders_changed += 1

        self.songlist.connect("orders-changed", orders_changed_cb)
Exemplo n.º 10
0
    def test__on_new_playlist_activate(self):
        main = qltk.MenuItem('Menu')
        menu = StubbedPlaylistMenu(self.SONGS,
                                   PlaylistLibrary(SongFileLibrary()))
        main.set_submenu(menu)

        pl = menu._on_new_playlist_activate(main, self.SONGS)

        self.failUnless(pl, msg="No playlists added")
        self.failUnlessEqual(pl.songs, self.SONGS)
Exemplo n.º 11
0
    def setUp(self):
        config.init()
        self.lib = SongFileLibrary()
        self.songlist = SongList(self.lib)
        assert not self.lib.librarian, "not expecting a librarian - leaky test?"

        self.orders_changed = 0
        self.songs_removed: List[Set] = []

        def orders_changed_cb(*args):
            self.orders_changed += 1

        def orders_removed_cb(songlist, removed):
            self.songs_removed.append(removed)

        self.__sigs = [
            self.songlist.connect("orders-changed", orders_changed_cb),
            self.songlist.connect("songs-removed", orders_removed_cb)
        ]
Exemplo n.º 12
0
    def test__on_new_playlist_activate(self):
        main = qltk.MenuItem('Menu')
        menu = StubbedPlaylistMenu(self.SONGS, PlaylistLibrary(SongFileLibrary()))
        main.set_submenu(menu)

        # Run it (with stubbed dialog)
        pl = menu._on_new_playlist_activate(main, self.SONGS)

        assert pl, "No playlists added"
        assert pl.name == FIXED_NAME, "Wrong name used"
        assert pl.songs == self.SONGS
Exemplo n.º 13
0
 def setUp(self):
     quodlibet.config.init()
     self.lib = quodlibet.browsers.tracks.library = SongFileLibrary()
     quodlibet.browsers.tracks.library.librarian = SongLibrarian()
     for af in self.SONGS:
         af.sanitize()
     self.lib.add(self.SONGS)
     self._dir = mkdtemp()
     self.pl = FileBackedPlaylist.new(self._dir, "Foobar", self.lib,
                                      self.lib.playlists)
     self.pl.extend(self.SONGS)
    def setUp(self):
        config.init()

        class App(Application):
            browser = None

        app = App()
        app.player = NullPlayer()
        app.library = SongFileLibrary()
        app.library.librarian = SongLibrarian()
        app.browser = EmptyBar(app.library, True)
        app.window = Gtk.OffscreenWindow()

        self.fifo = FIFOControl(app)
Exemplo n.º 15
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
Exemplo n.º 16
0
def init_fake_app():
    from quodlibet import app

    from quodlibet import browsers
    from quodlibet.player.nullbe import NullPlayer
    from quodlibet.library import SongFileLibrary
    from quodlibet.library.librarians import SongLibrarian
    from quodlibet.qltk.quodlibetwindow import QuodLibetWindow, PlayerOptions
    from quodlibet.util.cover import CoverManager

    browsers.init()
    app.name = "Quod Libet"
    app.id = "io.github.quodlibet.QuodLibet"
    app.player = NullPlayer()
    app.library = SongFileLibrary()
    app.library.librarian = SongLibrarian()
    app.cover_manager = CoverManager()
    app.window = QuodLibetWindow(app.library, app.player, headless=True)
    app.player_options = PlayerOptions(app.window)
Exemplo n.º 17
0
    def setUp(self):
        self.lib = lib = SongFileLibrary()
        self.received = []

        def listen(name, items):
            self.received.append(name)

        self._sigs = [
            connect_obj(lib, 'added', listen, 'added'),
            connect_obj(lib, 'changed', listen, 'changed'),
            connect_obj(lib, 'removed', listen, 'removed'),
        ]

        self.playlists = lib.playlists
        self._asigs = [
            connect_obj(self.playlists, 'added', listen, 'pl_added'),
            connect_obj(self.playlists, 'changed', listen, 'pl_changed'),
            connect_obj(self.playlists, 'removed', listen, 'pl_removed'),
        ]
        songs = AFrange(3)
        self.lib.add(songs)
Exemplo n.º 18
0
class TSongsMenu(TestCase):

    def _confirmer(self, *args):
        self.confirmed = True
        return False

    def setUp(self):
        config.init()
        self.library = SongFileLibrary()
        backend = quodlibet.player.init_backend("nullbe")
        self.device = backend.init(self.library)

        self.songs = [AudioFile({"title": x}) for x in
                      ["song1", "song2", "song3"]]
        for song in self.songs:
            song.sanitize(fsnative(str(song["title"])))
        self.confirmed = False

    def test_empty(self):
        self.menu = self.empty_menu_with()
        self.failIf(len(self.menu))

    def test_simple(self):
        self.menu = SongsMenu(self.library, self.songs, plugins=False)

    def test_playlists(self):
        self.menu = self.empty_menu_with(playlists=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = self.empty_menu_with(playlists=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_queue(self):
        self.menu = self.empty_menu_with(queue=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].can_add = False
        self.menu = self.empty_menu_with(queue=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_remove(self):
        self.menu = self.empty_menu_with(remove=True,
                                         removal_confirmer=self._confirmer)
        self.failUnlessEqual(len(self.menu), 1)
        item = self.menu.get_children()[0]
        self.failIf(item.props.sensitive)
        item.activate()
        self.failUnless(self.confirmed, "Should have confirmed song removal")

    def test_remove_sensitive(self):
        self.library.add(self.songs)
        self.menu = self.empty_menu_with(remove=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failUnless(self.menu.get_children()[0].props.sensitive)

    def test_delete(self):
        self.menu = self.empty_menu_with(delete=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failUnless(self.menu.get_children()[0].props.sensitive)

        self.songs[0].is_file = False
        self.menu = self.empty_menu_with(delete=True)
        self.failIf(self.menu.get_children()[0].props.sensitive)

    def test_show_files(self):
        self.menu = self.empty_menu_with(show_files=True)
        self.failUnlessEqual(len(self.menu), 1)
        self.failUnless(self.menu.get_children()[0].props.sensitive)
        item = self.menu.get_children()[0]
        self.failUnless(item.props.sensitive)

    def test_show_files_remote_songs(self):
        self.songs = self.library.songs = [an_rf(1)]
        self.menu = self.empty_menu_with(show_files=True)
        self.failIf(len(self.menu))

    def test_show_files_too_many_songs(self):
        self.songs = self.library.songs = [an_af(i) for i in range(50)]
        self.menu = self.empty_menu_with(show_files=True)
        item = self.menu.get_children()[0]
        self.failIf(item.props.sensitive,
                    msg="Should have disabled show files for 50 files")

    def test_download(self):
        def choose(*args, **kwargs):
            return [mkdtemp()]
        self.songs = self.library.songs = [an_rf(i) for i in range(3)]
        self.menu = self.empty_menu_with(download=True, folder_chooser=choose)
        last = self.menu.get_children()[-1]
        assert last.props.sensitive, "should have enabled download for remotes"
        # TODO: some useful assertions, without needing a UI

    def empty_menu_with(self, plugins=False, playlists=False, queue=False,
                        remove=False, delete=False, edit=False, ratings=False,
                        show_files=False, download=False,
                        removal_confirmer=None, folder_chooser=None):
        return SongsMenu(self.library, self.songs, plugins=plugins, playlists=playlists,
                         queue=queue, remove=remove, delete=delete, edit=edit,
                         ratings=ratings, show_files=show_files,
                         removal_confirmer=removal_confirmer,
                         download=download, folder_chooser=folder_chooser)

    def tearDown(self):
        self.device.destroy()
        self.library.destroy()
        try:
            self.menu.destroy()
        except AttributeError:
            pass
        else:
            del(self.menu)
        config.quit()
Exemplo n.º 19
0
class StorageDevice(Device):
    protocol = 'storage'

    defaults = {
        'pattern': '<artist>/<album>/<title>',
        'covers': True,
        'unclutter': True,
    }

    __library = None
    __pattern = None

    def __init__(self, backend_id, device_id):
        super(StorageDevice, self).__init__(backend_id, device_id)
        filename = escape_filename(device_id)
        self.__library_path = os.path.join(CACHE, filename)
        self.__library_name = device_id

    def __set_pattern(self, widget=None):
        self.__pattern = FileFromPattern(
            os.path.join(self.mountpoint, self['pattern']))

    def Properties(self):
        props = []

        entry = Gtk.Entry()
        entry.set_text(self['pattern'])
        entry.connect_after('changed', self.__set_pattern)
        props.append((_("_Filename pattern:"), entry, 'pattern'))

        check = Gtk.CheckButton()
        check.set_active(self['covers'])
        props.append((_("Copy _album covers"), check, 'covers'))

        check = Gtk.CheckButton()
        check.set_active(self['unclutter'])
        props.append(
            (_("_Remove unused covers and directories"), check, 'unclutter'))

        return props

    def list(self, wlb):
        self.__load_library()

        wlb.setup()
        next = self.__library.rebuild([self.mountpoint]).next
        while True:
            if wlb.quit:
                wlb.hide()
                break
            if not wlb.paused:
                try:
                    next()
                except StopIteration:
                    break
            Gtk.main_iteration()

        self.__save_library()
        return self.__library.values()

    def contains(self, song):
        return song in self.__library

    def copy(self, parent_widget, song):
        if not self.__pattern:
            self.__set_pattern()

        target = strip_win32_incompat_from_path(self.__pattern.format(song))
        dirname = os.path.dirname(target)

        if os.path.exists(target):
            dialog = ConfirmFileReplace(parent_widget, target)
            resp = dialog.run()
            if resp == ConfirmFileReplace.RESPONSE_REPLACE:
                try:
                    # Remove the current song
                    self.__library.remove([self.__library[target]])
                except KeyError:
                    pass
            else:
                return False

        try:
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            shutil.copyfile(song['~filename'], target)

            if self['covers']:
                coverfile = os.path.join(dirname, 'folder.jpg')
                cover = app.cover_manager.get_cover(song)
                if cover and mtime(cover.name) > mtime(coverfile):
                    image = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        cover.name, 200, 200)
                    image.savev(coverfile, "jpeg", [], [])

            song = copy.deepcopy(song)
            song.sanitize(target)
            self.__library.add([song])
            return song
        except (OSError, IOError, GLib.GError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def delete(self, parent_widget, song):
        try:
            path = song['~filename']
            dir = os.path.dirname(path)

            os.unlink(path)
            self.__library.remove([song])

            if self['unclutter']:
                files = glob(dir + '/*')
                if len(files) == 1 and os.path.isfile(files[0]) and \
                        os.path.basename(files[0]) == 'folder.jpg':
                    os.unlink(files[0])
                try:
                    os.removedirs(os.path.dirname(path))
                except OSError:
                    pass

            return True
        except (OSError, IOError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def cleanup(self, wlb, action):
        self.__save_library()
        return True

    def close(self):
        if self.__library:
            self.__library.destroy()
            self.__library = None

    def __load_library(self):
        if self.__library is None:
            self.__library = SongFileLibrary(self.__library_name)
            if os.path.isfile(self.__library_path):
                self.__library.load(self.__library_path)

    def __save_library(self):
        self.__library.save(self.__library_path)
Exemplo n.º 20
0
class TSongList(TestCase):
    HEADERS = [
        "acolumn", "~#lastplayed", "~foo~bar", "~#rating", "~#length",
        "~dirname", "~#track"
    ]

    def setUp(self):
        config.init()
        self.lib = SongFileLibrary()
        self.songlist = SongList(self.lib)
        assert not self.lib.librarian, "not expecting a librarian - leaky test?"

        self.orders_changed = 0
        self.songs_removed: List[Set] = []

        def orders_changed_cb(*args):
            self.orders_changed += 1

        def orders_removed_cb(songlist, removed):
            self.songs_removed.append(removed)

        self.__sigs = [
            self.songlist.connect("orders-changed", orders_changed_cb),
            self.songlist.connect("songs-removed", orders_removed_cb)
        ]

    def test_set_all_column_headers(self):
        SongList.set_all_column_headers(self.HEADERS)
        headers = [col.header_name for col in self.songlist.get_columns()]
        self.failUnlessEqual(headers, self.HEADERS)

    def test_set_column_headers(self):
        self.songlist.set_column_headers(self.HEADERS)
        headers = [col.header_name for col in self.songlist.get_columns()]
        self.failUnlessEqual(headers, self.HEADERS)

    def test_drop(self):
        self.songlist.enable_drop()
        self.songlist.disable_drop()

    def test_sort_by(self):
        self.songlist.set_column_headers(["one", "two", "three"])
        for key, order in [("one", True), ("two", False), ("three", False)]:
            self.songlist.set_sort_orders([(key, order)])
            self.failUnlessEqual(self.songlist.get_sort_orders(),
                                 [(key, order)])

        self.songlist.toggle_column_sort(self.songlist.get_columns()[-1])
        self.failUnlessEqual(self.songlist.get_sort_orders(),
                             [("three", True)])

    def test_sort_orders(self):
        s = self.songlist

        s.set_column_headers(["foo", "quux", "bar"])
        values = [("foo", True), ("bar", False)]
        s.set_sort_orders(values)
        self.assertEqual(s.get_sort_orders(), values)

        s.toggle_column_sort(s.get_columns()[1], replace=False)
        self.assertEqual(s.get_sort_orders(), values + [("quux", False)])

        s.toggle_column_sort(s.get_columns()[1], replace=True)
        self.assertEqual(s.get_sort_orders(), [("quux", False)])

    def test_toggle_sort(self):
        s = self.songlist

        s.set_column_headers(["foo"])
        self.assertEqual(self.orders_changed, 1)
        s.toggle_column_sort(s.get_columns()[0], replace=True)
        self.assertEqual(self.orders_changed, 2)
        self.assertEqual(s.get_sort_orders(), [("foo", False)])
        s.toggle_column_sort(s.get_columns()[0], replace=True)
        self.assertEqual(self.orders_changed, 3)
        self.assertEqual(s.get_sort_orders(), [("foo", True)])

    def test_clear_sort(self):
        s = self.songlist
        s.set_column_headers(["foo"])
        s.toggle_column_sort(s.get_columns()[0], replace=True)
        self.assertTrue(s.get_sort_orders())
        s.clear_sort()
        self.assertFalse(s.get_sort_orders())

    def test_not_sortable(self):
        s = self.songlist
        s.sortable = False
        s.set_column_headers(["foo"])
        s.toggle_column_sort(s.get_columns()[0])
        self.assertEqual(self.orders_changed, 0)
        self.assertFalse(s.get_sort_orders())

    def test_find_default_sort_column(self):
        s = self.songlist
        self.assertTrue(s.find_default_sort_column() is None)
        s.set_column_headers(["~#track"])
        self.assertTrue(s.find_default_sort_column())

    def test_inline_search_state(self):
        self.assertEqual(self.songlist.get_search_column(), 0)
        self.assertTrue(self.songlist.get_enable_search())

    def test_set_songs(self):
        self.songlist.set_songs([], sorted=True)
        self.songlist.set_songs([], sorted=False)
        self.songlist.set_songs([], scroll_select=True)
        self.songlist.set_songs([], scroll_select=False)
        self.songlist.set_songs([], scroll=True)
        self.songlist.set_songs([], scroll=False)

    def test_set_songs_restore_select(self):
        song = AudioFile({"~filename": "/dev/null"})
        self.songlist.add_songs([song])
        sel = self.songlist.get_selection()
        sel.select_path(Gtk.TreePath.new_first())

        self.songlist.set_songs([song], scroll_select=True)
        self.assertEqual(self.songlist.get_selected_songs(), [song])

        song2 = AudioFile({"~filename": "/dev/null"})
        self.songlist.set_songs([song2], scroll_select=True)
        self.assertEqual(self.songlist.get_selected_songs(), [])

    def test_set_songs_no_restore_select(self):
        song = AudioFile({"~filename": "/dev/null"})
        self.songlist.add_songs([song])
        model = self.songlist.get_model()
        model.go_to(song)
        self.assertIs(model.current, song)
        # only restore if there was a selected one
        self.songlist.set_songs([song], scroll_select=True)
        self.assertEqual(self.songlist.get_selected_songs(), [])

    def test_get_selected_songs(self):
        song = AudioFile({"~filename": "/dev/null"})
        self.songlist.add_songs([song])
        sel = self.songlist.get_selection()

        sel.select_path(Gtk.TreePath.new_first())
        self.assertEqual(self.songlist.get_selected_songs(), [song])
        self.assertEqual(self.songlist.get_first_selected_song(), song)

        sel.unselect_all()
        self.assertEqual(self.songlist.get_selected_songs(), [])
        self.assertIs(self.songlist.get_first_selected_song(), None)

    def test_add_songs(self):
        song = AudioFile({"~filename": "/dev/null"})

        # unsorted
        self.songlist.add_songs([song])
        self.songlist.add_songs([song])

        # sorted
        self.songlist.set_column_headers(["foo"])
        self.songlist.toggle_column_sort(self.songlist.get_columns()[0])
        self.songlist.add_songs([])
        self.songlist.add_songs([song])
        self.songlist.add_songs([song])

        self.assertEqual(self.songlist.get_songs(), [song] * 4)

    def test_remove_songs(self):
        song = AudioFile({"~filename": "/dev/null"})
        song.sanitize()
        self.lib.add([song])
        assert song in self.lib, "Broken library?"
        self.songlist.add_songs([song])
        assert set(self.songlist.get_songs()) == {song}
        self.lib.remove([song])
        assert not list(self.lib), "Didn't get removed"
        run_gtk_loop()
        assert self.songs_removed == [{song}
                                      ], f"Signal not emitted: {self.__sigs}"

    def test_header_menu(self):
        song = AudioFile({"~filename": fsnative(u"/dev/null")})
        song.sanitize()
        self.songlist.set_songs([song])

        library = self.lib
        librarian = SongLibrarian()
        librarian.register(self.lib, "test")
        self.lib.librarian = librarian
        browser = TrackList(library)

        self.songlist.set_column_headers(["foo"])

        self.assertFalse(self.songlist.Menu("foo", browser, library))
        sel = self.songlist.get_selection()
        sel.select_all()
        self.assertTrue(self.songlist.Menu("foo", browser, library))
        librarian.destroy()
        self.lib.librarian = None

    def test_get_columns_migrated(self):
        self.failIf(config.get("settings", "headers", None))
        columns = "~album,~#replaygain_track_gain,foobar"
        config.set("settings", "columns", columns)
        self.failUnlessEqual(get_columns(),
                             ["~album", "~#replaygain_track_gain", "foobar"])
        self.failIf(config.get("settings", "headers", None))

    def test_get_set_columns(self):
        self.failIf(config.get("settings", "headers", None))
        self.failIf(config.get("settings", "columns", None))
        columns = ["first", "won't", "two words", "4"]
        set_columns(columns)
        self.failUnlessEqual(columns, get_columns())
        columns += ["~~another~one"]
        set_columns(columns)
        self.failUnlessEqual(columns, get_columns())
        self.failIf(config.get("settings", "headers", None))

    def test_header_tag_split(self):
        self.assertEqual(header_tag_split("foo"), ["foo"])
        self.assertEqual(header_tag_split("~foo~bar"), ["foo", "bar"])
        self.assertEqual(header_tag_split("<foo>"), ["foo"])
        self.assertEqual(header_tag_split("<~foo~bar>"), ["foo", "bar"])
        self.assertEqual(header_tag_split("pattern <~foo~bar>"),
                         ["foo", "bar"])

    def test_get_sort_tag(self):
        self.assertEqual(get_sort_tag("~#track"), "")
        self.assertEqual(get_sort_tag("artist"), "artistsort")
        self.assertEqual(get_sort_tag("date"), "date")
        self.assertEqual(get_sort_tag("~artist~date"), "~artistsort~date")
        self.assertEqual(get_sort_tag("~date~artist"), "~date~artistsort")
        self.assertEqual(get_sort_tag("composer"), "composersort")
        self.assertEqual(get_sort_tag("originalartist"), "originalartistsort")

    def test_check_sensible_menu_items(self):
        col = SongListColumn("title")

        menu = self.songlist._menu(col)
        submenus = [item.get_submenu() for item in menu.get_children()]
        names = {
            item.get_label()
            for child in submenus
            if child and not isinstance(child, Gtk.SeparatorMenuItem)
            for item in child.get_children()
        }
        assert {"Title", "Genre", "Comment", "Artist"} < names

    def tearDown(self):
        for sig in self.__sigs:
            self.songlist.disconnect(sig)
        self.songlist.destroy()
        self.lib.destroy()
        config.quit()
Exemplo n.º 21
0
 def setUp(self):
     self.pl_lib = PlaylistLibrary(SongFileLibrary())
Exemplo n.º 22
0
class StorageDevice(Device):
    protocol = 'storage'

    defaults = {
        'pattern': '<artist>/<album>/<title>',
        'covers': True,
        'unclutter': True,
    }

    __library = None
    __pattern = None

    def __init__(self, backend_id, device_id):
        super(StorageDevice, self).__init__(backend_id, device_id)
        filename = escape_filename(device_id)
        self.__library_path = os.path.join(CACHE, filename)
        self.__library_name = device_id

    def __set_pattern(self, widget=None):
        self.__pattern = FileFromPattern(
            os.path.join(self.mountpoint, self['pattern']))

    def Properties(self):
        props = []

        entry = Gtk.Entry()
        entry.set_text(self['pattern'])
        entry.connect_after('changed', self.__set_pattern)
        props.append((_("_Filename pattern:"), entry, 'pattern'))

        check = Gtk.CheckButton()
        check.set_active(self['covers'])
        props.append((_("Copy _album covers"), check, 'covers'))

        check = Gtk.CheckButton()
        check.set_active(self['unclutter'])
        props.append((_("_Remove unused covers and directories"),
            check, 'unclutter'))

        return props

    def list(self, wlb):
        self.__load_library()

        wlb.setup()
        next = self.__library.rebuild([self.mountpoint]).next
        while True:
            if wlb.quit:
                wlb.hide()
                break
            if not wlb.paused:
                try:
                    next()
                except StopIteration:
                    break
            Gtk.main_iteration()

        self.__save_library()
        return self.__library.values()

    def contains(self, song):
        return song in self.__library

    def copy(self, parent_widget, song):
        if not self.__pattern:
            self.__set_pattern()

        target = strip_win32_incompat_from_path(self.__pattern.format(song))
        dirname = os.path.dirname(target)

        if os.path.exists(target):
            dialog = ConfirmFileReplace(parent_widget, target)
            resp = dialog.run()
            if resp == ConfirmFileReplace.RESPONSE_REPLACE:
                try:
                    # Remove the current song
                    self.__library.remove([self.__library[target]])
                except KeyError:
                    pass
            else:
                return False

        try:
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            shutil.copyfile(song['~filename'], target)

            if self['covers']:
                coverfile = os.path.join(dirname, 'folder.jpg')
                cover = app.cover_manager.get_cover(song)
                if cover and mtime(cover.name) > mtime(coverfile):
                    image = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        cover.name, 200, 200)
                    image.savev(coverfile, "jpeg", [], [])

            song = copy.deepcopy(song)
            song.sanitize(target)
            self.__library.add([song])
            return song
        except (OSError, IOError, GLib.GError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def delete(self, parent_widget, song):
        try:
            path = song['~filename']
            dir = os.path.dirname(path)

            os.unlink(path)
            self.__library.remove([song])

            if self['unclutter']:
                files = glob(dir + '/*')
                if len(files) == 1 and os.path.isfile(files[0]) and \
                        os.path.basename(files[0]) == 'folder.jpg':
                    os.unlink(files[0])
                try:
                    os.removedirs(os.path.dirname(path))
                except OSError:
                    pass

            return True
        except (OSError, IOError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def cleanup(self, wlb, action):
        self.__save_library()
        return True

    def close(self):
        if self.__library:
            self.__library.destroy()
            self.__library = None

    def __load_library(self):
        if self.__library is None:
            self.__library = SongFileLibrary(self.__library_name)
            if os.path.isfile(self.__library_path):
                self.__library.load(self.__library_path)

    def __save_library(self):
        self.__library.save(self.__library_path)
Exemplo n.º 23
0
 def __load_library(self):
     if self.__library is None:
         self.__library = SongFileLibrary(self.__library_name)
         if os.path.isfile(self.__library_path):
             self.__library.load(self.__library_path)
Exemplo n.º 24
0
 def test(self):
     lib = SongFileLibrary()
     MaskedBox(lib).destroy()
Exemplo n.º 25
0
 def Library(self):
     lib = SongFileLibrary(watch_dirs=[text2fsn(str(self.temp_path))])
     # Setup needs copools
     run_gtk_loop()
     return lib
Exemplo n.º 26
0
    def test(self):
        lib = SongFileLibrary()

        with temp_filename() as song_fn:
            song = AudioFile({"~filename": song_fn})
            song.sanitize()
            lib.add([song])

            # test recovery of basic song
            data = {"path": song("~filename"), "rating": 1,
            "playcount": 1, "skipcount": 2,
            "lastplayed": 1371802107, "added": 1260691996}

            db = get_example_db(data["path"], data["rating"],
                                data["playcount"], data["skipcount"],
                                data["lastplayed"], data["added"])

            importer = self.mod.BansheeDBImporter(lib)
            importer.read(db)
            count = importer.finish()
            db.close()

            self.assertEqual(song("~#rating"), data["rating"] / 5.0)
            self.assertEqual(song("~#playcount"), data["playcount"])
            self.assertEqual(song("~#skipcount"), data["skipcount"])
            self.assertEqual(song("~#lastplayed"), data["lastplayed"])
            self.assertEqual(song("~#added"), data["added"])
            self.assertEqual(count, 1)

            # test recovery of different version of same song
            data_mod = {"path": song("~filename"), "rating": 2,
            "playcount": 4, "skipcount": 1,
            "lastplayed": data["lastplayed"] - 1, "added": data["added"] + 1}

            db = get_example_db(data_mod["path"], data_mod["rating"],
                                data_mod["playcount"], data_mod["skipcount"],
                                data_mod["lastplayed"], data_mod["added"])

            importer = self.mod.BansheeDBImporter(lib)
            importer.read(db)
            count = importer.finish()
            db.close()

            self.assertEqual(song("~#rating"), data_mod["rating"] / 5.0)
            self.assertEqual(song("~#playcount"), data_mod["playcount"])
            self.assertEqual(song("~#skipcount"), data_mod["skipcount"])
            self.assertEqual(song("~#lastplayed"), data["lastplayed"])
            self.assertEqual(song("~#added"), data["added"])
            self.assertEqual(count, 1)

            # test that no recovery is performed when data is identical
            db = get_example_db(data_mod["path"], data_mod["rating"],
                                data_mod["playcount"], data_mod["skipcount"],
                                data_mod["lastplayed"], data_mod["added"])

            importer = self.mod.BansheeDBImporter(lib)
            importer.read(db)
            count = importer.finish()
            db.close()

            self.assertEqual(count, 0)
Exemplo n.º 27
0
 def setUp(self):
     self.sfLib = SongFileLibrary()
     self.plLib = PlaylistLibrary(self.sfLib)
Exemplo n.º 28
0
class TPlaylistUtil(TestCase):

    PLAYLIST_FILE_PATH = get_data_path('test.m3u8')
    sfLib: SongFileLibrary = None
    plLib: PlaylistLibrary = None

    def setUp(self):
        self.sfLib = SongFileLibrary()
        self.plLib = PlaylistLibrary(self.sfLib)

    def tearDown(self):
        self.plLib.destroy()
        self.sfLib.destroy()

    def test_dir_for(self):
        # uri format of files added via drag and drop or add button
        # (Gtk.SelectionData.get_uris()): file:///path/to/file.ext
        url_based_file: addinfourl = urlopen("file:///" +
                                             self.PLAYLIST_FILE_PATH)
        reader_based_file: BufferedReader = open(self.PLAYLIST_FILE_PATH, "rb")

        try:
            dir_of_url_based_file: str = _dir_for(url_based_file)
            self.assertEqual(
                os.path.realpath(os.path.dirname(self.PLAYLIST_FILE_PATH)),
                os.path.realpath(dir_of_url_based_file),
                "determining the directory of url based files"
                " should result in a correct path")

            dir_of_reader_based_file: str = _dir_for(reader_based_file)
            self.assertEqual(
                os.path.realpath(os.path.dirname(self.PLAYLIST_FILE_PATH)),
                os.path.realpath(dir_of_reader_based_file, ),
                "determining the directory of reader based files"
                " should result in a correct path")

        finally:
            url_based_file.close()
            reader_based_file.close()

    def test_parse_m3u8(self):
        fileName = os.path.basename(self.PLAYLIST_FILE_PATH)
        playlist: Playlist = None

        with open(self.PLAYLIST_FILE_PATH, "rb") as file:
            try:
                playlist = parse_m3u(file, fileName, self.sfLib, self.plLib)
            except:
                assert False, ("parsing m3u8 playlists in correct format"
                               " should not cause errors")

        self.assertIsNotNone(playlist,
                             ("parsing an m3u8 playlist in the correct format"
                              " should result in a playlist"))
        # the test.m3u8 contains:
        #   - 3 existing and supported audio files from the tests/data folder:
        #     lame.mp3, test.wav, sine-110hz.flac
        #   - 1 non existing file: non_existing_audio_file.mp3
        #   - 1 not supported file: test.jpg
        # parsing the file correctly should result in a playlist with 3 entries
        self.assertEqual(
            3, len(playlist),
            "only existing files should be added to the playlist")
Exemplo n.º 29
0
 def __load_library(self):
     if self.__library is None:
         self.__library = SongFileLibrary(self.__library_name)
         if os.path.isfile(self.__library_path):
             self.__library.load(self.__library_path)
Exemplo n.º 30
0
 def setUp(self):
     config.init()
     self.p = NullPlayer()
     self.l = SongFileLibrary()
     self.w = gtk.Window()
     self.fifo = FIFOControl(self.l, self.w, self.p)