Mpd uses pubsub
authorMyhailo Danylenko <isbear@ukrpost.net>
Sat, 14 Mar 2009 16:51:11 +0200
changeset 19 365e77518376
parent 18 ba74a9aadaf4
child 20 fd96da2c3acc
Mpd uses pubsub
TODO
examples/mpd.lua
--- a/TODO	Sun Mar 08 01:03:22 2009 +0200
+++ b/TODO	Sat Mar 14 16:51:11 2009 +0200
@@ -10,4 +10,5 @@
 well, so, mcabber will pass all arguments to hooks in utf. but do we really need to convert names to utf?
 use glib filename charset conversion functions?
 toggle routine should handle multiple status toggles.
+dig, why mpd does not sends empty publish request on start
 
--- a/examples/mpd.lua	Sun Mar 08 01:03:22 2009 +0200
+++ b/examples/mpd.lua	Sat Mar 14 16:51:11 2009 +0200
@@ -115,33 +115,76 @@
 	['?'] = 'message',
 }
 
+mpd_pub_song = { xmlns = 'http://jabber.org/protocol/tune' }
+
 function mpd_getstatus ()
 	if not mpd_enabled then
-		return ''
+		mpd_pub_song.artist = nil
+		mpd_pub_song.length = nil
+		mpd_pub_song.source = nil
+		mpd_pub_song.title  = nil
+		mpd_pub_song.track  = nil
+		return mpd_pub_song
 	end
 	
 	local stats = mpd.call_command { 'status', 'currentsong' }
 	if stats[1].state ~= 'play' and stats[1].state ~= 'pause' then
-		return ''
+		mpd_pub_song.artist = nil
+		mpd_pub_song.length = nil
+		mpd_pub_song.source = nil
+		mpd_pub_song.title  = nil
+		mpd_pub_song.track  = nil
+		return mpd_pub_song
+	end
+
+	local dir, file = stats[2].file:match ( '(.+)/(.-)' )
+	local modified  = false
+	-- populate according to currentsong fields: artist - artist, length - time, source - album, title - title, track - id, rating - ?, uri - ?
+	local artist, length, source, title, track = stats[2].artist, stats[2].time, stats[2].album, stats[2].title, stats[2].id
+	
+	if not artist or artist == '' then
+		artist = 'Unknown'
+	end
+	if not mpd_pub_song.artist or artist ~= mpd_pub_song.artist[1] then
+		mpd_pub_song.artist = { artist }
+		modified = true
 	end
 
-	local title = stats[2].title
-	if not title then
-		if stats[2].file then
-			title = stats[2].file
-		else
-			title = ''
+	if length and length ~= 0 then
+		if not mpd_pub_song.length or length ~= mpd_pub_song.length[1] then
+			mpd_pub_song.length = { length }
+			modified = true
 		end
-	elseif not stats[2].artist then
-		title = string.format ( "%s (%s)", title, stats[2].file )
-	else
-		title = string.format ( "%s - %s", stats[2].artist, title )
+	elseif mpd_pub_song.length then -- no length
+		mpd_pub_song.length = nil
+		modified = true
+	end
+
+	if not source or source == '' then
+		source = dir
+	end
+	if not mpd_pub_song.source or source ~= mpd_pub_song.source[1] then
+		mpd_pub_song.source = { source }
+		modified = true
 	end
 
-	if stats[1].state == 'pause' then
-		return string.format ( "[mpd: <зупинено> %s]", title )
+	if not title or title == '' then
+		title = file
+	end
+	if not mpd_pub_song.title or title ~= mpd_pub_song.title[1] then
+		mpd_pub_song.title = { title }
+		modified = true
+	end
+
+	if not mpd_pub_song.track or track ~= mpd_pub_song.track[1] then
+		mpd_pub_song.track = { track }
+		modified = true
+	end
+
+	if modified then
+		return mpd_pub_song
 	else
-		return string.format ( "[mpd: %s]", title )
+		return nil
 	end
 end
 
@@ -157,10 +200,21 @@
 end
 
 function mpd_callback ()
-	local new_mpd_string = mpd_getstatus ()
-	local status, message, mpd_string = parse_status ()
-	if new_mpd_string ~= mpd_string then
-		main.run ( string.format ( 'status %s %s %s', status, message, new_mpd_string ) )
+	local sdata = mpd_getstatus ()
+	if sdata then
+		local conn = lm.connection.bless ( main.connection () )
+		if conn:status () == 'authenticated' then
+			conn:send (
+				lm.message.create { mtype = 'iq-set', from = conn:jid (),
+					pubsub = { xmlns = 'http://jabber.org/protocol/pubsub',
+						publish = { node = 'http://jabber.org/protocol/tune',
+							item = {
+								tune = sdata,
+							},
+						},
+					},
+				})
+		end
 	end
 	if mpd_enabled then
 		return true
@@ -204,12 +258,51 @@
 
 commands_help['mpd'] = "[enable|disable|on|off|yes|no|true|false]\n\nSets state of mpd string in your status.\nIf state is omitted, prints current state."
 
--- XXX: why post-connect, why not start?
+mpd_incoming_message_handler = lm.message_handler.new (
+	function ( conn, mess )
+		-- we can add that validation stuff later, if it will be necessary
+		local tune = mess:path ( 'event', 'items', 'item', 'tune' )
+		if tune then
+			local from = mess:attribute ( 'from' )
+			local item = tune:children ()
+			main.print_info ( from, "Tunes notification:" )
+			while item do
+				main.print_info ( from, ("- %s: %s"):format ( item:name (), item:value () ) )
+				item = item:next ()
+			end
+			return true
+		end
+		return false
+	end )
+
+mpd_handler_registered = false
+
 hooks_d['hook-post-connect'].mpd =
 	function ( args )
+		lm.connection.bless( main.connection () ):handler ( mpd_incoming_message_handler, 'message', 'normal' )
+		mpd_handler_registered = true
+		hooks_d['hook-post-connect'].mpd =
+			function ( args )
+				if mpd_enabled then
+					mpd_callback ()
+				end
+			end
+		hooks_d['hook-quit'].mpd =
+			function ( args )
+				if mpd_handler_registered then
+					lm.connection.bless( main.connection () ):handler ( mpd_incoming_message_handler, 'message' )
+					mpd_handler_registered = false
+				end
+			end
 		if mpd_enabled then
 			mpd_callback ()
 		end
 	end
 
+-- XXX: this really should be initialized after connection establishment?
+-- but as this thing is implemented by now, it will be cached by server,
+-- and, thus, we will be unable to get notifications.
+main.add_feature ( 'http://jabber.org/protocol/tune' )
+main.add_feature ( 'http://jabber.org/protocol/tune+notify' )
+
 -- vim: se ts=4: --