8 votes

Comment démarrer une application lorsqu'un disque spécifique est monté ?

Je stocke toute ma musique sur un disque externe. J'ai configuré iTunes pour qu'il démarre lorsque je me connecte. Cependant, iTunes démarre toujours avant que mon disque crypté ne soit monté, et iTunes se plaint alors de ne pas pouvoir trouver sa bibliothèque.

J'ai essayé d'écrire un Applescript qui vérifie de manière répétée si un disque est monté, et lorsqu'il l'est, lance iTunes.

tell application "System Events" to set diskNames to name of every disk
set iTunesDiskName to "Media"
set iTunesDiskIsMounted to false
set iTunesLaunched to false
if iTunesDiskName is in diskNames then set iTunesDiskIsMounted to true

repeat while iTunesLaunched is false
    if iTunesDiskIsMounted is true then
        tell application "iTunes" to launch
        set iTunesLaunched to true
    end if
    delay 5
end repeat

Cela fonctionne pour lancer iTunes si je l'exécute avec le disque monté. Cependant, si je l'exécute avec le disque démonté, il continue à fonctionner et ne détecte jamais si le disque est ensuite monté.

Qu'est-ce que je fais de mal ?

6voto

moodforaday Points 2633

Je n'ai pas voté contre. wch1zpink's réponse, mais c'est vraiment no la façon dont je résoudrais le problème.

Faire en sorte qu'une application exécute un AppleScript toutes les 5 secondes est une manière très inefficace de gérer cette situation, d'autant plus que Mac OS dispose déjà d'une fonction intégrée pour faire cela, à savoir launchd.

Enregistrer sous ~/Library/LaunchAgents/com.tjluoma.itunes-on-mount.plist (vous pouvez changer la partie "com.tjluoma.itunes-on-mount" par ce que vous voulez) :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.tjluoma.itunes-on-mount</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>test -d /Volumes/Media &amp;&amp; open -j -g -a iTunes</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>WatchPaths</key>
    <array>
        <string>/Volumes</string>
    </array>
</dict>
</plist>

Ensuite, redémarrez votre Mac ou faites

launchctl load ~/Library/LaunchAgents/com.tjluoma.itunes-on-mount.plist

dans le terminal. Ensuite, à chaque fois que /Volumes/ change, launchd cherchera à savoir si /Volumes/Media existe, et si c'est le cas, il lancera iTunes.

3voto

OnePablo Points 1

Une application "stay-open" (sondage)

Bien que cette question ait déjà été marquée comme ayant une solution satisfaisante, je suis obligé de fournir une alternative. Je suis tout à fait d'accord avec @TJ Luoma qui a fourni ce que je crois être, de loin, la solution optimale, en notant qu'une Restez ouvert application qui sondages pour les noms de disques toutes les 5 secondes et qui doit faire appel à une application externe pour ce faire, est no la façon d'aborder ce problème. Il est inefficace, gourmand en ressources et très lourd d'avoir une applet qui vit en permanence dans le dock, ou même juste invisiblement en arrière-plan, et qui n'exécute qu'une seule fonction de façon épouvantable, alors que MacOS dispose de moyens intégrés pour surveiller les événements du système de fichiers, et d'un gestionnaire de services pour répondre à ces événements et exécuter des tâches de façon planifiée et efficace.

launchd

La méthode de TJ Luoma tire profit de launchd pour résoudre le problème de la manière recommandée, pour autant que je sache. Il surveille les changements dans le /Volumes folderpath, et agit en conséquence. C'est la méthode que je choisirais, sachant que je n'ai pas à me soucier de ce qui se passe en coulisses.

Actions des dossiers

Certains ne savent peut-être pas que l'option de MacOS Actions des dossiers peut également surveiller le /Volumes et si AppleScript se sent plus à l'aise pour quelqu'un qu'une .plist et un shell script, alors cette solution peut être plus attrayante. Pour autant que je sache, les actions sur les dossiers s'exécutent en tant que processus sous le nom de launchd Ainsi, bien qu'ils fonctionnent de manière ouvertement différente pour l'utilisateur, les mécanismes sous-jacents sont probablement les mêmes, ou similaires, et il est peu probable que l'on constate des différences de performances entre les deux.

Mise en œuvre

La mise en place est très facile, même si vous ne l'avez jamais fait auparavant. Elle se fait en deux étapes :

  1. Enregistrez l'AppleScript suivant, en lui donnant le nom que vous voulez et en l'enregistrant dans le répertoire Dossier Action scripts situé à l'adresse ~/Library/Scripts/Folder Action Scripts . J'ai sauvegardé le mien comme un simple .applescript fichier texte en utilisant scriptÉditeur et l'a nommé New Volume Mounted.applescript :

    property diskName : "Media" -- whatever the disk is named
    property _objRef : a reference to reference
    
    script disks
        property path : missing value
        property kind : "public.volume"
        property list : missing value
    
        on _get(mountPoints)
            local mountPoints
    
            set my list to mountPoints
    
            tell application id "com.apple.systemevents" to ¬
                repeat with fURL in (a reference to my list)
                    if fURL's type identifier = my kind ¬
                        then set fURL's contents to ¬
                        the disk named fURL
                end repeat
    
            return every reference in my list
        end _get
    
        on _eval(key)
            if my list = missing value then return
    
            tell application id "com.apple.systemevents"
                tell {}
                    repeat with _disk in (a reference to my list)
                        set _objRef to _disk
                        set the end to contents of the key
                    end repeat
    
                    return it
                end tell
            end tell
        end _eval
    end script
    
    on adding folder items to mountedVolumes after receiving mountPoints
        local mountedVolumes, mountPoints
    
        disks's _get(mountPoints)
    
        set propertyKey to a reference to the name of my _objRef
        set disknames to disks's _eval(propertyKey)
    
        if the diskname is in the disknames then exec()
    end adding folder items to
    
    on removing folder items from mountedVolumes after losing diskNames
        local mountedVolumes, diskNames
    
        -- display alert "Disk removed: " & diskNames
    end removing folder items from
    
    on exec()
        -- display alert "Disk attached"
        run application id "com.apple.iTunes"
    end exec
  2. Il existe une méthode conventionnelle pour jumeler une action de dossier script avec un dossier surveillé, mais de loin la plus simple. † est de copier et coller le script ci-dessous dans scriptÉditeur et, si nécessaire, modifiez la troisième ligne qui déclare property script . Il doit porter le même nom (avec l'extension de fichier) que votre script ci-dessus. Si vous avez choisi le même nom que moi dans la première étape, vous n'avez pas besoin de faire d'ajustements. Exécutez simplement le script et tout sera mis en place, prenant effet immédiatement. Il n'est pas nécessaire de sauvegarder ce script, ni de redémarrer l'ordinateur.

    use sys : application id "com.apple.systemevents"
    
    property path : "/Volumes"
    property script : "New Volume Mounted.applescript"
    
    property name : a reference to the name of folder path
    property folder action : a reference to folder action named (my name)
    property folder : a reference to Folder Action scripts folder
    property file : a reference to the file named (my script) in my folder
    
    set folder actions enabled to true
    
    if not (my file exists) then return open my folder
    
    tell my folder action
        if (exists) then return its scripts
    
        make new folder action with properties my {name:name, path:path}
        make new script with properties my file's ¬
            {name:name, POSIX path:POSIX path}
    
        set [its enabled, its scripts's enabled] to [true, true]
    end tell

    Ce script n'a été testé que dans High Sierra

Post-scriptum

Le script de l'étape 1 ci-dessus est celui que j'ai écrit il y a quelque temps comme un script généralisé que ceux qui sont à l'aise avec AppleScript pourraient facilement adapter et étendre pour effectuer toutes les tâches que l'on souhaite, et ont déjà à disposition une liste de tous les nouveaux points de montage créés en /Volumes sous la forme d'une liste validée de disk objets.

Cependant, c'est en fait plus que ce qui est nécessaire pour cette tâche à accomplir. Vous pouvez vous y tenir, et cela devrait fonctionner parfaitement. Mais, si vous préférez un script plus simple, alors celui ci-dessous exécute exactement la même fonction que celui ci-dessus, mais avec tout le gras en moins :

property diskName : "Media" -- whatever the disk is named
property path : "/Volumes"
property diskVolumePath : [path, "/", diskName, "/"] as text

on adding folder items to mountedVolumes after receiving mountPaths
    local mountedVolumes, mountPoints

    repeat with mountPath in mountPaths
        set mountPath's contents to ¬
            mountPath's POSIX path
    end repeat

    if the mountPaths contains the diskVolumePath then exec()
end adding folder items to

on removing folder items from mountedVolumes after losing diskNames
    local mountedVolumes, diskNames

    -- display alert "Disk removed: " & diskNames
end removing folder items from

on exec()
    -- display alert "Disk attached"
    run application id "com.apple.iTunes"
end exec

3voto

OnePablo Points 1

Il s'agit d'un suivi de La réponse de TJ Luoma qui, je l'espère, résoudra les problèmes liés à l'utilisation de la fonction .plist qui empêche le travail d'être exécuté de manière correcte.

De man launchd.plist :

**WatchPaths** <array of strings>

Cette clé facultative permet de lancer le travail si l'une des conditions suivantes est remplie sont modifiés.

IMPORTANT : L'utilisation de cette clé est fortement déconseillée car la surveillance des du système de fichiers est très sensible à la concurrence, et il est tout à fait possible que des modifications soient manquées. Lorsque des modifications sont détectées, il n'y a aucune garantie que le fichier sera dans un état cohérent lorsque le travail sera lancé.

**StartOnMount** <boolean>

Cette clé optionnelle fait en sorte que le job soit lancé chaque fois qu'un système de fichier est monté.

Voici une version révisée .plist définition de l'incorporation StartOnMount en faveur de WatchPaths . Il est actuellement étiqueté "local.startOnMount.iTunes" qui, s'il est inchangé, signifie que le fichier doit être enregistré à l'adresse suivante ~/Library/LaunchAgents/local.StartOnMount.iTunes.plist :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>local.StartOnMount.iTunes</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/osascript</string>
        <string>-e</string>
        <string>if (list disks) contains "Media" then ¬
                run application id "com.apple.iTunes"</string>
    </array>
    <key>RunAtLoad</key>
    <false/>
    <key>StandardErrorPath</key>
    <string>/tmp/local.StartOnMount.iTunes.stderr</string>
    <key>StandardOutPath</key>
    <string>/tmp/local.StartOnMount.iTunes.stdout</string>
    <key>StartOnMount</key>
    <true/>
</dict>
</plist>

Le site ProgramArguments peut aussi être plus proche de la clé originale de TJ. bash commandement :

<key>ProgramArguments</key>
<array>
    <string>/bin/bash</string>
    <string>-c</string>
    <string>[[ -d "/Volumes/Media" ]] &amp;&amp; open -jg -b "com.apple.iTunes"</string>
</array>

Cependant, en testant, j'ai constaté que si iTunes est déjà en cours d'exécution et est caché, alors l'appel de la fonction open même avec la commande -j et/ou -g option(s)-marques iTunes au premier plan. J'ai donc décidé d'utiliser osascript pour effectuer les mêmes actions, mais de manière plus cohérente.

Cette nouvelle .plist semble résoudre les problèmes, et ne lance le travail que lorsqu'un système de fichiers est monté, qui à son tour n'exécute une action que s'il s'agit du bon nom de disque. A remplacer :

cd ~/Library/LaunchAgents
launchctl unload com.tjluoma.itunes-on-mount.plist
launchctl load local.StartOnMount.iTunes.plist

Toutefois, si un élément ne fonctionne pas comme prévu, et que la raison n'est pas évidente, regardez dans l'onglet /tmp/ pour le(s) fichier(s) nommé(s) local.StartOnMount.iTunes.stderr et/ou local.StartOnMount.iTunes.stdout :

cat local.StartOnMount.iTunes.stderr

EDIT : Post Catalina Bonus
Ajouté par @dunxd le 2021-03-18

Apple a divisé iTunes en applications distinctes (Musique, TV et Podcasts) avec le lancement de Catalina. Il est possible d'ajuster le script ci-dessus pour lancer Musique et TV en une seule fois en ajoutant des chaînes supplémentaires au tableau ProgramArguments comme suit :

<key>ProgramArguments</key>
<array>
    <string>/usr/bin/osascript</string>
    <string>-e</string>
    <string>if (list disks) contains "Media" then run application id "com.apple.music"</string>
    <string>-e</string>
    <string>if (list disks) contains "Media" then run application id "com.apple.TV"</string>
</array>

EDIT : Affinement de "Post Catalina Bonus".
Ajouté par @CJK le 2021-04-17

<key>ProgramArguments</key>
<array>
    <string>/usr/bin/osascript</string>
    <string>-e</string>
    <string>
        if (list disks) does not contain "Media" then return
        run application id "com.apple.music"
        run application id "com.apple.TV"
    </string>
</array>

1voto

wch1zpink Points 6067

Enregistrez le code AppleScript suivant comme une application "stay open" dans script Editor.app. Désactivez le démarrage d'iTunes à la connexion mais activez votre nouvelle application "stay open" pour qu'elle démarre à la connexion.

Veillez à accorder les autorisations appropriées dans les Préférences Système pour que votre nouvelle applet puisse contrôler votre ordinateur.

on run
    --  Executed when the script is launched
    checkForMedia()
end run

on idle
    -- checks every five seconds if diskNames contains "Media"
    checkForMedia()
    return 5 -- in seconds
end idle

on checkForMedia()
    tell application "System Events" to set diskNames to name of every disk
    if diskNames contains "Media" then
        tell application "iTunes" to launch
        quit me -- Quits this applet after diskNames contains "Media" and launches itunes
    end if
end checkForMedia

on quit
    continue quit -- allows the script to quit
end quit

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X