Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 27 additions & 82 deletions kodi-plugin.coffee
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = (env) ->

@framework.deviceManager.registerDeviceClass("KodiPlayer", {
configDef: deviceConfigDef.KodiPlayer,
createCallback: (config) => new KodiPlayer(config)
createCallback: (config, lastState) => new KodiPlayer(config, @, lastState)
})

@framework.ruleManager.addActionProvider(
Expand All @@ -38,7 +38,6 @@ module.exports = (env) ->
@framework.ruleManager.addActionProvider(
new KodiShowToastActionProvider(@framework,@config)
)
@framework.ruleManager.addPredicateProvider(new PlayingPredicateProvider(@framework))

prepareConfig: (config) ->
base = commons.base @, 'KodiPlugin'
Expand Down Expand Up @@ -90,14 +89,14 @@ module.exports = (env) ->
_type: ""
_connectionProvider : null

constructor: (@config) ->
constructor: (@config, @plugin, lastState) ->
@name = @config.name
@id = @config.id
@debug = kodiPlugin.config.debug ? false
@debug = @plugin.config.debug ? false
@base = commons.base @, @config.class
@interval = 60000
@interval = 10000

@_state = 'stop'
@_state = lastState?.state?.value

@actions = _.cloneDeep @actions
@attributes = _.cloneDeep @attributes
Expand Down Expand Up @@ -225,7 +224,11 @@ module.exports = (env) ->
_updateInfo: ->
Promise.all([@_updatePlayerStatus(), @_updatePlayer()])
.catch (error) =>
@base.rejectWithErrorString null, error, "Unable to update player"

# Changed code to prevent log flooding with EHOSTUNREACH errors when mediaplayer is turned off

#@base.rejectWithErrorString null, error, "Unable to update player" # OLD
Promise.resolve() # NEW
.finally () =>
@base.scheduleUpdate @_updateInfo, @interval

Expand All @@ -252,7 +255,7 @@ module.exports = (env) ->
else
@base.debug 'Kodi Stopped'
@_setState 'stop'
@emit 'state', @_state
#@emit 'state', @_state
return Promise.resolve()

_updatePlayer: () ->
Expand All @@ -274,7 +277,7 @@ module.exports = (env) ->
info.label
else ''
)
@_setCurrentArtist(if info.artist? then info.artist else "")
@_setCurrentArtist(if info.artist.length > 0 then info.artist[0] else "")
else
@_setCurrentArtist ''
@_setCurrentTitle ''
Expand Down Expand Up @@ -325,14 +328,14 @@ module.exports = (env) ->
return {
token: match
nextInput: input.substring(match.length)
actionHandler: new KodiExecuteOpenActionHandler(device, @config, state)
actionHandler: new KodiExecuteOpenActionHandler(@framework, device, @config, state)
}
else
return null

class KodiExecuteOpenActionHandler extends env.actions.ActionHandler

constructor: (@device, @config, @name) ->
constructor: (@framework, @device, @config, @name) ->
@debug = kodiPlugin.config.debug ? false
@base = commons.base @, "KodiExecuteOpenActionHandler"

Expand All @@ -345,78 +348,20 @@ module.exports = (env) ->
for command in @config.customOpenCommands
@base.debug "checking for (1): #{command.name} == #{@name}"
if command.name is @name
return @device.executeOpenCommand(
command.command).then( => __("executed %s", @device.name)
)

class PlayingPredicateProvider extends env.predicates.PredicateProvider
constructor: (@framework) ->
@debug = kodiPlugin.config.debug ? false
@base = commons.base @, "PlayingPredicateProvider"

parsePredicate: (input, context) ->
kodiDevices = _(@framework.deviceManager.devices).values()
.filter((device) => device.hasAttribute( 'state')).value()

device = null
state = null
negated = null
match = null

M(input, context)
.matchDevice(kodiDevices, (next, d) =>
next.match([' is', ' reports', ' signals'])
.match([' playing', ' stopped',' paused', ' not playing'], (m, s) =>
if device? and device.id isnt d.id
context?.addError(""""#{input.trim()}" is ambiguous.""")
return
device = d
mapping = {'playing': 'play', 'stopped': 'stop', 'paused': 'pause', 'not playing': 'not play'}
state = mapping[s.trim()] # is one of 'playing', 'stopped', 'paused', 'not playing'

match = m.getFullMatch()

{variables, functions} = @framework.variableManager.getVariablesAndFunctions()
input = __('"%s"', command.command)
context = M.createParseContext(variables, functions)
match = null
m = M(input, context)
parseCommand = (m, tokens) => match = tokens
m.matchStringWithVars(parseCommand)

return @framework.variableManager.evaluateStringExpression(match).then( (cmd) =>
@device.executeOpenCommand(cmd).then( =>
__("executed %s on %s", command.name, @device.name)
)
)
)

if match?
assert device?
assert state?
assert typeof match is "string"
return {
token: match
nextInput: input.substring(match.length)
predicateHandler: new PlayingPredicateHandler(device, state)
}
else
return null

class PlayingPredicateHandler extends env.predicates.PredicateHandler

constructor: (@device, @state) ->
@debug = kodiPlugin.config.debug ? false
@base = commons.base @, "PlayingPredicateHandler"
@dependOnDevice(@device)

setup: ->
@playingListener = (p) =>
@base.debug "checking whether current state #{p} matches #{@state}"
if @state is p or (@state is 'not play' and p isnt 'play')
@emit 'change', true

@device.on 'state', @playingListener
super()

getValue: ->
return @device.getUpdatedAttributeValue('state').then(
(p) =>
@state is p or (@state is 'not play' and p isnt 'play')
)

destroy: ->
@device.removeListener 'state', @playingListener
super()

getType: -> 'state'

class KodiShowToastActionProvider extends env.actions.ActionProvider
constructor: (@framework, @config) ->
Expand Down