2009-12-28 2 views
9

Я пытаюсь создать новый пользовательский плейлист, используя мост сценариев какао, но, похоже, не может заставить его работать. У меня до сих пор:создать плейлист iTunes с помощью скриптового моста

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]; 
} 

Когда я пытаюсь и добавить имя для списка воспроизведения, я получаю сообщение об ошибке:

iTunesBridge [630: 80F] *** - [SBProxyByClass SetName:] : объект еще не добавлен в контейнер; селектор не признан

Может ли кто-нибудь указать мне правильное направление?

+0

'[имя источника] isEqualToString: @" Library "]' Вы протестировали это в неанглийских системах? Кажется хрупким ... – Kornel

+1

В неанглийских системах вы должны использовать '([исходный вид] == iTunesESrcLibrary)' – fabian789

ответ

5

Создание новых объектов приложения ужасно запутано в SB. Процедура псевдо-Cocoa-ish alloc-init-insert не имеет никакого сходства с тем, что происходит на самом деле. Хотя init-init, похоже, создает обычный объект, с которым вы можете манипулировать с последующими вызовами методов, результат на самом деле является прокладкой, единственная функция которой должна быть «вставлена» в «массив», после чего SB отправляет фактическое событие make к целевому процессу. (См. Также here и here для критических замечаний 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 

И FWIW, вот как я бы это сделать в ObjC, используя objc-appscript (который я писал, так что я бы не использовать SB, спичечный).

#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]; 

(недостаток ObjC-appscript является то, что вы должны создать и внедрить копию базы в вашей связке приложений преимущества что он более способен, менее подвержен проблемам совместимости приложений и гораздо менее запутан. Кроме того, вы можете использовать инструмент appscript ASTranslate, чтобы преобразовать события Apple, отправленные вышеуказанным AppleScript в синтаксис ObjC - очень удобно при определении того, как создавать ссылки и команды.)

+2

эй, спасибо, вы правы, работа с скриптовым мостом - это немного кошмар. objc-appscript выглядит хорошо, но в моем случае немного переборщит, так как добавление файлов в список воспроизведения - это все, что я хочу. Я получил это с помощью: playlist = [[[[iTunes classForScriptingClass: @ "playlist"] alloc] initWithProperties: [NSDictionary blah]]]; так спасибо за указатель – 2009-12-30 12:07:02

1

Вы должны заглянуть в EyeTunes. Это среда с открытым исходным кодом для взаимодействия с iTunes с использованием Objective-C. Вы бы выглядели намного проще, если бы вы сделали это через EyeTunes.

http://www.liquidx.net/eyetunes/

+2

EyeTunes делает то же самое, что и ScriptingBridge. Всегда выбирал путь Apple над сторонним участником, исправляя ошибки и уменьшая размер приложения. – jarjar

+2

На самом деле это не вопрос OP. – ray

2

Только быстрое примечание, что [[source name] isEqualToString:@"Library"] определенно не работает на неанглийских систем. Возможно, было бы лучше просто использовать iTunesSource *library = [[_iTunes sources] objectAtIndex: 0];, поскольку первый элемент источника - тот, который находится наверху, например. основная библиотека.

9

В сообщении об ошибке сообщается, что объекты сценариев Bridge, подобные вашему плейлисту, не могут получать сообщения до тех пор, пока они не будут добавлены в соответствующий 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]; 
} 

Другой вариант заключается в использовании initWithProperties:, который в соответствии с вашим комментарием на другой ответ, что вы в конечном итоге делает.

+1

Это должен быть принятый ответ. – ray

2

Это то, что я сделал, чтобы надежно идентифицировать библиотеку. Я мог бы сделать это неправильно.

- (iTunesSource *)iTunesLibrary 
{ 
    NSArray *librarySource = [[[self iTunes] sources] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"kind == %@", [NSAppleEventDescriptor descriptorWithTypeCode:iTunesESrcLibrary]]]; 
    if ([[librarySource lastObject] exists]) { 
    return [librarySource lastObject]; 
    } 
    return nil; 
} 
Смежные вопросы