以下は『虚網ノ書』のソースコード全文です:
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import xml.etree.ElementTree as ET
from datetime import datetime
class SitemapGUI:
def __init__(self, root):
self.root = root
self.root.title("サイトマップ作成機 - 虚網ノ書")
self.folder_path = tk.StringVar()
self.site_url = tk.StringVar()
self.output_path = tk.StringVar(value=os.path.join(os.path.expanduser("~"), "Desktop"))
self.file_check_vars = {}
self.tree_items = {}
self.search_query = tk.StringVar()
self.search_results = []
self.create_widgets()
def create_widgets(self):
frame1 = tk.Frame(self.root)
frame1.pack(pady=5, padx=10, fill='x')
tk.Label(frame1, text="対象フォルダ:").pack(side='left')
tk.Entry(frame1, textvariable=self.folder_path, width=50).pack(side='left', padx=5)
tk.Button(frame1, text="参照", command=self.browse_folder).pack(side='left')
tk.Button(self.root, text="🔍 探索", command=self.explore).pack(pady=5)
self.tree_frame = tk.Frame(self.root)
self.tree_frame.pack(fill='both', expand=True, padx=10, pady=5)
self.tree = ttk.Treeview(self.tree_frame, columns=("path",), selectmode="none")
self.tree.heading("#0", text="ファイル/フォルダ")
self.tree.column("path", width=0, stretch=False)
self.tree.pack(side='left', fill='both', expand=True)
self.vsb = ttk.Scrollbar(self.tree_frame, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side='right', fill='y')
frame_buttons = tk.Frame(self.root)
frame_buttons.pack(pady=5)
tk.Button(frame_buttons, text="全て選択", command=self.select_all).pack(side='left', padx=5)
tk.Button(frame_buttons, text="全て解除", command=self.deselect_all).pack(side='left', padx=5)
frame_search = tk.Frame(self.root)
frame_search.pack(pady=5, padx=10, fill='x')
tk.Label(frame_search, text="検索:").pack(side='left')
tk.Entry(frame_search, textvariable=self.search_query, width=30).pack(side='left', padx=5)
tk.Button(frame_search, text="検索結果を表示", command=self.show_search_results_window).pack(side='left', padx=5)
tk.Button(frame_search, text="検索結果を一括選択", command=self.select_search_result).pack(side='left', padx=5)
tk.Button(frame_search, text="検索結果を一括解除", command=self.deselect_search_result).pack(side='left')
self.status_label = tk.Label(self.root, text="選択: 0 / 0")
self.status_label.pack(fill='x')
#self.status_label.pack(side='bottom', fill='x')
frame2 = tk.Frame(self.root)
frame2.pack(pady=5, padx=10, fill='x')
tk.Label(frame2, text="サイトのURL:").pack(side='left')
tk.Entry(frame2, textvariable=self.site_url, width=50).pack(side='left', padx=5)
frame3 = tk.Frame(self.root)
frame3.pack(pady=5, padx=10, fill='x')
tk.Label(frame3, text="保存場所:").pack(side='left')
tk.Entry(frame3, textvariable=self.output_path, width=50).pack(side='left', padx=5)
tk.Button(frame3, text="参照", command=self.browse_output_folder).pack(side='left')
tk.Button(self.root, text="📝 sitemap.xml 作成", command=self.create_sitemap).pack(pady=10)
def update_status(self):
file_paths = [path for path in self.file_check_vars if not os.path.isdir(path)]
total = len(file_paths)
selected = sum(self.file_check_vars[path].get() for path in file_paths)
self.status_label.config(text=f"選択: {selected} / {total}")
def browse_folder(self):
folder = filedialog.askdirectory()
if folder:
self.folder_path.set(folder)
def browse_output_folder(self):
folder = filedialog.askdirectory()
if folder:
self.output_path.set(folder)
def explore(self):
for item in self.tree.get_children():
self.tree.delete(item)
self.file_check_vars.clear()
self.tree_items.clear()
folder = self.folder_path.get()
if not folder:
messagebox.showwarning("警告", "フォルダを選択してください")
return
self.insert_items('', folder)
self.update_status()
def insert_items(self, parent, path):
for name in sorted(os.listdir(path)):
full_path = os.path.join(path, name)
if os.path.isdir(full_path):
var = tk.BooleanVar(value=True)
self.file_check_vars[full_path] = var
node_id = self.tree.insert(parent, 'end', text=f"[✓] 📁 {name}", open=False, tags=(full_path,))
self.tree_items[full_path] = node_id
self.tree.tag_bind(full_path, '<Button-1>', lambda e, p=full_path, i=node_id: self.toggle_folder_checkbox(p, i))
self.insert_items(node_id, full_path)
elif name.endswith(".html"):
var = tk.BooleanVar(value=True)
self.file_check_vars[full_path] = var
item_id = self.tree.insert(parent, 'end', text=f"[✓] {name}", values=(full_path,), tags=(full_path,))
self.tree_items[full_path] = item_id
self.tree.tag_bind(full_path, '<Button-1>', lambda e, p=full_path, i=item_id: self.toggle_checkbox(p, i))
def toggle_checkbox(self, path, item_id):
var = self.file_check_vars[path]
var.set(not var.get())
self.update_checkbox_label(path, item_id)
self.update_status()
def toggle_folder_checkbox(self, path, item_id):
var = self.file_check_vars[path]
new_state = not var.get()
var.set(new_state)
self.update_checkbox_label(path, item_id, is_folder=True)
self.update_status()
for sub_path in self.file_check_vars:
if sub_path.startswith(path + os.sep) and not os.path.isdir(sub_path):
self.file_check_vars[sub_path].set(new_state)
self.update_checkbox_label(sub_path, self.tree_items[sub_path])
def update_checkbox_label(self, path, item_id, is_folder=False):
name = os.path.basename(path)
checked_text = f"[✓] {'📁 ' if is_folder else ''}{name}" if self.file_check_vars[path].get() else f"[ ] {'📁 ' if is_folder else ''}{name}"
self.tree.item(item_id, text=checked_text)
def select_all(self):
for path, var in self.file_check_vars.items():
var.set(True)
name = os.path.basename(path)
self.tree.item(self.tree_items[path], text=f"[✓] {'📁 ' if os.path.isdir(path) else ''}{name}")
self.update_status()
def deselect_all(self):
for path, var in self.file_check_vars.items():
var.set(False)
name = os.path.basename(path)
self.tree.item(self.tree_items[path], text=f"[ ] {'📁 ' if os.path.isdir(path) else ''}{name}")
self.update_status()
def search_files(self):
self.search_results = []
query = self.search_query.get().lower()
for path in self.file_check_vars:
if os.path.isdir(path):
continue
if query in os.path.basename(path).lower():
self.search_results.append(path)
def select_search_result(self):
self.search_files()
for path in self.search_results:
self.file_check_vars[path].set(True)
name = os.path.basename(path)
self.tree.item(self.tree_items[path], text=f"[✓] {'📁 ' if os.path.isdir(path) else ''}{name}")
self.update_status()
def deselect_search_result(self):
self.search_files()
for path in self.search_results:
self.file_check_vars[path].set(False)
name = os.path.basename(path)
self.tree.item(self.tree_items[path], text=f"[ ] {'📁 ' if os.path.isdir(path) else ''}{name}")
self.update_status()
def show_search_results_window(self):
self.search_files()
win = tk.Toplevel(self.root)
win.title("検索結果一覧")
listbox = tk.Listbox(win, width=80)
for path in self.search_results:
listbox.insert(tk.END, path)
listbox.pack(padx=10, pady=10, fill='both', expand=True)
def create_sitemap(self):
url_base = self.site_url.get().rstrip('/')
if not url_base:
messagebox.showwarning("警告", "サイトURLを入力してください")
return
output_dir = self.output_path.get()
if not output_dir:
messagebox.showwarning("警告", "保存場所を指定してください")
return
urlset = ET.Element("urlset", xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
for path, var in self.file_check_vars.items():
if var.get() and not os.path.isdir(path):
rel_path = os.path.relpath(path, self.folder_path.get()).replace(os.sep, '/')
url = ET.SubElement(urlset, "url")
loc = ET.SubElement(url, "loc")
loc.text = f"{url_base}/{rel_path}"
lastmod = ET.SubElement(url, "lastmod")
lastmod.text = datetime.fromtimestamp(os.path.getmtime(path)).date().isoformat()
tree = ET.ElementTree(urlset)
output_file = os.path.join(output_dir, "sitemap.xml")
tree.write(output_file, encoding="utf-8", xml_declaration=True)
messagebox.showinfo("完了", f"sitemap.xml を作成しました\n{output_file}")
if __name__ == "__main__":
root = tk.Tk()
##タイトルバーアイコン表示用
data = '''R0lGODlhEAAQAIQAAAAAAB0gIB0gIBsbGx0gIB0eICMjIx0gIB0eHh4eIR0fIB0eIB0iIh0dIiAgIBgnJxweHhsbJB4eHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAQAibAAEIHEiwoMAHAgAsIDBgwQIDASAAEGBg4IACAQQkCMAggYCMAwoiDBCAQAMFBApUNGggQYEDCjSuJFiAQEcDDgYMQNAgJUECNg8EKKAgwAEHBBAYtBhyqdOnAAYIQFCSKoICEQraBIBSaEYADZQKhIjggIADCzCeJQChKYACC4ZKDWDg41eLFBMwkDAgQIK6bi2mhFkzMFSDAQEAOw==
'''
root.tk.call('wm', 'iconphoto', root._w, tk.PhotoImage(data=data))
####
app = SitemapGUI(root)
root.mainloop()