// Class BackgroundLoader
// Part of Swimming Icons 1
// David Tames, Version 1d, July 14, 2010
// Periodically delete ten images to the pool and add 10 new images. Searches
// for images on flickr using tags as specified in the qTags global variable.
// Dependent on a php script running on a web server (source code at and of
// this file).
// Based, in part, on the example posted by Marius Watz at:
// http://processing.org/discourse/yabb2/YaBB.pl?board=Integrate;action=display;num=1204990614
// Copyright 2010 by David Tames, some rights reserved. This code is released
// under the terms of a Creative Commons Share-Alike Attribution License, for
// license text visit http://creativecommons.org/licenses/by-sa/2.5/ and for
// attribution please link to: http://kino-eye.com/dmi/swimming-icons/
// Serious Bug: does not stop at 4000....
class BackgroundLoader implements Runnable {
// query parameters
int qPerPage = 10; // how many images to get each query
int qPage = 0; // we'll start on page one (this gets incremented at start of loop)
String qTags = "arduino,processing,diy"; // default to something interesting
int total = 0; // total images processed so far with this query
int qTotal= 0; // total based on Flickr's response
int qMax= 4000; // limit you can fetch based on Flickr API documentation
PVector here;
boolean resultsAvailable = false;
// the specific icon in question in loops
SwimmingIcon thisIcon;
XMLElement xml;
void BackgroundLoader() {
if (TRACE) println ("BackgroundLoader: created");
}
void setQuery(String ns) {
qPage = 0;
qPerPage = 10;
qTags = ns;
total = 0;
qTotal= 0;
if (TRACE) println ("BackgroundLoader: query reset to tags=" + qTags);
}
void run () {
boolean running = true;
while (running) {
// Delete icons that swim out of bounds
for (int i = SwimmingIcons.size()-1; i >= 0; i--) {
SwimmingIcon thisIcon = (SwimmingIcon) SwimmingIcons.get(i);
PVector here = thisIcon.getPosition();
// did the icon swim out of bounds w/out getting tagged? then delete it!
if ((here.x < -80 || here.x > width || here.y < -60 || here.y > height) && !thisIcon.tagged()){
if (TRACE) println ("BackgroundLoader: delete icon (swam out of bounds) " + thisIcon.getImageName());
SwimmingIcons.remove(i);
} else if (thisIcon.deleted() == true) {
if (TRACE) println ("BackgroundLoader: delete icon (tagged) " + thisIcon.getImageName());
SwimmingIcons.remove(i);
}
}
// Delete icons
// if (SwimmingIcons.size() >= iconMaxCount)
// get 10 images at a time
// right now we don't fetch the total image count from flickr on the
// the server, WE NEED TO DO THAT SOON!
qPage++;
// please run query.php on your own server, source code is
// at the end of this file. The functionality of query.php will get
// moved into Processing in a future version.
String qURL = "http://kino-eye.com/dmi/flickr/query.php";
String qParameters = "?tags=" + qTags + "&p=" + qPage + "&pp=" + qPerPage;
// right now we use an array, eventually we'll use an ArrayList of
// images so we can delete images and when we do, we'll be loading
// more
// add more images to the pool (we'll go up to 10 over given this check?)
resultsAvailable = true;
if (SwimmingIcons.size() < iconMaxCount) {
if (TRACE) println ("BackgroundLoader: fetching: page=" + qPage + " perpage=" + qPerPage + " tags=" + qTags);
try {
xml = new XMLElement(getMyParent(), qURL + qParameters);
} catch (Exception e) {
if (TRACE) println ("BackgroundLoader: Error accessing server");
resultsAvailable = false;
if (TRACE) e.printStackTrace();
}
if (!resultsAvailable) {
if (TRACE) println ("BackgroundLoader: Data not available from server");
// eventually we'll load some test data here so we can run without net access
} else {
int page = xml.getIntAttribute("page");
int perpage = xml.getIntAttribute("perpage");
int qTotal = xml.getIntAttribute("total");
// NEED TO DEAL w/ Flickr's 4000 max from one query and when we get less than
// 400 back as well, as well better error handling
String querytags = xml.getStringAttribute("tags");
String errorsmsg = xml.getStringAttribute("error");
if (errorsmsg.equals("none")) {
if (TRACE) println ("BackgroundLoader: query: page=" + page + " perpage=" + perpage + " total=" + qTotal + " error=" + errorsmsg + " tags=" + querytags);
XMLElement[] imageResults = xml.getChildren();
if (qTotal > 4000) qTotal = qMax;
if (total <= qTotal) {
for (int i=0; i < imageResults.length; i++) {
String name = imageResults[i].getStringAttribute("name");
if (TRACE) println ("BackgroundLoader: loading image " + total + " " + name);
thisIcon = new SwimmingIcon(new PVector(width/2,height/2), initMaxSpeed, initMaxForce);
thisIcon.setImageIconURL(imageResults[i].getStringAttribute("icon"));
thisIcon.setImageName(name);
thisIcon.setImagePageURL(imageResults[i].getStringAttribute("page"));
thisIcon.setUserName(imageResults[i].getStringAttribute("user"));
thisIcon.setUserPageURL(imageResults[i].getStringAttribute("profile"));
thisIcon.setImageTags(imageResults[i].getContent());
//println ("BackgroundLoader: loading " + total + " of " +
// qTotal + ": " + imageResults[i].getStringAttribute("name"));
SwimmingIcons.add(thisIcon);
iconsAvailable = true;
total++;
// we have at least one icon, so we can start to call
// the update/draw functions in the main loop
}
}
} else {
if (TRACE) println ("BackgroundLoader: images not loaded, error: " + errorsmsg + "page=" + page + " perpage=" + perpage + " total=" + qTotal + " tags=" + querytags);
}
}
} else {
try {
// sleep while we're waiting so we don't overtax the CPU
if (TRACE) println ("BackgroundLoader: image pool is full, sleeping (try deleting some icons)");
loadThread.sleep(10000);
} catch (InterruptedException e) {
if (TRACE) println ("BackgroundLoader: error");
if (TRACE) e.printStackTrace();
}
}
} // end while running
} // end run()
} // end class definition
/******************** begin query.php **************************
//
// TAGn1,TAGn2,TAGn3...
// ...
//
//
// error="none" if everything worked OK, otherwise, contains error message
// returned by Flickr, note, even if total is over 4000, Flickr only returns
// a max of 4000 images for any single query.
//
//
//
header ("Content-Type:text/xml");
// Credentials
$flickr_key = "YOUR-API-KEY";
$flickr_sec = "YOUR-FLICKR-SECRET";
require_once("LOCATION-OF-phpFlickr-ON-YOUR-SERVER");
// Create new phpFlickr object
$f = new phpFlickr($flickr_key, $flickr_sec);
// enable caching
// $f->enableCache("db", "mysql://[username]:[password]@[server]/[database]");
$i = 0;
$page=1; // the page to respond with, default to page one and 20 images
// api notes: per_page is omitted, it defaults to 100.
// The maximum allowed value is 500.
$per_page=20; // api note: If omitted, defaults to 1.
$total=0;
$querymode = "or";
$sort = "interestingness";
// photos_getInfo
if ($_GET && $_GET['tags']) {
$tags = urlencode($_GET['tags']);
$tag_mode = 'any';
$querymode = "or";
if (strstr($tags, '+')) {
$tags = str_replace('+', ',', $tags);
$tag_mode = 'all';
$querymode = "and";
} else if (strstr($tags, "%2C")) {
$tags = str_replace('%2C', ',', $tags);
$tag_mode = 'any';
$querymode = "or";
}
}
if ($_GET && $_GET['p']) {
$page = urlencode($_GET['p']);
}
if ($_GET && $_GET['pp']) {
$per_page = urlencode($_GET['pp']);
}
// look into how Flickr throttles the results.
// flickr.photos.search
// http://www.flickr.com/services/api/flickr.photos.search.html
// Flickr will return at most the first 4,000 results for any query.
$photos = $f->photos_search(array('tags' => $tags, 'tag_mode' => $tag_mode, "sort"=>"interestingness-desc", 'page' => $page, 'per_page' => $per_page));
$count = 0;
$total = $photos['total'];
if ($total==NULL) $total="0";
echo '' . "\n";
$errormessage = "none";
if ($f->getErrorCode()) {
$errormessage = $f->getErrorMsg();
echo '' . "\n";
echo "\n";
echo '' . "\n";
exit();
}
echo "\n";
echo '' . "\n";
// we get an associative array of the XML results
foreach ($photos['photo'] as $photo) {
$count++;
$owner = $f->people_getInfo($photo['owner']);
echo '';
$tags = $f->tags_getListPhoto($photo['id']);
$numtags = count ($tags);
if (!$f->getErrorCode()) {
$first = true;
$some = false;
foreach($tags as $thisTag) {
if ($thisTag['raw']) {
$n = count ($thisTag['raw']);
// Print_r($thisTag['raw']);
if ($first) {
echo htmlspecialchars($thisTag['raw']);
$first=false;
$some=true;
} else {
echo ", ". htmlspecialchars($thisTag['raw']);
}
}
}
if ($some) {
echo '' . "\n";
} else {
echo 'notag' . "\n";
}
} else {
echo 'notag' . "\n" . 'Flickr Error: ' . $f->getErrorCode(). ' : ' .$f->getErrorMsg();
echo '' . "\n";
}
}
echo '' . "\n";
?>
************************* end query.php *********************************/