├── .gitignore ├── PixivAgent.py ├── PixivAgent.ui ├── README.md ├── cert.cer ├── icon.bmp ├── ui_PixivAgent.py └── uic.bat /.gitignore: -------------------------------------------------------------------------------- 1 | # Pixiv Agent 2 | Download/ 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *.pyc 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | 60 | # ========================= 61 | # Operating System Files 62 | # ========================= 63 | 64 | # OSX 65 | # ========================= 66 | 67 | .DS_Store 68 | .AppleDouble 69 | .LSOverride 70 | 71 | # Thumbnails 72 | ._* 73 | 74 | # Files that might appear on external disk 75 | .Spotlight-V100 76 | .Trashes 77 | 78 | # Directories potentially created on remote AFP share 79 | .AppleDB 80 | .AppleDesktop 81 | Network Trash Folder 82 | Temporary Items 83 | .apdisk 84 | 85 | # Windows 86 | # ========================= 87 | 88 | # Windows image file caches 89 | Thumbs.db 90 | ehthumbs.db 91 | 92 | # Folder config file 93 | Desktop.ini 94 | 95 | # Recycle Bin used on file shares 96 | $RECYCLE.BIN/ 97 | 98 | # Windows Installer files 99 | *.cab 100 | *.msi 101 | *.msm 102 | *.msp 103 | 104 | # Windows shortcuts 105 | *.lnk 106 | -------------------------------------------------------------------------------- /PixivAgent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import re 5 | import sys 6 | import threading 7 | import queue 8 | import shutil 9 | from zipfile import ZipFile 10 | 11 | import requests 12 | from lxml import html 13 | from wand.image import Image 14 | 15 | import ui_PixivAgent 16 | from PyQt5.QtCore import * 17 | from PyQt5.QtWidgets import * 18 | from PyQt5.QtGui import * 19 | 20 | 21 | class Work(object): 22 | def __init__(self, session, url_work): 23 | super(Work, self).__init__() 24 | self.session = session 25 | self.url = url_work 26 | self.page = self.get_page(self.url) 27 | self.type = self.get_type() 28 | self.id = self.get_id() 29 | self.title = self.get_title() 30 | self.urls_image = self.get_urls_image() 31 | 32 | def __len__(self): 33 | return len(self.urls_image) 34 | 35 | def get_page(self, url): 36 | request = self.session.get(url=url) 37 | etree = html.document_fromstring(request.content) 38 | etree.make_links_absolute("http://www.pixiv.net/") 39 | return etree 40 | 41 | def get_type(self): 42 | elem_works_display = self.page.find_class("works_display") 43 | if elem_works_display[0].find_class("player"): 44 | return "ugoira" 45 | elif elem_works_display[0].find_class("manga"): 46 | return "manga" 47 | elif elem_works_display[0].find_class("multiple"): 48 | return "multiple" 49 | else: 50 | return "illust" 51 | 52 | def get_id(self): 53 | return re.findall(r"\d+$", self.url)[0] 54 | 55 | def get_title(self): 56 | return self.page.find_class("work-info")[0].find_class("title")[0].text 57 | 58 | def get_urls_image(self): 59 | if self.type == "ugoira": 60 | url = re.findall(r'http\S*?1080\.zip', html.tostring(self.page).decode('utf-8')) 61 | return url[0].replace("\\", "") # TODO: __len__相关 62 | elif self.type == "illust": 63 | elems_image = self.page.find_class("original-image") 64 | elif self.type == "multiple": 65 | url = self.page.find_class("works_display")[0].find("a").get("href") 66 | elems_image = self.get_page(url).find_class("image") 67 | elif self.type == "manga": 68 | url = self.page.find_class("works_display")[0].find("a").get("href") 69 | elems_image = self.get_page(url).find_class("image") 70 | return [elem_image.get("data-src") for elem_image in elems_image] 71 | 72 | def download(self, dir, signal): 73 | # windows不合法文件名转义 74 | dir_name = self.title+" "+self.id 75 | escaped = re.sub(r'[/\\:*?"<>|]', '-', dir_name) 76 | dir_download = os.path.join(dir, escaped) 77 | if not os.path.exists(dir_download): 78 | os.makedirs(dir_download) 79 | 80 | if self.type == "ugoira": 81 | dir_temp = os.path.join(dir_download, "temp") 82 | dir_zip = os.path.join(dir_temp, self.id+".zip") 83 | 84 | # 下载压缩包至临时文件夹 85 | if not os.path.exists(dir_temp): 86 | os.makedirs(dir_temp) 87 | url = self.urls_image 88 | request_zip = self.session.get(url, stream=True) 89 | total_length = int(request_zip.headers.get('content-length')) 90 | downloaded_len = 0 91 | with open(dir_zip, "wb") as file: 92 | for chunk in request_zip.iter_content(128): 93 | file.write(chunk) 94 | downloaded_len += len(chunk) 95 | percent = int(downloaded_len*100/total_length) 96 | signal.emit(self.progress, percent) 97 | 98 | # 解压&转换gif 99 | frames = [] 100 | with ZipFile(dir_zip) as file_zip: 101 | for image in file_zip.namelist(): 102 | file_zip.extract(image, dir_temp) 103 | frames.append(Image(filename=os.path.join(dir_temp, image))) 104 | 105 | dir_gif = os.path.join(dir_download, self.id+'.gif') 106 | 107 | delay = 10 108 | with Image() as file_gif: 109 | file_gif.sequence.extend(frames) 110 | for frame in file_gif.sequence: 111 | with frame: 112 | frame.delay = delay 113 | file_gif.save(filename=dir_gif) 114 | 115 | # 删除临时文件 116 | shutil.rmtree(dir_temp) 117 | else: 118 | for i, url in enumerate(self.urls_image): 119 | request_image = self.session.get(url, stream=True) 120 | total_length = int(request_image.headers.get('content-length')) 121 | downloaded_len = 0 122 | if self.type == "illust": 123 | with open(os.path.join(dir_download, self.id+".jpg"), "wb") as file: 124 | for chunk in request_image.iter_content(128): 125 | file.write(chunk) 126 | downloaded_len += len(chunk) 127 | percent = int(downloaded_len*100/total_length) 128 | signal.emit(self.progress, percent) 129 | elif self.type == "multiple" or "manga": 130 | with open(os.path.join(dir_download, self.id+"_"+str(i+1)+r".jpg"), "wb") as file: 131 | for chunk in request_image.iter_content(256): 132 | file.write(chunk) 133 | downloaded_len += len(chunk) 134 | percent = int((i+downloaded_len/total_length)*100/len(self)) 135 | signal.emit(self.progress, percent) 136 | 137 | 138 | class Main(QDialog, ui_PixivAgent.Ui_main): 139 | # Signals 140 | signal_login_status = pyqtSignal(bool) 141 | 142 | signal_analyse_start = pyqtSignal() 143 | signal_analyse_status = pyqtSignal(bool) 144 | 145 | signal_add_row = pyqtSignal(Work) 146 | signal_update_bar = pyqtSignal(QProgressBar, int) 147 | 148 | def __init__(self): 149 | QDialog.__init__(self) 150 | ui_PixivAgent.Ui_main.__init__(self) 151 | self.setupUi(self) 152 | self.set_login_mode(True) 153 | self.amount.setValue(5) 154 | self.dir.setText(os.path.join(os.getcwd(), "Download")) 155 | 156 | # 初始化下载列表Gui 157 | self.hide_table() 158 | self.table.setSelectionBehavior(QTableWidget.SelectRows) 159 | self.table.setEditTriggers(QTableWidget.NoEditTriggers) 160 | self.table.setColumnWidth(0, 64) 161 | self.table.setColumnWidth(2, 150) 162 | self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) 163 | 164 | # 初始化会话 165 | self.session = requests.Session() 166 | headers = {"User-Agent": r"Chrome/40.0.2214.93", 167 | "Referer": r"http://www.pixiv.net/"} 168 | self.session.headers.update(headers) 169 | 170 | # 初始化队列 171 | self.queue = queue.Queue() 172 | 173 | # 初始化线程 174 | self.threads_num = 5 175 | self.event_analyse = threading.Event() 176 | self.create_thread_analyse() 177 | self.create_thread_download() 178 | 179 | # Connections 180 | self.btn_login.clicked.connect(self.login) 181 | self.signal_login_status.connect(self.check_login) 182 | 183 | self.btn_dir.clicked.connect(self.show_dir) 184 | 185 | self.btn_analyse.clicked.connect(self.event_analyse.set) 186 | self.signal_analyse_start.connect(self.analyse_start) 187 | self.signal_analyse_status.connect(self.check_analyse) 188 | 189 | self.signal_add_row.connect(self.add_row) 190 | self.signal_update_bar.connect(self.update_bar) 191 | 192 | # Gui 193 | def set_login_mode(self, bool): 194 | self.widget_login.setVisible(bool) 195 | self.widget_analyse.setVisible(not bool) 196 | 197 | # 登录线程 198 | def login(self): 199 | self.enable_login_input(False) 200 | 201 | # 登录 202 | def thread_login(): 203 | url_login = r"https://www.secure.pixiv.net/login.php" 204 | data = {"mode": "login", 205 | "pixiv_id": str(self.email.text()), 206 | "pass": str(self.password.text())} 207 | request_login = self.session.post(url=url_login, data=data, allow_redirects=False, verify="cert.cer") 208 | 209 | # 确认 210 | if request_login.status_code != 302: 211 | self.signal_login_status.emit(False) 212 | else: 213 | self.signal_login_status.emit(True) 214 | 215 | self.thread_login = threading.Thread(target=thread_login) 216 | self.thread_login.setDaemon(True) 217 | self.thread_login.start() 218 | 219 | # Slots 220 | def check_login(self, bool): 221 | if bool: 222 | self.set_login_mode(False) 223 | else: 224 | self.warning = QMessageBox(QMessageBox.Warning, u"登录失败", u"登录失败, 请重试", QMessageBox.Ok) 225 | self.warning.show() 226 | self.enable_login_input(True) 227 | 228 | # Gui 229 | def enable_login_input(self, bool): 230 | self.email.setEnabled(bool) 231 | self.password.setEnabled(bool) 232 | self.btn_login.setEnabled(bool) 233 | 234 | # 解析线程 235 | def create_thread_analyse(self): 236 | def iter_urls_work(id_user, type, num): 237 | for page in range(num//20+1): 238 | url = "http://www.pixiv.net/member_illust.php?id=%d&type=%s&p=%d" % (id_user, type, page+1) 239 | etree_work = html.document_fromstring(self.session.get(url).content) 240 | etree_work.make_links_absolute("http://www.pixiv.net/") 241 | elems_work = etree_work.find_class("image-item") 242 | if elems_work: 243 | for i, elem_work in enumerate(elems_work): 244 | if page*20+i+1 <= num: 245 | yield elem_work.find("a").get("href") 246 | else: 247 | raise StopIteration 248 | else: 249 | raise Exception 250 | 251 | def thread_analyse(): 252 | while True: 253 | self.event_analyse.wait() 254 | self.signal_analyse_start.emit() 255 | try: 256 | iter = iter_urls_work(int(self.id.text()), "", int(self.amount.text())) 257 | for url in iter: 258 | work = Work(self.session, url) 259 | self.queue.put(work) 260 | self.signal_add_row.emit(work) 261 | self.signal_analyse_status.emit(True) 262 | except Exception as e: 263 | print(e) 264 | self.signal_analyse_status.emit(False) 265 | self.event_analyse.clear() 266 | 267 | self.thread_analyse = threading.Thread(target=thread_analyse) 268 | self.thread_analyse.setDaemon(True) 269 | self.thread_analyse.start() 270 | 271 | # Slots 272 | def analyse_start(self): 273 | self.enable_analyse_input(False) 274 | 275 | def check_analyse(self, bool): 276 | if bool: 277 | self.show_table() 278 | else: 279 | self.warning = QMessageBox(QMessageBox.Warning, u"输入无效", u"ID或项数输入有误, 请重试", QMessageBox.Ok) 280 | self.warning.show() 281 | self.enable_analyse_input(True) 282 | 283 | # Gui 284 | def enable_analyse_input(self, bool): 285 | self.id.setEnabled(bool) 286 | self.amount.setEnabled(bool) 287 | self.dir.setEnabled(bool) 288 | self.btn_dir.setEnabled(bool) 289 | self.btn_analyse.setEnabled(bool) 290 | 291 | def show_table(self): 292 | self.btn_table.clicked.disconnect() 293 | self.btn_table.setText(u"收起下载列表") 294 | self.btn_table.clicked.connect(self.hide_table) 295 | self.table.setVisible(True) 296 | self.setMinimumHeight(297) 297 | self.setMaximumHeight(10800) 298 | 299 | def hide_table(self): 300 | self.btn_table.setText(u"展开下载列表") 301 | self.btn_table.clicked.connect(self.show_table) 302 | self.table.setVisible(False) 303 | self.setMinimumHeight(99) 304 | self.setMaximumHeight(99) 305 | 306 | def add_row(self, work): 307 | row_num = self.table.rowCount() 308 | self.table.insertRow(row_num) 309 | 310 | item_id = QTableWidgetItem(work.id) 311 | item_id.setTextAlignment(Qt.AlignHCenter) 312 | item_id.setTextAlignment(Qt.AlignVCenter) 313 | self.table.setItem(row_num, 0, item_id) 314 | 315 | item_title = QTableWidgetItem(work.title) 316 | item_title.setTextAlignment(Qt.AlignHCenter) 317 | item_title.setTextAlignment(Qt.AlignVCenter) 318 | self.table.setItem(row_num, 1, item_title) 319 | 320 | progress = QProgressBar() 321 | progress.setAlignment(Qt.AlignHCenter) 322 | progress.setValue(0) 323 | work.progress = progress 324 | self.table.setCellWidget(row_num, 2, progress) 325 | 326 | def update_bar(self, progress, percent): 327 | progress.setValue(percent) 328 | 329 | # 下载线程 330 | def create_thread_download(self): 331 | def thread_download(): 332 | while True: 333 | work = self.queue.get() 334 | work.download(str(self.dir.text()), self.signal_update_bar) 335 | 336 | self.threads_download = [threading.Thread(target=thread_download) for i in range(self.threads_num)] 337 | for thread in self.threads_download: 338 | thread.setDaemon(True) 339 | thread.start() 340 | 341 | # 目录选择窗口 342 | def show_dir(self): 343 | dir_download = QFileDialog.getExistingDirectory(self, u"选择下载目录") 344 | self.dir.setText(dir_download) 345 | 346 | 347 | if __name__ == '__main__': 348 | app = QApplication(sys.argv) 349 | app.setWindowIcon(QIcon("icon.bmp")) 350 | main = Main() 351 | main.show() 352 | app.exec_() 353 | -------------------------------------------------------------------------------- /PixivAgent.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | main 4 | 5 | 6 | 7 | 0 8 | 0 9 | 386 10 | 391 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 386 22 | 99 23 | 24 | 25 | 26 | 27 | 16777215 28 | 16777215 29 | 30 | 31 | 32 | Pixiv Agent 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | E-mail: 44 | 45 | 46 | email 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 密码: 61 | 62 | 63 | password 64 | 65 | 66 | 67 | 68 | 69 | 70 | QLineEdit::Password 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 登录 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | true 95 | 96 | 97 | 画师ID: 98 | 99 | 100 | id 101 | 102 | 103 | 104 | 105 | 106 | 107 | true 108 | 109 | 110 | Qt::ImhDigitsOnly 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | true 121 | 122 | 123 | Qt::Vertical 124 | 125 | 126 | 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | 136 | amount 137 | 138 | 139 | 140 | 141 | 142 | 143 | true 144 | 145 | 146 | QAbstractSpinBox::UpDownArrows 147 | 148 | 149 | 1 150 | 151 | 152 | 999 153 | 154 | 155 | 156 | 157 | 158 | 159 | true 160 | 161 | 162 | 163 | 164 | 165 | amount 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | true 177 | 178 | 179 | 下载目录: 180 | 181 | 182 | dir 183 | 184 | 185 | 186 | 187 | 188 | 189 | true 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | true 200 | 201 | 202 | ... 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | true 214 | 215 | 216 | 添加任务 217 | 218 | 219 | 220 | 221 | 222 | 223 | true 224 | 225 | 226 | 下载列表 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | true 239 | 240 | 241 | 242 | 0 243 | 0 244 | 245 | 246 | 247 | false 248 | 249 | 250 | 251 | 作品ID 252 | 253 | 254 | 255 | 256 | 作品名称 257 | 258 | 259 | 260 | 261 | 下载进度 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | id 270 | amount 271 | dir 272 | btn_dir 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PixivAgent 2 | 3 | a friendly GUI downloader for Pixiv base on **Python3** & Qt 4 | 5 | # Demo 6 | 7 | ![demo](http://7xig7r.com1.z0.glb.clouddn.com/demo.gif) 8 | 9 | # Installation 10 | 11 | 1. Install [Qt Community](http://www.qt.io/download-open-source/) 12 | 2. Install [PyQt5](http://pyqt.sourceforge.net/Docs/PyQt5/installation.html) 13 | 3. Intall the following liberaries & dependencies 14 | 15 | ### For Fedora/CentOS: 16 | 17 | ``` 18 | $ sudo yum update 19 | $ sudo yum install python3-lxml ImageMagick-devel 20 | $ sudo pip3 install requests Wand 21 | $ git clone https://github.com/GeQi/PixivAgent.git && cd PixivAgent 22 | ``` 23 | 24 | And then 25 | 26 | `$ python3 PixivAgent.py` 27 | 28 | ### For Debian/Ubuntu: 29 | 30 | ``` 31 | $ sudo apt-get update 32 | $ sudo apt-get install python3-lxml libmagickwand-dev 33 | $ sudo pip3 install requests Wand 34 | $ git clone https://github.com/GeQi/PixivAgent.git && cd PixivAgent 35 | ``` 36 | 37 | And then 38 | 39 | `$ python3 PixivAgent.py` 40 | 41 | ### For Windows: 42 | 43 | Use `pip` to `intsall` the `.whl` pakage from [here](http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml) 44 | 45 | Install [ImageMagick on Windows](http://docs.wand-py.org/en/latest/guide/install.html#install-imagemagick-on-windows) 46 | 47 | ``` 48 | $ pip install requests Wand 49 | $ git clone https://github.com/GeQi/PixivAgent.git && cd PixivAgent 50 | ``` 51 | And then 52 | 53 | `$ python PixivAgent.py` 54 | 55 | # Credits 56 | 57 | - [requests](https://github.com/kennethreitz/requests) 58 | - [lxml](https://github.com/lxml/lxml) 59 | - [wand](https://github.com/dahlia/wand) 60 | - [imagemagick](http://www.imagemagick.org/) 61 | - [pyqt](http://www.riverbankcomputing.co.uk/software/pyqt/intro) 62 | -------------------------------------------------------------------------------- /cert.cer: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG 3 | A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 4 | b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw 5 | MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i 6 | YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT 7 | aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ 8 | jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp 9 | xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 10 | 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG 11 | snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ 12 | U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 13 | 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E 14 | BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B 15 | AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz 16 | yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 17 | 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP 18 | AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad 19 | DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME 20 | HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeQi/PixivAgent/9e26a03ad031b4601e048cfbbd0ade306c212fff/icon.bmp -------------------------------------------------------------------------------- /ui_PixivAgent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'PixivAgent.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.4.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_main(object): 12 | def setupUi(self, main): 13 | main.setObjectName("main") 14 | main.resize(386, 391) 15 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) 16 | sizePolicy.setHorizontalStretch(0) 17 | sizePolicy.setVerticalStretch(0) 18 | sizePolicy.setHeightForWidth(main.sizePolicy().hasHeightForWidth()) 19 | main.setSizePolicy(sizePolicy) 20 | main.setMinimumSize(QtCore.QSize(386, 99)) 21 | main.setMaximumSize(QtCore.QSize(16777215, 16777215)) 22 | self.verticalLayout = QtWidgets.QVBoxLayout(main) 23 | self.verticalLayout.setObjectName("verticalLayout") 24 | self.widget_login = QtWidgets.QWidget(main) 25 | self.widget_login.setObjectName("widget_login") 26 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget_login) 27 | self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) 28 | self.verticalLayout_2.setObjectName("verticalLayout_2") 29 | self.horizontalLayout_5 = QtWidgets.QHBoxLayout() 30 | self.horizontalLayout_5.setObjectName("horizontalLayout_5") 31 | self.label_6 = QtWidgets.QLabel(self.widget_login) 32 | self.label_6.setObjectName("label_6") 33 | self.horizontalLayout_5.addWidget(self.label_6) 34 | self.email = QtWidgets.QLineEdit(self.widget_login) 35 | self.email.setObjectName("email") 36 | self.horizontalLayout_5.addWidget(self.email) 37 | self.verticalLayout_2.addLayout(self.horizontalLayout_5) 38 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout() 39 | self.horizontalLayout_4.setObjectName("horizontalLayout_4") 40 | self.label_5 = QtWidgets.QLabel(self.widget_login) 41 | self.label_5.setObjectName("label_5") 42 | self.horizontalLayout_4.addWidget(self.label_5) 43 | self.password = QtWidgets.QLineEdit(self.widget_login) 44 | self.password.setEchoMode(QtWidgets.QLineEdit.Password) 45 | self.password.setObjectName("password") 46 | self.horizontalLayout_4.addWidget(self.password) 47 | self.verticalLayout_2.addLayout(self.horizontalLayout_4) 48 | self.btn_login = QtWidgets.QPushButton(self.widget_login) 49 | self.btn_login.setObjectName("btn_login") 50 | self.verticalLayout_2.addWidget(self.btn_login) 51 | self.verticalLayout.addWidget(self.widget_login) 52 | self.widget_analyse = QtWidgets.QWidget(main) 53 | self.widget_analyse.setObjectName("widget_analyse") 54 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget_analyse) 55 | self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) 56 | self.verticalLayout_3.setObjectName("verticalLayout_3") 57 | self.horizontalLayout = QtWidgets.QHBoxLayout() 58 | self.horizontalLayout.setObjectName("horizontalLayout") 59 | self.label = QtWidgets.QLabel(self.widget_analyse) 60 | self.label.setEnabled(True) 61 | self.label.setObjectName("label") 62 | self.horizontalLayout.addWidget(self.label) 63 | self.id = QtWidgets.QLineEdit(self.widget_analyse) 64 | self.id.setEnabled(True) 65 | self.id.setInputMethodHints(QtCore.Qt.ImhDigitsOnly) 66 | self.id.setPlaceholderText("") 67 | self.id.setObjectName("id") 68 | self.horizontalLayout.addWidget(self.id) 69 | self.line = QtWidgets.QFrame(self.widget_analyse) 70 | self.line.setEnabled(True) 71 | self.line.setFrameShape(QtWidgets.QFrame.VLine) 72 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken) 73 | self.line.setObjectName("line") 74 | self.horizontalLayout.addWidget(self.line) 75 | self.label_3 = QtWidgets.QLabel(self.widget_analyse) 76 | self.label_3.setEnabled(True) 77 | self.label_3.setObjectName("label_3") 78 | self.horizontalLayout.addWidget(self.label_3) 79 | self.amount = QtWidgets.QSpinBox(self.widget_analyse) 80 | self.amount.setEnabled(True) 81 | self.amount.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows) 82 | self.amount.setMinimum(1) 83 | self.amount.setMaximum(999) 84 | self.amount.setObjectName("amount") 85 | self.horizontalLayout.addWidget(self.amount) 86 | self.label_4 = QtWidgets.QLabel(self.widget_analyse) 87 | self.label_4.setEnabled(True) 88 | self.label_4.setObjectName("label_4") 89 | self.horizontalLayout.addWidget(self.label_4) 90 | self.verticalLayout_3.addLayout(self.horizontalLayout) 91 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 92 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 93 | self.label_2 = QtWidgets.QLabel(self.widget_analyse) 94 | self.label_2.setEnabled(True) 95 | self.label_2.setObjectName("label_2") 96 | self.horizontalLayout_2.addWidget(self.label_2) 97 | self.dir = QtWidgets.QLineEdit(self.widget_analyse) 98 | self.dir.setEnabled(True) 99 | self.dir.setPlaceholderText("") 100 | self.dir.setObjectName("dir") 101 | self.horizontalLayout_2.addWidget(self.dir) 102 | self.btn_dir = QtWidgets.QToolButton(self.widget_analyse) 103 | self.btn_dir.setEnabled(True) 104 | self.btn_dir.setObjectName("btn_dir") 105 | self.horizontalLayout_2.addWidget(self.btn_dir) 106 | self.verticalLayout_3.addLayout(self.horizontalLayout_2) 107 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 108 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 109 | self.btn_analyse = QtWidgets.QPushButton(self.widget_analyse) 110 | self.btn_analyse.setEnabled(True) 111 | self.btn_analyse.setObjectName("btn_analyse") 112 | self.horizontalLayout_3.addWidget(self.btn_analyse) 113 | self.btn_table = QtWidgets.QPushButton(self.widget_analyse) 114 | self.btn_table.setEnabled(True) 115 | self.btn_table.setObjectName("btn_table") 116 | self.horizontalLayout_3.addWidget(self.btn_table) 117 | self.verticalLayout_3.addLayout(self.horizontalLayout_3) 118 | self.verticalLayout.addWidget(self.widget_analyse) 119 | self.table = QtWidgets.QTableWidget(main) 120 | self.table.setEnabled(True) 121 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) 122 | sizePolicy.setHorizontalStretch(0) 123 | sizePolicy.setVerticalStretch(0) 124 | sizePolicy.setHeightForWidth(self.table.sizePolicy().hasHeightForWidth()) 125 | self.table.setSizePolicy(sizePolicy) 126 | self.table.setObjectName("table") 127 | self.table.setColumnCount(3) 128 | self.table.setRowCount(0) 129 | item = QtWidgets.QTableWidgetItem() 130 | self.table.setHorizontalHeaderItem(0, item) 131 | item = QtWidgets.QTableWidgetItem() 132 | self.table.setHorizontalHeaderItem(1, item) 133 | item = QtWidgets.QTableWidgetItem() 134 | self.table.setHorizontalHeaderItem(2, item) 135 | self.table.verticalHeader().setVisible(False) 136 | self.verticalLayout.addWidget(self.table) 137 | self.label_6.setBuddy(self.email) 138 | self.label_5.setBuddy(self.password) 139 | self.label.setBuddy(self.id) 140 | self.label_3.setBuddy(self.amount) 141 | self.label_4.setBuddy(self.amount) 142 | self.label_2.setBuddy(self.dir) 143 | 144 | self.retranslateUi(main) 145 | QtCore.QMetaObject.connectSlotsByName(main) 146 | main.setTabOrder(self.id, self.amount) 147 | main.setTabOrder(self.amount, self.dir) 148 | main.setTabOrder(self.dir, self.btn_dir) 149 | 150 | def retranslateUi(self, main): 151 | _translate = QtCore.QCoreApplication.translate 152 | main.setWindowTitle(_translate("main", "Pixiv Agent")) 153 | self.label_6.setText(_translate("main", "E-mail:")) 154 | self.label_5.setText(_translate("main", "密码:")) 155 | self.btn_login.setText(_translate("main", "登录")) 156 | self.label.setText(_translate("main", "画师ID:")) 157 | self.label_3.setText(_translate("main", "前")) 158 | self.label_4.setText(_translate("main", "项")) 159 | self.label_2.setText(_translate("main", "下载目录:")) 160 | self.btn_dir.setText(_translate("main", "...")) 161 | self.btn_analyse.setText(_translate("main", "添加任务")) 162 | self.btn_table.setText(_translate("main", "下载列表")) 163 | item = self.table.horizontalHeaderItem(0) 164 | item.setText(_translate("main", "作品ID")) 165 | item = self.table.horizontalHeaderItem(1) 166 | item.setText(_translate("main", "作品名称")) 167 | item = self.table.horizontalHeaderItem(2) 168 | item.setText(_translate("main", "下载进度")) 169 | 170 | 171 | if __name__ == "__main__": 172 | import sys 173 | app = QtWidgets.QApplication(sys.argv) 174 | main = QtWidgets.QDialog() 175 | ui = Ui_main() 176 | ui.setupUi(main) 177 | main.show() 178 | sys.exit(app.exec_()) 179 | 180 | -------------------------------------------------------------------------------- /uic.bat: -------------------------------------------------------------------------------- 1 | pyuic5 -x PixivAgent.ui -o ui_PixivAgent.py --------------------------------------------------------------------------------