サイトマップ作成機『虚網ノ書』 ソースコード

以下は『虚網ノ書』のソースコード全文です:

 
        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()

    

📦 ダウンロード 🏠 ホームへ