Skip to content

Commit

Permalink
More documentation, use slf4j
Browse files Browse the repository at this point in the history
  • Loading branch information
Xerus committed Mar 14, 2018
1 parent 452fa3c commit 54cc232
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 51 deletions.
86 changes: 49 additions & 37 deletions extensions/src/xerus/mpris/AbstractMPRISPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,16 @@ package xerus.mpris

import org.freedesktop.DBus
import org.freedesktop.dbus.DBusConnection
import org.freedesktop.dbus.DBusInterfaceName
import org.freedesktop.dbus.DBusMemberName
import org.freedesktop.dbus.Variant
import org.mpris.MediaPlayer2.LoopStatus
import org.mpris.MediaPlayer2.MaybePlaylist
import org.mpris.MediaPlayer2.MediaPlayer2
import org.mpris.MediaPlayer2.PlaybackStatus
import org.mpris.MediaPlayer2.Player
import org.mpris.MediaPlayer2.PlaylistOrdering
import org.mpris.MediaPlayer2.Playlists
import org.mpris.MediaPlayer2.TrackId
import org.mpris.MediaPlayer2.TrackList
import org.mpris.MediaPlayer2.*

/** Provides a typesafe foundation for implementing an MPRISPlayer.
*
* Every property inherited from an interface must either be null (if it is nullable and you don't want to implement it)
* or delegated by a [DBusProperty]
*
* A val represents a Read-only field as declared by MPRIS, it is perfectly valid to implement it as var */
abstract class AbstractMPRISPlayer: MediaPlayerX, PlayerX, DefaultDBus {
abstract class AbstractMPRISPlayer : MediaPlayerX, PlayerX, DefaultDBus {

val connection = DBusConnection.getConnection(DBusConnection.SESSION)
val properties = HashMap<String, MutableMap<String, Variant<*>>>()
Expand All @@ -41,41 +31,61 @@ abstract class AbstractMPRISPlayer: MediaPlayerX, PlayerX, DefaultDBus {

/** sends a [DBus.Properties.PropertiesChanged] signal via [connection] */
override fun propertyChanged(interface_name: String, property_name: String) =
super.propertyChanged(interface_name, property_name).also { connection.sendSignal(it) }
super.propertyChanged(interface_name, property_name).also { connection.sendSignal(it) }

override val hasTrackList by DBusConstant(this is TrackList)

}

interface PlayerX: Player {
interface PlayerX : Player {
/** Whether the media player may be controlled over this interface.
* Setting this to false assumes all properties as Read-only */
val canControl: Boolean
val canGoNext: Boolean
val canGoPrevious: Boolean
val canPlay: Boolean
val canPause: Boolean
val canSeek: Boolean

val playbackStatus: PlaybackStatus
/** _Optional_ */
var loopStatus: LoopStatus
var rate: Double
/** _Optional_ */
/** A value of false indicates that playback is progressing linearly through a playlist,
* while true means playback is progressing through a playlist in some other order.
*
* _Optional_ */
var shuffle: Boolean
/** Metadata of the current Track
* [https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/#index2h2] */
val metadata: Map<String, Variant<*>>
var volume: Double
/** The current track position in microseconds, between 0 and the 'mpris:length' metadata entry (see [metadata]. */
val position: Long
/** Metadata of the current Track.
* [https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/#index2h2] */
val metadata: Map<String, Variant<*>>

/** The current playback rate.
*
* The value must fall in the range described by [minimumRate] and [maximumRate], and must not be 0.0 */
var rate: Double
/** The minimum value which the [rate] property can take. */
val minimumRate: Double
/** The maximum value which the [rate] property can take. */
val maximumRate: Double
val canGoNext: Boolean
val canGoPrevious: Boolean
val canPlay: Boolean
val canPause: Boolean
val canSeek: Boolean
val canControl: Boolean

}

interface MediaPlayerX: MediaPlayer2 {
interface MediaPlayerX : MediaPlayer2 {
val supportedUriSchemes: Array<String>
val supportedMimeTypes: Array<String>
/** Indicates whether this object implements the org.mpris.MediaPlayer2.TrackList interface. */
val hasTrackList: Boolean

val canRaise: Boolean
val canQuit: Boolean
/** _Optional_ */
var fullscreen: Boolean
/** _Optional_ */
val canSetFullscreen: Boolean
val canRaise: Boolean
/** Indicates whether this object implements the org.mpris.MediaPlayer2.TrackList interface. */
val hasTrackList: Boolean

/** _Optional_ */
var fullscreen: Boolean
/** A friendly name to identify the media player to users.
* This should usually match the name found in the [desktopEntry]. */
val identity: String
Expand All @@ -84,17 +94,19 @@ interface MediaPlayerX: MediaPlayer2 {
*
* _Optional_ */
val desktopEntry: String
val supportedUriSchemes: Array<String>
val supportedMimeTypes: Array<String>
}

interface TrackListX: TrackList {
val tracks: Array<TrackId>
interface TrackListX : TrackList {
/** If false, calling AddTrack or RemoveTrack will have no effect, and may raise a NotSupported error. */
val canEditTracks: Boolean

/** An array which contains the identifier of each track in this [TrackList], in order. */
val tracks: Array<TrackId>
}

interface PlaylistsX: Playlists {
val playlistCount: Int
interface PlaylistsX : Playlists {
val orderings: Array<PlaylistOrdering>

val playlistCount: Int
val activePlaylist: MaybePlaylist
}
39 changes: 25 additions & 14 deletions extensions/src/xerus/mpris/DBusPropertyDelegate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

package xerus.mpris

import javafx.beans.value.ObservableValue
import org.freedesktop.dbus.DBusInterfaceName
import org.mpris.MediaPlayer2.PlaylistOrdering
import org.slf4j.LoggerFactory
import kotlin.properties.ObservableProperty
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
Expand All @@ -12,16 +15,22 @@ fun main(args: Array<String>) {
println(arrayOf(PlaylistOrdering.Alphabetical).variant())
}

private fun findInterface(clazz: Class<*>, name: String): Class<*>? {
if (clazz.declaredMethods.any { it.name.contains(name) })
return clazz.interfaces.first()
return (clazz.interfaces + clazz.superclass).firstOrNull { findInterface(it, name) != null }
}
val logger = LoggerFactory.getLogger("xerus.mpris.properties")

fun
private fun findInterface(clazz: Class<*>, name: String): Class<*>? =
(clazz.interfaces + clazz.superclass).firstOrNull {
if(it == null) return@firstOrNull false
if (it.declaredMethods.any { it.name.contains(name) }) {
logger.debug("Found $it for property $name")
return it.interfaces.first()
}
findInterface(it, name) != null
}

class DBusProperty<T : Any>(private val initial: T, private val observable: ObservableValue<T>? = null, private val onSet: ((T) -> Unit)? = null) {

constructor(observable: ObservableValue<T>, onSet: ((T) -> Unit)? = null) : this(observable.value, observable, onSet)

class DBusProperty<T : Any>(private val initial: T, private val onSet: ((T) -> Unit)? = null) {

operator fun provideDelegate(
thisRef: AbstractMPRISPlayer,
prop: KProperty<*>
Expand All @@ -31,16 +40,18 @@ class DBusProperty<T : Any>(private val initial: T, private val onSet: ((T) -> U
?: throw RuntimeException("No interface found for Property $name")
val interfaceName = (clazz.annotations.find { it is DBusInterfaceName } as? DBusInterfaceName)?.value
?: clazz.name
println("${prop.name} - $clazz - $interfaceName")
logger.debug("Registered Property ${prop.name} for $interfaceName")
thisRef.properties.getOrPut(interfaceName) { HashMap() }.put(name, initial.variant())
val property = Property<T>(interfaceName, name)
if (onSet != null)
thisRef.propertyListeners[name] = onSet as ((Any) -> Unit)
return Property(interfaceName, name)
observable?.addListener { _, _, new -> property.setValue(thisRef, prop, new) }
return property
}

}

class DBusConstant<T : Any>(private val initial: T) {
class DBusConstant<out T : Any>(private val value: T) {

operator fun provideDelegate(
thisRef: AbstractMPRISPlayer,
Expand All @@ -51,9 +62,9 @@ class DBusConstant<T : Any>(private val initial: T) {
?: throw RuntimeException("No interface found for Property $name")
val interfaceName = (clazz.annotations.find { it is DBusInterfaceName } as? DBusInterfaceName)?.value
?: clazz.name
println("${prop.name} - $clazz - $interfaceName")
thisRef.properties.getOrPut(interfaceName) { HashMap() }.put(name, initial.variant())
return Constant(initial)
logger.debug("Registered Constant ${prop.name} for $interfaceName")
thisRef.properties.getOrPut(interfaceName) { HashMap() }.put(name, value.variant())
return Constant(value)
}
}

Expand Down

0 comments on commit 54cc232

Please sign in to comment.