ふぁメモ

主に技術系のメモをしたいけどやっぱり適当日記。たまにPHPコード載ってるけどメモ書き程度のスクリプトなのでそのまま使っちゃダメ。

Chromeのファイル参照ダイアログの初期フォルダを変更する

序文

Chromeブラウザでファイルアップロードのフォルダ参照ダイアログを開いたら、昨夜寝る前に使っていたフォルダがサムネイル付きで展開されてしまった。

後ろに人がいなくてよかった…。

こんなことにならないように、ファイルを開くフォルダをリセットしておこう。

Windowsのエクスプローラの場合はオプションのプライバシー設定で「エクスプローラーの履歴を消去する」「使用頻度の高いフォルダーを表示する」といった項目がカスタマイズできるようになっているけど、Chromeブラウザには影響しない。

Chromeブラウザのデフォルト参照フォルダの設定はどこ?

ChatGPTで調べていたら

AppData\Local\Google\Chrome\User Data\Default\Preferences

"savefile":{"default_directory":"C:\\"},
"selectfile":{"last_directory":"C:\\"},

これだ。

これを書き換えればOK。

ただChromeの起動中は頻繁に更新されるのと、1行のものすごく長いJSONテキストなのと、エスケープされていない日本語や改行が混ざっていてjqとかのちゃんとしたJSONツールではパースエラーになる。

ChatGPTがBATファイルやPowerShellで書き換えるツールを書いてくれたのだけどうまくいかない(プロファイルが壊れる)。

Pythonで書いてもらった

import os
import shutil
import re
import subprocess
import sys
import json

print("=== Chrome Preferences 修正 ===")

# 引数処理
target_dir = None
if len(sys.argv) > 1:
    target_dir = sys.argv[1]
    print(f"指定ディレクトリ: {target_dir}")
else:
    print("ディレクトリ指定なし → 空にします")

# Chrome終了
subprocess.run(["taskkill", "/f", "/im", "chrome.exe"],
               stdout=subprocess.DEVNULL,
               stderr=subprocess.DEVNULL)

pref_path = os.path.join(
    os.environ["LOCALAPPDATA"],
    r"Google\Chrome\User Data\Default\Preferences"
)

backup_path = pref_path + ".bak"

if not os.path.exists(pref_path):
    print("Preferences が見つかりません")
    sys.exit()

# 1世代バックアップ
shutil.copyfile(pref_path, backup_path)
print("バックアップ作成: Preferences.bak")

# 読み込み(BOM対応)
with open(pref_path, "rb") as f:
    raw = f.read()

text = raw.decode("utf-8-sig")

# JSON用に安全エスケープ
if target_dir is not None:
    target_dir_json = json.dumps(target_dir)[1:-1]  # 両端の"を除去
else:
    target_dir_json = ""

def replace_value(match):
    return f'{match.group(1)}{target_dir_json}{match.group(3)}'

# default_directory
text = re.sub(
    r'("default_directory"\s*:\s*")([^"]*)(")',
    replace_value,
    text
)

# last_directory
text = re.sub(
    r'("last_directory"\s*:\s*")([^"]*)(")',
    replace_value,
    text
)

# 書き戻し(UTF-8)
with open(pref_path, "wb") as f:
    f.write(text.encode("utf-8"))

print("処理完了。Chromeを起動してください。")

※実行するとChromeブラウザは強制終了になります。

さらに改良を進めてプロファイル選択機能やGUI指定を付けた

import os
import shutil
import subprocess
import json
import tkinter as tk
from tkinter import filedialog, messagebox

# --- Chrome User Data パス ---
user_data_dir = os.path.join(
    os.environ["LOCALAPPDATA"],
    r"Google\Chrome\User Data"
)

if not os.path.exists(user_data_dir):
    messagebox.showerror("エラー", "Chrome User Data が見つかりません")
    exit()

# --- 表示名取得 ---
local_state_path = os.path.join(user_data_dir, "Local State")
profile_names = {}

if os.path.isfile(local_state_path):
    try:
        with open(local_state_path, "r", encoding="utf-8") as f:
            local_state = json.load(f)
            info_cache = local_state.get("profile", {}).get("info_cache", {})
            for key, value in info_cache.items():
                profile_names[key] = value.get("name", key)
    except Exception:
        pass

# --- プロファイル検出 ---
profiles = []
for folder in os.listdir(user_data_dir):
    pref_path = os.path.join(user_data_dir, folder, "Preferences")
    if os.path.isfile(pref_path):
        profiles.append(folder)

profiles.sort()

if not profiles:
    messagebox.showerror("エラー", "プロファイルが見つかりません")
    exit()

# --- GUI ---
root = tk.Tk()
root.title("Chrome プロファイル選択")

selected_profile = tk.StringVar()

display_map = {}
for p in profiles:
    display = f"{profile_names.get(p, p)} ({p})"
    display_map[display] = p

tk.Label(root, text="プロファイルを選択してください").pack(pady=5)

listbox = tk.Listbox(root, width=50, height=10)
for name in display_map.keys():
    listbox.insert(tk.END, name)
listbox.pack(padx=10, pady=5)

def on_execute():
    selection = listbox.curselection()
    if not selection:
        messagebox.showerror("エラー", "プロファイルを選択してください")
        return

    display_name = listbox.get(selection[0])
    profile_name = display_map[display_name]

    root.withdraw()

    initial_dir = "C:\\"

    if not os.path.exists(initial_dir):
        initial_dir = os.path.expanduser("~")  # fallback

    target_dir = filedialog.askdirectory(
        title="設定するフォルダを選択(キャンセルで空にする)",
        initialdir=initial_dir
    )

    # パス正規化
    if target_dir:
        target_dir = os.path.normpath(target_dir)
    else:
        target_dir = ""

    # Chrome終了
    subprocess.run(
        ["taskkill", "/f", "/im", "chrome.exe"],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )

    pref_path = os.path.join(user_data_dir, profile_name, "Preferences")
    backup_path = pref_path + ".bak"

    # バックアップ
    shutil.copyfile(pref_path, backup_path)

    # JSON安全編集
    with open(pref_path, "r", encoding="utf-8") as f:
        prefs = json.load(f)

    if "savefile" in prefs:
        prefs["savefile"]["default_directory"] = target_dir

    if "selectfile" in prefs:
        prefs["selectfile"]["last_directory"] = target_dir

    with open(pref_path, "w", encoding="utf-8") as f:
        json.dump(prefs, f, ensure_ascii=False)

    messagebox.showinfo(
        "完了",
        f"{display_name} を更新しました。\n\n"
        f"設定フォルダ: {target_dir if target_dir else '空'}\n\n"
        "【復旧方法】\n"
        "1. Chromeを終了\n"
        "2. Preferences を削除\n"
        "3. Preferences.bak を Preferences にリネーム\n"
        "4. Chrome起動"
    )

    root.destroy()

tk.Button(root, text="実行", command=on_execute).pack(pady=10)

root.mainloop()

※実行するとChromeブラウザは強制終了になります。

ChatGPTに勧められるままに実行ファイルを作成してみた

github.com

Windowsに止められると思うけど…


NSFW

プライバシーポリシー |ページトップへ