# [メタ情報] # 識別子: 公開用スクリプトを生成する # システム名: <<公開用スクリプトを生成する>>再生URLの?v=を削除した。置き換え文字列にペア行を追加した。 # 技術種別: Misc # 機能名: Misc # 使用言語: AppleScript ShellScript # 状態: 実行用 # [/メタ情報] on run {input, parameters} -- ===== 設定 ===== set DEFAULT_SAVE_DIR to POSIX file "/Volumes/dropbox_1/pmedia/scripts_pub/" set SITE_BASE to "https://xxxxxxxx.com/wp-content/pmedia/" -- pmedia 直下のURLベース(末尾 / 必須) -- ================ if input is {} then display alert "ファイル未選択" message "Finderで *_exe.txt を選んで実行してください。" return end if -- 保存先フォルダを選択(毎回) set outFolderAlias to choose folder with prompt "公開用テキストの保存先フォルダを選んでください(pmedia/scripts_pub を推奨)" default location DEFAULT_SAVE_DIR set outFolder to POSIX path of outFolderAlias if outFolder does not end with "/" then set outFolder to outFolder & "/" set processed to 0 set urlBlocks to {} -- 完了時に表示・コピーする「直リンク+エンコードURL」ブロック repeat with selAlias in input try set srcPath to POSIX path of selAlias set qsrc to quoted form of srcPath -- *_exe.txt(大小区別なし/末尾空白除去)で終わるか判定 set isExe to do shell script "/bin/echo " & qsrc & " | /usr/bin/tr -d '\\r' | /usr/bin/sed -E 's/[[:space:]]+$//' | /usr/bin/grep -Eiq '_exe\\.txt$' && echo YES || echo NO" if isExe is not "YES" then display notification "受け取った: " & srcPath with title "対象外(*_exe.txt 判定NG)" else -- 出力ファイル名:*_exe.txt → *_pub.txt(NFC 正規化) set baseName to do shell script "/usr/bin/basename " & qsrc set pubNameRaw to do shell script "/bin/echo " & quoted form of baseName & " | /usr/bin/sed -E 's/_exe\\.txt$/_pub\\.txt/I'" set pubName to do shell script "/usr/bin/python3 -c 'import sys,unicodedata;print(unicodedata.normalize(\"NFC\",sys.argv[1]))' " & quoted form of pubNameRaw set destPath to outFolder & pubName set qdst to quoted form of destPath -- 既存チェック → 上書き確認 set skipThisFile to false set fileExists to do shell script "[ -e " & qdst & " ] && echo YES || echo NO" if fileExists is "YES" then set msg to "公開先に同名のファイルが存在します:" & return & return & destPath & return & return & "上書き保存しますか?" set dlgRes to display dialog msg buttons {"キャンセル", "上書き保存"} default button 2 cancel button 1 with icon note if (button returned of dlgRes) is not "上書き保存" then set skipThisFile to true end if end if if skipThisFile then -- このファイルの処理はスキップ else -- 先頭が [メタ情報] かチェック set hasMeta to do shell script "head -1 " & qsrc & " | /usr/bin/grep -q '^# \\[メタ情報\\]' && echo YES || echo NO" if hasMeta is "NO" then -- 識別子 = ファイル名(.txt を除いたもの)/更新日時は書かない set ident to do shell script "/bin/echo " & quoted form of baseName & " | /usr/bin/sed -E 's/\\.txt$//I'" set metaHeader to "# [メタ情報]" & return & ¬ "# 識別子: " & ident & return & ¬ "# システム名: 未分類" & return & ¬ "# 技術種別: Misc" & return & ¬ "# 機能名: Misc" & return & ¬ "# 使用言語: []" & return & ¬ "# 状態: 実行用" & return & ¬ "# [/メタ情報]" & return & return set tmpMeta to do shell script "/usr/bin/mktemp -t metahead" do shell script "/usr/bin/printf %s " & quoted form of metaHeader & " > " & quoted form of tmpMeta -- 先頭に挿入(.work を使用) do shell script "/bin/cat " & quoted form of tmpMeta & " " & qsrc & " > " & qsrc & ".work && /bin/mv " & qsrc & ".work " & qsrc & " && /bin/rm -f " & quoted form of tmpMeta else -- 既存メタ内の「# 更新日時: …」行を削除(.work を使用) do shell script "/usr/bin/awk 'BEGIN{inm=0} /^# \\[メタ情報\\]/{inm=1} inm && /^# *更新日時:/{next} {print} /^# \\[\\/メタ情報\\]/{inm=0}' " & qsrc & " > " & qsrc & ".work && /bin/mv " & qsrc & ".work " & qsrc end if -- 公開用メタ(状態=公開用 にし、更新日時は削除) set tmpMetaPub to do shell script "/usr/bin/mktemp -t metapub" do shell script "/usr/bin/awk 'BEGIN{inm=0} /^# \\[メタ情報\\]/{inm=1} inm{ if($0 ~ /^# 状態:/){print \"# 状態: 公開用\"} else if($0 ~ /^# *更新日時:/){next} else {print} } /^# \\[\\/メタ情報\\]/{print; exit}' " & qsrc & " > " & quoted form of tmpMetaPub -- 本文抽出(メタブロック以降) set tmpBody to do shell script "/usr/bin/mktemp -t bodyraw" do shell script "/usr/bin/sed '1,/^# \\[\\/メタ情報\\]$/d' " & qsrc & " > " & quoted form of tmpBody -- 本文サニタイズ(鍵・パス等の粗い匿名化) set tmpBodySan to do shell script "/usr/bin/mktemp -t bodysan" set sedRules to "/usr/bin/sed -E " & ¬ " -e 's#(https?://docs\\.google\\.com/(spreadsheets|document|presentation)/d/)[^/]+#\\1<あなたのGoogleID>#g' " & ¬ " -e 's#(https?://drive\\.google\\.com/file/d/)[^/]+#\\1<あなたのGoogleID>#g' " & ¬ " -e 's#([?&]rlkey=)[A-Za-z0-9_-]+#\\1<あなたのID>#g' " & ¬ " -e 's#(APP_KEY\\s*=\\s*[\"])[^\"]+([\"])#\\1<あなたのキー>\\2#g' " & ¬ " -e 's#(APP_SECRET\\s*=\\s*[\"])[^\"]+([\"])#\\1<あなたのキー>\\2#g' " & ¬ " -e 's#(REFRESH_TOKEN\\s*=\\s*[\"])[^\"]*([\"])#\\1<あなたのキー>\\2#g' " & ¬ " -e 's#\\b(API_KEY|TOKEN|XSERVER_EMBED_TOKEN)\\b\\s*=\\s*\\\"[^\\\"]*\\\"#\\1 = \"<あなたのキー>\"#g' " & ¬ " -e 's#(token=)[A-Za-z0-9]+#\\1<あなたのキー>#g' " & ¬ " -e 's#(/Users/)[^ \\t\\n\\r]+#<あなたのファイルパス>#g' " & ¬ " -e 's#(/Volumes/)[^ \\t\\n\\r]+#<あなたのファイルパス>#g' " & ¬ " -e 's#(/home/)[^ \\t\\n\\r]+#<あなたのファイルパス>#g' " & ¬ " -e 's#xxxxxxxx\\.com#xxxxxxxx.com#g' " & ¬ " -e 's#[iI][mM][aA][kK][aA][tT]#xxxxxxxx#g' " & ¬ " -e 's#([A-Za-z0-9_-]{20,})#<あなたのID>#g' " do shell script sedRules & quoted form of tmpBody & " > " & quoted form of tmpBodySan -- 公開用を書き出し(メタ + 本文) do shell script "/bin/cat " & quoted form of tmpMetaPub & " " & quoted form of tmpBodySan & " > " & qdst & " && /bin/rm -f " & quoted form of tmpMetaPub & " " & quoted form of tmpBody & " " & quoted form of tmpBodySan -- ★ 最終スクラブ(全体もう一度)(.work を使用) do shell script "/usr/bin/sed -E 's#xxxxxxxx\\.com#xxxxxxxx.com#g; s#[iI][mM][aA][kK][aA][tT]#xxxxxxxx#g' " & qdst & " > " & qdst & ".work && /bin/mv " & qdst & ".work " & qdst -- ★★ 追加:key_patterns.txt に基づく秘密キー置換(KEY = \"…\" / KEY = '…' → KEY = \"\") ★★ -- key_patterns.txt は _pub.txt と同じフォルダに置く set pubDir to do shell script "dirname " & qdst set keyFile to pubDir & "/key_patterns.txt" set keyFileExists to do shell script "[ -f " & quoted form of keyFile & " ] && echo YES || echo NO" if keyFileExists is "YES" then -- 1) キー名(= "..." / = '...' を に)※「,」を含む行は除外 set rawKeys to do shell script "/usr/bin/grep -a -E '^[[:space:]]*[^#[:space:]][^#]*$' " & quoted form of keyFile & " | /usr/bin/grep -a -v ',' | /usr/bin/sed -E 's/[[:space:]]+#.*$//; s/^[[:space:]]+//; s/[[:space:]]+$//'" if rawKeys is not "" then set keyList to paragraphs of rawKeys repeat with k in keyList set keyName to contents of k if keyName is not "" then set escName to do shell script "/usr/bin/python3 -c " & quoted form of "import sys,re;print(re.escape(sys.argv[1]))" & " " & quoted form of keyName set sedExpr to "s#[[:<:]]" & escName & "[[:>:]][[:space:]]*=[[:space:]]*[\\\"\\'][^\\\"\\']*[\\\"\\']#" & keyName & " = \\\"<" & keyName & ">\\\"#g" do shell script "/usr/bin/sed -E -e " & quoted form of sedExpr & " " & qdst & " > " & qdst & ".work && /bin/mv " & qdst & ".work " & qdst end if end repeat end if -- 2) ペア行(元,置換後)での全体置換:awk で (orig \t repl) 抽出 → Perl でリテラル置換 -- 置換後文字列に / \ & # などが含まれてもOK(Perlに引数で渡して \Q...\E で置換) set pairsTSV to do shell script "/usr/bin/awk 'BEGIN{FS=\",\"; OFS=\"\\t\"} /^[[:space:]]*($|#)/{next} {orig=$1; sub(/^[[:space:]]+/,\"\",orig); sub(/[[:space:]]+$/,\"\",orig); repl=$0; sub(/^[^,]*,/,\"\",repl); sub(/^[[:space:]]+/,\"\",repl); sub(/[[:space:]]+$/,\"\",repl); if(orig!=\"\" && repl!=\"\"){print orig, repl}}' " & quoted form of keyFile if pairsTSV is not "" then set pairLines to paragraphs of pairsTSV repeat with lineText in pairLines set t to contents of lineText set tidx to offset of tab in t if tidx > 0 then set origVal to text 1 thru (tidx - 1) of t set replVal to text (tidx + 1) thru -1 of t -- Perl で \Q...\E 置換(引数で渡すのでエスケープ不要) do shell script "/usr/bin/perl -0777 -pe 'BEGIN{$o=shift;$r=shift;} s/\\Q$o\\E/$r/g' -- " & quoted form of origVal & " " & quoted form of replVal & " " & qdst & " > " & qdst & ".work && /bin/mv " & qdst & ".work " & qdst end if end repeat end if end if -- ★★ 追加ここまで ★★ -- ★★ 追加:置換しきれていない「疑わしい秘密候補」をピックアップ(キー名は除外) ★★ set excludeFilter to "" if keyFileExists is "YES" then set excludeFilter to " | /usr/bin/grep -a -v -F -f " & quoted form of keyFile end if set suspectCmd to "/bin/cat " & qdst & " | " & ¬ "/usr/bin/grep -a -E -o '([A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,})|([A-Fa-f0-9]{32,})|([A-Za-z0-9+/]{32,}={0,2})|([A-Za-z0-9_-]{24,})' | " & ¬ "/usr/bin/grep -a -v '<[^>]+>'" & excludeFilter & " | " & ¬ "/usr/bin/sed -E 's/^/・/;' | /usr/bin/sort -u | /usr/bin/head -n 50" set suspects to do shell script suspectCmd if suspects is not "" then set blockSus to "秘密候補(未置換の可能性がある文字列・最大50件):" & return & suspects & return & "※必要に応じて key_patterns.txt にキー名またはペア行を追加し、再出力してください。" copy blockSus to end of urlBlocks end if -- pmedia 以降の相対パス(NFC 正規化してから URL を作成) set containsPmedia to do shell script "echo " & qdst & " | /usr/bin/grep -q '/pmedia/' && echo YES || echo NO" if containsPmedia is "YES" then set relPathRaw to do shell script "echo " & qdst & " | /usr/bin/sed -E 's#^.*/pmedia/##'" set relPathNFC to do shell script "/usr/bin/python3 -c 'import sys,unicodedata;print(unicodedata.normalize(\"NFC\",sys.argv[1]))' " & quoted form of relPathRaw -- ヒアドキュメント非使用で安全にURLエンコード set pyEnc to "from urllib.parse import quote; import sys,unicodedata as u; p=sys.argv[1]; print('/'.join(quote(u.normalize(\"NFC\", s)) for s in p.split('/')))" set encRel to do shell script "/usr/bin/python3 -c " & quoted form of pyEnc & " " & quoted form of relPathNFC -- ▼ キャッシュバスター用タイムスタンプ(両URLに ?v= を付与) set ts to do shell script "/bin/date +%s" set urlPlain to SITE_BASE & relPathNFC set urlEncoded to SITE_BASE & encRel set blockText to "直リンク: " & urlPlain & return & "エンコードURL: " & urlEncoded copy blockText to end of urlBlocks end if set processed to processed + 1 end if end if on error errm display notification errm with title "公開用生成エラー" end try end repeat -- 完了メッセージ(2種URL+秘密候補をボックス表示&クリップボードへ) if processed > 0 then if (count of urlBlocks) > 0 then set AppleScript's text item delimiters to return & return set urlText to urlBlocks as text set AppleScript's text item delimiters to "" set the clipboard to urlText display dialog ("完了:" & processed & " 件更新" & return & return & urlText) buttons {"OK"} default button "OK" with icon note else display dialog ("完了:" & processed & " 件更新(pmedia 配下でなかったためURLは表示していません)") buttons {"OK"} default button "OK" with icon note end if else display alert "対象なし" message "選択の中に *_exe.txt が見つかりませんでした。" end if end run