Example #1
0
def wait_for_metadata(info_hash):
    close_busy_dialog()
    percent = 0
    timeout = get_metadata_timeout()
    start_time = time.time()
    monitor = Monitor()
    progress = DialogProgress()
    progress.create(ADDON_NAME, translate(30237))

    try:
        while not api.torrent_status(info_hash).has_metadata:
            if monitor.waitForAbort(0.5):
                raise PlayError("Abort requested")
            passed_time = time.time() - start_time
            if 0 < timeout:
                if timeout < passed_time:
                    notification(translate(30238))
                    raise PlayError("No metadata after timeout")
                percent = int(100 * passed_time / timeout)
            else:
                percent = 0 if percent == 100 else (percent + 5)
            progress.update(percent)
            if progress.iscanceled():
                raise CanceledError("User canceled metadata", info_hash)
    finally:
        progress.close()
Example #2
0
def play_info_hash(info_hash, buffer=True):
    if not api.torrent_status(info_hash).has_metadata:
        wait_for_metadata(info_hash)

    files = api.files(info_hash, status=False)
    min_candidate_size = get_min_candidate_size() * 1024 * 1024
    candidate_files = [
        f for f in files if is_video(f.path) and f.length >= min_candidate_size
    ]
    if not candidate_files:
        notification(translate(30239))
        raise PlayError("No candidate files found for {}".format(info_hash))
    elif len(candidate_files) == 1:
        chosen_file = candidate_files[0]
    else:
        sort_files(candidate_files)
        chosen_index = Dialog().select(translate(30240),
                                       [f.name for f in candidate_files])
        if chosen_index < 0:
            raise PlayError("User canceled dialog select")
        chosen_file = candidate_files[chosen_index]

    if buffer:
        buffer_and_play(info_hash, chosen_file.id)
    else:
        play(info_hash, chosen_file.id)
Example #3
0
def clear_entries():
    entries = Entries()
    if entries.length() == 0:
        notification(translate(30010))
    else:
        entries.clear()
        entries.save()
        update_repository()
        notification(translate(30011))
Example #4
0
def import_entries():
    path = str_to_unicode(
        xbmc.translatePath(xbmcgui.Dialog().browse(1, translate(30002),
                                                   "files", ".json|.zip")))
    if path:
        entries = Entries()
        entries.add_entries_from_file(path)
        entries.save()
        update_repository()
        notification(translate(30012))
Example #5
0
def delete_entries():
    entries = Entries()
    if entries.length() == 0:
        notification(translate(30010))
    else:
        selected = xbmcgui.Dialog().multiselect(translate(30003), entries.ids)
        if selected:
            for index in selected:
                entries.remove(index)
            entries.save()
            update_repository()
            notification(translate(30011))
Example #6
0
def torrents():
    for torrent in api.torrents():
        torrent_li = list_item(torrent.name, "download.png")
        torrent_li.addContextMenuItems([
            (translate(30235),
             media(play_info_hash, info_hash=torrent.info_hash)),
            (translate(30208),
             action(torrent_action, torrent.info_hash, "stop"))
            if torrent.status.total == torrent.status.total_wanted else
            (translate(30209),
             action(torrent_action, torrent.info_hash, "download")),
            (translate(30210),
             action(torrent_action, torrent.info_hash, "resume"))
            if torrent.status.paused else
            (translate(30211),
             action(torrent_action, torrent.info_hash, "pause")),
            (translate(30242),
             action(torrent_action, torrent.info_hash, "remove_torrent")),
            (translate(30212),
             action(torrent_action, torrent.info_hash,
                    "remove_torrent_and_files")),
            (translate(30245),
             action(torrent_action, torrent.info_hash, "torrent_status"))
        ])
        addDirectoryItem(plugin.handle,
                         plugin.url_for(torrent_files, torrent.info_hash),
                         torrent_li,
                         isFolder=True)
Example #7
0
 def _set_type(self, t):
     self.getControl(self._radio_button_1_id).setSelected(t == self.TYPE_URL)  # Radio Button 1
     self.getControl(self._radio_button_2_id).setSelected(t == self.TYPE_PATH)  # Radio Button 2
     self.getControl(self._label_id).setLabel(translate(30203 if t == self.TYPE_URL else 30204))  # Box label
     self._type = t
     label = self._ret_val[t]
     self.getControl(self._input_button_id).setLabel(label if label else " ")
Example #8
0
def handle_player_stop(info_hash,
                       name=None,
                       initial_delay=0.5,
                       listing_timeout=10):
    if not ask_to_delete_torrent():
        return
    try:
        info = api.torrent_info(info_hash)
    except TorrestError:
        return
    if name is None:
        name = info.name

    sleep(int(initial_delay * 1000))
    start_time = time.time()
    while getCondVisibility(
            "Window.IsActive(busydialog)"
    ) and not 0 < listing_timeout < time.time() - start_time:
        sleep(100)

    remove_torrent = Dialog().yesno(ADDON_NAME, name + "\n" + translate(30241))
    if remove_torrent:
        api.remove_torrent(info_hash, delete=True)
        current_folder = getInfoLabel("Container.FolderPath")
        if current_folder == plugin.url_for(torrent_files, info_hash):
            executebuiltin("Action(Back)")
        elif current_folder == plugin.url_for(torrents):
            refresh()
Example #9
0
    def _update_progress(self):
        torrents = [
            t for t in self._api.torrents()
            if t.status.state not in (STATUS_FINISHED, STATUS_SEEDING,
                                      STATUS_PAUSED)
        ]
        torrents_count = len(torrents)

        if torrents_count > 0:
            if self._index >= torrents_count:
                download_rate = sum(t.status.download_rate for t in torrents)
                upload_rate = sum(t.status.upload_rate for t in torrents)
                progress = sum(t.status.progress
                               for t in torrents) / torrents_count
                name = kodi.translate(30106)
                self._index = 0
            else:
                download_rate = torrents[self._index].status.download_rate
                upload_rate = torrents[self._index].status.upload_rate
                progress = torrents[self._index].status.progress
                name = torrents[self._index].name
                if len(name) > 30:
                    name = name[:30] + "..."
                self._index += 1

            message = "{} - D:{}/s U:{}/s".format(name,
                                                  sizeof_fmt(download_rate),
                                                  sizeof_fmt(upload_rate))
            self._get_dialog().update(int(progress), kodi.ADDON_NAME, message)
        else:
            self._close_dialog()
Example #10
0
    def handle_crashes(self, max_crashes=5, max_consecutive_crash_time=20):
        crash_count = 0
        last_crash = 0

        while not self.waitForAbort(1):
            # Initial check to avoid using the lock most of the time
            if self._daemon.daemon_poll() is None:
                continue

            with self._lock:
                if self._enabled and self._daemon.daemon_poll() is not None:
                    logging.info("Deamon crashed")
                    kodi.notification(kodi.translate(30105))
                    self._stop()

                    crash_time = time.time()
                    time_between_crashes = crash_time - last_crash
                    if 0 < max_consecutive_crash_time < time_between_crashes:
                        crash_count = 1
                    else:
                        crash_count += 1

                    if last_crash > 0:
                        logging.info("%s seconds passed since last crash",
                                     time_between_crashes)
                    last_crash = crash_time

                    if crash_count <= max_crashes:
                        logging.info("Re-starting daemon - %s/%s", crash_count,
                                     max_crashes)
                        self._start()
                        self._wait(timeout=get_daemon_timeout(),
                                   notification=True)
Example #11
0
def dialog_insert():
    window = DialogInsert("DialogInsert.xml", ADDON_PATH, "Default")
    window.doModal()
    if window.type == DialogInsert.TYPE_PATH:
        api.add_torrent(window.ret_val, download=download_after_insert())
    elif window.type == DialogInsert.TYPE_URL:
        api.add_magnet(window.ret_val, download=download_after_insert())
    else:
        return
    notification(translate(30243), time=2000)
Example #12
0
def play_info_hash(info_hash, timeout=30, buffer=True):
    start_time = time.time()
    monitor = Monitor()
    progress = DialogProgress()
    progress.create(ADDON_NAME, translate(30237))

    try:
        while not api.torrent_status(info_hash).has_metadata:
            if monitor.waitForAbort(0.5):
                raise PlayError("Abort requested")
            passed_time = time.time() - start_time
            if 0 < timeout < passed_time:
                notification(translate(30238))
                raise PlayError("No metadata after timeout")
            progress.update(int(100 * passed_time / timeout))
            if progress.iscanceled():
                raise PlayError("User canceled metadata")
    finally:
        progress.close()

    files = api.files(info_hash, status=False)
    min_candidate_size = get_min_candidate_size() * 1024 * 1024
    candidate_files = [
        f for f in files if is_video(f.path) and f.length >= min_candidate_size
    ]
    if not candidate_files:
        notification(translate(30239))
        raise PlayError("No candidate files found for {}".format(info_hash))
    elif len(candidate_files) == 1:
        chosen_file = candidate_files[0]
    else:
        sort_files(candidate_files)
        chosen_index = Dialog().select(translate(30240),
                                       [f.name for f in candidate_files])
        if chosen_index < 0:
            raise PlayError("User canceled dialog select")
        chosen_file = candidate_files[chosen_index]

    if buffer:
        buffer_and_play(info_hash, chosen_file.id)
    else:
        play(info_hash, chosen_file.id)
Example #13
0
 def _wait(self, timeout=-1, notification=False):
     start = time.time()
     while not 0 < timeout < time.time() - start:
         try:
             self._request("get", "")
             if notification:
                 kodi.notification(kodi.translate(30104))
             return
         except requests.exceptions.ConnectionError:
             if self.waitForAbort(0.5):
                 raise AbortRequestedError("Abort requested")
     raise DaemonTimeoutError("Timeout reached")
Example #14
0
def run():
    kodi.set_logger()
    handle_first_run()
    try:
        with DaemonMonitor() as monitor:
            monitor.handle_crashes()
    except DaemonNotFoundError:
        logging.info("Daemon not found. Aborting service...")
        if service_enabled():
            set_service_enabled(False)
            xbmcgui.Dialog().ok(kodi.ADDON_NAME, kodi.translate(30103))
            kodi.open_settings()
Example #15
0
    def handle_crashes(self, max_crashes=5, max_consecutive_crash_time=20):
        crash_count = 0
        last_crash = 0

        while not self.waitForAbort(1):
            # Initial check to avoid using the lock most of the time
            if self._daemon.daemon_poll() is None:
                continue

            with self._lock:
                if self._enabled and self._daemon.daemon_poll() is not None:
                    logging.warning("Deamon crashed")
                    kodi.notification(kodi.translate(30105))
                    self._stop()

                    if os.path.exists(self._log_path):
                        path = os.path.join(
                            kodi.ADDON_DATA,
                            time.strftime("%Y%m%d_%H%M%S.") + self.log_name)
                        shutil.copy(self._log_path, path)

                    crash_time = time.time()
                    time_between_crashes = crash_time - last_crash
                    if 0 < max_consecutive_crash_time < time_between_crashes:
                        crash_count = 1
                    else:
                        crash_count += 1

                    if last_crash > 0:
                        logging.info("%.2f seconds passed since last crash",
                                     time_between_crashes)
                    last_crash = crash_time

                    if crash_count <= max_crashes:
                        logging.info("Re-starting daemon - %s/%s", crash_count,
                                     max_crashes)

                        if crash_count > 1 and os.path.exists(
                                self._settings_path):
                            logging.info("Removing old settings file")
                            os.remove(self._settings_path)

                        self._start()

                        try:
                            self._wait(timeout=get_daemon_timeout(),
                                       notification=True)
                            self._update_daemon_settings()
                        except DaemonTimeoutError:
                            logging.error("Timed out waiting for daemon")
                            last_crash = time.time()
                    else:
                        logging.info("Max crashes (%d) reached", max_crashes)
Example #16
0
def wait_for_buffering_completion(info_hash, file_id):
    close_busy_dialog()
    info = api.file_info(info_hash, file_id)
    of = translate(30244)
    timeout = get_buffering_timeout()
    last_time = last_done = 0
    start_time = time.time()

    monitor = Monitor()
    progress = DialogProgress()
    progress.create(ADDON_NAME)

    try:
        while True:
            current_time = time.time()
            status = api.file_status(info_hash, file_id)
            if status.buffering_progress >= 100:
                break

            total_done = status.buffering_total * status.buffering_progress / 100
            speed = float(total_done - last_done) / (current_time - last_time)
            last_time = current_time
            last_done = total_done
            progress.update(
                int(status.buffering_progress),
                "{} - {:.2f}%\n{} {} {} - {}/s\n{}\n".format(
                    get_state_string(status.state), status.buffering_progress,
                    sizeof_fmt(total_done), of,
                    sizeof_fmt(status.buffering_total), sizeof_fmt(speed),
                    info.name))

            if progress.iscanceled():
                raise CanceledError("User canceled buffering", info_hash)
            if 0 < timeout < current_time - start_time:
                notification(translate(30236))
                raise PlayError("Buffering timeout reached")
            if monitor.waitForAbort(1):
                raise PlayError("Abort requested")
    finally:
        progress.close()
Example #17
0
def buffer_and_play(info_hash, file_id):
    api.download_file(info_hash, file_id, buffer=True)

    monitor = Monitor()
    progress = DialogProgress()
    progress.create(ADDON_NAME)

    try:
        timeout = get_buffering_timeout()
        start_time = time.time()
        last_time = 0
        last_done = 0
        while True:
            current_time = time.time()
            status = api.file_status(info_hash, file_id)
            if status.buffering_progress >= 100:
                break

            total_done = status.buffering_total * status.buffering_progress / 100
            speed = float(total_done - last_done) / (current_time - last_time)
            last_time = current_time
            last_done = total_done
            progress.update(
                int(status.buffering_progress),
                "{} - {:.2f}%\n{} {} {} - {}/s\n\n".format(
                    get_state_string(status.state), status.buffering_progress,
                    sizeof_fmt(total_done), translate(30244),
                    sizeof_fmt(status.buffering_total), sizeof_fmt(speed)))

            if progress.iscanceled():
                raise PlayError("User canceled buffering")
            if 0 < timeout < current_time - start_time:
                notification(translate(30236))
                raise PlayError("Buffering timeout reached")
            if monitor.waitForAbort(1):
                raise PlayError("Abort requested")
    finally:
        progress.close()

    play(info_hash, file_id)
Example #18
0
def torrent_files(info_hash):
    files = api.files(info_hash)
    sort_files(files)
    for f in files:
        serve_url = api.serve_url(info_hash, f.id)
        file_li = list_item(f.name, "download.png")
        file_li.setPath(serve_url)

        context_menu_items = []
        info_labels = {"title": f.name}
        if is_picture(f.name):
            url = plugin.url_for(display_picture, info_hash, f.id)
            file_li.setInfo("pictures", info_labels)
        elif is_text(f.name):
            url = plugin.url_for(display_text, info_hash, f.id)
        else:
            url = serve_url
            if is_video(f.name):
                info_type = "video"
            elif is_music(f.name):
                info_type = "music"
            else:
                info_type = None

            if info_type is not None:
                kwargs = dict(info_hash=info_hash, file_id=f.id)
                url = plugin.url_for(play, **kwargs)
                file_li.setInfo(info_type, info_labels)
                file_li.setProperty("IsPlayable", "true")
                context_menu_items.append(
                    (translate(30235), media(buffer_and_play, **kwargs)))

        context_menu_items.append((
            translate(30209), action(file_action, info_hash, f.id, "download")
        ) if f.status.priority == 0 else (
            translate(30208), action(file_action, info_hash, f.id, "stop")))
        file_li.addContextMenuItems(context_menu_items)

        addDirectoryItem(plugin.handle, url, file_li)
Example #19
0
    def _update_daemon_settings(self):
        daemon_settings = self._get_daemon_settings()
        if daemon_settings is None:
            return False

        kodi_settings = self._get_kodi_settings()
        if daemon_settings != kodi_settings:
            logging.debug("Need to update daemon settings")
            r = self._request("post", self._settings_set_uri, json=kodi_settings)
            if r.status_code != 200:
                xbmcgui.Dialog().ok(kodi.translate(30102), r.json()["error"])
                return False

        return True
Example #20
0
def run():
    if len(sys.argv) == 1:
        selected = xbmcgui.Dialog().select(
            ADDON_NAME, [translate(30002 + i) for i in range(4)])
    elif len(sys.argv) == 2:
        method = sys.argv[1]
        try:
            selected = ("import_entries", "delete_entries", "clear_entries",
                        "update_repository").index(method)
        except ValueError:
            raise NotImplementedError("Unknown method '{}'".format(method))
    else:
        raise NotImplementedError("Unknown arguments")

    if selected == 0:
        import_entries()
    elif selected == 1:
        delete_entries()
    elif selected == 2:
        clear_entries()
    elif selected == 3:
        update_repository(True)
Example #21
0
def handle_first_run():
    logging.info("Handling first run")
    xbmcgui.Dialog().ok(kodi.translate(30100), kodi.translate(30101))
    kodi.open_settings()
Example #22
0
def update_repository(notify=False):
    get_request("http://127.0.0.1:{}/update".format(get_repository_port()),
                timeout=2)
    if notify:
        notification(translate(30013))
Example #23
0
def get_state_string(state):
    if 0 <= state <= 9:
        return translate(30220 + state)
    return translate(30230)
Example #24
0
def li(tid, icon):
    return list_item(translate(tid), icon)