3Dモデルやテクスチャを配布するための zip圧縮ファイルの作成が面倒なので、ChatGPTで自動化ツールを作ってみました。
ファイルの拡張子やフォルダ名によって、自動で名前を付けてzipファイルを作成します。
スクリプト
import os
import zipfile
import tkinter as tk
from tkinter import messagebox
from tkinter import filedialog
def process_directory():
directory = filedialog.askdirectory()
if not directory:
return
try:
for name in os.listdir(directory):
path = os.path.join(directory, name)
if os.path.isfile(path):
base_name, ext = os.path.splitext(name)
ext = ext.lstrip('.')
if ext == "obj" and os.path.isfile(f"{directory}/{base_name}.mtl"):
with zipfile.ZipFile(f"{directory}/{base_name}_obj.zip", "w", zipfile.ZIP_DEFLATED) as zip_file:
zip_file.write(path, arcname=name)
zip_file.write(f"{directory}/{base_name}.mtl", arcname=f"{base_name}.mtl")
elif ext in ["fbx", "unitypackage"]:
with zipfile.ZipFile(f"{directory}/{base_name}_{ext}.zip", "w", zipfile.ZIP_DEFLATED) as zip_file:
zip_file.write(path, arcname=name)
elif os.path.isdir(path) and name == "Textures":
with zipfile.ZipFile(f"{directory}/{name}.zip","w", zipfile.ZIP_DEFLATED) as zip_file:
for foldername, subfolders, filenames in os.walk(path):
for filename in filenames:
filepath = os.path.join(foldername, filename)
zip_file.write(filepath, arcname=os.path.relpath(filepath, start=directory))
messagebox.showinfo("Success", "Directory processed successfully!")
os.startfile(directory)
except Exception as e:
messagebox.showerror("Error", str(e))
root = tk.Tk()
process_button = tk.Button(root, text="Process Directory", command=process_directory)
process_button.pack()
root.mainloop()
まず、モジュールをインストールします。osはファイルやディレクトリ操作のために、オペレーティングシステムとやり取りをします。
import os
zipfileはzipファイルの読み書きをします。
import zipfile
tkinterはGUIを作成するためのPython標準のモジュールで、tkという名前でインポートしています。
import tkinter as tk
ダイアログボックスを表示するためのtkinterのサブモジュールも使います。
from tkinter import messagebox
from tkinter import filedialog
ウィンドウを表示するには、tkinter.Tkクラスのインスタンスを作ります。rootという変数に入れています。
root = tk.Tk()
ウィンドウには処理を開始するボタンを表示します。ボタンウィジェットを作るには、tkinter.Buttonクラスをインスタンス化します。引数には、ウィンドウや、表示テキスト、ボタンをクリックしたときの処理を渡します。
process_button = tk.Button(root, text="Process Directory", command=process_directory)
process_button.pack()
packメソッドでウィンドウに配置します。
mainloopメソッドでイベントループを開始します。このループの中でプログラムがボタンクリックなどのイベントを待ち、イベントが発生すると、command引数に設定されたメソッドを実行します。
root.mainloop()
ボタンがクリックされると、まずfiledialog.askdirectoryメソッドで、ディレクトリを選択するためのダイアログを表示します。選択したフォルダのパスが返ります。
def process_directory():
directory = filedialog.askdirectory()
if not directory:
return
os.listdirメソッドでディレクトリ内のすべてのフォルダとファイルの名前のリストを返します。for文で一つずつ処理します。
try:
for name in os.listdir(directory):
os.path.joinメソッドで、ディレクトリと名前を結合してパスを作成します。
path = os.path.join(directory, name)
ファイルかどうかを確認した後、os.path.splitextメソッドでファイル名と拡張子を分割し、lstripメソッドで拡張子の「.」を削除します。
if os.path.isfile(path):
base_name, ext = os.path.splitext(name)
ext = ext.lstrip('.')
拡張子が obj の場合、同じフォルダに同名の.mtlファイルがあるか確認します。
if ext == "obj" and os.path.isfile(f"{directory}/{base_name}.mtl"):
ファイル名に「_obj」という接尾辞を付けて通常のZIP圧縮方法で、zipファイルを作ります。
with zipfile.ZipFile(f"{directory}/{base_name}_obj.zip", "w", zipfile.ZIP_DEFLATED) as zip_file:
with文は、C#のusingステートメントのように、取得したリソースが使い終わると必ず解放します。as句の後ろの変数にZipFileオブジェクトが代入されます。
そして、writeメソッドで、第一引数のファイルを第二引数の名前でzipファイルに追加していきます。
zip_file.write(path, arcname=name)
zip_file.write(f"{directory}/{base_name}.mtl", arcname=f"{base_name}.mtl")
fbxファイルやunitypackageファイルの場合も、同様に名前に「_拡張子」を付けて個別のzipファイルを作成します。
elif ext in ["fbx", "unitypackage"]:
with zipfile.ZipFile(f"{directory}/{base_name}_{ext}.zip", "w", zipfile.ZIP_DEFLATED) as zip_file:
zip_file.write(path, arcname=name)
「Textures」という名前のフォルダの場合は、「Textures.zip」というzipファイルを作ります。
elif os.path.isdir(path) and name == "Textures":
with zipfile.ZipFile(f"{directory}/{name}.zip","w", zipfile.ZIP_DEFLATED) as zip_file:
os.walkメソッドを使ってこのフォルダを走査し、フォルダ内のテクスチャ画像のパスを作ります。
for foldername, subfolders, filenames in os.walk(path):
for filename in filenames:
filepath = os.path.join(foldername, filename)
それをzipファイルに追加します。arcnameに入れるのは相対パスなので、os.path.relpathメソッドを使っています。
zip_file.write(filepath, arcname=os.path.relpath(filepath, start=directory))
終わったらメッセージを表示して、選択したフォルダを表示します。
messagebox.showinfo("Success", "Directory processed successfully!")
os.startfile(directory)
エラーの場合も出力します。
except Exception as e:
messagebox.showerror("Error", str(e))
スクリプトを実行する
上記のようなフォルダやファイルが一つのフォルダにあります。
スクリプトを実行すると、ウィンドウとボタンが表示されます。
ボタンを押すと、フォルダーの選択ダイアログが表示されるので、このフォルダを選択します。
ダイアログが出るので「OK」を押すとzipファイルが出来ています。
これで、zipファイルの作成を自動化できました。
ChatGPT
ChatGPTに具体的な操作を入力して方法聞くと、Pythonを勧められました。
私の提案は、Pythonを使うことです。Pythonはファイルやフォルダの操作、そしてzip圧縮など、このタスクに必要な機能を持つ標準ライブラリを持っています。また、PythonはWindows10で広くサポートされており、比較的短いコードで効率的にこのタスクを達成することができます。
GUIについて聞くと、選択肢が出力されました。
ythonでGUI(グラフィカルユーザーインターフェース)を作成するためのいくつかの選択肢があります。以下に主なものをご紹介します。
この中から選ぶとすれば、Windows環境で利用すること、学習曲線を考慮すると、TkinterやPyQt/PySideが最も適していると思います。ただし、PyQt/PySideはライセンスが商用とフリーの2つの形式で提供されているので、用途によっては注意が必要です。商用利用をする場合はライセンス料が発生します。
- Tkinter: Pythonの標準ライブラリで、直感的な操作性を持ちます。しかし、見た目が少し古めであると感じるかもしれません。
- PyQt or PySide: QtフレームワークのPythonバインディングで、見た目が現代的でプロフェッショナルなGUIを作ることができます。ただし、ライセンスや学習曲線に注意が必要です。
- wxPython: wxWidgetsのPythonバインディングで、プラットフォームに応じて異なるネイティブなルック&フィールを提供します。
- Kivy: タッチスクリーン対応のアプリケーションを作成するためのライブラリで、WindowsだけでなくAndroidやiOSにも対応しています。
- PyGTK: GTKフレームワークのPythonバインディングで、Linux環境での使用に最適です。
簡単な操作性とシンプルさを重視するならTkinterが、豊富なウィジェットと現代的な見た目を優先するならPyQt/PySideがおすすめです。
以上のライブラリを使用して、ユーザーが処理を始めるためのボタンや、エラーメッセージを表示するためのダイアログなどのUIを作成することが可能です。具体的なコードの作成が必要であれば、その旨お知らせください。
Tkinterを選んでコードを選んでコードを書くように指示するとはじめのスクリプトが出ました。