def handle_ignore(self):
        """Dummy files are in the format: .{name} 
        Do not have to get the actual filename
        """
        alert = QtWidgets.QMessageBox()
        alert.setWindowTitle("Ignore selected files")
        alert.setIcon(QtWidgets.QMessageBox.Warning)
        alert.setText(
            "You are about to ignore some files. This will generate hidden files in your download directory"
        )
        alert.setDetailedText(
            "This will generate hidden files in the download directory so that ignored "
            "files will not appear the menu in the future.\n"
            "To undo, you need to enable show hidden files in your file "
            "explorer and remove the files you want to download. E.g. if you want to download Tut_4, look for .Tut_4 and remove it"
        )
        alert.setStandardButtons(QtWidgets.QMessageBox.Ok
                                 | QtWidgets.QMessageBox.Cancel)

        retval = alert.exec_()
        if retval == QtWidgets.QMessageBox.Ok:
            path_and_nodes = self.get_paths_and_selected_nodes()
            for path, node in path_and_nodes:
                node_data = node.data(0, Qt.UserRole)
                create_dummy_file(path, sanitise_filename(node_data["name"]))
            self.downloadProgressText.setText(
                "Ignored {} files and recorded lectures".format(
                    len(path_and_nodes)))
        if retval == QtWidgets.QMessageBox.Cancel:
            pass
        def download_from_nodes(progress_callback):
            """Return tuple (files downloaded, files skipped, download_links)
            """

            numDownloaded, numSkipped = 0, 0
            data_deltas = []

            for idx, (path, node) in enumerate(paths_and_nodes):
                node_data = node.data(0, Qt.UserRole)
                node_type = node_data["type"]

                save_flag = False
                # load the download link and file name from API if needed
                if node_data.get("download_link") is None:
                    save_flag = True
                    try:
                        if node_type == "file":
                            download_link = get_file_download_link(
                                self.BbRouter, node_data["predownload_link"])
                            filename = get_filename_from_url(download_link)
                        elif node_type == "recorded_lecture":
                            download_link = get_recorded_lecture_download_link(
                                self.BbRouter, node_data["predownload_link"])
                            filename = node_data["name"] + ".mp4"
                    except Exception as e:
                        trace = traceback.format_exc()
                        progress_callback.emit((idx + 1, node_data['name'],
                                                False, None, None, trace))
                        data_deltas.append(None)
                        continue
                else:
                    download_link = node_data.get("download_link")
                    filename = node_data.get("filename")

                full_file_path = os.path.join(path,
                                              sanitise_filename(filename))
                if os.path.exists(full_file_path):
                    numSkipped += 1
                    progress_callback.emit(
                        (idx + 1, filename, False, None, None, None))
                else:
                    numDownloaded += 1
                    download(
                        self.BbRouter,
                        download_link,
                        full_file_path,
                        lambda bytes_downloaded, total_content_length:
                        progress_callback.emit(
                            (idx + 1, filename, True, bytes_downloaded,
                             total_content_length, None)),
                    )

                data_deltas.append((download_link,
                                    filename) if save_flag else None)

            return (numDownloaded, numSkipped, data_deltas)
        def traverse(data, parent, path):
            """recursively traverse NTU Learn data and render all file/video nodes, if the 
            file/video already exists, set the node as hidden
            """
            node = QtWidgets.QTreeWidgetItem(parent)
            # save relevant data fields into node.data
            node_data = {"name": data["name"], "type": data["type"]}

            data_type = data["type"]
            if data_type == "folder":
                node.setIcon(0, self.folderIcon)
                node.setFlags(node.flags() | Qt.ItemIsTristate
                              | Qt.ItemIsUserCheckable)
                next_path = os.path.join(path, sanitise_filename(data["name"]),
                                         "")
                for child in data["children"]:
                    traverse(child, node, next_path)
            elif data_type == "file" or data_type == "recorded_lecture":
                # add file/video attributes
                node_data["predownload_link"] = data["predownload_link"]
                node_data["download_link"] = data.get("download_link")
                node_data["filename"] = data.get("filename")

                # ignore file if dummy file is present
                is_dummy_file_present = dummy_file_exists(
                    path, sanitise_filename(node_data["name"]))
                is_file_present = node_data["filename"] and os.path.exists(
                    os.path.join(path, sanitise_filename(
                        node_data["filename"])))

                if is_dummy_file_present or is_file_present:
                    node.setHidden(True)

                node.setIcon(
                    0,
                    self.fileIcon if data_type == "file" else self.videoIcon)
                node.setFlags(node.flags() | Qt.ItemIsUserCheckable)
            else:
                raise Exception("unknown type", data_type)
            node.setText(0, data["name"])
            node.setCheckState(0, Qt.Unchecked)
            node.setData(0, Qt.UserRole, node_data)
        def traverse(node, path):
            if node.checkState(0) == Qt.Unchecked or node.isHidden():
                return

            node_data = node.data(0, Qt.UserRole)
            node_type = node_data["type"]
            if node_type == "file" or node_type == "recorded_lecture":
                result.append((path, node))
            else:
                next_path = os.path.join(path,
                                         sanitise_filename(node_data["name"]))
                for index in range(node.childCount()):
                    traverse(node.child(index), next_path)
 def test_sanitise_filename(self):
     name = 'Week 1: Tutorial (1/2).mp4'
     self.assertEqual('Week 1 Tutorial (1-2).mp4', sanitise_filename(name))
示例#6
0
def download_files(
    BbRouter: str,
    obj: Dict,
    download_path: str,
    ignore_files: bool = False,
    ignore_recorded_lectures: bool = False,
    to_prompt: bool = False,
):
    if obj["type"] == "folder":
        download_path = os.path.join(download_path,
                                     sanitise_filename(obj["name"]), "")
        for c in obj["children"]:
            download_files(
                BbRouter,
                c,
                download_path,
                ignore_files,
                ignore_recorded_lectures,
                to_prompt,
            )
    elif obj["type"] == "file":
        if ignore_files:
            return
        download_link = get_file_download_link(BbRouter,
                                               obj["predownload_link"])
        filename = get_filename_from_url(download_link)
        if filename is None:
            print("Unable to get filename from: {}".format(download_link))
            return
        full_file_path = os.path.join(download_path,
                                      sanitise_filename(filename))
        # although we get the filename from the download link, some have the same name as in the
        # download link so we can potentially save a network call here
        if os.path.exists(full_file_path):
            return
        print("- {}".format(full_file_path))
        download(BbRouter, download_link, full_file_path)
        return
    elif obj["type"] == "recorded_lecture":
        if ignore_recorded_lectures:
            return
        # can infer video name without expensive call to get download link
        video_name = sanitise_filename(obj["name"] + ".mp4")
        full_file_path = os.path.join(download_path, video_name)
        if os.path.exists(full_file_path) or dummy_file_exists(
                download_path, video_name):
            return
        download_link = get_recorded_lecture_download_link(
            BbRouter, obj["predownload_link"])
        video_size = get_video_download_size(download_link)
        to_download = True
        if to_prompt:
            to_download = (query_yes_no(
                "Download {}, ({})? ['Enter' for Y]".format(
                    video_name, video_size),
                default="yes") == "yes")
        if to_download:
            print("- {} ({})".format(full_file_path, video_size or "Unknown"))
            download(BbRouter, download_link, full_file_path)
        else:
            dummy_file_path = create_dummy_file(download_path, video_name)
            print("Created dummy file:", dummy_file_path)

        return