Cómo compartir scripts de AppleScript con ficheros de sonido, texto y demás usando paquetes de scripts

Ya hemos visto cómo crear scripts y aplicaciones a partir de nuestros scripts para realizar y automatizar tareas y, por ahora, podemos compartirlos con otros usuarios sin demasiados problemas ya que siempre hemos accedido a elementos del sistema. Pero imaginemos que queremos crear un script con sus propios sonidos, ficheros de texto o ficheros de recursos y que siga ejecutándose sin problemas en nuestro Mac y el de nuestros amigos. En este artículo veremos cómo hacerlo.

Usar un paquete de scripts en lugar de un script de AppleScript

El editor de AppleScript nos permite guardar nuestro script de diversas formas, por ejemplo como script, como aplicación, como texto o como un paquete de scripts.

Un paquete de scripts es el formato idóneo para compartir nuestros scripts con amigos ya que es un formato que consiste en un conjunto de ficheros cuyo fichero principal es un archivo de script que se ejecutará al abrirlo con Finder.

En este paquete de scripts podemos incluir casi cualquier tipo de archivo que necesitemos para que nuestro script funcione perfectamente.

Creando un paquete de scripts

Para crear un paquete de scripts simplemente debemos crear un nuevo script de AppleScript desde la herramienta editor de AppleScripts y a la hora de guardarlo especificar que lo guardaremos con el formato paquete de scripts

En el editor de AppleScript se mostrará el código fuente de nuestro script como si se tratase de un script normal en lugar de un paquete de scripts.

La única diferencia es que la opción mostrar contenido del paquete del menú Visualización del editor de scripts estará disponible.

Al activar la opción mostrar contenido del paquete se nos mostrará información de nuestro paquete y una tabla con los ficheros que se incluyen dentro del paquete.

Por defecto en todos los paquetes se incluye el fichero description.rtfd y la carpeta Scripts y debemos evitar modificar estos dos elementos para mantener la estabilidad de nuestro paquete.

Añadiendo ficheros a nuestro paquete

Para agregar nuevos ficheros dentro de nuestro paquete sólo debemos arrastrar los nuevos ficheros hasta soltarlos dentro de la tabla con los ficheros de nuestro paquete. Por desgracia esta operación de arrastrar y soltar no es sencilla para los usuarios de producto de apoyo pero no es demasiado problema gracias a MacOS y su filosofía de multitud de alternativas y a la potencia de Finder.

Añadiendo ficheros a nuestro paquete a través de Finder

Podemos agregar los nuevos ficheros simplemente abriendo el contenido de nuestro paquete en Finder y tratándolo como una carpeta más en la que podemos pegar y duplicar ficheros así como cambiar sus nombres o crear carpetas.

Para hacer esto simplemente nos debemos colocar en el primer elemento de la tabla, que suele ser el fichero description.rtfd y utilizando el menú contextual activar la opción Mostrar en el Finder

Para activar el menú contextual debemos hacer una pulsación con el botón derecho del ratón o, si usamos VoiceOver, pulsar la combinación de teclas Mayúsculas + Control + Option + M

Al activar la opción Mostrar en el Finder se abrirá una carpeta en el Finder en la que podremos pegar o renombrar los archivos para nuestro paquete. Cualquier cambio que hagamos se verá reflejado en el editor de scripts

Accediendo a nuestros recursos desde nuestros scripts

Para acceder a uno de nuestros ficheros almacenados en el paquete debemos hacer referencia a él usando una referencia relativa a su ruta y a la del paquete almacenándo la ruta en una variable. Por ejemplo, imaginemos que hemos incluido el sonido prueba.caf en nuestro paquete y queremos almacenar su ruta en la variable misonido. El código sería:


set miSonido to POSIX path of (path to resource "prueba.caf")

Y para reproducir el sonido debemos crear el comando de terminal que solemos utilizar para reproducir sonidos con AppleScript incluyendo la ruta a nuestro fichero de audio. El script completo quedaría así:


on run
set miSonido to POSIX path of (path to resource "prueba.caf")
do shell script "afplay " & quoted form of miSonido
end run

Si el fichero a ejecutar no está en nuestro paquete aparecerá el mensaje de error Recurso no encontrado.

Ejecutar comandos de terminal desde AppleScript con permisos de administrador

En artículos anteriores hemos visto cómo ejecutar comandos del terminal desde un script de AppleScript gracias al comando do shell script. Pero puede que necesitemos ejecutar un comando de terminal con permisos de administrador.

Desde AppleScript podemos usar el comando do shell script indicando que se requiere la contrase&ntidle;a de administrador para ejecutar el programa. Esto lo podemos hacer incluyendo en la llamada do shell script los atributos with administrator privileges para indicar que el comando a ejecutar requiere la contraseña de administrador.

Su sintaxis es la siguiente:


do shell script "sudo comando a ejecutar" with administrator privileges

Hacer el mantenimiento de nuestro Mac gracias a AppleScript

Como ejemplo para este artículo vamos a crear un simple script que ejecute los scripts de mantenimiento diario, semanal y mensual para nuestro Mac.

El comando de terminal a ejecutar es:


periodic daily weekly monthly

Este comando se debe ejecutar con permisos de administrador por lo que es un candidato idóneo para nuestro ejemplo.

Nuestro script quedaría así:


on run
try
do shell script "sudo periodic daily weekly monthly" with administrator privileges
do shell script "afplay /System/Library/Sounds/Glass.aiff"
display alert "Proceso de mantenimiento realizado."
on error
do shell script "afplay /System/Library/Sounds/Basso.aiff"
display alert "Error al intentar inicializar el mantenimiento de este Mac."
end try
end run

Abrir una dirección web con Safari desde AppleScript

Ya hemos visto cómo comunicarnos con aplicaciones usando AppleScripts y diccionarios. En este artículo veremos cómo activar la ventana del navegador web Safari y abrir una dirección web.

El código sería el siguiente:


tell application "Safari"
activate
set URL of document 1 to "http://www.tyflosaccessiblesoftware.com"
end tell

Habría que sustituir el texto http://www.tyflosaccessiblesoftware.com por la dirección web que queramos o convertir este script en una función para nuestra librería. Por ejemplo:


on openWeb(direccionWeb)
tell application "Safari"
activate
set URL of document 1 to direccionWeb
end tell
end openWeb

Operaciones básicas con Aplicaciones MacOS y diccionarios de AppleScript

Ya hemos visto que muchas de las aplicaciones para MacOS incluyen diccionarios para AppleScript para realizar operaciones específicas con cada aplicación pero existen comandos y propiedades comunes para todas las aplicaciones.

En este artículo veremos algunas funciones comunes para todas las aplicaciones de MacOS que incluyan diccionario.

Pero antes de empezar debemos aprender a comunicarnos con las aplicaciones. Esta operación de comunicarnos con una aplicación se realiza mediante el bloque tell. Su sintaxis es sencilla.


tell "Nombre de aplicación entre comillas"
-- lista de operaciones
end tell

Cuando decimos comunicarnos con una aplicación nos referimos tanto a enviar órdenes a la aplicación como a consultar propiedades y variables que posee la aplicación o utilizar objetos y elementos de operación que la aplicación ofrece para ser utilizados con AppleScript.

Abrir la ventana de la aplicación

El comando activate abre la aplicación con la que nos estemos comunicando y si ya estaba abierta pasa su ventana a primer plano.


tell application "TextEdit"
activate
end tell

Cerrar una aplicación

Con el comando quit podemos cerrar la aplicación que queramos.


tell application "Mail"
quit
end tell

Diccionarios en AppleScript

Ya hemos visto en artículos anteriores que AppleScript nos permite realizar ciertas operaciones sobre el sistema operativo y, en algunas ocasiones, también podemos utilizar o manipular algunas aplicaciones a través de AppleScript. Esto se consigue gracias a los diccionarios de AppleScript.

Los diccionarios de AppleScript son manuales que indican al motor de AppleScript cómo poder interactuar con una aplicación utilizando AppleScript.

Estos diccionarios son creados por los propios desarrolladores de las aplicaciones para MacOS X. Las aplicaciones más comunes y todas las de Apple para MacOS X poseen sus diccionarios.

Para ver qué diccionarios tenemos disponible en nuestro equipo debemos abrir la aplicación del Editor de scripts y en el menú Archivo encontraremos la opción Abrir diccionario.

Al pulsar esa opción se nos abrirá un cuadro de diálogo que nos permite abrir un diccionario para consultar su documentación para poder escribir nuestro script de AppleScript.

En esa lista encontraremos aplicaciones ya conocidas como Automator, Finder, Pages, Keynote, Microsoft Word, xCode, System events o Safari.

Todos los diccionarios suelen estar escritos en inglés ya que es el idioma oficial para AppleScript.

Explorando un diccionario

Al abrir un diccionario nos encontraremos una barra de herramientas, una zona de selección de categorías (identificada por VoiceOver como Explorador) y una zona de lectura (identificada por VoiceOver como Contenido web).

En el explorador se encuentran las suites de comandos y los tipos y elementos disponibles. en el contenido web se puede leer la documentación del diccionario o del elemento seleccionado en el Explorador.

En la barra de herramientas encontraremos elementos para buscar términos, cambiar el tamaño de letra, cambiar el lenguaje de programación para consultar el diccionario o cambiar el modo de visualización del explorador.

Un pequeño ejemplo con Finder

El Finder es una de las aplicaciones más poderosas de MacOS X y su diccionario es muy interesante. Buscando entre sus comandos y propiedades podemos crear sin demasiada complicación un script que nos permita expulsar todas las unidades y memorias USB que estén conectadas a nuestro ordenador en ese momento. El código sería algo así:


tell application "Finder"
eject (disks whose ejectable is true)
end tell

Mejorando el ejercicio

Aunque el script anterior puede ser muy útil es mejor que el usuario pueda seleccionar qué unidad expulsar. Con los conocimientos que ya hemos visto en artículos anteriores podemos hacer ese script.

A continuación veremos un código inicial no terminado para dar pistas de cómo se podría hacer ese script.


tell application "Finder"
set unidades to (disks whose ejectable is true) as text
choose from list unidades with title "Expulsar una unidad" with prompt "Selecciona la unidad que quieras expulsar" OK button name "Expulsar"
end tell

Puedes compartir tu propuesta de solución con otros lectores en los comentarios de este artículo.

Juega a adivinar el número con AppleScript

Con los conocimientos que ya tenemos en AppleScript podemos empezar a hacer aplicaciones más complejas como puede ser un simple juego de adivinar un número.

Nuestro script debe realizar las siguientes operaciones:

  • Guardar un número aleatorio entre 1 y 100 que hay que adivinar
  • Preguntar al usuario por un número entre 1 y 100
  • Comprobar que lo introducido por el usuario es correcto
  • Ver si el número del usuario es igual, mayor o menor que el número que hay que adivinar
  • Si el número es menor o mayor hay que dar un mensaje y seguir jugando
  • Si se ha acertado el número se da un mensaje y se termina el juego

El código propuesto a continuación usa funciones, manejo de errores, estructuras condicionales, variables globales, cuadros de diálogo y generación de números aleatorios. Todo esto ya lo hemos visto en artículos anteriores.

El código es el siguiente:


global numeroPensado
set numeroPensado to 0
juego()

on juego()
if numeroPensado = 0 then
set numeroPensado to random number from 1 to 10
end if
set dialogResult to display dialog "?Qué número he pensado?" default answer ""
try
set miNumero to the text returned of (dialogResult) as number
on error
set miNumero to 0
display alert "Debes introducir un número entre 1 y 100"
juego()
end try
if miNumero ≥ 1 and miNumero ≤ 100 then
if miNumero = numeroPensado then
display alert "¡Muy bien! Has acertado el número que he pensado"
else if miNumero < numeroPensado then display alert "El número que he pensado es mayor que " & (miNumero as text) juego() else if miNumero > numeroPensado then
display alert "El número que he pensado es menor que " & (miNumero as text)
juego()
end if
else
display alert "Debes introducir un número entre 1 y 100"
juego()
end if
end juego

Propuesta de mejora

El código de este pequeño juego es simple pero se puede mejorar de muchas maneras. Aquí se indican algunas mejoras que se podrían hacer por parte de los lectores:

  • Controlar que sólo se tengan 5 oportunidades para adivinar el número
  • Reproducir sonidos cuando se acierte y se falle
  • Hacer el juego inverso en el que el usuario piensa el número y el ordenador va preguntando por el número y el usuario responde si es mayor, menor o se ha acertado

Podéis enviarnos vuestras propuestas en los comentarios a este artículo.

Mejorando nuestra salud gracias a AppleScript

Es conocido que la empresa Apple está incluyendo en todos sus dispositivos móviles elementos y características para mejorar la salud de sus clientes. En el Apple watch, por ejemplo, existe una característica que nos invita a levantarnos de la silla cada hora para que mejoremos nuestra salud y adoptemos hábitos saludables.

En MacOS todavía no se ha incluido ninguna de estas características pero gracias a AppleScript podemos crear nuestras propias soluciones.

Descripción de la solución

Queremos crear con AppleScript una aplicación que cada hora nos muestre un aviso para que nos levantemos de nuestro sitio durante al menos un minuto.

Con lo que hemos aprendido en artículos anteriores esto no es demasiado complicado.

Debemos aprovechar el evento idle para crear una aplicación con AppleScript que se ejecute automáticamente cada 60 segundos y compruebe la hora. Si el valor de los minutos del reloj es igual a 50 entonces mostramos nuestro aviso.

El código podría ser algo como lo siguiente:


on mostrarAviso()
display alert "Levántate durante un minuto"
end mostrarAviso

on idle
set currentDate to current date
set minutos to (currentDate's minutes)
if minutos = 50 then
mostrarAviso()
end if
return 60
end idle

Recuerda exportar el script como aplicación como se indicó en el artículo Eventos de ejecución en aplicaciones creadas con AppleScript para que el evento idle funcione de forma apropiada.

Propuestas de mejora

El script es sencillo y funciona pero se puede mejorar de muchas formas. A continuación se indican algunas posibles mejoras que puedes incluir investigando un poco con AppleScript:

  • Reproducir un sonido de campana para que el usuario no se confunda con otra notificación
  • En lugar de mostrar una alerta ejecutemos el salvapantallas de MacOS para obligar al usuario a dejar de trabajar
  • Contabilizar cuántas horas se ha mostrado el aviso para dejar de hacerlo tras 12 horas como sucede en el Apple Watch
  • Mostrar una alerta personalizada indicando cuántas horas nos quedan por levantarnos para motivar más al usuario

Todas estas propuestas se pueden realizar con lo que ya hemos ido aprendiendo en los artículos publicados sobre AppleScript e investigando un poco.

Controlar errores de ejecución en AppleScript

A la hora de diseñar y codificar nuestros scripts de AppleScript debemos tener en cuenta que se pueden producir errores y debemos controlar lo que sucede cuando aparecen estos errores.

Por defecto en AppleScript cuando sucede un error se para la ejecución del script y, a veces, se da un mensaje de error.

Veamos un ejemplo intentando verbalizar un mensaje con una voz no instalada en el sistema:


say "Hola a todos!" using "Manolo"

Al intentar ejecutar ese código obtendremos el mensaje de error No se ha encontrado la voz.. Debemos controlar esto para que nuestro script siga funcionando perfectamente.

Bloques seguros con try

AppleScript nos permite ejecutar un bloque de código de forma segura utilizando el bloque try. Permitiendo que se ejecute el código pero si aparece un error no se parará la ejecución de nuestro script.

El bloque try utiliza la siguiente sintaxis:


try
-- código a ejecutar de forma segura
end try

Volviendo a nuestro ejemplo anterior ahora podemos evitar que se de el mensaje de error utilizando el bloque try. El código quedaría así:


try
say "Hola a todos!" using "Manolo"
end try

Reaccionando a los errores

A veces nos interesa reaccionar ante la aparición de un error. Por ejemplo, si la voz Manolo no existe, aunque usemos el bloque try tendremos un problema en nuestro script ya que el mensaje nunca llegaá al usuario ya que el mensaje no se verbalizará. La solución pasa por reaccionar al error verbalizando el mensaje de todas formas con cualquier voz que esté disponible. Para ello el bloque try posee la cláusula on error que nos permite definir un sub bloque de código dentro del bloque try que se ejecutará sólo si se produce un error. Su sintaxis es la siguiente:


try
-- Código a ejecutar
on error
-- Código a ejecutar si se produce un error
end try

El código de nuestro ejemplo quedaría así:


try
say "Hola a todos!" using "Manolo"
on error
say "Hola a todos!"
end try

Creando nuestra función

El código necesario para verbalizar un mensaje con una voz en específico de forma segura es candidato a convertirse en una de nuestras funciones habituales. El código podría ser algo como lo siguiente:


on sayWithVoice(texto, nombreDeVoz)
try
say texto using nombreDeVoz
on error
say texto
end try
end sayWithVoice

Para probar nuestra función simplemente debemos llamarla de la siguiente forma:


sayWithVoice("Hola a todos, soy Mónica", "Monica")

Cómo usar la voz de VoiceOver con AppleScript para nuestros scriptss

Otra función muy útil para aquellos usuarios de VoiceOver es la de poder utilizar la voz de VoiceOver para dar mensajes.

Con esta función podremos utilizar la voz por defecto de VoiceOver para verbalizar un mensaje pero si VoiceOver no está disponible utilizará la voz del sistema.


on sayWithVoiceOver( textToSay )
try
tell application "VoiceOver"
output textToSay
end tell
on error
say textToSay
end try
end sayWithVoiceOver

Cómo saber si VoiceOver puede ser controlado con AppleScript desde un script de AppleScript

Una función muy necesaria para los scripts de AppleScript destinados a funcionar con VoiceOver, el lector de pantallas de Apple para sus productos, es saber si VoiceOver para MacOS tiene habilitada la opción de poder ser controlado por AppleScript ya que esto nos permitirá manipular el comportamiento de VoiceOver desde nuestros scripts de AppleScript.

Para ello lo que hacemos es comunicarnos con la aplicación VoiceOver y probamos a llamar a alguna de sus funciones internas.

El código de nuestra función sería el siguiente:


on isVoiceOverRunningWithAppleScript()
set isRunning to true
-- is AppleScript enabled on VoiceOver --
tell application "VoiceOver"
try
set x to bounds of vo cursor
on error
set isRunning to false
end try
end tell
return isRunning
end isVoiceOverRunningWithAppleScript