Da Brucey wieder einmal ein sehr nützliches Modul für den Mac geschrieben hat und ich grade zu dem Zeitpunkt meinen Programm iTunesLyrics(Showcase) geschrieben habe. Welches seit Version 1.2 das Modul nutzt um mit iTunes Daten auszutauschen. Dies hat einen Geschwindigkeitszuwachs von min. 20% gebracht. Habe ich mir gedacht, vereinfache ich die Kommunikation und schreibe ein paar Funktionen(Einen Type) für die Kommunikation zwischen iTunes und der eigenen Anwendung.
Hier das Modul: blitzbasic.com
Hier der Code zusammen mit einem kleinen Player(basieren auf Brucey Beispiel):
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict Framework BaH.ScriptingBridge Import BRL.GLMax2D Import BRL.PNGLoader Import BRL.JPGLoader Import BRL.RamStream Import BRL.Timer
Const STATE_STOPPED:Int = 1800426323 Const STATE_PLAYING:Int = 1800426320 Const STATE_PAUSED:Int = 1800426352 Const STATE_FASTFORWARDING:Int = 1800426310 Const STATE_REWINDING:Int = 1800426322
Type iTunes
Const iTunesESrAAlbums:Int = 1800630860 Const iTunesESrAAll:Int = 1799449708 Const iTunesESrAArtists:Int = 1800630866 Const iTunesESrAComposers:Int = 1800630851 Const iTunesESrADisplayed:Int = 1800630870 Const iTunesESrASongs:Int = 1800630867
Field app:SBApplication Method New() app = SBApplication.applicationWithBundleIdentifier("com.apple.iTunes") End Method Method GetSelection:TList() Local Count:Int Local selection:SBElementArray = SBElementArray(app.propertyAsObject("selection")) Local SelectionList:TList = New TList If selection Then For Local Track:SBObject = EachIn selection SelectionList.AddLast TTrack.Create(Track) Next Return SelectionList Else Return Null End If End Method
Method isRunning:Byte() Return app.isRunning() End Method Method GetCurrentTrack:TTrack() If Self.GetState() = STATE_STOPPED Then Return Null Return TTrack.Create(SBObject(app.propertyAsObject("currentTrack"))) End Method
Method GetState:Int() Return app.propertyAsInt("playerState") End Method Method PlayPause() app.call("playpause") End Method Method backTrack() app.call("backTrack") End Method Method previousTrack() app.call("previousTrack") End Method Method nextTrack() app.call("nextTrack") End Method Method playerPostion:Int() Return app.propertyAsInt("playerPosition") End Method Method GetVolume:Int() Return app.propertyAsInt("soundVolume") End Method Method setVolume(vol:Int) app.setPropertyAsInt("soundVolume", vol) End Method Method GetSongByName:TTrack(Name:String) If Self.GetState() = STATE_STOPPED Then Return Null Local Playlist:SBObject = SBObject(app.propertyAsObject("currentPlaylist")) Local tracks:SBElementArray = SBElementArray(Playlist.callWithStringIntReturningObject("searchFor:only:", Name, iTunesESrASongs)) Local Track:TTrack = TTrack.Create(SBObject(tracks.ObjectEnumerator().NextObject())) Return Track End Method
Method Search:TList(Query:String,SearchFor:Int = iTunesESrAAll) Local Playlist:SBObject = SBObject(app.propertyAsObject("currentPlaylist")) Local tracks:SBElementArray = SBElementArray(Playlist.callWithStringIntReturningObject("searchFor:only:", Query, Searchfor)) Local NewList:TList = New TList For Local track:SBObject = EachIn tracks NewList.AddLast TTrack.Create(Track) Next Return newList End Method End Type
Type TTrack Field _Track:SBObject
Field Id:Int Field Title:String Field Artist:String Field Album:String Field Genre:String Field Lyrics:String Field AlbumArtist:String Field AlbumRating:Int Field DiscNumber:Int Field DiscCount:Int Field Duration:Double Field PlayCount:Int Field Rating:Int Field Shufflable:Byte Field Size:Int Field unplayed:Byte Field Location:String Field Artwork:TImage Function Create:TTrack(Track:SBObject) If Not Track.exists() Return Null Local Item:TTrack = New TTrack Item._Track = Track Item.Id = Track.propertyAsInt("databaseID") Item.Title = Track.propertyAsString("name") Item.Artist = Track.propertyAsString("artist") Item.Album = Track.propertyAsString("album") Item.AlbumArtist = Track.propertyAsString("albumArtist") Item.AlbumRating = Track.propertyAsInt("albumRating") Item.DiscNumber = Track.propertyAsInt("discNumber") Item.DiscCount = Track.propertyAsInt("discCount") Item.Duration = Track.propertyAsDouble("duration") Item.Genre = Track.propertyAsString("genre") Item.Lyrics = Track.propertyAsString("lyrics") Item.PlayCount = Track.propertyAsInt("playedCount") Item.Rating = Track.propertyAsInt("rating") Item.shufflable = Byte(Track.propertyAsInt("shufflable")) Item.Size = Track.propertyAsInt("size") Item.unplayed = Byte(Track.propertyAsInt("unplayed")) Item.Location = Track.propertyAsUrl("location") Return Item End Function Method equals:Int(track:TTrack) Return Self.id = track.id End Method Method GetArtwork:TImage() If Not Self.Artwork Then Local Artworks:SBElementArray = SBElementArray(Self._Track.propertyAsList("artworks")) Local Artwork:SBObject = SBObject(Artworks.ObjectEnumerator().NextObject()) Local Size:Int Local Data:Byte Ptr = Artwork.propertyAsPtr("rawData",Size) If Size>0 Then Local Stream:TStream = CreateRamStream(Data,Size,True,False) Self.Artwork = LoadImage(Stream) Stream.Close End If End If Return Self.Artwork End Method Method FreeArtwork() If Self.Artwork <> Null Self.Artwork = Null End Method
Method SetString(Property:String,newString:String) Self._Track.setpropertyAsString(property,newString) End Method Method SetInt(Property:String,newInt:Int) Self._Track.setPropertyAsInt(property,newInt) End Method Method Exist:Int() Return Self._Track.callReturningInt("exists") End Method Method Play() Self._Track.callWithInt("playOnce:",True) End Method End Type
Graphics 800,600,0
Local iTunesP:iTunesPlayer = iTunesPlayer.Create(New iTunes)
Local Timer:TTImer = CreateTimer(10)
While Not AppTerminate() WaitTimer Timer Cls iTunesP.Update() iTunesP.Draw(50,70) Flip Wend
Type iTunesPlayer Field iTunesC:iTunes Field currentTrack:TTrack Field state:Int Field volume:Int Field FirstPosition:Int Field NewSongInitTime:Int Field LastUpdate:Int Field TimeBetweenUpdates:Int = 2000 Field MoreInfo:Byte Function Create:iTunesPlayer(iTunesC:iTunes) Local Player:iTunesPlayer = New iTunesPlayer Player.iTunesC = iTunesC Return Player End Function Method Update() If Self.LastUpdate+Self.TimeBetweenUpdates <= MilliSecs() Then Self.LastUpdate = MilliSecs() Self.state = Self.iTunesC.GetState() Local NewTrack:TTrack = Self.iTunesC.GetCurrentTrack() If NewTrack Then If Not Self.currentTrack Or Not NewTrack.equals(currentTrack) Then Self.NewSongInitTime = MilliSecs() Self.FirstPosition = Self.iTunesC.playerPostion() Self.CurrentTrack = Null Self.CurrentTrack = newTrack Self.CurrentTrack.GetArtwork() End If End If Self.volume = Self.iTunesC.GetVolume() End If Self.MoreInfo = Self.MoreInfo ~ KeyHit( KEY_I ) If KeyHit(KEY_P) Then Self.iTunesC.PlayPause() End If If KeyHit(KEY_RIGHT) Then Self.iTunesC.NextTrack() End If If KeyHit(KEY_LEFT) Then Self.iTunesC.PreviousTrack() End If If KeyDown(KEY_DOWN) Then Self.iTunesC.setVolume(volume - 2) End If If KeyDown(KEY_UP) Then Self.iTunesC.setVolume(volume + 2) End If End Method Method stateString:String() Select Self.State Case STATE_STOPPED Return "Stopped" Case STATE_PLAYING Return "Playing" Case STATE_PAUSED Return "Paused" Case STATE_FASTFORWARDING Return "Fast Forwarding" Case STATE_REWINDING Return "Rewinding" End Select End Method Method draw(X:Int,Y:Int) DrawText "iTunes is " + stateString() + ".", 10, 10 Self.drawBar() Self.drawVolume() Self.drawInput() If Self.currentTrack Then If Not MoreInfo Then DrawText "Album : " + Self.CurrentTrack.Album, x + 10, y + 14 DrawText "Track : " + Self.CurrentTrack.Title, x + 10, y + 28 DrawText "Duration : " + secondsToMinSec(Self.CurrentTrack.Duration).Trim(), x + 10, y + 42 Else DrawText "Album : " + Self.CurrentTrack.Album, x + 300, y + 50 + 14 DrawText "Track : " + Self.CurrentTrack.Title, x + 300, y + 50 + 28 DrawText "Duration : " + secondsToMinSec(Self.CurrentTrack.Duration).Trim(), x + 300, y + 50 + 42 DrawText "AlbumArtist : " + Self.CurrentTrack.albumArtist, x + 300, y + 50 + 56 DrawText "AlbumRating : " + Self.CurrentTrack.albumRating, x + 300, y + 50 + 70 DrawText "DiscNumber : " + Self.CurrentTrack.discNumber, x + 300, y + 50 + 84 DrawText "DiscCount : " + Self.CurrentTrack.discCount, x + 300, y + 50 + 98 DrawText "Genre : " + Self.CurrentTrack.genre, x + 300, y + 50 + 112 DrawText "Lyrics : " + Self.CurrentTrack.lyrics[..30]+"...", x + 300, y + 50 + 126 DrawText "PlayCount : " + Self.CurrentTrack.PlayCount, x + 300, y + 50 + 140 DrawText "Rating : " + Self.CurrentTrack.rating, x + 300, y + 50 + 154 DrawText "shufflable : " + Self.CurrentTrack.shufflable, x + 300, y + 50 + 168 DrawText "Size : " + Self.CurrentTrack.size, x + 300, y + 50 + 182 DrawText "unplayed : " + Self.CurrentTrack.unplayed, x + 300, y + 50 + 196 DrawText "Location : " + Self.CurrentTrack.location[..30]+"...", x + 300, y + 50 + 210 End If Local Art:TImage = Self.CurrentTrack.GetArtwork() Local scale:Float = 256.0 / art.width SetScale scale, scale DrawImage Art,x + 10, y + 70 Art = Null SetScale 1, 1 End If End Method Method drawInput() Local s:String Select state Case STATE_STOPPED, STATE_PAUSED, STATE_FASTFORWARDING, STATE_REWINDING s = "P : Play" Case STATE_PLAYING s = "P : Pause" End Select DrawText s, 600, 20 DrawText "UP : Volume Up", 600, 36 DrawText "DN : Volume Down", 600, 52 DrawText "Key i: More Infos",600,69 End Method
Method drawBar() DrawRect 40, 60, 400, 5 If currentTrack Then
Local totaltime:Int = Self.CurrentTrack.Duration Local currentPos:Int = Self.FirstPosition + (MilliSecs()-Self.NewSongInitTime)/1000 Local timeScale:Float = 400.0 / Self.CurrentTrack.Duration SetColor 220, 0, 0 DrawRect 40, 60, currentPos * timeScale, 5 SetColor 255, 255, 255 DrawText secondsToMinSec(currentPos), 12 + currentPos * timeScale, 45 End If End Method Method drawVolume() SetColor 220, 0, 0 DrawRect 500, 10, 5, 55 SetColor 255, 255, 255 Local volumeScale:Float = 55.0 / 100
DrawRect 500, 10, 5, 55 - volume * volumeScale DrawText volume, 510, 5 + 55 - volume * volumeScale End Method End Type
Function secondsToMinSec:String(seconds:Int) Local minutes:Int = seconds / 60 Local secs:Int = seconds Mod 60 Local m:String = " " + minutes m = m[m.length - 3..] Local s:String = "00" + secs s = s[s.length - 2..] Return m + ":" + s End Function
Hier noch ein Screenshot+Download:
Download .app
Der Code sollte selbsterklärend sein. Würde mich drüber freuen, wenn der ein oder andere es Testen würde, da es Problem mit der ScriptingBridge zu geben scheint. (Bei mir war es so das einige Objekte anders Reagierten als bei Brucey selbst.)
Tipp: Mit den Pfeiltasten Rechts bzw. Links ein ein Song Vor/Zurück gesprungen werden.
MfG
ich
|