Пример #1
0
def is_external(book):
    """
    Tests whether the given book is saved on external storage.
    """
    return any(storage.path in Track.select().join(Book).where(
        Book.id == book.id).first().file
               for storage in Storage.select().where(Storage.external == True))
Пример #2
0
def load_last_book():
    """
    Load the last played book into the player.
    """
    global __current_track
    global __player

    last_book = Settings.get().last_played_book

    if last_book and last_book.position != 0:

        query = Track.select().where(Track.id == last_book.position)
        if query.exists():
            last_track = query.get()

            if last_track:
                __player.set_state(Gst.State.NULL)
                if cozy.control.filesystem_monitor.FilesystemMonitor(
                ).is_track_online(last_track):
                    path = last_track.file
                else:
                    path = OfflineCache().get_cached_path(last_track)
                    if not path:
                        return
                __player.set_property("uri", "file://" + path)
                __player.set_state(Gst.State.PAUSED)
                __current_track = last_track

                Book.update(last_played=int(time.time())).where(
                    Book.id == last_book.id).execute()

                emit_event("track-changed", last_track)
Пример #3
0
    def __on_button_press(self, eventbox, event):
        """
        Play the selected track.
        """
        current_track = player.get_current_track()

        if current_track and current_track.id == self.track.id:
            player.play_pause(None)
            if player.get_gst_player_state() == Gst.State.PLAYING:
                player.jump_to_ns(Track.select().where(
                    Track.id == self.track.id).get().position)
        else:
            player.load_file(
                Track.select().where(Track.id == self.track.id).get())
            player.play_pause(None, True)
            Book.update(position=self.track).where(
                Book.id == self.track.book.id).execute()
Пример #4
0
def search_tracks(search_string):
    """
    Search all tracks in the db with the given substring.
    This ignores upper/lowercase.
    :param search_string: substring to search for
    :return: tracks matching the substring
    """
    return Track.select(Track.name).where(
        Track.name.contains(search_string)).order_by(Track.name)
Пример #5
0
def get_tracks(book):
    """
    Find all tracks that belong to a given book

    :param book: the book object
    :return: all tracks belonging to the book object
    """
    return Track.select().join(Book).where(Book.id == book.id).order_by(
        Track.disk, Track.number, Track.name)
Пример #6
0
def rebase_location(ui, oldPath, newPath):
    """
    This gets called when a user changes the location of the audio book folder.
    Every file in the database updated with the new path.
    Note: This does not check for the existence of those files.
    """
    trackCount = Track.select().count()
    currentTrackCount = 0
    for track in Track.select():
        newFilePath = track.file.replace(oldPath, newPath)
        Track.update(file=newFilePath).where(Track.id == track.id).execute()
        StorageBlackList.update(path=newFilePath).where(
            StorageBlackList.path == track.file).execute()
        Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE,
                             ui.titlebar.update_progress_bar.set_fraction,
                             currentTrackCount / trackCount)
        currentTrackCount = currentTrackCount + 1

    Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.switch_to_playing)
Пример #7
0
def clean_books():
    """
    Remove all books that have no tracks
    """
    for book in Book.select():
        if not get_track_for_playback(book):
            Book.update(position=0).where(Book.id == book.id).execute()
        if Track.select().where(Track.book == book).count() < 1:
            if Settings.get().last_played_book.id == book.id:
                Settings.update(last_played_book=None).execute()
            book.delete_instance()
Пример #8
0
def remove_tracks_with_path(ui, path):
    """
    Remove all tracks that contain the given path.
    """
    if path == "":
        return

    for track in Track.select():
        if path in track.file:
            track.delete_instance()

    clean_books()

    Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.refresh_content)
Пример #9
0
def remove_invalid_entries(ui=None, refresh=False):
    """
    Remove track entries from db that no longer exist in the filesystem.
    """
    # remove entries from the db that are no longer existent
    for track in Track.select():
        from cozy.control.filesystem_monitor import FilesystemMonitor
        if not os.path.isfile(
                track.file) and FilesystemMonitor().is_track_online(track):
            track.delete_instance()

    clean_books()

    if refresh:
        Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.refresh_content)
Пример #10
0
def get_current_track():
    """
    Get the currently loaded track object.
    :return: currently loaded track object
    """
    global __current_track
    if __current_track:
        query = Track.select().where(Track.id == __current_track.id)
        if query.exists():
            return query.get()
        else:
            __current_track = None
            return None
    else:
        return None
Пример #11
0
    def locate(self, button):
        """
        Locate the file and update the database if the user selected one.
        """
        directory, filename = os.path.split(self.missing_file)
        dialog = Gtk.FileChooserDialog(
            "Please locate the file " + filename, self.parent.window,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        filter = Gtk.FileFilter()
        filter.add_pattern(filename)
        filter.set_name(filename)
        dialog.add_filter(filter)
        path, file_extension = os.path.splitext(self.missing_file)
        filter = Gtk.FileFilter()
        filter.add_pattern("*" + file_extension)
        filter.set_name(file_extension + " files")
        dialog.add_filter(filter)
        filter = Gtk.FileFilter()
        filter.add_pattern("*")
        filter.set_name(_("All files"))
        dialog.add_filter(filter)
        dialog.set_local_only(False)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            new_location = dialog.get_filename()
            Track.update(file=new_location).where(
                Track.file == self.missing_file).execute()

            directory, filename = os.path.split(new_location)
            importer.import_file(filename,
                                 directory,
                                 new_location,
                                 update=True)
            self.parent.refresh_content()
            self.dialog.destroy()
            self.parent.dialog_open = False
            player.load_file(
                Track.select().where(Track.file == new_location).get())
            player.play_pause(None, True)

        dialog.destroy()
Пример #12
0
def get_track_for_playback(book):
    """
    Finds the current track to playback for a given book.
    :param book: book which the next track is required from
    :return: current track position from book db
    """
    book = Book.select().where(Book.id == book.id).get()
    query = Track.select().where(Track.id == book.position)
    if book.position < 1:
        track_items = get_tracks(book)
        if len(track_items) > 0:
            track = get_tracks(book)[0]
        else:
            track = None
    elif query.exists():
        track = query.get()
    else:
        track = None
    return track
Пример #13
0
def update_database(ui, force=False):
    """
    Scans the audio book directory for changes and new files.
    Also removes entries from the db that are no longer existent.
    """
    paths = []
    for location in Storage.select():
        if os.path.exists(location.path):
            paths.append(location.path)

    # clean artwork cache
    artwork_cache.delete_artwork_cache()

    # are UI buttons currently blocked?
    player_blocked, importer_blocked = ui.get_ui_buttons_blocked()

    i = 0
    percent_counter = 0
    file_count = 0
    for path in paths:
        file_count += sum([len(files) for r, d, files in os.walk(path)])

    percent_threshold = file_count / 1000
    failed = ""
    tracks_to_import = []
    # Tracks which changed and need to be updated if they are cached
    tracks_cache_update = []
    start = time.time()
    for path in paths:
        for directory, subdirectories, files in os.walk(path):
            for file in files:
                if file.lower().endswith(
                    ('.mp3', '.ogg', '.flac', '.m4a', '.wav', '.opus')):
                    path = os.path.join(directory, file)

                    imported = True
                    try:
                        if force:
                            imported, ignore = import_file(
                                file, directory, path, True)
                            tracks_cache_update.append(path)
                        # Is the track already in the database?
                        elif Track.select().where(
                                Track.file == path).count() < 1:
                            imported, track_data = import_file(
                                file, directory, path)
                            if track_data:
                                tracks_to_import.append(track_data)
                        # Has the modified date changed?
                        elif (Track.select().where(
                                Track.file == path).first().modified <
                              os.path.getmtime(path)):
                            imported, ignore = import_file(file,
                                                           directory,
                                                           path,
                                                           update=True)
                            tracks_cache_update.append(path)

                        if not imported:
                            failed += path + "\n"
                    except UnicodeEncodeError as e:
                        log.warning(
                            "Could not import file because of invalid path or filename: "
                            + path)
                        reporter.exception("importer", e)
                        failed += path + "\n"
                    except Exception as e:
                        log.warning("Could not import file: " + path)
                        log.warning(traceback.format_exc())
                        reporter.exception("importer", e)
                        failed += path + "\n"

                    i = i + 1

                    if len(tracks_to_import) > 100:
                        write_tracks_to_db(tracks_to_import)
                        tracks_to_import = []

                    # don't flood gui updates
                    if percent_counter < percent_threshold:
                        percent_counter = percent_counter + 1
                    else:
                        percent_counter = 1
                        Gdk.threads_add_idle(
                            GLib.PRIORITY_DEFAULT_IDLE,
                            ui.titlebar.progress_bar.set_fraction,
                            i / file_count)
                        Gdk.threads_add_idle(
                            GLib.PRIORITY_DEFAULT_IDLE,
                            ui.titlebar.update_progress_bar.set_fraction,
                            i / file_count)

    write_tracks_to_db(tracks_to_import)
    end = time.time()
    log.info("Total import time: " + str(end - start))

    # remove entries from the db that are no longer existent
    remove_invalid_entries()
    artwork_cache.generate_artwork_cache()

    Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.refresh_content)
    Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.switch_to_playing)
    Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, ui.check_for_tracks)

    if len(failed) > 0:
        Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE,
                             ui.display_failed_imports, failed)

    OfflineCache().update_cache(tracks_cache_update)
    OfflineCache()._process_queue()
Пример #14
0
def Search(search):
    return Track.select().where(search in Track.name)