[PATCH 2/2] Add boardgamegeek fetch script
Steve Beattie
sbeattie at suse.de
Tue Oct 3 17:23:20 MDT 2006
This patch adds a fetcher script for pulling boardgames from the
boardgamegeek.com website, as well as the requisite bits to incorporate
the script into the tellico fetch dialogs. It of course depends on the
boardgame collection having been applied previously.
I've never used kdevelop; I'm not sure how concerned I should be that
I had to edit src/fetch/scripts/Makefile.am below the "don't edit below
this line" warning.
It's written in ruby; note that this was also a learning exercise to
familiarize myself with ruby. There are quite likely some ruby idioms
unknown to me that would simplify the code.
Quite likely this should have been done as some kind of XSLT thingy,
given the boardgamegeek is emitting xml. But I know nothing about XSLT
and I wouldn't have had an excuse to write ruby code. :-)
---
src/fetch/fetchmanager.cpp | 2
src/fetch/scripts/Makefile.am | 9 +
src/fetch/scripts/boardgamegeek.rb | 175 ++++++++++++++++++++++++++++++++
src/fetch/scripts/boardgamegeek.rb.spec | 7 +
4 files changed, 190 insertions(+), 3 deletions(-)
Index: tellico/src/fetch/scripts/boardgamegeek.rb
===================================================================
--- /dev/null
+++ tellico/src/fetch/scripts/boardgamegeek.rb
@@ -0,0 +1,175 @@
+#!/usr/bin/env ruby
+#
+# ***************************************************************************
+# copyright : (C) 2006 by Steve Beattie
+# email : sbeattie at suse.de
+# ***************************************************************************
+#
+# ***************************************************************************
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of version 2 of the GNU General Public License as *
+# * published by the Free Software Foundation; *
+# * *
+# ***************************************************************************
+
+# $Id: boardgamegeek.rb 313 2006-10-02 22:17:11Z steve $
+
+# This program is expected to be invoked from tellico
+# (http://periapsis.org/tellico) as an external data source. It provides
+# searches for boardgames from the boardgamegeek.com website, via
+# boardgamegeek's xmlapi interface
+# (http://www.boardgamegeek.com/xmlapi/)
+#
+# It only allows searches via name; the boardgamegeek xmlapi is not yet
+# rich enough to support queries by designer, publisher, category, or
+# mechanism. I'd like to add support for querying by boardgamegeek id,
+# but that needs additional support in tellico.
+#
+require 'rexml/document'
+require 'net/http'
+require 'cgi'
+include REXML
+
+$my_version = '$Rev: 313 $'
+
+class Game
+ attr_writer :year
+ attr_writer :description
+
+ def initialize(name, id)
+ @name = name
+ @id = id
+ @publishers = []
+ @designers = []
+ @players = []
+ end
+
+ def add_publisher(publisher)
+ @publishers << publisher
+ end
+
+ def add_designer(designer)
+ @designers << designer
+ end
+
+ def add_players(players)
+ @players << players
+ end
+
+ def to_s()
+ "@name (#@id #@publishers #@year)"
+ end
+
+ def toXML()
+ element = Element.new 'entry'
+ element.add_element Element.new('title').add_text(@name)
+ element.add_element Element.new('description').add_text(@description) if @description
+ element.add_element Element.new('year').add_text(@year) if @year
+ element.add_element Element.new('boardgamegeek-link').add_text("http://www.boardgamegeek/game/#{@id}") if @id
+ element.add_element Element.new('bggid').add_text(@id) if @id
+ if @publishers.length > 0
+ pub_elements = Element.new('publishers')
+ @publishers.each {|p| pub_elements.add_element Element.new('publisher').add_text(p)}
+ element.add_element pub_elements
+ end
+ if @designers.length > 0
+ des_elements = Element.new('designers')
+ @designers.each {|d| des_elements.add_element Element.new('designer').add_text(d)}
+ element.add_element des_elements
+ end
+ if @players.length > 0
+ players_elements = Element.new('num-players')
+ @players.each {|n| players_elements.add_element Element.new('num-player').add_text(n.to_s)}
+ element.add_element players_elements
+ end
+ return element
+ end
+end
+
+def getGameList(query)
+ #puts("Query is #{query}")
+
+ search_result = nil
+ Net::HTTP.start('www.boardgamegeek.com', 80) do
+ |http| search_result = (http.get("/xmlapi/search?search=#{CGI.escape(query)}",
+ {"User-Agent" => "BoardGameGeek plugin for Tellico #{$my_version}"}).body)
+ http.finish
+ end
+ doc = REXML::Document.new(search_result)
+
+ games = XPath.match(doc, "//game")
+ #games.each {|g| puts g.elements['name'].text+g.attributes['gameid']}
+ ids = []
+ games.each {|g| ids << g.attributes['gameid']}
+ return ids
+end
+
+def getGameDetails(ids)
+ #ids.each {|id| puts id}
+
+ query = "/xmlapi/game/#{ids.join(',')}"
+ #puts query
+ search_result = nil
+ Net::HTTP.start('www.boardgamegeek.com', 80) do
+ |http| search_result = (http.get(query, {"User-Agent" => "BoardGameGeek plugin for Tellico #{$my_version}"}).body)
+ end
+ doc = REXML::Document.new(search_result)
+
+ games_xml = XPath.match(doc, "//game")
+
+ games = []
+ games_xml.each do
+ |g| game = Game.new(g.elements['name'].text,
+ g.attributes['gameid'])
+ game.year = g.elements['yearpublished'].text
+ game.description = g.elements['description'].text
+ g.elements.each('publisher'){|p| game.add_publisher p.elements['name'].text}
+ g.elements.each('designer'){|d| game.add_designer d.elements['name'].text}
+ minp = Integer(g.elements['minplayers'].text)
+ maxp = Integer(g.elements['maxplayers'].text)
+ minp.upto(maxp) {|n| game.add_players(n)}
+ games << game
+ end
+ return games
+end
+
+def listToXML(gameList)
+ doc = REXML::Document.new
+ doc << REXML::DocType.new('tellico PUBLIC', '"-//Robby Stephenson/DTD Tellico V9.0//EN" "http://periapsis.org/tellico/dtd/v9/tellico.dtd"')
+ doc << XMLDecl.new
+ tellico = Element.new 'tellico'
+ tellico.add_attribute('xmlns', 'http://periapsis.org/tellico/')
+ tellico.add_attribute('syntaxVersion', '9')
+ collection = Element.new 'collection'
+ collection.add_attribute('title', 'My Collection')
+ collection.add_attribute('type', '13')
+ id = 0
+ gameList.each do
+ |g| element = g.toXML()
+ element.add_attribute('id', id)
+ id = id + 1
+ collection.add_element(element)
+ end
+ tellico.add_element(collection)
+ doc.add_element(tellico)
+ doc.write($stdout, 0)
+ puts ""
+end
+
+if __FILE__ == $0
+
+ def showUsage
+ warn "usage: #{__FILE__} game_query"
+ exit 1
+ end
+
+ showUsage unless ARGV.length == 1
+
+ idList = getGameList(ARGV.shift)
+ if idList
+ gameList = getGameDetails(idList)
+ end
+
+ listToXML(gameList)
+end
Index: tellico/src/fetch/scripts/boardgamegeek.rb.spec
===================================================================
--- /dev/null
+++ tellico/src/fetch/scripts/boardgamegeek.rb.spec
@@ -0,0 +1,7 @@
+Name=BoardGameGeek
+Type=data-source
+ArgumentKeys=1
+Arguments=%1
+CollectionType=13
+FormatType=0
+UpdateArgs=%{title}
Index: tellico/src/fetch/fetchmanager.cpp
===================================================================
--- tellico.orig/src/fetch/fetchmanager.cpp
+++ tellico/src/fetch/fetchmanager.cpp
@@ -512,6 +512,8 @@ QPixmap Manager::fetcherIcon(Fetch::Fetc
u = QString::fromLatin1("http://www.mcu.es");
} else if(p.find(QString::fromLatin1("dark_horse_comics")) > -1) {
u = QString::fromLatin1("http://www.darkhorse.com");
+ } else if(p.find(QString::fromLatin1("boardgamegeek")) > -1) {
+ u = QString::fromLatin1("http://www.boardgamegeek.com");
} else if(f->source().find(QString::fromLatin1("amarok"), 0, false /*case-sensitive*/) > -1) {
return SmallIcon(QString::fromLatin1("amarok"));
}
Index: tellico/src/fetch/scripts/Makefile.am
===================================================================
--- tellico.orig/src/fetch/scripts/Makefile.am
+++ tellico/src/fetch/scripts/Makefile.am
@@ -3,7 +3,8 @@
EXTRA_DIST = \
fr.allocine.py fr.allocine.py.spec \
ministerio_de_cultura.py ministerio_de_cultura.py.spec \
-dark_horse_comics.py dark_horse_comics.py.spec
+dark_horse_comics.py dark_horse_comics.py.spec \
+boardgamegeek.rb boardgamegeek.rb.spec
####### kdevelop will overwrite this part!!! (end)############
@@ -11,11 +12,13 @@ scriptdir = $(kde_datadir)/tellico/data-
script_SCRIPTS = \
fr.allocine.py \
ministerio_de_cultura.py \
-dark_horse_comics.py
+dark_horse_comics.py \
+boardgamegeek.rb
script_DATA = \
fr.allocine.py.spec \
ministerio_de_cultura.py.spec \
-dark_horse_comics.py.spec
+dark_horse_comics.py.spec \
+boardgamegeek.rb.spec
KDE_OPTIONS = noautodist
--
Steve Beattie
SUSE Labs, Novell Inc.
<sbeattie at suse.de>
http://NxNW.org/~steve/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://forge.novell.com/pipermail/tellico-users/attachments/20061003/9a02c917/attachment.pgp
More information about the tellico-users
mailing list