Skip to content

Commit

Permalink
[feat] 框架换用 PySimpleGUI,并添加分类选项
Browse files Browse the repository at this point in the history
  • Loading branch information
findix committed Mar 24, 2023
1 parent 0bec596 commit 5f09dcc
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 157 deletions.
14 changes: 11 additions & 3 deletions src/ArtStationDownloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
Copyright 2018 Sean Feng([email protected])
"""

__version__ = "0.2.2"
__version__ = "0.3.0"
# $Source$

import argparse

from app import App
from core import DownloadSorting
from console import Console


Expand All @@ -37,6 +38,13 @@ def main():
default="all",
help="what do you what to download, default is all",
)
parser.add_argument(
"-s",
"--sorting",
choices=[sorting.name for sorting in DownloadSorting],
default=DownloadSorting.TITLE_BASED.name,
help="download sorting",
)
parser.add_argument(
"-v", "--verbosity", action="count", help="increase output verbosity"
)
Expand All @@ -45,12 +53,12 @@ def main():
if args.username:
if args.directory:
console = Console()
console.download_by_usernames(args.username, args.directory, args.type)
console.download_by_usernames(args.username, args.directory, args.type, DownloadSorting[args.sorting])
else:
print("no output directory, please use -d or --directory option to set")
else:
app = App(version=__version__)
app.mainloop() # 进入主循环,程序运行
app.run() # 进入主循环,程序运行


if __name__ == "__main__":
Expand Down
268 changes: 134 additions & 134 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,99 @@
# -*- coding: utf-8 -*-

import os
from concurrent import futures

from tkinter import (
Tk,
Frame,
Label,
Button,
Scrollbar,
Text,
Entry,
messagebox,
filedialog,
StringVar,
) # 引入Tkinter工具包
from tkinter import TOP, LEFT, BOTTOM, BOTH, X, Y, END
from tkinter import ttk
import PySimpleGUI as sg

import config
from core import Core
from core import Core, DownloadSorting


class App(Frame):
class App:
def __init__(self, version):
self.core = Core(self.log)
self.user_settings = sg.UserSettings()

# 兼容模式
if not self.user_settings.exists("root_path"):
root_path = config.read_config("config.ini", "Paths", "root_path")
if root_path:
self.user_settings.set("root_path", root_path)

self.root_path = self.user_settings.get(
"root_path", os.path.join(os.path.expanduser("~"), "ArtStation")
)
self.download_sorting: DownloadSorting = DownloadSorting[
self.user_settings.get("download_sorting", DownloadSorting.TITLE_BASED.name)
]
self.window = sg.Window(
"ArtStation Downloader " + version,
layout=self.create_layout(),
finalize=True,
)

self.window["-DOWNLOAD-SORTING-"].Update(self.download_sorting)

self.event_callbacks = {
"-DOWNLOAD-": lambda: self.window.perform_long_operation(self.download, ""),
"-DOWNLOAD_TXT-": self.get_download_txt_file,
"continue_download_txt": lambda args: self.window.perform_long_operation(
lambda: self.download_txt(args), ""
),
"-DOWNLOAD-SORTING-": self._set_download_sorting,
"log": self._log,
"popup": self._popup,
"set_download_buttons": self._set_download_buttons,
}

def _set_download_sorting(self, value: DownloadSorting):
self.download_sorting = value
self.user_settings.set("download_sorting", value.name)

def _log(self, value):
current_text = self.window["-LOG-"].get()
self.window["-LOG-"].update(f"{current_text}\n{value}\n")
self.window["-LOG-"].Widget.see("end")

def log(self, value):
self.text.configure(state="normal")
self.text.insert(END, value + "\n")
self.text.see(END)
self.text.configure(state="disabled")
self.window.write_event_value("log", value)

def _set_download_buttons(self, state):
if state:
self.btn_download.configure(state="normal")
self.btn_download_txt.configure(state="normal")
else:
self.btn_download.configure(state="disabled")
self.btn_download_txt.configure(state="disabled")
self.window["-DOWNLOAD-"].update(disabled=not state)
self.window["-DOWNLOAD_TXT-"].update(disabled=not state)

def _popup(self, args):
message, title = args
sg.popup_ok(
message,
title=title,
modal=True,
)

def download(self):
username_text = self.entry_filename.get()
username_text = self.window["-USERNAME-"].get()
if not username_text:
messagebox.showinfo(title="Warning", message="Please input usernames")
self.window.write_event_value(
"popup", ("Please input usernames", "Warning")
)
return
self._set_download_buttons(False)
self.window.write_event_value("set_download_buttons", False)
usernames = username_text.split(",")
self.core.root_path = self.root_path.get()
self.core.download_by_usernames(usernames, self.combobox_type.current())
self._set_download_buttons(True)

def download_txt(self):
self.btn_download.configure(state="disabled")
self.btn_download_txt.configure(state="disabled")
filename = os.path.normpath(
filedialog.askopenfilename(
filetypes=(("text files", "*.txt"), ("all files", "*.*"))
)
self.core.root_path = self.root_path
self.core.download_by_usernames(
usernames, self.window["-TYPE-"].get(), self.download_sorting
)
if filename != ".":
self.window.write_event_value("set_download_buttons", True)

def get_download_txt_file(self):
self.window.write_event_value("set_download_buttons", False)
filename = sg.popup_get_file(
"Select a file", file_types=(("Text Files", "*.txt"), ("All Files", "*.*"))
)
self.window.write_event_value("continue_download_txt", filename)

def download_txt(self, filename):
if filename and filename != ".":
with open(filename, "r", encoding="utf-8") as f:
usernames = []
# 预处理,去掉注释与空白符
for username in f.readlines():
username = username.strip()
if not username:
Expand All @@ -70,98 +104,64 @@ def download_txt(self):
if sharp_at != -1:
username = username[:sharp_at]
usernames.append(username.strip())
self.core.root_path = self.root_path.get()
self.core.download_by_usernames(usernames, self.combobox_type.current())
self.btn_download.configure(state="normal")
self.btn_download_txt.configure(state="normal")

def load_root_path(self):
return config.read_config("config.ini", "Paths", "root_path")

def save_root_path(self, root_path):
config.write_config("config.ini", "Paths", "root_path", root_path)
self.core.root_path = self.root_path
self.core.download_by_usernames(
usernames, self.window["-TYPE-"].get(), self.download_sorting
)
self.window.write_event_value("set_download_buttons", True)

def browse_directory(self):
root_path = os.path.normpath(filedialog.askdirectory())
root_path = sg.popup_get_folder("Select a folder")
if root_path:
self.root_path.set(root_path)
self.save_root_path(root_path)

def createWidgets(self):
frame_tool = Frame(self.window)
frame_path = Frame(self.window)
frame_log = Frame(self.window)
self.lbl_username = Label(frame_tool, text="Usernames(split by ','):")
self.entry_filename = Entry(frame_tool)
self.btn_download = Button(
frame_tool,
text="Download",
command=lambda: self.invoke(self.download),
)
self.btn_download_txt = Button(
frame_tool,
text="Download txt",
command=lambda: self.invoke(self.download_txt),
)
self.lbl_type = Label(frame_path, text="Type:")
self.combobox_type = ttk.Combobox(frame_path, state="readonly")
self.combobox_type["values"] = ("all", "image", "video")
self.combobox_type.current(0)
self.lbl_path = Label(frame_path, text="Path:")
self.entry_path = Entry(frame_path, textvariable=self.root_path)
self.btn_path_dialog = Button(
frame_path, text="Browse", command=self.browse_directory
)
self.scrollbar = Scrollbar(frame_log)
self.text = Text(frame_log)
self.text.configure(state="disabled")
self.lbl_status = Label(
self.window,
text="Feel free to use! Support: Sean Feng([email protected])",
)
self.root_path = root_path
self.window["-PATH-"].update(root_path)
self.user_settings.set("root_path", root_path)

frame_tool.pack(side=TOP, fill=X)
self.lbl_username.pack(side=LEFT)
self.entry_filename.pack(side=LEFT, fill=X, expand=True)
self.btn_download.pack(side=LEFT)
self.btn_download_txt.pack(side=LEFT)
frame_path.pack(side=TOP, fill=X)
self.lbl_type.pack(side=LEFT)
self.combobox_type.pack(side=LEFT)
self.lbl_path.pack(side=LEFT)
self.entry_path.pack(side=LEFT, fill=X, expand=True)
self.btn_path_dialog.pack(side=LEFT)
self.text.pack(side=LEFT, fill=BOTH, expand=True)
self.scrollbar.pack(side=LEFT, fill=Y)
frame_log.pack(side=TOP, fill=BOTH, expand=True)
self.scrollbar.config(command=self.text.yview)
self.text.config(yscrollcommand=self.scrollbar.set)
self.text.focus()
self.lbl_status.pack(side=LEFT, fill=X, expand=True)

def invoke(self, func):
def done_callback(worker):
worker_exception = worker.exception()
if worker_exception:
self.log(str(worker_exception))
self._set_download_buttons(True)
raise(worker_exception)
return self.executor_ui.submit(func).add_done_callback(done_callback)
def create_layout(self):
sg.theme("Dark Blue 3")
layout = [
[sg.Text('Usernames (split by ","):'), sg.InputText(key="-USERNAME-")],
[
sg.Text("Type:"),
sg.Combo(
values=("all", "image", "video"),
key="-TYPE-",
default_value="all",
readonly=True,
enable_events=True,
),
sg.Text("File Download Sorting"),
sg.Combo(
tuple(DownloadSorting.__members__.values()),
key="-DOWNLOAD-SORTING-",
default_value=DownloadSorting.TITLE_BASED,
readonly=True,
enable_events=True,
),
],
[
sg.Text("Path:"),
sg.InputText(key="-PATH-", default_text=self.root_path),
sg.FolderBrowse("Browse", key="-BROWSE-"),
],
[
sg.Button("Download", key="-DOWNLOAD-", bind_return_key=True),
sg.Button("Download txt", key="-DOWNLOAD_TXT-"),
],
[sg.Multiline(size=(80, 20), key="-LOG-", disabled=True)],
[sg.StatusBar("Feel free to use! Support: Sean Feng([email protected])")],
]
return layout

def __init__(self, version):
self.core = Core(self.log)
master = Tk()
Frame.__init__(self, master)
master.title("ArtStation Downloader " + version) # 定义窗体标题
self.root_path = StringVar()
self.root_path.trace_add(
"write", lambda name, index, mode: self.save_root_path(self.root_path.get())
)
root_path_config = self.load_root_path()
self.root_path.set(
root_path_config or os.path.join(os.path.expanduser("~"), "ArtStation")
)
self.executor_ui = futures.ThreadPoolExecutor(1)
self.window = master
self.pack()
self.createWidgets()
def run(self):
while True:
event, values = self.window.read()
if event == sg.WINDOW_CLOSED:
break
elif event in self.event_callbacks:
if event in values:
self.event_callbacks[event](values[event])
else:
self.event_callbacks[event]()

self.window.close()
4 changes: 2 additions & 2 deletions src/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ class Console:
def __init__(self):
self.core = Core()

def download_by_usernames(self, usernames, directory, type):
def download_by_usernames(self, usernames, directory, download_type, download_sorting):
self.core.root_path = directory
self.core.download_by_usernames(usernames, type)
self.core.download_by_usernames(usernames, download_type, download_sorting)
Loading

0 comments on commit 5f09dcc

Please sign in to comment.