Upload 2 files
Browse files- .gitattributes +1 -0
- NAIA/artist_thumbnail 뷰어.exe +3 -0
- NAIA/artist_thumbnail_viewer.py +137 -0
.gitattributes
CHANGED
|
@@ -215,3 +215,4 @@ NAIA/NAIA_2025/NAIA[[:space:]]v1.5[[:space:]]testv8.exe filter=lfs diff=lfs merg
|
|
| 215 |
NAIA/NAIA_2025/NAIA[[:space:]]v1.5[[:space:]]testv9.exe filter=lfs diff=lfs merge=lfs -text
|
| 216 |
NAIA/NAID4.5_artist_thumbnail/artist_thumbnail_nai filter=lfs diff=lfs merge=lfs -text
|
| 217 |
NAIA/Noob_artist_thumbnail/artist_thumbnail filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 215 |
NAIA/NAIA_2025/NAIA[[:space:]]v1.5[[:space:]]testv9.exe filter=lfs diff=lfs merge=lfs -text
|
| 216 |
NAIA/NAID4.5_artist_thumbnail/artist_thumbnail_nai filter=lfs diff=lfs merge=lfs -text
|
| 217 |
NAIA/Noob_artist_thumbnail/artist_thumbnail filter=lfs diff=lfs merge=lfs -text
|
| 218 |
+
NAIA/artist_thumbnail[[:space:]]뷰어.exe filter=lfs diff=lfs merge=lfs -text
|
NAIA/artist_thumbnail 뷰어.exe
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:004f3fef8184bf7a782284bbac3f181e77538b7798fc908eddb0a66234fc5147
|
| 3 |
+
size 32225187
|
NAIA/artist_thumbnail_viewer.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import tkinter as tk
|
| 2 |
+
from tkinter import filedialog
|
| 3 |
+
from PIL import Image, ImageTk
|
| 4 |
+
import json
|
| 5 |
+
import base64
|
| 6 |
+
import io
|
| 7 |
+
import re
|
| 8 |
+
|
| 9 |
+
from artist_dictionary import artist_dict
|
| 10 |
+
|
| 11 |
+
class ArtistThumbnailViewer:
|
| 12 |
+
def __init__(self, master):
|
| 13 |
+
self.master = master
|
| 14 |
+
self.master.title("NAIA/WEBUIA 대체용 작가명 태그 미리보기 뷰어, Ctrl+C로 작가명 복사 가능")
|
| 15 |
+
self.master.geometry("728x525")
|
| 16 |
+
|
| 17 |
+
self.artist_data = {}
|
| 18 |
+
self.artist_list = []
|
| 19 |
+
self.last_search = ""
|
| 20 |
+
|
| 21 |
+
self.left_frame = tk.Frame(master, width=300)
|
| 22 |
+
self.left_frame.pack(side=tk.LEFT, fill=tk.Y)
|
| 23 |
+
|
| 24 |
+
self.right_frame = tk.Frame(master)
|
| 25 |
+
self.right_frame.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH)
|
| 26 |
+
|
| 27 |
+
self.search_entry = tk.Entry(self.left_frame, font=("Malgun Gothic", 12))
|
| 28 |
+
self.search_entry.pack(pady=5)
|
| 29 |
+
self.search_entry.bind('<KeyRelease>', self.popup_search)
|
| 30 |
+
self.search_entry.bind('<FocusOut>', lambda e: self.popup.withdraw())
|
| 31 |
+
|
| 32 |
+
self.listbox_frame = tk.Frame(self.left_frame)
|
| 33 |
+
self.listbox_frame.pack(pady=5, fill=tk.BOTH, expand=True)
|
| 34 |
+
|
| 35 |
+
self.scrollbar = tk.Scrollbar(self.listbox_frame)
|
| 36 |
+
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
| 37 |
+
|
| 38 |
+
self.listbox = tk.Listbox(self.listbox_frame, font=("Malgun Gothic", 12), width=20, height=30, yscrollcommand=self.scrollbar.set)
|
| 39 |
+
self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
| 40 |
+
self.scrollbar.config(command=self.listbox.yview)
|
| 41 |
+
self.listbox.pack(pady=5)
|
| 42 |
+
self.listbox.bind('<<ListboxSelect>>', self.display_image)
|
| 43 |
+
|
| 44 |
+
self.canvas = tk.Canvas(self.right_frame, bg="white")
|
| 45 |
+
self.canvas.pack(expand=True, fill=tk.BOTH)
|
| 46 |
+
|
| 47 |
+
self.menu = tk.Menu(master)
|
| 48 |
+
self.menu.add_command(label="artist_thumbnail 파일 불러오기", command=self.load_json_file)
|
| 49 |
+
master.config(menu=self.menu)
|
| 50 |
+
|
| 51 |
+
# Popup listbox for search
|
| 52 |
+
self.popup = tk.Toplevel(master)
|
| 53 |
+
self.popup.withdraw()
|
| 54 |
+
self.popup.overrideredirect(True)
|
| 55 |
+
self.plistbox = tk.Listbox(self.popup, font=("Malgun Gothic", 12), width=40, height=11, borderwidth=2, highlightbackground='lightgrey')
|
| 56 |
+
self.plistbox.pack()
|
| 57 |
+
self.plistbox.bind('<<ListboxSelect>>', self.select_popup_result)
|
| 58 |
+
|
| 59 |
+
def load_json_file(self):
|
| 60 |
+
filepath = filedialog.askopenfilename(filetypes=[("All", "artist_thumb*")])
|
| 61 |
+
if not filepath:
|
| 62 |
+
return
|
| 63 |
+
|
| 64 |
+
with open(filepath, 'r', encoding='utf-8') as file:
|
| 65 |
+
self.artist_data = json.load(file)
|
| 66 |
+
|
| 67 |
+
self.artist_list = sorted(
|
| 68 |
+
[key for key in self.artist_data if key in artist_dict],
|
| 69 |
+
key=lambda k: artist_dict[k], reverse=True
|
| 70 |
+
)
|
| 71 |
+
self.update_listbox(self.artist_list)
|
| 72 |
+
|
| 73 |
+
def update_listbox(self, items):
|
| 74 |
+
self.listbox.delete(0, tk.END)
|
| 75 |
+
for item in items:
|
| 76 |
+
self.listbox.insert(tk.END, item)
|
| 77 |
+
|
| 78 |
+
def display_image(self, event=None):
|
| 79 |
+
try:
|
| 80 |
+
selected = self.listbox.get(self.listbox.curselection())
|
| 81 |
+
except:
|
| 82 |
+
return
|
| 83 |
+
|
| 84 |
+
img_data = self.artist_data.get(selected, [None])[0]
|
| 85 |
+
if img_data:
|
| 86 |
+
img_bytes = base64.b64decode(img_data)
|
| 87 |
+
image = Image.open(io.BytesIO(img_bytes))
|
| 88 |
+
image = image.resize((512, 512), Image.LANCZOS)
|
| 89 |
+
self.tk_image = ImageTk.PhotoImage(image)
|
| 90 |
+
self.canvas.delete("all")
|
| 91 |
+
self.canvas.create_image(10, 10, anchor='nw', image=self.tk_image)
|
| 92 |
+
else:
|
| 93 |
+
self.canvas.delete("all")
|
| 94 |
+
|
| 95 |
+
def popup_search(self, event=None):
|
| 96 |
+
search_text = self.search_entry.get().strip().lower()
|
| 97 |
+
self.plistbox.delete(0, tk.END)
|
| 98 |
+
|
| 99 |
+
results = []
|
| 100 |
+
for artist in self.artist_list:
|
| 101 |
+
if search_text in artist.lower():
|
| 102 |
+
value = artist_dict.get(artist, 0)
|
| 103 |
+
results.append((artist, value))
|
| 104 |
+
|
| 105 |
+
results.sort(key=lambda x: x[1], reverse=True)
|
| 106 |
+
results = results[:40]
|
| 107 |
+
|
| 108 |
+
if results:
|
| 109 |
+
for k, v in results:
|
| 110 |
+
v_formatted = f"{v:>9}".replace(' ', ' ')
|
| 111 |
+
formatted_line = f"{v_formatted} {k}"
|
| 112 |
+
self.plistbox.insert(tk.END, formatted_line)
|
| 113 |
+
|
| 114 |
+
abs_x = self.search_entry.winfo_rootx()
|
| 115 |
+
abs_y = self.search_entry.winfo_rooty() + 30
|
| 116 |
+
self.popup.geometry(f"+{abs_x}+{abs_y}")
|
| 117 |
+
self.popup.deiconify()
|
| 118 |
+
else:
|
| 119 |
+
self.popup.withdraw()
|
| 120 |
+
|
| 121 |
+
def select_popup_result(self, event=None):
|
| 122 |
+
try:
|
| 123 |
+
selection = self.plistbox.get(self.plistbox.curselection())
|
| 124 |
+
keyword = re.sub(r'^\s*\d+\s+', '', selection.strip().split(maxsplit=1)[-1])
|
| 125 |
+
index = self.artist_list.index(keyword)
|
| 126 |
+
self.popup.withdraw()
|
| 127 |
+
self.listbox.select_clear(0, tk.END)
|
| 128 |
+
self.listbox.select_set(index)
|
| 129 |
+
self.listbox.see(index)
|
| 130 |
+
self.display_image()
|
| 131 |
+
except:
|
| 132 |
+
pass
|
| 133 |
+
|
| 134 |
+
if __name__ == "__main__":
|
| 135 |
+
root = tk.Tk()
|
| 136 |
+
app = ArtistThumbnailViewer(root)
|
| 137 |
+
root.mainloop()
|