-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
187 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
||
|
||
|
@@ -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" | ||
) | ||
|
@@ -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__": | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | ||
|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.