# [メタ情報] # 識別子: 公開用スクリプトを生成する # 補足: 一括処理のものだけに統一した # [/メタ情報] 要約:この workflow は、選択した *_exe.txt ファイルから公開用 *_pub.txt を生成する自動処理である。保存先は M1 側ボリュームに固定し、Dropbox へは直接書き込まない。メタ情報が無い場合は自動付与し、既存メタでは更新日時を除去、状態を「公開用」に変更する。本文から個人情報・キー・パス等を匿名化し、key_patterns.txt に基づく追加置換も行う。未置換の秘密候補を抽出して警告し、生成後は公開 URL とエンコード URL を表示・コピーする。付属のシェルスクリプトで生成物を Dropbox に rsync 同期する。 出力先は常に M1 側の共有ボリューム /aaaaa/XXXXXX/scripts_pub に固定 aaaaaはM2の場合はVolumes M1の場合はUsersと記述 公開用スクリプトを生成する_一括.workflow ``` on run {input, parameters} -- ===== 設定 ===== -- 公開用生成物の保存先(正):M1 側ボリュームに固定 -- ※ この workflow は Dropbox には書き込まない set currentUser to short user name of (system info) if currentUser is "XXXXXX" then set FACTORY_SAVE_DIR to "<任意のフォルダパス>" else set FACTORY_SAVE_DIR to "<任意のフォルダパス>" end if -- Xserver 側での公開パス: wp-content/pmedia/scripts_pub/ 以下に置く前提 set SITE_BASE to "https://XXXXXX.com/wp-content/pmedia/" -- ================ -- 保存先フォルダを必ず作成(ボリュームがマウントされていないとエラー) try do shell script "/bin/mkdir -p " & quoted form of FACTORY_SAVE_DIR on error errm display alert "保存先フォルダエラー" message ("保存先フォルダ " & FACTORY_SAVE_DIR & " を作成/利用できませんでした。" & return & return & "・M1 Mac 側のボリューム XXXXXX がマウントされているか確認してください。" & return & return & "システムメッセージ: " & errm) return end try if input is {} then display alert "ファイル未選択" message "Finderで *_exe.txt を選んで実行してください。" return end if -- 保存先フォルダ(文字列パス)を設定 set outFolder to FACTORY_SAVE_DIR if outFolder does not end with "/" then set outFolder to outFolder & "/" set processed to 0 set urlBlocks to {} -- 完了時に表示・コピーする直リンクリスト 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 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 & ¬ "# [/メタ情報]" & 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 -- 一時ファイルは /tmp に作成 set tmpWorkExe to do shell script "/usr/bin/mktemp -t exework" do shell script "/bin/cat " & quoted form of tmpMeta & " " & qsrc & " > " & quoted form of tmpWorkExe do shell script "/bin/mv " & quoted form of tmpWorkExe & " " & qsrc do shell script "/bin/rm -f " & quoted form of tmpMeta else -- 既存メタ内の「# 更新日時: …」行を削除 set tmpWorkExe2 to do shell script "/usr/bin/mktemp -t exework" do shell script "/usr/bin/awk 'BEGIN{inm=0} /^# \\[メタ情報\\]/{inm=1} inm && /^# *更新日時:/{next} {print} /^# \\[\\/メタ情報\\]/{inm=0}' " & qsrc & " > " & quoted form of tmpWorkExe2 do shell script "/bin/mv " & quoted form of tmpWorkExe2 & " " & 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} } /^# \\[\\/メタ情報\\]/{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#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#g' " & ¬ " -e 's#(https?://docs\\.google\\.com/(spreadsheets|document|presentation)/d/)[^/]+#\\1<各GoogleファイルのID>#g' " & ¬ " -e 's#(https?://drive\\.google\\.com/file/d/)[^/]+#\\1#g' " & ¬ " -e 's#(https?://www\\.dropbox\\.com/scl/fi/)[A-Za-z0-9_-]+#\\1#g' " & ¬ " -e 's#(https?://www\\.dropbox\\.com/s/)[A-Za-z0-9_-]+#\\1#g' " & ¬ " -e 's#([?&]rlkey=)[A-Za-z0-9_-]+#\\1#g' " & ¬ " -e 's#([A-Za-z0-9_]*KEY\\s*=\\s*[\"])[^\"]+([\"])#\\1<各APIキー>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*SECRET\\s*=\\s*[\"])[^\"]+([\"])#\\1<各シークレット値>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*TOKEN\\s*=\\s*[\"])[^\"]*([\"])#\\1<各トークン値>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*SPREADSHEET_ID\\s*=\\s*[\"])[^\"]+([\"])#\\1<スプレッドシートID>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*DOC_ID_[0-9]+\\s*=\\s*[\"])[^\"]+([\"])#\\1<ドキュメントID>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*SHEET_ID\\s*=\\s*[\"])[^\"]+([\"])#\\1<シートID>\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*_F[0-9]*_ID\\s*=\\s*[\"])[^\"]+([\"])#\\1<連携用ID>\\2#g' " & ¬ " -e 's#(PUSH_META_LIB_JSON_ID\\s*=\\s*[\"])[^\"]+([\"])#\\1\\2#g' " & ¬ " -e 's#([A-Za-z0-9_]*SA_JSON[A-Za-z0-9_]*\\s*=\\s*[\"])[^\"]+([\"])#\\1<サービスアカウントJSONのパス>\\2#g' " & ¬ " -e 's#(GOOGLE_APPLICATION_CREDENTIALS\\s*=\\s*[\"])[^\"]+([\"])#\\1<認証情報JSONのパス>\\2#g' " & ¬ " -e 's#(XXXXXX_BLOG_DRIVE_PATH\\s*=\\s*[\"])[^\"]+([\"])#\\1<ご自身のドライブパス>\\2#g' " & ¬ " -e 's#(GAS_URL\\s*=\\s*[\"])[^\"]+([\"])#\\1<公開したGASのURL>\\2#g' " & ¬ " -e 's#(VIMEO_EMBED_JSON_ENDPOINT\\s*=\\s*[\"])[^\"]+([\"])#\\1<エンドポイントURL>\\2#g' " & ¬ " -e 's#(MY_SCREEN_SHARING_PASSCODE\\s*=\\s*[\"])[^\"]+([\"])#\\1<設定したパスコード>\\2#g' " & ¬ " -e 's#(token=)[A-Za-z0-9_-]+#\\1<個別のトークン文字列>#g' " & ¬ " -e 's#bbbbbbbb\\.yyyyyyyy@gmail\\.com#<ご自身のメールアドレス>#g' " & ¬ " -e 's#(/Users/|/Volumes/|/home/)[^[:space:]\"]*[iI][mM][aA][kK][aA][tT][^[:space:]\"]*/([^/[:space:]\"]+\\.[a-zA-Z0-9_-]+)#<任意のフォルダパス>/\\2#g' " & ¬ " -e 's#(/Users/|/Volumes/|/home/)[^[:space:]\"]*[iI][mM][aA][kK][aA][tT][^[:space:]\"]*#<任意のフォルダパス>#g' " & ¬ " -e 's#\\\"([A-Za-z0-9_-]{28,})\\\"#\\\"<固有のランダム文字列>\\\"#g' " & ¬ " -e 's#'\\''([A-Za-z0-9_-]{28,})'\\''#'\\''<固有のランダム文字列>'\\''#g' " & ¬ " -e 's#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#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 -- 最終スクラブ(URL等の XXXXXX を XXXXXX に変換) set tmpWorkPub1 to do shell script "/usr/bin/mktemp -t pubwork" do shell script "/usr/bin/sed -E 's#[iI][mM][aA][kK][aA][tT][mM]1#XXXXXX#g; s#[iI][mM][aA][kK][aA][tT]#XXXXXX#g' " & qdst & " > " & quoted form of tmpWorkPub1 do shell script "/bin/mv " & quoted form of tmpWorkPub1 & " " & qdst -- ★★ key_patterns.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" set tmpWorkPub2 to do shell script "/usr/bin/mktemp -t pubwork" do shell script "/usr/bin/sed -E -e " & quoted form of sedExpr & " " & qdst & " > " & quoted form of tmpWorkPub2 do shell script "/bin/mv " & quoted form of tmpWorkPub2 & " " & qdst end if end repeat end if -- 2) ペア行(元,置換後)での全体置換 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 set tmpWorkPub3 to do shell script "/usr/bin/mktemp -t pubwork" 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 & " > " & quoted form of tmpWorkPub3 do shell script "/bin/mv " & quoted form of tmpWorkPub3 & " " & qdst end if end repeat end if end if -- ★★ 追加ここまで ★★ -- URL 用の相対パス(Xserver 側) set relPathNFC to "scripts_pub/" & pubName set urlPlain to SITE_BASE & relPathNFC copy urlPlain to end of urlBlocks set processed to processed + 1 end if on error errm display notification errm with title "公開用生成エラー" end try end repeat -- 完了メッセージ(直リンクのみ表示&クリップボードへ) if processed > 0 then if (count of urlBlocks) > 0 then set my text item delimiters to return set fullUrlText to urlBlocks as text set my text item delimiters to "" set the clipboard to fullUrlText -- ダイアログが縦長になりすぎるのを防ぐため、表示は最大15件までにする if processed > 15 then set my text item delimiters to return set displayUrlText to (items 1 thru 15 of urlBlocks as text) & return & "(...他 " & (processed - 15) & " 件)" set my text item delimiters to "" else set displayUrlText to fullUrlText end if display dialog ("完了:" & processed & " 件更新" & return & return & displayUrlText & return & return & "※直リンクURLをクリップボードにコピーしました") buttons {"OK"} default button "OK" with icon note else display dialog ("完了:" & processed & " 件更新") buttons {"OK"} default button "OK" with icon note end if else display alert "対象なし" message "選択の中に *_exe.txt が見つかりませんでした。" end if end run ``` <任意のフォルダパス>/sync_scripts_pub_to_dropbox.sh ``` #!/bin/bash set -x export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" if [ -x /opt/homebrew/bin/rsync ]; then RSYNC="/opt/homebrew/bin/rsync" else RSYNC="/usr/bin/rsync" fi if [ "$(whoami)" = "XXXXXX" ]; then SRC="<任意のフォルダパス>" else SRC="<任意のフォルダパス>" fi DST="/Volumes/NO3_SSD/Dropbox/dropbox_1/pmedia/scripts_pub" mkdir -p "$DST" sleep 8 "$RSYNC" -av --delete --iconv=utf-8,utf-8-mac "$SRC/" "$DST/" exit 0 ```