Beispiel #1
0
def test_update_track_db_object_updates_object():
    from cozy.model.library import Library
    from cozy.media.media_file import MediaFile
    from cozy.db.book import Book
    from cozy.media.chapter import Chapter
    from cozy.db.track import Track

    library = Library()

    chapter = Chapter("New Chapter", 0)
    media_file = MediaFile(book_name="New Book Name",
                           author="New Author",
                           reader="New Reader",
                           disk=999,
                           track_number=999,
                           length=1234567,
                           cover=b"cover",
                           path="test.mp3",
                           modified=1234567,
                           chapters=[chapter])

    book = Book.select().get()

    library._update_track_db_object(media_file, book)

    track_in_db: Track = Track.select().where(Track.file == "test.mp3").get()

    assert track_in_db.name == "New Chapter"
    assert track_in_db.disk == 999
    assert track_in_db.number == 999
    assert track_in_db.length == 1234567
    assert track_in_db.modified == 1234567
Beispiel #2
0
def test_create_book_db_object_creates_object():
    from cozy.model.library import Library
    from cozy.media.media_file import MediaFile
    from cozy.db.book import Book
    from cozy.media.chapter import Chapter

    library = Library()

    chapter = Chapter("New Chapter", 0)
    media_file = MediaFile(book_name="New Book",
                           author="New Author",
                           reader="New Reader",
                           disk=999,
                           track_number=999,
                           length=1234567,
                           cover=b"cover",
                           path="test.mp3",
                           modified=1234567,
                           chapters=[chapter])

    library._create_book_db_object(media_file)

    book_in_db: Book = Book.select().where(Book.name == "New Book").get()

    assert book_in_db.name == "New Book"
    assert book_in_db.author == "New Author"
    assert book_in_db.reader == "New Reader"
    assert book_in_db.cover == b"cover"
    assert book_in_db.position == 0
    assert book_in_db.rating == -1
Beispiel #3
0
def test_create_track_db_object_creates_object():
    from cozy.model.library import Library
    from cozy.media.media_file import MediaFile
    from cozy.db.book import Book
    from cozy.media.chapter import Chapter

    library = Library()

    chapter = Chapter("New Chapter", 0)
    media_file = MediaFile(book_name="New Book Name",
                           author="New Author",
                           reader="New Reader",
                           disk=999,
                           track_number=999,
                           length=1234567,
                           cover=b"cover",
                           path="New File",
                           modified=1234567,
                           chapters=[chapter])

    book = Book.select().get()

    res_dict = library._get_track_dictionary_for_db(media_file, book)

    assert res_dict["name"] == "New Chapter"
    assert res_dict["disk"] == 999
    assert res_dict["number"] == 999
    assert res_dict["book"] == book
    assert res_dict["file"] == "New File"
    assert res_dict["length"] == 1234567
    assert res_dict["modified"] == 1234567
    assert res_dict["position"] == 0
Beispiel #4
0
def test_deleted_book_removed_from_list():
    from cozy.model.library import Library

    library = Library()

    book = next(iter(library.books))
    library._on_book_event("book-deleted", next(iter(library.books)))

    assert book not in library.books
Beispiel #5
0
def test_rebase_path():
    from cozy.model.library import Library

    library = Library()
    chapters = {
        chapter
        for chapter in library.chapters
        if chapter.file.startswith("20.000 Meilen unter dem Meer")
    }
    library.rebase_path("20.000 Meilen unter dem Meer", "new path")
Beispiel #6
0
    def __init__(self):
        super().__init__()

        self._model = Library(get_db())

        self._fs_monitor: FilesystemMonitor = FilesystemMonitor()
        self._application_settings: ApplicationSettings = ApplicationSettings()
        self._importer: Importer = importer_instance
        self._player: Player = Player()

        self._library_view_mode: LibraryViewMode = LibraryViewMode.CURRENT
        self._selected_filter: str = _("All")

        self._connect()
Beispiel #7
0
 def configure_inject(self, binder):
     binder.bind_to_provider(SqliteDatabase, get_db)
     binder.bind("MainWindow", self.main_window)
     binder.bind_to_constructor(
         Gio.Settings, lambda: Gio.Settings("com.github.geigi.cozy"))
     binder.bind_to_constructor(ApplicationSettings,
                                lambda: ApplicationSettings())
     binder.bind_to_constructor(Settings, lambda: Settings())
     binder.bind_to_constructor("FilesystemMonitor",
                                lambda: FilesystemMonitor())
     binder.bind_to_constructor(OfflineCache, lambda: OfflineCache())
     binder.bind_to_constructor(Player, lambda: Player())
     binder.bind_to_constructor(Library, lambda: Library())
     binder.bind_to_constructor(LibraryViewModel,
                                lambda: LibraryViewModel())
     binder.bind_to_constructor(SearchViewModel, lambda: SearchViewModel())
     binder.bind_to_constructor(UISettings, lambda: UISettings())
     binder.bind_to_constructor(StorageBlockList,
                                lambda: StorageBlockList())
     binder.bind_to_constructor(Files, lambda: Files())
     binder.bind_to_constructor(BookDetailViewModel,
                                lambda: BookDetailViewModel())
     binder.bind_to_constructor(PlaybackControlViewModel,
                                lambda: PlaybackControlViewModel())
     binder.bind_to_constructor(HeaderbarViewModel,
                                lambda: HeaderbarViewModel())
     binder.bind_to_constructor(PlaybackSpeedViewModel,
                                lambda: PlaybackSpeedViewModel())
     binder.bind_to_constructor(SleepTimerViewModel,
                                lambda: SleepTimerViewModel())
Beispiel #8
0
def test_empty_last_book_returns_none():
    from cozy.model.library import Library

    library = Library()
    library._settings.last_played_book = library.books[0]._db_object

    assert library.last_played_book is library.books[0]
Beispiel #9
0
def test_empty_last_book_returns_none():
    from cozy.model.library import Library

    library = Library()
    library._settings.last_played_book = None

    assert library.last_played_book is None
Beispiel #10
0
def test_deleted_chapter_removed_from_lists():
    from cozy.model.library import Library

    library = Library()

    chapter = next(iter(library.chapters))
    library._load_all_files()
    library._load_all_chapters()
    library._on_chapter_event("chapter-deleted", next(iter(library.chapters)))

    assert chapter not in library.chapters
    assert chapter.file not in library.files
Beispiel #11
0
def setup_inject(peewee_database):
    inject.clear_and_configure(
        lambda binder: binder.bind(SqliteDatabase, peewee_database).
        bind_to_constructor("FilesystemMonitor", MagicMock(
        )).bind_to_constructor(GstPlayer, MagicMock()).bind_to_constructor(
            ApplicationSettings, MagicMock()).bind_to_constructor(
                Library, lambda: Library()).bind_to_constructor(
                    Settings, lambda: Settings()))

    yield
    inject.clear()
Beispiel #12
0
    def __init__(self, main_window_builder, main_window):
        self.main_window: CozyUI = main_window
        self.library_model: Library = Library(get_db())

        self.library_view_model: LibraryViewModel = LibraryViewModel(self.library_model)
        self.search_view_model: SearchViewModel = SearchViewModel(self.library_model)

        self.library_view: LibraryView = LibraryView(main_window_builder, self.library_view_model)
        self.search_view: SearchView = SearchView(main_window_builder, self.search_view_model)

        self.search_view_model.add_listener(self._on_open_view)
Beispiel #13
0
def test_authors_contains_every_author_from_db(peewee_database):
    from cozy.model.library import Library
    from cozy.db.book import Book

    library = Library(peewee_database)
    books = Book.select(Book.author).distinct().order_by(Book.author)
    authors_from_db = [book.author for book in books]

    # we cannot assert the same content as the library filters books without chapters
    assert len(library.authors) > 0
    assert library.authors.issubset(authors_from_db)
Beispiel #14
0
def test_readers_contains_every_reader_from_db():
    from cozy.model.library import Library
    from cozy.db.book import Book

    library = Library()
    books = Book.select(Book.reader).distinct().order_by(Book.reader)
    readers_from_db = [book.reader for book in books]
    readers_from_db = list(split_strings_to_set(set(readers_from_db)))

    # we cannot assert the same content as the library filters books without chapters
    assert len(library.readers) > 0
    assert library.readers.issubset(readers_from_db)
Beispiel #15
0
def test_prepare_db_objects_raises_not_implemented_for_multi_chapter_file(mocker):
    from cozy.model.library import Library
    from cozy.media.media_file import MediaFile
    from cozy.media.chapter import Chapter

    library = Library()

    chapter = Chapter("New Chapter", 0)
    media_file = MediaFile(book_name="Test Book New",
                           author="New Author2",
                           reader="New Reader",
                           disk=999,
                           track_number=999,
                           length=1234567,
                           cover=b"cover",
                           path="New test File",
                           modified=1234567,
                           chapters=[chapter, chapter])

    with pytest.raises(NotImplementedError):
        res_dict = library._prepare_db_objects([media_file])
        list(res_dict)
Beispiel #16
0
def test_prepare_db_objects_creates_new_book(mocker):
    from cozy.model.library import Library
    from cozy.media.media_file import MediaFile
    from cozy.media.chapter import Chapter

    library = Library()
    spy = mocker.spy(library, "_create_book_db_object")

    chapter = Chapter("New Chapter", 0)
    media_file = MediaFile(book_name="Test Book New",
                           author="New Author2",
                           reader="New Reader",
                           disk=999,
                           track_number=999,
                           length=1234567,
                           cover=b"cover",
                           path="New test File",
                           modified=1234567,
                           chapters=[chapter])

    res_dict = library._prepare_db_objects([media_file])

    assert len(list(res_dict)) == 1
    spy.assert_called_once()
Beispiel #17
0
 def configure_inject(binder):
     binder.bind_to_provider(SqliteDatabase, get_db)
     binder.bind_to_constructor(
         Gio.Settings, lambda: Gio.Settings("com.github.geigi.cozy"))
     binder.bind_to_constructor(ApplicationSettings,
                                lambda: ApplicationSettings())
     binder.bind_to_constructor(Settings, lambda: Settings())
     binder.bind_to_constructor("FilesystemMonitor",
                                lambda: FilesystemMonitor())
     binder.bind_to_constructor(Library, lambda: Library())
     binder.bind_to_constructor(LibraryViewModel,
                                lambda: LibraryViewModel())
     binder.bind_to_constructor(SearchViewModel, lambda: SearchViewModel())
     binder.bind_to_constructor(UISettings, lambda: UISettings())
     binder.bind_to_constructor(StorageBlockList,
                                lambda: StorageBlockList())
     binder.bind_to_constructor(Files, lambda: Files())
Beispiel #18
0
def test_library_contains_books(peewee_database):
    from cozy.model.library import Library

    library = Library(peewee_database)

    assert len(library.books) > 0
Beispiel #19
0
def test_library_contains_books():
    from cozy.model.library import Library

    library = Library()

    assert len(library.books) > 0
Beispiel #20
0
class LibraryViewModel(Observable):
    def __init__(self):
        super().__init__()

        self._model = Library(get_db())

        self._fs_monitor: FilesystemMonitor = FilesystemMonitor()
        self._application_settings: ApplicationSettings = ApplicationSettings()
        self._importer: Importer = importer_instance
        self._player: Player = Player()

        self._library_view_mode: LibraryViewMode = LibraryViewMode.CURRENT
        self._selected_filter: str = _("All")

        self._connect()

    def _connect(self):
        self._fs_monitor.add_listener(self._on_fs_monitor_event)
        self._application_settings.add_listener(
            self._on_application_setting_changed)
        self._importer.add_listener(self._on_importer_event)
        self._player.add_listener(self._on_player_event)

    @property
    def books(self):
        return self._model.books

    @property
    def library_view_mode(self):
        return self._library_view_mode

    @library_view_mode.setter
    def library_view_mode(self, value):
        self._library_view_mode = value
        self._notify("library_view_mode")

    @property
    def selected_filter(self):
        return self._selected_filter

    @selected_filter.setter
    def selected_filter(self, value):
        self._selected_filter = value
        self._notify("selected_filter")

    @property
    def is_any_book_in_progress(self):
        return any(book.position > 0 for book in self.books)

    @property
    def authors(self):
        is_book_online = self._fs_monitor.get_book_online
        show_offline_books = not self._application_settings.hide_offline
        swap_author_reader = self._application_settings.swap_author_reader

        authors = {
            book.author if not swap_author_reader else book.reader
            for book in self._model.books
            if is_book_online(book) or show_offline_books
        }

        return sorted(authors)

    @property
    def readers(self):
        is_book_online = self._fs_monitor.get_book_online
        show_offline_books = not self._application_settings.hide_offline
        swap_author_reader = self._application_settings.swap_author_reader

        readers = {
            book.reader if not swap_author_reader else book.author
            for book in self._model.books
            if is_book_online(book) or show_offline_books
        }

        return sorted(readers)

    def playback_book(self, book: Book):
        # Pause/Play book here
        pass

    def remove_book(self, book: Book):
        book.blacklist()
        self._model.invalidate()
        self._notify("authors")
        self._notify("readers")
        self._notify("books")
        self._notify("books-filter")

    def switch_screen(self, screen: str):
        pass

    def display_book_filter(self, book_element: BookElement):
        book = book_element.book
        swap_author_reader = self._application_settings.swap_author_reader
        author = book.author if not swap_author_reader else book.reader
        reader = book.reader if not swap_author_reader else book.author

        hide_offline_books = self._application_settings.hide_offline
        book_is_online = self._fs_monitor.get_book_online(book)

        if hide_offline_books and not book_is_online and not book.downloaded:
            return False

        if self.library_view_mode == LibraryViewMode.CURRENT:
            return True if book.last_played > 0 else False

        if self.selected_filter == _("All"):
            return True
        elif self.library_view_mode == LibraryViewMode.AUTHOR:
            return True if author == self.selected_filter else False
        elif self.library_view_mode == LibraryViewMode.READER:
            return True if reader == self.selected_filter else False

    def display_book_sort(self, book_element1, book_element2):
        if self._library_view_mode == LibraryViewMode.CURRENT:
            return book_element1.book.last_played < book_element2.book.last_played
        else:
            return book_element1.book.name.lower(
            ) > book_element2.book.name.lower()

    def _on_fs_monitor_event(self, event, _):
        if event == "storage-online":
            self._notify("authors")
            self._notify("readers")
            self._notify("books-filter")
        elif event == "storage-offline":
            self._notify("authors")
            self._notify("readers")
            self._notify("books-filter")
        elif event == "external-storage-added":
            pass
        elif event == "external-storage-removed":
            pass

    def _on_application_setting_changed(self, event, _):
        if event == "hide-offline":
            self._notify("authors")
            self._notify("readers")
            self._notify("books-filter")
        elif event == "swap-author-reader":
            self._notify("authors")
            self._notify("readers")

    def _on_importer_event(self, event, _):
        if event == "import-finished":
            self._model.invalidate()
            self._notify("authors")
            self._notify("readers")
            self._notify("books")
            self._notify("books-filter")
            self._notify("library_view_mode")

    def _on_player_event(self, event, message):
        if event == "play":
            track_id = message
            book = None

            for b in self._model.books:
                if any(chapter.id == track_id for chapter in b.chapters):
                    book = b
                    break

            if book:
                book.reload()
                self._notify("books-filter")
Beispiel #21
0
def test_prepare_db_objects_skips_none():
    from cozy.model.library import Library
    library = Library()

    library._prepare_db_objects([None, None, None])