使用脚本桥创建iTunes播放列表

9 cocoa itunes scripting-bridge

我正在尝试使用cocoa脚本桥创建一个新的用户播放列表,但似乎无法让它工作.我到目前为止:

iTunesApplication *iTunes = [SBApplication 
                            applicationWithBundleIdentifier:@"com.apple.iTunes"];
SBElementArray *iSources = [iTunes sources];
iTunesSource *library = nil;
for (iTunesSource *source in iSources) {
    if ([[source name] isEqualToString:@"Library"]) {
        library = source;
        break;
    }
}

// could not find the itunes library
if (!library) {
    NSLog(@"Could not connect to the iTunes library");
    return;
}

// now look for our playlist
NSString *playlistName = @"new playlist";
SBElementArray *playlists = [library userPlaylists];
iTunesUserPlaylist *playlist = nil;
for (iTunesUserPlaylist *thisList in playlists) {
    if ([[thisList name] isEqualToString:playlistName]) {
        playlist = thisList;
        break;
    }
}

// if the playlist was not found, create it
if (!playlist) {
    playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] init];
    [playlist setName:playlistName];
    [[library userPlaylists] insertObject:playlist atIndex:0];
}
Run Code Online (Sandbox Code Playgroud)

当我尝试为播放列表添加名称时,收到错误消息:

iTunesBridge [630:80f]*** - [SBProxyByClass setName:]:对象尚未添加到容器中; 选择器无法识别

谁能指出我正确的方向?

Gab*_*oth 10

错误消息告诉您脚本桥对象(如播放列表)在添加到相关SBElementArray之前无法接收消息,因此您尝试在将播放列表添加到阵列之前在播放列表上设置属性将失败.

最简单的解决方案是重新排列最后两行代码,如下所示:

// if the playlist was not found, create it
if (!playlist) {
    playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] init];
    [[library userPlaylists] insertObject:playlist atIndex:0];
    [playlist setName:playlistName];
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是initWithProperties:根据你对其他答案的评论使用你最终做的事情.


has*_*has 5

在SB中,使新的应用程序对象变得非常混乱.伪Cocoa-ish alloc-init-insert程序与下面的实际内容没有任何相似之处.虽然alloc-init似乎创建了一个可以通过后续方法调用操作的常规对象,但结果实际上是一个垫片,其唯一的功能是"插入"'数组',此时SB发送一个实际的make事件给目标过程.(另请参见此处此处的SB批评.)

IIRC,你可以实际指定初始属性的唯一一点是-initWithProperties:.您可以在对象被"插入"之后设置它们,但这是一个完全不同的操作(操纵已经存在的对象而不是为正在创建的对象指定初始状态),因此如果您不小心,很容易产生意想不到的后果.

无论如何,如果一个新播放列表尚不存在,通常会创建一个新的播放列表:

set playlistName to "new playlist"
tell application "iTunes"
    if not (exists playlist playlistName) then
        make new playlist with properties {name:playlistName}
    end if
end tell
Run Code Online (Sandbox Code Playgroud)

而且,FWIW,这是我在ObjC中如何使用objc-appscript(我写的所以我不必使用SB,natch):

#import "ITGlue/ITGlue.h"

NSString *playlistName = @"new playlist";

ITApplication *itunes = [ITApplication applicationWithName: @"iTunes"];
ITReference *playlist = [[itunes playlists] byName: playlistName];

if ([[[playlist exists] send] boolValue])
    playlist = [playlist getItem];
else
    playlist = [[[[itunes make] new_: [ITConstant playlist]] 
                      withProperties: [NSDictionary dictionaryWithObject: playlistName
                                                                  forKey: [ITConstant name]]] send];
Run Code Online (Sandbox Code Playgroud)

(objc-appscript的缺点是你必须在你的应用程序包中构建和嵌入一个框架的副本.好处是它更有能力,更不容易出现应用程序兼容性问题,而且更少混淆.另外你可以使用appscript的ASTranslate工具将上述AppleScript发送的Apple事件转换为ObjC语法 - 在确定如何构建引用和命令时非常方便.)

  • 嘿,谢谢,你是对的,使用脚本桥是一个噩梦.objc-appscript看起来不错,但在我的情况下有点矫枉过正,因为将文件添加到播放列表是我所追求的.我确实得到了它:playlist = [[[iTunes classForScriptingClass:@"playlist"] alloc] initWithProperties:[NSDictionary blah]]]; 所以感谢指针 (2认同)