class HBDDialog(QDialog):

    restart_required = False

    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config
        self.threadpool = QThreadPool()

        # The current database shown in the GUI
        # db is an instance of the class LibraryDatabase from db/legacy.py
        # This class has many, many methods that allow you to do a lot of
        # things. For most purposes you should use db.new_api, which has
        # a much nicer interface from db/cache.py
        self.db = gui.current_db

        # Window properties
        self.setWindowTitle('Humble-Bundle Downloader')
        self.setWindowIcon(icon)

        # Create main layout
        self.mainlayout = QHBoxLayout()
        self.setLayout(self.mainlayout)

        # Create layout for buttons
        self.buttonlayout = QVBoxLayout()
        self.mainlayout.addLayout(self.buttonlayout)

        # Add label
        self.label = QLabel('')
        self.buttonlayout.addWidget(self.label)

        # Add config button
        self.conf_button = QPushButton('Configure', self)
        self.conf_button.clicked.connect(self.config)
        self.buttonlayout.addWidget(self.conf_button)

        # Add Sync button
        self.Import_button = QPushButton('Import', self)
        self.Import_button.clicked.connect(self.Download)
        self.buttonlayout.addWidget(self.Import_button)

        # Add 'about' button
        self.about_button = QPushButton('About', self)
        self.about_button.clicked.connect(self.about)
        self.buttonlayout.addWidget(self.about_button)

        # Add log pane
        self.textlog = QTextEdit(self)
        self.mainlayout.addWidget(self.textlog)
        self.textlog.setReadOnly(True)

        self.refresh_label()
        self.check_field_exists()
        self.resize(800, 200)

    def check_field_exists(self):
        db = self.db.new_api

        if HBDDialog.restart_required:
            self.textlog.append('Restart required before plugin can be used.')
        elif '#humble_filenames' in db.get_categories():
            self.textlog.append('#humble_filenames field exists.')
        else:
            self.textlog.append('#humble_filenames field does not exist...')
            self.add_field()

    def add_field(self):
        # Reference at
        # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/gui2/preferences/create_custom_column.py

        db = self.gui.library_view.model().db

        col = 'humble_filenames'
        col_heading = 'Original HB filenames'
        col_type = 'text'
        is_multiple = True
        display_dict = {
            'description':
            'Original filenames of ebooks downloaded via the HB Downloader plugin'
        }

        db.create_custom_column(label=col,
                                name=col_heading,
                                datatype=col_type,
                                is_multiple=is_multiple,
                                display=display_dict)

        HBDDialog.restart_required = True
        self.textlog.append(
            'The field has been created and will be usable after a restart.')
        self.refresh_label()

    def refresh_label(self):
        if HBDDialog.restart_required:
            self.label.setText('Calibre restart required')
            self.Import_button.setEnabled(False)
        elif prefs['cookie_auth_token'] == '':
            self.label.setText('Authentication token not set.')
            self.Import_button.setEnabled(False)
        else:
            self.label.setText('Authentication token set.')
            self.Import_button.setEnabled(True)

    def Download(self):
        db = self.db.new_api
        auth_token = prefs['cookie_auth_token']
        dl_loc = prefs['download_loc']
        log = self.textlog

        I = importer(db, auth_token, dl_loc)
        I.signals.log.connect(self.textlog.append)
        I.signals.done_downloads.connect(self.Import)

        self.threadpool.start(I)

    def Import(self, download_names):
        paths = [prefs['download_loc'] + name for name in download_names]

        Adder(paths,
              db=self.gui.current_db,
              parent=self.gui,
              pool=self.gui.spare_pool())

    def config(self):
        self.do_user_config(parent=self)
        self.refresh_label()
        self.textlog.append('Config changed.')

    def about(self):
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About Humble-Bundle downloader',
                          text.decode('utf-8'))
示例#2
0
class MainWindow(QWidget):
    def __init__(self, controller):
        super().__init__()

        self.controller = controller

        self._pomo_start_ts = None
        self._current_dropdown_tasks = []
        self._taskw_sel_task = None

        self.initUI()

    def initUI(self):
        grid = QGridLayout()
        grid.setVerticalSpacing(0.5)
        self.setLayout(grid)

        self.timer_lbl = QLabel(self)
        font = QFont('Courier New')
        font.setBold(True)
        font.setPointSize(70)
        self.timer_lbl.setFont(font)
        grid.addWidget(self.timer_lbl, 0, 0, 3, 2, Qt.AlignCenter)

        self.main_btn = QPushButton('Start', self)
        self.main_btn.clicked.connect(self.on_click_main_btn)
        grid.addWidget(self.main_btn, 0, 3, 1, 1)

        self.skip_btn = QPushButton('Skip', self)
        self.skip_btn.clicked.connect(self.on_click_skip_btn)
        grid.addWidget(self.skip_btn, 1, 3, 1, 1)

        self.reset_btn = QPushButton('Reset', self)
        self.reset_btn.clicked.connect(self.on_click_reset_btn)
        grid.addWidget(self.reset_btn, 2, 3, 1, 1)

        self.dropdown = QComboBox()
        self.dropdown.setMinimumWidth(250)
        self.dropdown.setMaximumWidth(250)
        self.dropdown.currentIndexChanged.connect(self.on_change_select_task)
        grid.addWidget(self.dropdown, 4, 0, Qt.AlignCenter)

        self.complete_btn = QPushButton('Completed', self)
        self.complete_btn.clicked.connect(self.on_click_complete_btn)
        grid.addWidget(self.complete_btn, 4, 3, 1, 1)

        self.threadpool = QThreadPool()

        self.update_timer_lbl()
        self.refresh_dropdown()

    @log_call
    def on_click_main_btn(self, _):
        if self.main_btn.text() == 'Start':
            self.start_session()
        else:
            self.stop_session()

    @log_call
    def on_click_complete_btn(self, _):
        self.stop_session()
        self.controller.taskw.complete_task(self._taskw_sel_task)
        self.refresh_dropdown()

    @log_call
    def on_click_skip_btn(self, _):
        self.controller.pomo.skip()
        self.update_timer_lbl()

    @log_call
    def on_click_reset_btn(self, _):
        self.controller.pomo.reset()
        self.update_timer_lbl()

    @log_call
    def on_change_select_task(self, i):
        self._taskw_sel_task = self._current_dropdown_tasks[i]
        log.info('Changed selected task to "%s"',
                 self._taskw_sel_task.description)

    @log_call
    def start_session(self):
        for component in [
                self.complete_btn, self.skip_btn, self.reset_btn, self.dropdown
        ]:
            component.setEnabled(False)
        if self.controller.pomo.is_work_task:
            #  self.complete_btn.setEnabled(True)
            self.threadpool.start(
                Worker(self.controller.taskw.start_task, self._taskw_sel_task))
            self.threadpool.start(
                Worker(self.controller.slack.enable_dnd,
                       n_min=self.controller.pomo.current.value // 60))
        self._pomo_start_ts = datetime.datetime.now()
        self.main_btn.setText('Stop')

    @log_call
    def stop_session(self):
        for component in [
                self.complete_btn, self.skip_btn, self.reset_btn, self.dropdown
        ]:
            component.setEnabled(True)
        if self.controller.taskw.is_running:
            self.threadpool.start(
                Worker(self.controller.taskw.stop_task, self._taskw_sel_task))
            self.threadpool.start(Worker(self.controller.slack.disable_dnd))
        self._pomo_start_ts = None
        self.main_btn.setText('Start')

    @log_call
    def refresh_dropdown(self):
        if self._pomo_start_ts is None:
            log.info('Considering a dropdown list refresh')
            self.controller.taskw.refresh()
            new_tasks = self.controller.taskw.tasks
            if new_tasks != self._current_dropdown_tasks:
                log.info('Refreshing dropdown list')
                self._current_dropdown_tasks = new_tasks
                self.dropdown.clear()
                self.dropdown.addItems(
                    [t.description for t in self._current_dropdown_tasks])

    @log_call
    def update_timer_lbl(self):
        pomo = datetime.timedelta(seconds=self.controller.pomo.current.value)
        log.debug('Current pomodoro time: %s', pomo)
        if self._pomo_start_ts:
            pomo = (self._pomo_start_ts + pomo) - datetime.datetime.now()
        self.timer_lbl.setText("{:02}:{:02}".format(pomo.seconds // 60,
                                                    pomo.seconds % 60))
        if pomo.seconds <= 0:
            self.threadpool.start(Worker(self.controller.pomo.complete))
            self.stop_session()
示例#3
0
class ImageService:
    def __init__(self, path=None):
        self._image_queue = QueueService()
        self._classified_images = list()
        self.current_image = None
        self._next_image = None

        self.num_classified_single = 0
        self.num_classified_multi = 0

        self._thread_pool = QThreadPool()

        if path:
            self.load_images(path)
            # if no path was supplied load_images(path) has to be called, before working with ImageService!

    @property
    def num_images_to_classify(self):
        return len(self._image_queue)

    @property
    def done(self):
        return self.num_images_to_classify == 0 and not self.current_image

    def load_images(self, path):
        image_data_array = FileService().read_h5_file(path)
        for id, image_data in enumerate(image_data_array):
            self._image_queue.enqueue(Image(id, image_data))
        self._image_queue.shuffle()
        self._get_next_image()

    def _get_next_image(self):
        if self._next_image:
            self.current_image = self._next_image
            self._image_queue.dequeue()
        else:
            self.current_image = self._image_queue.dequeue()

        try:
            self._preload_next_image()
        except:
            pass

    def _preload_next_image(
        self
    ):  # preloads next image in queue into memory in a different thread
        self._next_image = self._image_queue.peek()
        self._thread_pool.start(
            ThreadingService(PlotService().convert_to_image,
                             image=self._next_image))

    def skip_image(self):
        self._image_queue.enqueue(self.current_image)
        self._get_next_image()

    def classify_image(self, category):
        if category == 'single':
            self.num_classified_single += 1
        elif category == 'multi':
            self.num_classified_multi += 1
        self.current_image.classify(category)
        self._classified_images.append(self.current_image)
        try:
            self._get_next_image()
        except:
            self.current_image = None

    def save_results(self, path=Defaults.output_path):
        output = 'image_id,category\n'
        for image in sorted(self._classified_images, key=lambda img: img.id):
            output += '{},{}\n'.format(image.id, image.classification)
        FileService().write_csv_file(path, output)
示例#4
0
文件: manga.py 项目: Wiz1991/mangamix
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.threadpool = QThreadPool()
        self.initUI()

        self.initList()
        self.initSearchTab()

    def initUI(self):

        self.tabWidget = QTabWidget(self)
        self.searchEngine = SearchEngine()
        self.setGeometry(0, 0, 495, 635)
        self.center()
        self.setCentralWidget(self.tabWidget)
        self.status = self.statusBar()
        self.mainMenu = self.menuBar()

        exitAct = QAction('&Exit', self)        
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit application')
        exitAct.triggered.connect(qApp.quit)

        exportList = QAction('Export &List',self)
        exportList.setShortcut('Ctrl+L')
        exportList.setStatusTip('Export your manga list(backup)')

        reloadList = QAction('Reload list',self)
        reloadList.setShortcut('Ctrl+R')
        reloadList.triggered.connect(self.loadManga)


        fileMenu = self.mainMenu.addMenu('&File')
        fileMenu.addAction(exportList)
        fileMenu.addAction(reloadList)
        fileMenu.addAction(exitAct)
    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.ContextMenu  and
            source is self.searchResults):
            menu = QMenu()

            infoAction = QAction('Info',self)
            infoAction.setStatusTip('Show information about this manga title')
            infoAction.triggered.connect(self.showMangaInfo)

            addMangaAction = QAction('Add to list',self)
         
            addMangaAction.triggered.connect(self.addToList)
      
            
            menu.addAction(infoAction)
            menu.addAction(addMangaAction)
            menu.exec_(event.globalPos())
            return True
        return super(QMainWindow, self).eventFilter(source, event)

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
    
        
    def loadManga(self):
        self.mainLayout.clearList()

        jsonObject = json.loads(open('mangalist.json').read())

        for manga in jsonObject['Manga']:
            manga = Series(self,manga['imagePath'],manga['title'])
            self.mainLayout.addWidget(manga)
        

    def initSearchTab(self):
        box = QVBoxLayout(self.tabWidget)

        widget = QWidget(self.tabWidget)

        self.inputLine = QLineEdit(widget)
        self.inputLine.returnPressed.connect(self.searchRequest)

        self.inputLine.setPlaceholderText("Search for a manga title")
        self.inputLine.setClearButtonEnabled(True)

        self.searchResults = QListWidget(widget)
        self.searchResults.setFont(QtGui.QFont('sans-serif', 10, 650))
        self.searchResults.installEventFilter(self)
        

        box.addWidget(self.inputLine)
        box.addWidget(self.searchResults)

        widget.setLayout(box)

        self.tabWidget.addTab(widget, "Search")
    
    def executeThread(self):
        self.worker = Worker(self.addToList)
        self.worker.signals.finished.connect(self.threadFinished)
        self.threadpool.start(self.worker)
    def threadFinished(self):
        
        self.loadManga()
    def addToList(self):
        url = self.searchResults.currentItem().data(QtCore.Qt.UserRole)
        self.statusBar().showMessage("Adding Manga to list.")
        driver = webdriver.PhantomJS()
        driver.get(url)
        
        soup = bs4.BeautifulSoup(driver.page_source,'lxml')

    

        title = soup.select('.tabletitle')     
        imageUrl = soup.select('.img-fluid')
        
        image  = open('images/'+title[0].text,'wb')
        image.write(requests.get(imageUrl[2]['src']).content)
        print(imageUrl[2])
        image.close()
        imagePath = 'images/'+title[0].text
        
        description = driver.find_element_by_class_name('sContent')
        
        item = {"title": "#","description":"#","imagePath":"#"}
        item["title"] =title[0].text
        item["description"]=description.text
        item["imagePath"]=imagePath

        config = json.loads(open('mangalist.json').read())

        config["Manga"].append(item)

        with open('mangalist.json','w') as f:
            f.write(json.dumps(config,indent=4))
            f.close()
    
        self.statusBar().showMessage("Manga added.",0.5)
        self.loadManga()

    def showMangaInfo(self):
        
        print(self.searchResults.currentItem().text())

    def searchRequest(self):
        resultList = self.searchEngine.search(self.inputLine.text())

        self.inputLine.clear()
        self.searchResults.clear()

        for result in resultList:
            item = QListWidgetItem(result['title'])
            item.setData(QtCore.Qt.UserRole,result['url'])

            self.searchResults.addItem(item)

    def initList(self):
        self.mainArea = QScrollArea(self)
        self.mainArea.setWidgetResizable(True)
        mangaWidget = QWidget(self.mainArea)
        self.mainLayout = FlowLayout(mangaWidget)
        self.loadManga()
        self.mainArea.setWidget(mangaWidget)
        self.tabWidget.addTab(self.mainArea, "MangaList")