Initial backup 2026-02-17
This commit is contained in:
47
skills/apple-shortcuts/scripts/generate-qr.py
Normal file
47
skills/apple-shortcuts/scripts/generate-qr.py
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
import qrcode
|
||||
from pathlib import Path
|
||||
|
||||
# Create shortcuts directory
|
||||
Path('qr-codes').mkdir(exist_ok=True)
|
||||
|
||||
shortcuts = [
|
||||
{
|
||||
'name': 'Trigger_Morning_Briefing',
|
||||
'url': 'https://t.me/clawdbot?start=morning_briefing_now',
|
||||
'desc': 'Trigger your Morning Intelligence Briefing'
|
||||
},
|
||||
{
|
||||
'name': 'Quick_Task',
|
||||
'url': 'https://t.me/clawdbot?start=task_new_medium',
|
||||
'desc': 'Add task to Notion'
|
||||
},
|
||||
{
|
||||
'name': 'Quick_Expense',
|
||||
'url': 'https://t.me/clawdbot?start=expense_0_general',
|
||||
'desc': 'Log expense'
|
||||
},
|
||||
{
|
||||
'name': 'Send_to_OpenClaw',
|
||||
'url': 'https://t.me/clawdbot',
|
||||
'desc': 'Open chat with OpenClaw'
|
||||
}
|
||||
]
|
||||
|
||||
for s in shortcuts:
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
box_size=10,
|
||||
border=5
|
||||
)
|
||||
qr.add_data(s['url'])
|
||||
qr.make(fit=True)
|
||||
|
||||
img = qr.make_image(fill_color='black', back_color='white')
|
||||
img.save(f"qr-codes/{s['name']}.png")
|
||||
print(f"✅ Generated: {s['name']}.png")
|
||||
print(f" URL: {s['url']}")
|
||||
print(f" Desc: {s['desc']}")
|
||||
print()
|
||||
|
||||
print('All QR codes generated in qr-codes/ directory')
|
||||
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()
|
||||
191
skills/apple-shortcuts/scripts/url-scheme.py
Normal file
191
skills/apple-shortcuts/scripts/url-scheme.py
Normal file
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
URL Scheme Integration for Apple Shortcuts
|
||||
Creates URL schemes that Shortcuts can use to communicate with OpenClaw
|
||||
"""
|
||||
import argparse
|
||||
import urllib.parse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
BASE_URL = "https://t.me/clawdbot"
|
||||
|
||||
def create_url_scheme(action, **params):
|
||||
"""Create a URL scheme for OpenClaw"""
|
||||
|
||||
# Build the start parameter
|
||||
param_str = "_".join([f"{k}:{v}" for k, v in params.items()])
|
||||
start_param = f"{action}_{param_str}"
|
||||
|
||||
# URL encode
|
||||
encoded = urllib.parse.quote(start_param, safe='')
|
||||
|
||||
return f"{BASE_URL}?start={encoded}"
|
||||
|
||||
def create_shortcut_url(name, input_type="text", input_value=""):
|
||||
"""Create a shortcuts:// URL to run a shortcut"""
|
||||
encoded_name = urllib.parse.quote(name, safe='')
|
||||
url = f"shortcuts://run-shortcut?name={encoded_name}"
|
||||
|
||||
if input_type and input_value:
|
||||
encoded_input = urllib.parse.quote(input_value, safe='')
|
||||
url += f"&input={input_type}&text={encoded_input}"
|
||||
|
||||
return url
|
||||
|
||||
def generate_n8n_webhook_url(webhook_id, data=None):
|
||||
"""Generate n8n webhook URL"""
|
||||
base = f"https://n8n.kangaroo-eel.ts.net/webhook/{webhook_id}"
|
||||
if data:
|
||||
params = urllib.parse.urlencode(data)
|
||||
return f"{base}?{params}"
|
||||
return base
|
||||
|
||||
def create_send_to_openclaw_url(message):
|
||||
"""Create URL to send message to OpenClaw via Telegram"""
|
||||
return create_url_scheme("msg", text=message[:100]) # Limit length
|
||||
|
||||
def create_home_assistant_url(entity_id, action="turn_on"):
|
||||
"""Create Home Assistant webhook URL"""
|
||||
return f"http://homeassistant.kangaroo-eel.ts.net:8123/api/webhook/{entity_id}_{action}"
|
||||
|
||||
def list_integrations():
|
||||
"""List available URL scheme integrations"""
|
||||
integrations = {
|
||||
"send-telegram": {
|
||||
"description": "Send text to OpenClaw via Telegram",
|
||||
"url": "https://t.me/clawdbot?start=msg_<text>",
|
||||
"example": "python3 url-scheme.py --action send-telegram --message 'Hello'"
|
||||
},
|
||||
"trigger-morning-briefing": {
|
||||
"description": "Manually trigger Morning Intelligence Briefing",
|
||||
"url": "https://t.me/clawdbot?start=morning_briefing_now",
|
||||
"example": "python3 url-scheme.py --action trigger-morning-briefing"
|
||||
},
|
||||
"log-expense": {
|
||||
"description": "Quick expense log",
|
||||
"url": "https://t.me/clawdbot?start=expense_<amount>_<category>",
|
||||
"example": "python3 url-scheme.py --action log-expense --amount 25.50 --category Food"
|
||||
},
|
||||
"add-task": {
|
||||
"description": "Add task to Notion",
|
||||
"url": "https://t.me/clawdbot?start=task_<name>_<priority>",
|
||||
"example": "python3 url-scheme.py --action add-task --task 'Buy milk' --priority High"
|
||||
},
|
||||
"trigger-n8n": {
|
||||
"description": "Trigger n8n workflow",
|
||||
"url": "https://n8n.kangaroo-eel.ts.net/webhook/<webhook-id>",
|
||||
"example": "python3 url-scheme.py --action trigger-n8n --webhook my-workflow"
|
||||
}
|
||||
}
|
||||
|
||||
print("🔗 Available URL Scheme Integrations:")
|
||||
print("=" * 60)
|
||||
for key, info in integrations.items():
|
||||
print(f"\n🔹 {key}")
|
||||
print(f" {info['description']}")
|
||||
print(f" URL: {info['url']}")
|
||||
print(f" Usage: {info['example']}")
|
||||
|
||||
def generate_qr_code(url, output_file=None):
|
||||
"""Generate QR code for URL (requires qrcode package)"""
|
||||
try:
|
||||
import qrcode
|
||||
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
||||
qr.add_data(url)
|
||||
qr.make(fit=True)
|
||||
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
|
||||
if output_file:
|
||||
img.save(output_file)
|
||||
print(f"📱 QR Code saved: {output_file}")
|
||||
else:
|
||||
print(f"📱 QR Code generated for: {url}")
|
||||
print(" (Install 'qrcode' and 'pillow' packages to save as image)")
|
||||
|
||||
except ImportError:
|
||||
print(f"📱 URL: {url}")
|
||||
print(" (Install 'qrcode' package to generate QR codes)")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="URL Scheme Integration for Apple Shortcuts")
|
||||
parser.add_argument("--action", "-a", help="Action type")
|
||||
parser.add_argument("--message", "-m", help="Message text")
|
||||
parser.add_argument("--amount", help="Expense amount")
|
||||
parser.add_argument("--category", help="Expense category")
|
||||
parser.add_argument("--task", help="Task name")
|
||||
parser.add_argument("--priority", default="Medium", help="Task priority")
|
||||
parser.add_argument("--webhook", help="n8n webhook ID")
|
||||
parser.add_argument("--list", "-l", action="store_true", help="List available integrations")
|
||||
parser.add_argument("--qr", "-q", action="store_true", help="Generate QR code")
|
||||
parser.add_argument("--output", "-o", help="Output file for QR code")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list:
|
||||
list_integrations()
|
||||
return
|
||||
|
||||
url = None
|
||||
|
||||
if args.action == "send-telegram":
|
||||
if not args.message:
|
||||
print("❌ --message required for send-telegram")
|
||||
return
|
||||
url = create_send_to_openclaw_url(args.message)
|
||||
print(f"📱 URL Scheme created:")
|
||||
print(f" {url}")
|
||||
print(f"\n Use in Shortcuts with 'Open URL' action")
|
||||
|
||||
elif args.action == "trigger-morning-briefing":
|
||||
url = f"{BASE_URL}?start=morning_briefing_now"
|
||||
print(f"📱 Morning Briefing trigger:")
|
||||
print(f" {url}")
|
||||
|
||||
elif args.action == "log-expense":
|
||||
if not args.amount or not args.category:
|
||||
print("❌ --amount and --category required for log-expense")
|
||||
return
|
||||
url = create_url_scheme("expense", amount=args.amount, category=args.category)
|
||||
print(f"📱 Expense logger URL:")
|
||||
print(f" {url}")
|
||||
|
||||
elif args.action == "add-task":
|
||||
if not args.task:
|
||||
print("❌ --task required for add-task")
|
||||
return
|
||||
url = create_url_scheme("task", name=args.task.replace(" ", "_"), priority=args.priority)
|
||||
print(f"📱 Task adder URL:")
|
||||
print(f" {url}")
|
||||
|
||||
elif args.action == "trigger-n8n":
|
||||
if not args.webhook:
|
||||
print("❌ --webhook required for trigger-n8n")
|
||||
return
|
||||
url = generate_n8n_webhook_url(args.webhook)
|
||||
print(f"📱 n8n Webhook URL:")
|
||||
print(f" {url}")
|
||||
|
||||
elif args.action == "run-shortcut":
|
||||
if not args.message:
|
||||
print("❌ --message (shortcut name) required")
|
||||
return
|
||||
url = create_shortcut_url(args.message)
|
||||
print(f"📱 Run Shortcut URL:")
|
||||
print(f" {url}")
|
||||
|
||||
else:
|
||||
print("❌ Unknown action. Use --list to see available options.")
|
||||
list_integrations()
|
||||
return
|
||||
|
||||
# Generate QR code if requested
|
||||
if args.qr and url:
|
||||
generate_qr_code(url, args.output)
|
||||
|
||||
# Copy to clipboard hint
|
||||
print(f"\n💡 Tip: This URL can be used in Shortcuts 'Open URLs' action")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user