#!/usr/bin/ruby # (c) 2005-2006 Frederik Deweerdt frederik.deweerdt@gmail.com # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA require 'net/ftp' class RGBColor def initialize(rgb, factor=0.9) @r = Float((rgb & 0xff0000) >> 16) @g = Float((rgb & 0x00ff00) >> 8) @b = Float((rgb & 0x0000ff)) @factor = Float(factor) end#def initialize def lighten! @r +=1; @g += 1; @b += 1 @r = (@r / @factor) % 255 @g = (@g / @factor) % 255 @b = (@b / @factor) % 255 return self end#def lighten! def darken! @r -=1; @g -= 1; @b -= 1 @r = (@r * @factor) % 255 @g = (@g * @factor) % 255 @b = (@b * @factor) % 255 return self end#def darken! def to_s return sprintf("%02x%02x%02x", @r.to_i, @g.to_i, @b.to_i); end#def to_s end#class RGBColor class Rectangle attr_writer :width,:height,:area attr_reader :width,:height,:area,:news_topic def initialize (width, height, news_topic) @width = Float(width) @height = Float(height) @news_topic = news_topic end#intialize def area return @width * @height end#def area def ratio ret = @width / @height ret = 1 / ret if ret < 1 return ret end#def ratio def to_s return "[#{@width},#{@height},@#{area},r#{ratio}]" end#to_s end#class Rectangle class Row attr_reader :kind,:elements HORIZ = 0 VERT = 1 def initialize(kind,length) @kind = kind @fixed_side_length = length @elements = Array.new @ratio = 9999 end#initialize def area area = 0.0 @elements.each { |r| area += r.area } return area end def width return area / @fixed_side_length if @kind == VERT return @fixed_side_length end#width def height return area / @fixed_side_length if @kind == HORIZ return @fixed_side_length end#height def recalculate_layout #puts "#{area} / #{@fixed_side_length}" variable_side_lenth = area / @fixed_side_length new_elem = Array.new if @kind == VERT then @elements.each { |r| new_elem.push(Rectangle.new(variable_side_lenth, r.area / variable_side_lenth,r.news_topic)) } else @elements.each { |r| new_elem.push(Rectangle.new(r.area / variable_side_lenth, variable_side_lenth, r.news_topic)) } end#if @elements = new_elem end#recalculate_layout public def push(o) @elements.push(o) recalculate_layout better = false better = true if @elements.last.ratio < @ratio @ratio = @elements.last.ratio return better end#push def pop() o = @elements.pop() recalculate_layout return o end#pop def to_s ret = String.new ret += "=====\n" @elements.each { |r| ret += "#{r.to_s}\n" } ret += "-----\n" end#dump_row end#class Row class Frame def initialize(org_x, org_y, width, height) @org_x = org_x @org_y = org_y @width = width @height = height @free_x = 0 @free_y = 0 @current_row = free_width > free_height ? Row.new(Row::VERT, free_height) : Row.new(Row::HORIZ,free_width) @rows = Array.new end#initialize def free_width @width - @free_x end#free_width def free_height @height - @free_y end#free_width def add(area, nt) r = Rectangle.new(area, 1, nt) if not @current_row.push(r) then @current_row.pop() @rows.push(@current_row) @free_x += @current_row.width if @current_row.kind == Row::VERT @free_y += @current_row.height if @current_row.kind == Row::HORIZ @current_row = free_width > free_height ? Row.new(Row::VERT, free_height) : Row.new(Row::HORIZ,free_width) @current_row.push(r) end#if end#add def to_s @rows.each do |row| puts row end#each puts @current_row end#to_s public def to_html(colors_by_topic) s = "" pencil_x = @org_x pencil_y = @org_y previous_pencil_x = pencil_x previous_pencil_y = pencil_y zoom = 1 border = 0 @rows.push(@current_row) @rows.each do |row| previous_pencil_x = pencil_x previous_pencil_y = pencil_y row.elements.each do |r| color = colors_by_topic[r.news_topic.category]; colors_by_topic[r.news_topic.category] = color.darken! news_title = r.news_topic.text.gsub(/"/,'"').gsub(/\[\d*\]/, '') font_size = Integer(Math.log(pus(r.area,6) / r.news_topic.title.length)/6) s += "
" s += "

#{r.news_topic.title} (#{r.news_topic.related_count} articles...)

" if r.news_topic.title_link != nil s += "
\"News
" if r.news_topic.image_url != nil s+= "
\n" pencil_y += Integer(r.height*zoom) + border if row.kind == Row::VERT pencil_x += Integer(r.width*zoom) + border if row.kind == Row::HORIZ end#do row.elements.each if row.kind == Row::VERT && row.elements.last != nil then pencil_x += Integer(row.elements.last.width * zoom) + border pencil_y = previous_pencil_y end#if if row.kind == Row::HORIZ && row.elements.last != nil then pencil_y += Integer(row.elements.last.height * zoom) + border pencil_x = previous_pencil_x end#if end#each @rows.pop() return s end#to_html def pus (int, pow) res = int while pow > 1 do res *= int pow -= 1 end#while return res end#pus end#class Frame class NewsLang private def initialize(end_of_gn, end_of_article, in_the_news, related_articles, topic_separator, \ top_stories, more_top_stories, command, customize_begin, customize_end) @end_of_gn = end_of_gn @end_of_article = end_of_article @in_the_news = in_the_news @related_articles = related_articles @topic_separator = topic_separator @top_stories = top_stories @more_top_stories = more_top_stories @command = command @customize_begin = customize_begin @customize_end = customize_end end#def initialize public attr_reader :end_of_gn, :related_articles,:end_of_article,:in_the_news,:top_stories,:command, :topic_separator, :more_top_stories, :customize_begin, :customize_end; FR = NewsLang.new("Versions internationales de Google Actualités disponibles", \ "articles connexes", \ "Google Actualit.s", \ '\[(\d+)\]et (\d+) articles connexes', \ '(\[\d+\]([\w|\/|\(|\)| ]+)\s\s>>)|(la une \(suite\))', \ "À la une", \ ". la une .suite.", \ '|lynx -cfg /dev/null -width 2000 -image_links -dump http://news.google.com/news?ned=fr', \ #'|wget --user-agent=Mozilla -O /dev/stdout http://news.google.com/news?ned=fr 2> /dev/null|lynx -width 200 -image_links -stdin -dump|iconv -c -f ISO_8859-1 -t UTF-8', \ #'|wget --user-agent=Mozilla -O /dev/stdout http://news.google.fr/news?ned=fr 2> /dev/null|lynx -width 200 -image_links -stdin -dump', \ #'|cat fr.txt', \ 'Personnaliser cette page', \ 'Personnaliser cette page fermer'); EN = NewsLang.new("International versions of Google News available in", \ 'related', \ "Google News", \ '\[(\d+)\]all ([\d|,]+) related', \ '(\[\d+\]([\w|\/|\(|\)| |\.]+)\s\s»)|(More Top Stories)', \ 'Top Stories', \ 'More Top Stories', \ '|lynx -cfg /dev/null -width 2000 -image_links -dump http://news.google.com/news', \ 'Customize this page', \ 'Customize this page close'); # ES = NewsLang.new("Versiones internacionales de Google Noticias disponibles en", # "culos relacionados", # "Es noticia", # '\[(\d+)\]y (\d+) art.culos relacionados', # '(\[\d+\]([\w|\/|\(|\)| ]+)\s\s>>)|(noticias destacadas)'); end#class NewsLang class NewsPage attr_reader :articles,:no_articles,:display_as_text,:no_articles_by_topic,:articles_by_topic,:topics LinesToSkip = 35 def initialize(lines, limit=0, ns=NewsLang::EN) end_of_article = false skip=LinesToSkip topic = "" @articles = Array.new @no_articles = 0 @links = Array.new @topics = Array.new @ns = ns category = @ns.top_stories lines.each do |line| if line =~ /(\d+)\. (http:\/\/.*)/ then @links[$1.to_i] = $2 end#if end#each image_index = nil image_url_index = nil in_the_news = false in_customize_html = false expecting_category = true lines.each { |line| in_the_news = true if line =~ /#{ns.in_the_news}/ next if not in_the_news in_customize_html = true if line =~ /#{ns.customize_begin}/ in_customize_html = false if line =~ /#{ns.customize_end}/ next if in_customize_html # Category? if line =~ /cleardot\.gif/ then expecting_category = true next end#if # Category found if expecting_category and in_the_news then expecting_category = false if line =~ /\[\d+\]([\w|\/| ]+) / or line =~ /(#{ns.more_top_stories})/ then category = $1 end#if next end#if # Article found if line =~ /#{ns.related_articles}/ then related_link = @links[$1.to_i] related_count = $2.strip.gsub(',','').to_i art_line_array = Array.new tmp_image_line_array = Array.new search_for_image = false image_url = nil image_link = nil lines.slice(0,lines.index(line)+1).reverse.each { |l| search_for_image = true if not search_for_image and l.strip.empty? # Search the image if search_for_image then tmp_image_line_array.push(l) break if tmp_image_line_array.size > 3 if l =~ /\[(.*)\]\[.*\]-\[(.*)\]\[.*\]/ then image_link = @links[$1.to_i] image_url = @links[$2.to_i] break; end#if else art_line_array.push(l.strip) end#if } art_line_array.reverse[0] =~ /\[(\d+)\](.*)/ title = $2.strip unless $2 == nil title_link = @links[$1.to_i] text = art_line_array.reverse.grep(/^[^\[]/).slice(1,4).join nt = NewsTopic.new(title, title_link, text, image_url, image_link, related_link, related_count, category) @articles.push(nt) @no_articles += nt.related_count end#if } # # Assign percentages # articles.each do |art| art.pct = art.related_count * 100 / @no_articles end#do # # Sort articles by topic # @articles_by_topic = Hash.new @no_articles_by_topic = Hash.new articles.each do |art| if not @articles_by_topic.has_key?(art.category) then @articles_by_topic[art.category] = Array.new @no_articles_by_topic[art.category] = 0 @topics.push(art.category) end#if @articles_by_topic[art.category].push(art) @no_articles_by_topic[art.category] += art.related_count end#do end#initialize def display_as_text pct = 0.0 articles.sort.each { |art| pct += art.no_articles.to_f * 100.0 / @no_articles.to_f #puts "#{art.no_articles.to_f * 100.0 / @no_articles.to_f}%" puts art.to_s } end#display_as_text end#class NewsPage class NewsTopic attr_reader :title, :title_link, :text, :image_url, :image_link, :related_link, :related_count, :category, :pct attr_writer :pct def initialize(title, title_link, text, image_url, image_link, related_link, related_count, category) @title = title @title_link = title_link @text = text @image_url = image_url @image_link = image_link @related_link = related_link @related_count = related_count @category = category @pct = nil end#initialize def <=>(nt) return @related_count <=> nt.related_count if @category != nt.category then return @category <=> nt.category else return @related_count <=> nt.related_count end#if end# <=> def to_s return "*#{@title}*\t #{@category}\t #{@related_count}\n#{@text}" end#to_s end#class NewsTopic def generate_html(fileout, lang, limit) file = Kernel.open(lang.command) np = NewsPage.new(file.readlines, limit, lang) file.close colors = Array.new colors.push(RGBColor.new(0xffcc11)) colors.push(RGBColor.new(0x111188)) colors.push(RGBColor.new(0x118111)) colors.push(RGBColor.new(0xcc11111)) colors.push(RGBColor.new(0xff6611)) colors.push(RGBColor.new(0x663399)) colors.push(RGBColor.new(0xcccccc)) colors.push(RGBColor.new(0x669999)) colors.push(RGBColor.new(0xfedcba)) coltop = Hash.new i = 0 np.topics.each { |t| coltop[t] = colors[i] i += 1 } fileout.puts < Open News Map logo
  • Legend

  • EOF coltop.each_key { |topic| fileout.puts "
  • #{topic}

  • " } fileout.puts <
  • Generated at #{Time.new.strftime("%I:%M%p")}

EOF width = 600 height = 800 pencil_x = 130 pencil_y = 150 area = width * height som_sqrt = 0 border = 5 f = Frame.new(pencil_x, pencil_y, width,height) border = 10 #fileout.puts "
" np.articles.sort.reverse.each do |art| next if art.related_count == 0 som_sqrt += Math.sqrt(art.related_count) end#each np.articles.sort.reverse.each do |art| next if art.related_count == 0 f.add(Math.sqrt(art.related_count)*area / som_sqrt, art) end#each_key fileout.puts f.to_html(coltop) fileout.puts "

© 2005 - open-news.net. Tous droits reservés

" fileout.puts "" end#def generate_html generate_html(File.new('index.html','w+'), NewsLang::EN, 30) generate_html(File.new('index_fr.html','w+'), NewsLang::FR, 10)