[MAC] iTunes ScriptingBridge

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

 

FWeinb

ehemals "ich"

Betreff: [MAC] iTunes ScriptingBridge

BeitragMo, Jan 04, 2010 18:31
Antworten mit Zitat
Benutzer-Profile anzeigen
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]

SuperStrict
Framework BaH.ScriptingBridge
Import BRL.GLMax2D
Import BRL.PNGLoader
Import BRL.JPGLoader
Import BRL.RamStream
Import BRL.Timer

Const STATE_STOPPED:Int = 1800426323 'Number are build like this:
Const STATE_PLAYING:Int = 1800426320 'Asc("k") Shl 24 | Asc("P") Shl 16 | Asc( "S") Shl 8 | Asc("P") in the iTunes.h
Const STATE_PAUSED:Int = 1800426352
Const STATE_FASTFORWARDING:Int = 1800426310
Const STATE_REWINDING:Int = 1800426322

Type iTunes

Const iTunesESrAAlbums:Int = 1800630860 'Search album names
Const iTunesESrAAll:Int = 1799449708 'Search all
Const iTunesESrAArtists:Int = 1800630866 'Search Artist
Const iTunesESrAComposers:Int = 1800630851 'Search Composer
Const iTunesESrADisplayed:Int = 1800630870 'Search visible text fields
Const iTunesESrASongs:Int = 1800630867 'Search Song names

Field app:SBApplication

Method New()
app = SBApplication.applicationWithBundleIdentifier("com.apple.iTunes")
End Method

Method GetSelection:TList() 'Get current selection
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() 'Current played Track as a TTrack
If Self.GetState() = STATE_STOPPED Then Return Null
Return TTrack.Create(SBObject(app.propertyAsObject("currentTrack")))
End Method

Method GetState:Int() 'PlayerState One of the States STATE_STOPPED,STATE_PLAYING,STATE_PAUSE ...
Return app.propertyAsInt("playerState")
End Method

'_-----------------------iTunes Control-----------------------------_

Method PlayPause() 'Play/Pause
app.call("playpause")
End Method

Method backTrack() 'Go back to beginning of the current played Song
app.call("backTrack")
End Method

Method previousTrack() 'Previouse track in current Playlist
app.call("previousTrack")
End Method

Method nextTrack() 'Next Song in current Playlist
app.call("nextTrack")
End Method


Method playerPostion:Int() 'Postion in current played Song
Return app.propertyAsInt("playerPosition")
End Method

Method GetVolume:Int() 'Get current Volumen
Return app.propertyAsInt("soundVolume")
End Method

Method setVolume(vol:Int) 'Set Volumen (0-100)
app.setPropertyAsInt("soundVolume", vol)
End Method

Method GetSongByName:TTrack(Name:String) 'Get a Song by Name as a TTrack
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())) 'Some Vodoo with the core Classes
Return Track
End Method


Method Search:TList(Query:String,SearchFor:Int = iTunesESrAAll) 'Returns the Result as a TList with TTrack's included
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) 'The ID is unique
Return Self.id = track.id
End Method

Method GetArtwork:TImage() ' Get the Artwork, first call load it
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 'Delete image
End Method

Method SetString(Property:String,newString:String) 'Set a String (only non "readonly" Property's)
Self._Track.setpropertyAsString(property,newString)
End Method

Method SetInt(Property:String,newInt:Int) 'Same for Int's
Self._Track.setPropertyAsInt(property,newInt)
End Method

Method Exist:Int() 'Exist this Track?
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 'Only a Demo Type to show the Usage
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 'In millisecs

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 ) 'A cool way of doing "If KeyHit( KEY_I ) Then ... = Not ...

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 'Compute the time, better than ask iTunes every time (CPU Usage)
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:
user posted image
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
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs

beanage.johannes

BeitragSa, Jan 09, 2010 22:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr buggy dein Programm...
die Lautstärke lässt sich bei mir NUR lauter machen und wenn man es pausiert läuft der counter weiter^^
 

FWeinb

ehemals "ich"

BeitragSa, Jan 09, 2010 23:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit dem Weiterlaufen, im Pause Modus ist mein Fehler Embarassed
Was passiert denn wenn du Leiser machst, einfach nix?

MfG
ich
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs

beanage.johannes

BeitragSo, Jan 10, 2010 12:25
Antworten mit Zitat
Benutzer-Profile anzeigen
der reagiert nicht auf die leiser -taste, bei mir.
 

FWeinb

ehemals "ich"

BeitragSo, Jan 10, 2010 16:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Welche Version von iTunes nutzt du? Werde ich aber wohl nicht so viel machen können da, dass an der ScriptingBridge liegen wird.

MfG
ich
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs

beanage.johannes

BeitragSo, Jan 10, 2010 17:45
Antworten mit Zitat
Benutzer-Profile anzeigen
die neuste version

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group