examples/pep.lua
changeset 59 4660c4f10ef1
parent 56 8561e55e0662
child 64 bf7521ed96eb
equal deleted inserted replaced
58:aa3376776cf2 59:4660c4f10ef1
     3 
     3 
     4 -- library
     4 -- library
     5 
     5 
     6 require 'lm'
     6 require 'lm'
     7 require 'iq'
     7 require 'iq'
     8 require 'mpd'
       
     9 
     8 
    10 -- public
     9 -- public
    11 
    10 
    12 pep = {
    11 pep = {
    13 	handlers = {},
    12 	handlers = {},
    39 
    38 
    40 -- private
    39 -- private
    41 
    40 
    42 -- XXX in fact, it is not a pep handler, it is pubsub handler.
    41 -- XXX in fact, it is not a pep handler, it is pubsub handler.
    43 --     should it go there?
    42 --     should it go there?
    44 local pep_handler_registered       = false
       
    45 local pep_incoming_message_handler = lm.message_handler.new (
    43 local pep_incoming_message_handler = lm.message_handler.new (
    46 	function ( conn, mess )
    44 	function ( conn, mess )
    47 		local e = mess:child ( 'event' )
    45 		local e = mess:child ( 'event' )
    48 		if e and e:attribute ( 'xmlns' ) == 'http://jabber.org/protocol/pubsub#event' then
    46 		if e and e:attribute ( 'xmlns' ) == 'http://jabber.org/protocol/pubsub#event' then
    49 			local is = e:child ( 'items' )
    47 			local is = e:child ( 'items' )
    72 		return false
    70 		return false
    73 	end )
    71 	end )
    74 
    72 
    75 -- mcabber
    73 -- mcabber
    76 
    74 
    77 local tune_enabled = false
    75 local pep_handler_registered = false
    78 local mpd_pub_song = { }
       
    79 
       
    80 -- XXX in fact, we should separate library code from client code here, but it is silly.
       
    81 --     seting up four registrators, four default handlers, four handler storage variables...
       
    82 --     and, in fact, we cannot do much about complex datatypes of mood and activity.
       
    83 pep.handlers['http://jabber.org/protocol/tune'] =
       
    84 		function ( from, node, data )
       
    85 			local self = false
       
    86 			if from == lm.connection.bless ( main.connection () ):jid():gsub ( '/.*', '' ) then -- o_O
       
    87 				self         = true
       
    88 				mpd_pub_song = { }
       
    89 			end
       
    90 			local item = data:children ()
       
    91 			local text = ''
       
    92 			while item do
       
    93 				local name  = item:name ()
       
    94 				local value = item:value ()
       
    95 				if self then
       
    96 					mpd_pub_song[name] = { value or '' }
       
    97 				end
       
    98 				text = ("%s\n- %s: %s"):format ( text, item:name (), item:value () or '' )
       
    99 				item = item:next ()
       
   100 			end
       
   101 			if main.yesno ( main.option ( 'lua_pep_notification' ) ) then
       
   102 				if text ~= '' then
       
   103 					text = 'Now listening to:' .. text
       
   104 				else
       
   105 					text = 'Now not listening to anything'
       
   106 				end
       
   107 			end
       
   108 			main.print_info ( from, text )
       
   109 			return true
       
   110 		end
       
   111 pep.handlers['http://jabber.org/protocol/mood'] =
       
   112 		function ( from, node, data )
       
   113 			if not main.yesno ( main.option ( 'lua_pep_notification' ) ) then
       
   114 				return true
       
   115 			end
       
   116 			local item = data:children ()
       
   117 			local mood, desc
       
   118 			while item do
       
   119 				if item:name () == 'text' then
       
   120 					desc = item:value ()
       
   121 				else
       
   122 					mood = item:name ()
       
   123 					-- here we can add child elements handling (by namespace)
       
   124 				end
       
   125 				item = item:next ()
       
   126 			end
       
   127 			if mood then
       
   128 				main.print_info ( from, ("Buddy's mood now %s %s"):format ( mood, desc or '' ) )
       
   129 			else
       
   130 				main.print_info ( from, "Buddy hides his mood" )
       
   131 			end
       
   132 		end
       
   133 pep.handlers['http://jabber.org/protocol/activity'] =
       
   134 		function ( from, node, data )
       
   135 			if not main.yesno ( main.option ( 'lua_pep_notification' ) ) then
       
   136 				return true
       
   137 			end
       
   138 			local item = data:children ()
       
   139 			local activity, desc
       
   140 			while item do
       
   141 				if item:name () == 'text' then
       
   142 					desc = item:value ()
       
   143 				else
       
   144 					activity = item:name ()
       
   145 					local subitem = item:children ()
       
   146 					if subitem then
       
   147 						-- here we can check for non-standard subactivity elements,
       
   148 						-- add subactivity child elements handling
       
   149 						activity = ("%s: %s"):format ( activity, subitem:name () )
       
   150 					end
       
   151 				end
       
   152 				item = item:next ()
       
   153 			end
       
   154 			if activity then
       
   155 				main.print_info ( from, ("Now %s %s"):format ( activity, desc or '' ) )
       
   156 			else
       
   157 				main.print_info ( from, "Buddy hides his activity" )
       
   158 			end
       
   159 			return true
       
   160 		end
       
   161 pep.handlers['http://jabber.org/protocol/geoloc'] =
       
   162 		function ( from, node, data )
       
   163 			if not main.yesno ( main.option ( 'lua_pep_notification' ) ) then
       
   164 				return true
       
   165 			end
       
   166 			local item = data:children ()
       
   167 			local text = ''
       
   168 			while item do
       
   169 				text = ("%s\n- %s: %s"):format ( text, item:name (), item:value () or '' )
       
   170 				item = item:next ()
       
   171 			end
       
   172 			if text ~= '' then
       
   173 				text = 'Now at:' .. text
       
   174 			else
       
   175 				text = 'Now in unknown location'
       
   176 			end
       
   177 			main.print_info ( from, text )
       
   178 			return true
       
   179 		end
       
   180 
       
   181 local function mpd_getstatus ()
       
   182 	local status = mpd.call_command { 'status' }
       
   183 	if not tune_enabled or ( status.state ~= 'play' and status.state ~= 'pause' ) then
       
   184 		for k, v in pairs ( mpd_pub_song ) do -- if there is anything published, publish nothing
       
   185 			return { }
       
   186 		end
       
   187 		return nil
       
   188 	end
       
   189 	
       
   190 	local song      = mpd.call_command { 'currentsong' }
       
   191 	local dir, file = song.file:match ( '(.+)/(.-)' )
       
   192 	-- populate according to currentsong fields: artist - artist, length - time, source - album, title - title, track - id, rating - ?, uri - ?
       
   193 	local ret = {
       
   194 		artist = { song.artist or 'Unknown' },
       
   195 		length = { song.time                },
       
   196 		source = { song.album  or dir       },
       
   197 		title  = { song.title  or file      },
       
   198 		track  = { song.id                  },
       
   199 	}
       
   200 
       
   201 	if not song.time or song.time == '0' then -- XXX
       
   202 		ret.length = nil
       
   203 	end
       
   204 
       
   205 	local modified = false
       
   206 	for k, v in pairs ( ret ) do
       
   207 		if not mpd_pub_song[k] or mpd_pub_song[k][1] ~= v[1] then
       
   208 			modified = true
       
   209 			break
       
   210 		end
       
   211 	end
       
   212 	if not modified then
       
   213 		for k, v in pairs ( mpd_pub_song ) do
       
   214 			if not ret[k] or ret[k][1] ~= v[1] then
       
   215 				modified = true
       
   216 				break
       
   217 			end
       
   218 		end
       
   219 	end
       
   220 
       
   221 	if modified then
       
   222 		return ret
       
   223 	else
       
   224 		return nil
       
   225 	end
       
   226 end
       
   227 
       
   228 local function dummy ()
       
   229 end
       
   230 
       
   231 local function mpd_callback ()
       
   232 	local sdata = mpd_getstatus ()
       
   233 	if sdata then
       
   234 		sdata.xmlns = 'http://jabber.org/protocol/tune'
       
   235 		pep.publish ( lm.connection.bless ( main.connection () ), 'http://jabber.org/protocol/tune', { tune = sdata }, dummy, dummy )
       
   236 	end
       
   237 	if tune_enabled then
       
   238 		return true
       
   239 	else
       
   240 		return false
       
   241 	end
       
   242 end
       
   243 
       
   244 -- do not call it too fast, or you end up with many daemons at once
       
   245 local function enable_tune ( yn )
       
   246 	if yn == nil then
       
   247 		yn = true
       
   248 	end
       
   249 	if yn then
       
   250 		if not tune_enabled then
       
   251 			main.timer ( 15, mpd_callback )
       
   252 			tune_enabled = true
       
   253 			-- update status
       
   254 		end
       
   255 	else
       
   256 		if tune_enabled then
       
   257 			tune_enabled = false
       
   258 			-- update status
       
   259 		end
       
   260 	end
       
   261 end
       
   262 
       
   263 main.command ( 'tune',
       
   264 	function ( args )
       
   265 		local enable = main.yesno ( args )
       
   266 		if enable == nil then
       
   267 			if tune_enabled then
       
   268 				print ( "Tune notifications enabled" )
       
   269 			else
       
   270 				print ( "Tune notifications disabled" )
       
   271 			end
       
   272 		else
       
   273 			enable_tune ( enable )
       
   274 		end
       
   275 	end, false, 'yesno' )
       
   276 main.command ( 'mood',
       
   277 	function ( args )
       
   278 		local data = { xmlns = 'http://jabber.org/protocol/mood' }
       
   279 		local mood, text = args[1], args[2]
       
   280 		if text then
       
   281 			data.text  = { text }
       
   282 		end
       
   283 		if mood then
       
   284 			data[mood] = { }
       
   285 		end
       
   286 		pep.publish ( lm.connection.bless ( main.connection () ), 'http://jabber.org/protocol/mood', { mood = data }, dummy, dummy )
       
   287 	end, true )
       
   288 main.command ( 'activity',
       
   289 	function ( args )
       
   290 		local data = { xmlns = 'http://jabber.org/protocol/activity' }
       
   291 		local activity, text = args[1], args[2]
       
   292 		if text then
       
   293 			data.text = { text }
       
   294 		end
       
   295 		local act, subact = activity:match ( "(.-)%-(.+)" )
       
   296 		if not act then
       
   297 			act = activity
       
   298 		end
       
   299 		if act ~= '' then
       
   300 			data[act] = { }
       
   301 			if subact then
       
   302 				data[act][subact] = { }
       
   303 			end
       
   304 		end
       
   305 		pep.publish ( lm.connection.bless ( main.connection () ), 'http://jabber.org/protocol/activity', { activity = data }, dummy, dummy )
       
   306 	end, true )
       
   307 main.command ( 'location',
       
   308 	function ( args )
       
   309 		local data = { xmlns = 'http://jabber.org/protocol/geoloc' }
       
   310 		for key, val in pairs ( args ) do
       
   311 			data[key] = { val }
       
   312 		end
       
   313 		pep.publish ( lm.connection.bless ( main.connection () ), 'http://jabber.org/protocol/geoloc', { geoloc = data }, dummy, dummy )
       
   314 	end, true )
       
   315 
       
   316 commands_help['tune']     = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables publishing of notifications about playing music in your player (currently only mpd is supported)."
       
   317 commands_help['mood']     = "[mood [message]]\n\nPublishes your mood.\nNote, that for now it does not checks for mood validity, so, see xep0107 for valid moods."
       
   318 commands_help['activity'] = "[activity[-specific_activity] [text]]\n\nPublishes your activity.\nNote, that for now it does not checks for activity validity, so, see xep0108 for valid activity values."
       
   319 commands_help['location'] = "[-key value [-key value ...]]\n\nPublishes your current geolocation.\nValid keys are accuracy, alt, area, bearing, building, country, datum, description, error, floor, lat, locality, lon, postalcode, region, room, speed, street, text, timestamp and uri, according to xep0080."
       
   320 
    76 
   321 hooks_d['hook-post-connect'].pep =
    77 hooks_d['hook-post-connect'].pep =
   322 	function ( args )
    78 	function ( args )
   323 		lm.connection.bless( main.connection () ):handler ( pep_incoming_message_handler, 'message', 'normal' )
    79 		lm.connection.bless( main.connection () ):handler ( pep_incoming_message_handler, 'message', 'normal' )
   324 		pep_handler_registered = true
    80 		pep_handler_registered = true
   325 		if tune_enabled then
    81 		hooks_d['hook-post-connect'].pep = nil
   326 			mpd_callback ()
       
   327 		end
       
   328 		-- XXX may it confuse pairs()?
       
   329 		hooks_d['hook-post-connect'].pep =
       
   330 			function ( args )
       
   331 				if tune_enabled then
       
   332 					mpd_callback ()
       
   333 				end
       
   334 			end
       
   335 		hooks_d['hook-quit'].pep =
    82 		hooks_d['hook-quit'].pep =
   336 			function ( args )
    83 			function ( args )
   337 				if pep_handler_registered then
    84 				if pep_handler_registered then
   338 					lm.connection.bless( main.connection () ):handler ( pep_incoming_message_handler, 'message' )
    85 					lm.connection.bless( main.connection () ):handler ( pep_incoming_message_handler, 'message' )
   339 					pep_handler_registered = false
    86 					pep_handler_registered = false
   340 				end
    87 				end
   341 			end
    88 			end
   342 	end
    89 	end
   343 
    90 
   344 -- XXX this really should be initialized after connection establishment (?)
       
   345 --     but as this thing is implemented by now, it will be cached by server,
       
   346 --     and, thus, we will be unable to get notifications.
       
   347 main.add_feature ( 'http://jabber.org/protocol/tune+notify' )
       
   348 main.add_feature ( 'http://jabber.org/protocol/tune' )
       
   349 main.add_feature ( 'http://jabber.org/protocol/mood+notify' )
       
   350 main.add_feature ( 'http://jabber.org/protocol/mood' )
       
   351 main.add_feature ( 'http://jabber.org/protocol/activity+notify' )
       
   352 main.add_feature ( 'http://jabber.org/protocol/activity' )
       
   353 main.add_feature ( 'http://jabber.org/protocol/geoloc+notify' )
       
   354 main.add_feature ( 'http://jabber.org/protocol/geoloc' )
       
   355 
       
   356 -- vim: se ts=4: --
    91 -- vim: se ts=4: --