X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Fyoutube.rb;h=abda9ca311fa88e5037f220c680a1583cd22a4fb;hb=6cf365c49ce5fbe24c0a4ff0663550390b501fea;hp=2f009f11994aeed6bb7555bb4c17b32d45202370;hpb=08e27c3aa7aa63bdd2f65e26c431804a182aee84;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/youtube.rb b/data/rbot/plugins/youtube.rb index 2f009f11..abda9ca3 100644 --- a/data/rbot/plugins/youtube.rb +++ b/data/rbot/plugins/youtube.rb @@ -10,7 +10,9 @@ class YouTubePlugin < Plugin YOUTUBE_SEARCH = "http://gdata.youtube.com/feeds/api/videos?vq=%{words}&orderby=relevance" - YOUTUBE_VIDEO = "http://gdata.youtube.com/feeds/api/videos/%{code}" + YOUTUBE_VIDEO = "http://gdata.youtube.com/feeds/api/videos/%{id}" + + YOUTUBE_VIDEO_URLS = %r{youtube.com/(?:watch\?(?:.*&)?v=|v/)(.*?)(&.*)?$} Config.register Config::IntegerValue.new('youtube.hits', :default => 3, @@ -18,13 +20,22 @@ class YouTubePlugin < Plugin Config.register Config::IntegerValue.new('youtube.descs', :default => 3, :desc => "When set to n > 0, the bot will return the description of the first n videos found") + Config.register Config::BooleanValue.new('youtube.formats', + :default => true, + :desc => "Should the bot display alternative URLs (swf, rstp) for YouTube videos?") + + def help(plugin, topic="") + 'youtube [search] : searches youtube videos | youtube info : returns description and video links' + end def youtube_filter(s) loc = Utils.check_location(s, /youtube\.com/) return nil unless loc - if s[:text].include? '
' - video_info = @bot.filter(:"youtube.video", s) - return nil # TODO + if s[:text].include? ' content) elsif s[:text].include? '' vids = @bot.filter(:"youtube.search", s)[:videos] if !vids.empty? @@ -33,10 +44,11 @@ class YouTubePlugin < Plugin end # otherwise, just grab the proper div if defined? Hpricot - content = (Hpricot(s[:text])/"#mainContent").to_html.ircify_html + content = (Hpricot(s[:text])/".watch-video-desc").to_html.ircify_html end # suboptimal, but still better than the default HTML info extractor - content ||= /
]*>/.match(s[:text]).post_match.ircify_html + dm = /]*>/.match(s[:text]) + content ||= dm ? dm.post_match.ircify_html : '(no description found)' return {:title => s[:text].ircify_html_title, :content => content} end @@ -49,32 +61,57 @@ class YouTubePlugin < Plugin # :title => mg["media:title"].text # fails because "media:title" is not an Integer. Bah vid = { + :formats => [], :author => (e.elements["author/name"].text rescue nil), :title => (e.elements["media:group/media:title"].text rescue nil), :desc => (e.elements["media:group/media:description"].text rescue nil), :cat => (e.elements["media:group/media:category"].text rescue nil), - :seconds => (e.elements["media:group/yt:duration/@seconds"].value.to_i rescue nil), - :url => (e.elements["media:group/media:player/@url"].value rescue nil), - :rating => (("%s/%s" % [e.elements["gd:rating/@average"].value, e.elements["gd:rating/@max"].value]) rescue nil), - :views => (e.elements["yt:statistics/@viewCount"].value rescue nil), - :faves => (e.elements["yt:statistics/@favoriteCount"].value rescue nil) + :seconds => (e.elements["media:group/yt:duration/"].attributes["seconds"].to_i rescue nil), + :url => (e.elements["media:group/media:player/"].attributes["url"] rescue nil), + :rating => (("%s/%s" % [e.elements["gd:rating"].attributes["average"], e.elements["gd:rating/@max"].value]) rescue nil), + :views => (e.elements["yt:statistics"].attributes["viewCount"] rescue nil), + :faves => (e.elements["yt:statistics"].attributes["favoriteCount"] rescue nil) } if vid[:desc] vid[:desc].gsub!(/\s+/m, " ") end if secs = vid[:seconds] - mins, secs = secs.divmod 60 - hours, mins = mins.divmod 60 - if hours > 0 - vid[:duration] = "%s:%s:%s" % [hours, mins, secs] - elsif mins > 0 - vid[:duration] = "%s'%s\"" % [mins, secs] - else - vid[:duration] = "%ss" % [secs] - end + vid[:duration] = Utils.secs_to_short(secs) else vid[:duration] = _("unknown duration") end + e.elements.each("media:group/media:content") { |c| + if url = (c.attributes["url"] rescue nil) + type = c.attributes["type"] rescue nil + medium = c.attributes["medium"] rescue nil + expression = c.attributes["expression"] rescue nil + seconds = c.attributes["duration"].to_i rescue nil + fmt = case num_fmt = (c.attributes["yt:format"] rescue nil) + when "1" + "h263+amr" + when "5" + "swf" + when "6" + "mp4+aac" + when nil + nil + else + num_fmt + end + vid[:formats] << { + :url => url, :type => type, + :medium => medium, :expression => expression, + :seconds => seconds, + :numeric_format => num_fmt, + :format => fmt + }.delete_if { |k, v| v.nil? } + if seconds + vid[:formats].last[:duration] = Utils.secs_to_short(seconds) + else + vid[:formats].last[:duration] = _("unknown duration") + end + end + } debug vid return vid end @@ -83,6 +120,7 @@ class YouTubePlugin < Plugin vids = [] title = nil begin +debug s.inspect doc = REXML::Document.new(s[:text]) title = doc.elements["feed/title"].text doc.elements.each("*/entry") { |e| @@ -102,8 +140,32 @@ class YouTubePlugin < Plugin return [] end + # Filter a YouTube video URL def youtube_video_filter(s) - # TODO + id = s[:youtube_video_id] + if not id + url = s.key?(:headers) ? s[:headers]['x-rbot-location'].first : s[:url] + debug url + id = YOUTUBE_VIDEO_URLS.match(url).captures.first rescue nil + end + return nil unless id + + debug id + + url = YOUTUBE_VIDEO % {:id => id} + resp = @bot.httputil.get_response(url) + xml = resp.body + unless resp.kind_of? Net::HTTPSuccess + debug("error looking for movie %{id} on youtube: %{e}" % {:id => id, :e => xml}) + return nil + end + debug xml + begin + return @bot.filter(:"youtube.apivideo", DataStream.new(xml, s)) + rescue => e + debug e + return nil + end end def initialize @@ -117,38 +179,24 @@ class YouTubePlugin < Plugin def info(m, params) movie = params[:movie] - code = "" - case movie - when %r{youtube.com/watch\?v=(.*?)(&.*)?$} - code = $1.dup - when %r{youtube.com/v/(.*)$} - code = $1.dup - when /^[A-Za-z0-9]+$/ - code = movie.dup - end - if code.empty? - m.reply _("What movie was that, again?") - return + id = nil + if movie =~ /^[A-Za-z0-9]+$/ + id = movie.dup end - url = YOUTUBE_VIDEO % {:code => code} - resp, xml = @bot.httputil.get_response(url) - unless Net::HTTPSuccess === resp - m.reply(_("error looking for movie %{code} on youtube: %{e}") % {:code => code, :e => xml}) - return - end - debug "filtering XML" - debug xml - begin - vid = @bot.filter(:"youtube.apivideo", DataStream.new(xml, params)) - rescue => e - debug e - end + vid = @bot.filter(:"youtube.video", :url => movie, :youtube_video_id => id) if vid - m.reply(_("Video: %{bold}%{title}%{bold} [%{cat}] %{rating} @ %{url} by %{author} (%{duration}). %{views} views, faved %{faves} times.\nDescription: %{desc}") % - {:bold => Bold}.merge(vid)) + str = _("%{bold}%{title}%{bold} [%{cat}] %{rating} @ %{url} by %{author} (%{duration}). %{views} views, faved %{faves} times. %{desc}") % + {:bold => Bold}.merge(vid) + if @bot.config['youtube.formats'] and not vid[:formats].empty? + str << _("\n -- also available at: ") + str << vid[:formats].inject([]) { |list, fmt| + list << ("%{url} %{type} %{format} (%{duration} %{expression} %{medium})" % fmt) + }.join(', ') + end + m.reply str else - m.reply(_("couldn't retrieve infos on video code %{code}") % {:code => code}) + m.reply(_("couldn't retrieve video info") % {:id => id}) end end @@ -156,8 +204,9 @@ class YouTubePlugin < Plugin what = params[:words].to_s searchfor = CGI.escape what url = YOUTUBE_SEARCH % {:words => searchfor} - resp, xml = @bot.httputil.get_response(url) - unless Net::HTTPSuccess === resp + resp = @bot.httputil.get_response(url) + xml = resp.body + unless resp.kind_of? Net::HTTPSuccess m.reply(_("error looking for %{what} on youtube: %{e}") % {:what => what, :e => xml}) return end @@ -193,3 +242,4 @@ plugin = YouTubePlugin.new plugin.map "youtube info :movie", :action => 'info', :threaded => true plugin.map "youtube [search] *words", :action => 'search', :threaded => true +