2

我写了一个AppleScript来挂载图像,我希望它在启动SparseBundle时准确执行。Time Machine

现在,我会定期检查 Time Machine 是否使用AppleScriptusingon idle语句运行:

on idle
    ....
    return <interval>
end idle

这不是一种稳健的方式。在我看来,为事件添加事件触发器Application Launch将是一种更好的方法。

能否请你帮忙?

一个Objective-CPython示例代码(我更喜欢Python)非常受欢迎。

4

3 回答 3

6

您正在寻找的是NSDistributedNotificationCenterNSWorkspace,这些可可类发布应用程序事件的通知,对于工作区,例如应用程序启动、驱动器安装等。

要在 python 中执行此操作,您需要PyObjC,它基本上是苹果可可类的 python 绑定。他们网站上的文档很少,这是有原因的,因为文档与 Apple 文档基本相同,因此它们仅包括 pyobjc api 和 cocoa API 之间的差异。如果您了解如何将目标 c api 转换为 python,那么您就可以开始了。在这里查看:http: //pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html

我在下面包含了一个示例,它使用 python 侦听分布式通知。下面的代码基本上添加了一个观察者并监听 iTunes 通知。您可以遵循类似的结构,但改为为 NSWorkspace 添加一个观察者。为了弄清楚你应该听什么,有一个应用程序可以显示通过你的系统的所有通知。它被称为通知观察者。用它来确定你应该听什么。您还可以将目标 c 代码转换为 python。

下面的代码在做什么

  1. 定义一个继承自 NSObject 的新类,由 PyObjC 定义
  2. 定义一个方法,该方法通过实际的通知并打印出来
  3. 创建 Foundation.NSDistributedNotificationCenter.defaultCenter 的实例
  4. 创建 GetSongs 的实例
  5. 注册一个观察者,向其传递类、收到通知时调用的方法以及要监视的应用程序和事件,即“com.apple.iTunes.playerInfo”
  6. 运行事件循环,

一件事会让您感到困惑,访问属性(目标 c 属性)与访问 python 属性的工作方式不同。即在python中,你在python中class_name.att为objective c做你必须像函数一样调用它,即在下面的示例中:song.userInfo()

import Foundation
from AppKit import *
from PyObjCTools import AppHelper

class GetSongs(NSObject):
    def getMySongs_(self, song):
        print "song:", song
        song_details = {}
        ui = song.userInfo()
        print 'ui:', ui
        for x in ui:
            song_details[x] = ui.objectForKey_(x)
        print song_details

nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
GetSongs = GetSongs.new()
nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)

NSLog("Listening for new tunes....")
AppHelper.runConsoleEventLoop()

这是实际输出的示例......(是 BRITNEY ROCKS!,不是!;)

song NSConcreteNotification 0x104c0a3b0 {name = com.apple.iTunes.playerInfo; object = com.apple.iTunes.player; userInfo = {
    Album = Circus;
    "Album Rating" = 0;
    "Album Rating Computed" = 1;
    Artist = "Britney Spears";
    "Artwork Count" = 1;
    Genre = Pop;
    "Library PersistentID" = 8361352612761174229;
    Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
    Name = Circus;
    PersistentID = 4028778662306031905;
    "Play Count" = 0;
    "Play Date" = "2010-06-26 08:20:57 +0200";
    "Player State" = Playing;
    "Playlist PersistentID" = 7784218291109903761;
    "Rating Computed" = 1;
    "Skip Count" = 1;
    "Skip Date" = "2010-06-26 12:20:57 +0200";
    "Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
    "Total Time" = 192444;
    "Track Count" = 16;
    "Track Number" = 2;
}}
ui {
    Album = Circus;
    "Album Rating" = 0;
    "Album Rating Computed" = 1;
    Artist = "Britney Spears";
    "Artwork Count" = 1;
    Genre = Pop;
    "Library PersistentID" = 8361352612761174229;
    Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
    Name = Circus;
    PersistentID = 4028778662306031905;
    "Play Count" = 0;
    "Play Date" = "2010-06-26 08:20:57 +0200";
    "Player State" = Playing;
    "Playlist PersistentID" = 7784218291109903761;
    "Rating Computed" = 1;
    "Skip Count" = 1;
    "Skip Date" = "2010-06-26 12:20:57 +0200";
    "Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
    "Total Time" = 192444;
    "Track Count" = 16;
    "Track Number" = 2;
}
{u'Album Rating Computed': 1, u'Album': u'Circus', u'Rating Computed': True, u'Name': u'Circus', u'Artist': u'Britney Spears', u'Track Number': 2, u'Skip Date': 2010-06-26 12:20:57 +0200, u'Library PersistentID': 8361352612761174229L, u'Player State': u'Playing', u'Total Time': 192444L, u'Genre': u'Pop', u'Playlist PersistentID': 7784218291109903761L, u'Album Rating': 0, u'Location': u'file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3', u'Skip Count': 1, u'Track Count': 16L, u'Artwork Count': 1, u'Play Date': 2010-06-26 08:20:57 +0200, u'PersistentID': 4028778662306031905L, u'Play Count': 0, u'Store URL': u'itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus'}
于 2010-12-06T21:45:51.227 回答
4

这在 Objc-C 中并不难做到。您可以通过 NSWorkspace 和 NSNotificationCenter 访问所有应用程序的通知。创建一个对象并注册它的方法之一,用于 NSWorkspaceDidTerminateApplicationNotification 类型的通知。就像是:

@interface NotificationObserver : NSObject { }
- (void) applicationDidLaunch:(NSNotification*)notification;
@end

@implementation NotificationObserver : NSObject
- (void) applicationDidLaunch:(NSNotification*)notification
{
  // Check the notification to see if Time Machine is being launched.
}
@end

void watch(void)
{
  NSNotificationCenter* notificationCenter
    = [[NSWorkspace sharedWorkspace] sharednotificationCenter];
  NotificationObserver* observer = [[NotificationObserver alloc] init];
  [notificationCenter addObserver:observer
                         selector:@selector(applicationDidTerminate:)
                             name:@"NSWorkspaceDidTerminateApplicationNotification"
                           object:nil];
}
于 2010-12-01T22:25:53.213 回答
0

这不是您问题的答案,但它可能会解决您的问题。

为什么不让 AppleScript 在安装磁盘映像后启动 Time Machine?然后,不要直接启动 Time Machine,而是始终通过脚本调用 Time Machine。您甚至可以将 Time Machine 图标粘贴到您的 AppleScript 文件中,并将其命名为“Time Machine”以使错觉完整。:-)

于 2010-12-06T08:42:35.077 回答