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
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
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
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
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")
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 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())
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]
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
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
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()
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)
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)
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)
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)
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()
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())
def test_library_contains_books(peewee_database): from cozy.model.library import Library library = Library(peewee_database) assert len(library.books) > 0
def test_library_contains_books(): from cozy.model.library import Library library = Library() assert len(library.books) > 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")
def test_prepare_db_objects_skips_none(): from cozy.model.library import Library library = Library() library._prepare_db_objects([None, None, None])