2009-12-28 11 views
9

Sto provando a creare una nuova playlist utente utilizzando il bridge di scripting del cacao, ma non riesco a farlo funzionare. Ho finora:crea playlist iTunes con bridge di scripting

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

Quando provo e aggiungi un nome per la playlist, ottengo il messaggio di errore:

iTunesBridge [630: 80F] *** - [SBProxyByClass setName:] : l'oggetto non è stato ancora aggiunto a un contenitore; selettore non riconosciuto

Qualcuno può indicarmi la direzione corretta?

+0

'[nome sorgente] isEqualToString: @" Libreria "]' l'hai testato in sistemi non inglesi? Sembra fragile ... – Kornel

+1

In sistemi non inglesi, dovresti usare '([tipo di fonte] == iTunesESrcLibrary)' – fabian789

risposta

5

La creazione di nuovi oggetti applicazione è terribilmente offuscata in SB. La procedura di alloc-init-insert pseudo-Cocoa-ish non ha alcuna somiglianza con ciò che sta effettivamente accadendo sotto. Mentre l'alloc-init sembra creare un oggetto regolare che puoi manipolare con chiamate di metodo successive, il risultato è in realtà uno shim la cui unica funzione deve essere 'inserita' in un 'array', in cui il punto SB invia un evento effettivo make al processo di destinazione. (Vedere anche here per le critiche SB.)

IIRC, l'unico punto in cui è possibile specificare le proprietà iniziali è in -initWithProperties:. Puoi impostarli dopo che l'oggetto è stato "inserito", ma si tratta di un'operazione completamente diversa (manipolando un oggetto già esistente piuttosto che specificando lo stato iniziale per un oggetto creato), quindi puoi facilmente avere conseguenze indesiderate se non stai attento .

In ogni caso, ecco come che normalmente si crea una nuova playlist se non esiste già:

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 

E, FWIW, ecco come lo farei in objC, utilizzando objc-appscript (che ho scritto in modo da non dover usare 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]; 

(il lato negativo di objc-appscript è che si deve costruire e incorporare una copia del quadro nel bundle dell'applicazione I vantaggi è che è più capace, meno soggetto a problemi di compatibilità delle applicazioni e molto meno offuscato. Inoltre è possibile utilizzare lo strumento ASTranslate di appscript per convertire gli eventi Apple inviati da AppleScript sopra nella sintassi ObjC - molto utile quando si capisce come costruire riferimenti e comandi.

+2

ehi grazie, hai ragione, lavorare con il bridge di script è un po 'un incubo. objc-appscript sembra buono, ma un po 'eccessivo nel mio caso, dato che aggiungere file a una playlist è tutto ciò che voglio. l'ho fatto funzionare con: playlist = [[[iTunes classForScriptingClass: @ "playlist"] alloc] initWithProperties: [NSDictionary blah]]]; quindi grazie per il puntatore –

1

Si dovrebbe cercare su EyeTunes. È un framework open source per interagire con iTunes usando Objective-C. Il codice sarebbe molto più semplice se lo facessi tramite EyeTunes.

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

+2

EyeTunes sta facendo esattamente la stessa cosa che sta facendo ScriptingBridge. Hai sempre scelto Apple come terza parte, per correzioni di bug e dimensioni di app più piccole. – jarjar

+2

Questo in realtà non risponde alla domanda dell'OP. – ray

2

Solo una breve nota che [[source name] isEqualToString:@"Library"] sicuramente non funziona su sistemi non in inglese. Potrebbe essere meglio utilizzare semplicemente iTunesSource *library = [[_iTunes sources] objectAtIndex: 0]; poiché il primo elemento di origine è quello in alto, ad es. la libreria principale.

9

Il messaggio di errore indica che oggetti Scripting Bridge come la playlist non possono ricevere messaggi fino a quando non sono stati aggiunti al relativo SBElementArray, quindi il tentativo di impostare una proprietà nella playlist prima di aggiungerlo all'array non riesce .

La soluzione più semplice è solo per riorganizzare le ultime due righe di codice, in questo modo:

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

L'altra opzione è quella di utilizzare initWithProperties: che secondo il vostro commento su un'altra risposta è quello che ha finito per fare.

+1

Questa dovrebbe essere la risposta accettata. – ray

2

Questo è ciò che ho fatto per identificare in modo affidabile la libreria. Potrei sbagliarmi.

- (iTunesSource *)iTunesLibrary 
{ 
    NSArray *librarySource = [[[self iTunes] sources] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"kind == %@", [NSAppleEventDescriptor descriptorWithTypeCode:iTunesESrcLibrary]]]; 
    if ([[librarySource lastObject] exists]) { 
    return [librarySource lastObject]; 
    } 
    return nil; 
}