Initial backup 2026-02-17
This commit is contained in:
342
skills/apple-shortcuts/scripts/generate.py
Normal file
342
skills/apple-shortcuts/scripts/generate.py
Normal file
@@ -0,0 +1,342 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Apple Shortcuts Generator
|
||||
Generates .shortcut files compatible with iOS/macOS Shortcuts app
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
import base64
|
||||
import plistlib
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
TEMPLATES = {
|
||||
"voice-to-notion": {
|
||||
"name": "Voice to Notion",
|
||||
"description": "Record voice, transcribe, and add to Notion inbox",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.recordaudio",
|
||||
"WFWorkflowActionParameters": {}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.transcribeaudio",
|
||||
"WFWorkflowActionParameters": {}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFTextActionText": "Add to Notion Inbox:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openapp",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFAppIdentifier": "com.philipyoungg.notione"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"expense-logger": {
|
||||
"name": "Quick Expense",
|
||||
"description": "Log expense to Notion database",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFAskActionPrompt": "Amount?",
|
||||
"WFAskActionAnswerType": "Number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.choosefromlist",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFChooseFromListActionPrompt": "Category?",
|
||||
"WFChooseFromListActionItems": ["Food", "Transport", "Entertainment", "Shopping", "Bills"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFTextActionText": {
|
||||
"Value": {
|
||||
"string": "Logged: $amount$ for $category$ on $date$"
|
||||
},
|
||||
"WFSerializationType": "WFTextTokenString"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": "https://t.me/clawdbot?start=expense_"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"ha-scene": {
|
||||
"name": "Home Assistant Scene",
|
||||
"description": "Trigger Home Assistant scene",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": "https://t.me/clawdbot?start=ha_scene_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
|
||||
"WFWorkflowActionParameters": {
|
||||
"Text": "Scene activated!"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"morning-briefing": {
|
||||
"name": "Trigger Morning Briefing",
|
||||
"description": "Manually trigger your Morning Intelligence Briefing",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": "https://t.me/clawdbot?start=morning_briefing_now"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
|
||||
"WFWorkflowActionParameters": {
|
||||
"Text": "Morning briefing requested! Check Telegram in a moment."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"send-to-openclaw": {
|
||||
"name": "Send to OpenClaw",
|
||||
"description": "Send text, clipboard, or input to OpenClaw",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFTextActionText": {
|
||||
"Value": {
|
||||
"attachmentsByRange": {
|
||||
"{0, 1}": {
|
||||
"Type": "Clipboard",
|
||||
"Aggrandizements": []
|
||||
}
|
||||
},
|
||||
"string": "$0"
|
||||
},
|
||||
"WFSerializationType": "WFTextTokenString"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.urlencode",
|
||||
"WFWorkflowActionParameters": {}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": {
|
||||
"Value": {
|
||||
"string": "https://t.me/clawdbot?start=shortcut_",
|
||||
"attachmentsByRange": {}
|
||||
},
|
||||
"WFSerializationType": "WFTextTokenString"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"quick-task": {
|
||||
"name": "Quick Task to Notion",
|
||||
"description": "Add a quick task to your Work To-do list",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFAskActionPrompt": "Task name?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.choosefromlist",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFChooseFromListActionPrompt": "Priority?",
|
||||
"WFChooseFromListActionItems": ["High", "Medium", "Low"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": "https://t.me/clawdbot?start=task_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
|
||||
"WFWorkflowActionParameters": {
|
||||
"Text": "Task sent to OpenClaw!"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"log-to-notion": {
|
||||
"name": "Log to Notion",
|
||||
"description": "Quick log entry to Notion journal/daily notes",
|
||||
"actions": [
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFAskActionPrompt": "What happened?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.getcurrentdatetime",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFCurrentDateFormat": "Short"
|
||||
}
|
||||
},
|
||||
{
|
||||
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
|
||||
"WFWorkflowActionParameters": {
|
||||
"WFURLActionURL": "https://t.me/clawdbot?start=log_"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
def create_shortcut_json(name, actions, description=""):
|
||||
"""Create the JSON structure for a .shortcut file"""
|
||||
shortcut = {
|
||||
"WFWorkflowClientVersion": "1092.0.2",
|
||||
"WFWorkflowClientRelease": "4.0",
|
||||
"WFWorkflowMinimumClientVersion": 900,
|
||||
"WFWorkflowMinimumClientVersionString": "900",
|
||||
"WFWorkflowIcon": {
|
||||
"WFWorkflowIconStartColor": 4292093695,
|
||||
"WFWorkflowIconGlyphNumber": 61456
|
||||
},
|
||||
"WFWorkflowImportQuestions": [],
|
||||
"WFWorkflowTypes": ["NCWidget", "WatchKit"],
|
||||
"WFWorkflowInputContentItemClasses": [
|
||||
"WFAppStoreAppContentItem",
|
||||
"WFArticleContentItem",
|
||||
"WFContactContentItem",
|
||||
"WFDateContentItem",
|
||||
"WFEmailAddressContentItem",
|
||||
"WFGenericFileContentItem",
|
||||
"WFImageContentItem",
|
||||
"WFiTunesProductContentItem",
|
||||
"WFLocationContentItem",
|
||||
"WFDCMapsLinkContentItem",
|
||||
"WFAVAssetContentItem",
|
||||
"WFPDFContentItem",
|
||||
"WFPhoneNumberContentItem",
|
||||
"WFRichTextContentItem",
|
||||
"WFSafariWebPageContentItem",
|
||||
"WFStringContentItem",
|
||||
"WFURLContentItem"
|
||||
],
|
||||
"WFWorkflowActions": actions,
|
||||
"WFWorkflowName": name
|
||||
}
|
||||
return shortcut
|
||||
|
||||
def generate_shortcut_file(template_name, output_dir="~/Downloads", custom_name=None):
|
||||
"""Generate a .shortcut file from template"""
|
||||
if template_name not in TEMPLATES:
|
||||
print(f"❌ Template '{template_name}' not found!")
|
||||
print(f"Available: {', '.join(TEMPLATES.keys())}")
|
||||
return None
|
||||
|
||||
template = TEMPLATES[template_name]
|
||||
name = custom_name or template["name"]
|
||||
|
||||
shortcut_data = create_shortcut_json(name, template["actions"], template["description"])
|
||||
|
||||
# Create output path
|
||||
output_path = Path(output_dir).expanduser() / f"{name.replace(' ', '_')}.shortcut"
|
||||
|
||||
# Write as plist (binary format that Shortcuts app expects)
|
||||
with open(output_path, 'wb') as f:
|
||||
plistlib.dump(shortcut_data, f)
|
||||
|
||||
print(f"✅ Generated: {output_path}")
|
||||
print(f" Description: {template['description']}")
|
||||
print(f" Actions: {len(template['actions'])}")
|
||||
print(f"\n📱 To install:")
|
||||
print(f" 1. AirDrop to your iPhone/Mac, or")
|
||||
print(f" 2. Open in Files app")
|
||||
print(f" 3. Tap 'Add Shortcut'")
|
||||
|
||||
return output_path
|
||||
|
||||
def list_templates():
|
||||
"""List all available templates"""
|
||||
print("📋 Available Shortcut Templates:")
|
||||
print("=" * 50)
|
||||
for key, template in TEMPLATES.items():
|
||||
print(f"\n🔹 {key}")
|
||||
print(f" Name: {template['name']}")
|
||||
print(f" Description: {template['description']}")
|
||||
print(f" Actions: {len(template['actions'])}")
|
||||
|
||||
def generate_custom_shortcut(description, output_dir="~/Downloads"):
|
||||
"""Generate a custom shortcut based on description"""
|
||||
print(f"🎯 Generating custom shortcut...")
|
||||
print(f" Description: {description}")
|
||||
print()
|
||||
print("⚠️ Custom shortcut generation requires AI processing.")
|
||||
print(" In a full implementation, this would:")
|
||||
print(" 1. Parse your description")
|
||||
print(" 2. Generate appropriate Shortcuts actions")
|
||||
print(" 3. Output a working .shortcut file")
|
||||
print()
|
||||
print(" For now, use --template with one of the pre-built options!")
|
||||
print()
|
||||
list_templates()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate Apple Shortcuts (.shortcut files)")
|
||||
parser.add_argument("--template", "-t", help="Template name to use")
|
||||
parser.add_argument("--list", "-l", action="store_true", help="List available templates")
|
||||
parser.add_argument("--output", "-o", default="~/Downloads", help="Output directory")
|
||||
parser.add_argument("--name", "-n", help="Custom name for the shortcut")
|
||||
parser.add_argument("--custom", "-c", help="Custom description for AI-generated shortcut")
|
||||
parser.add_argument("--scene", "-s", help="Scene name (for ha-scene template)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list:
|
||||
list_templates()
|
||||
return
|
||||
|
||||
if args.custom:
|
||||
generate_custom_shortcut(args.custom, args.output)
|
||||
return
|
||||
|
||||
if args.template:
|
||||
# Handle scene parameter for ha-scene template
|
||||
custom_name = args.name
|
||||
if args.template == "ha-scene" and args.scene:
|
||||
custom_name = f"Scene: {args.scene}"
|
||||
|
||||
generate_shortcut_file(args.template, args.output, custom_name)
|
||||
return
|
||||
|
||||
# No arguments - show help
|
||||
parser.print_help()
|
||||
print("\n")
|
||||
list_templates()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user