{{delicious[[a|o|n]?]TAG1 [TAG2 TAG3]}}
* a, o, n are optional:
* a = AND: all bookmarks tagged with each tag
* o = OR: all bookmarks tagged with any of the tags
* n = NOT: all bookmarks tagged with TAG1, but not TAG2, TAG3 etc.
* if you omit a, o or n, **a** will be presumed
* if you use a, o or n, don't forget the questionmark!
* You can use as many tags as you want, delimited by a whitespace (' ')
==== Examples ====
To make it easier to get into the usage of this plugin, I registered a demo account at del.icio.us: U/P are ''dokuwiki''. It is set as default account when you install the plugin. After [[#installation]], try these:
=== one tag ===
{{delicious>dokuwiki}}
which is the same as
{{delicious>a?dokuwiki}} or {{delicious>o?dokuwiki}} or {{delicious>n?dokuwiki}}
The result should be this:\\
{{http://kokstitan.ath.cx/delicious_dokuwiki.png}}
=== AND, multiple tags ===
Now let's search all posts that are tagged 'dokuwiki' and 'reference':
{{delicious>dokuwiki reference}}
which is the same as
{{delicious>a?dokuwiki reference}}
{{http://kokstitan.ath.cx/delicious_dokuwiki_reference.png}}
=== OR, multiple tags ===
We're searching for all bookmarks tagged either 'web2.0' or 'del.icio.us' or both 'web2.0' and 'del.icio.us':
{{delicious>o?web2.0 del.icio.us}}
{{http://kokstitan.ath.cx/delicious_web2.0_del.icio.us.png}}
=== NOT, multiple tags ===
Now we want to list all bookmarks tagged 'web2.0' but not tagged 'dokuwiki':
{{delicious>n?web2.0 del.icio.us}}
{{http://kokstitan.ath.cx/delicious_rss_dokuwiki.png}}
----
I think you see the point. You can use as many tags as you want.
===== Installation =====
To get the plugin to work, you have to do two essential things:
*
delicious http://del.icio.us/tag
and move/copy the file ''/lib/plugins/delicious/images/delicious.gif'' to ''/lib/images/interwiki/''
===== Configuration =====
^ ^what it means ^ default ^
^Username | Your del.icio.us username | dokuwiki |
^Update Interval | how long are local files valid? | 60*60*3 |
^Interwiki Icon | To add delicious Interwiki link icon | 0 |
^Links description | What to show after the links (**desc**ription, **tags** or **none**) | tags |
Be careful about the update interval: The shorter it is, the more often, data will be fetched from del.icio.us to your server.
The bookmarks save path can be any folder you want, as long as it exists. Make a new one!
If you set up ''interwiki.conf'' and put the icon in place and set ''Interwiki Icon'' to 1, then a post might look like this:\\
{{http://kokstitan.ath.cx/delicious_wikilink_example.png}}\\
Neat, huh? :-)
If you change ''Links description'' to desc you get something like this:\\
{{http://kokstitan.ath.cx/delicious_description.png}}
===== Known Bugs =====
* Amount of bookmarks is limited to 100 per request, i.e. per tag
* Characters in tags that can't conveniently be url-encoded (e.g. '?' and '&') will break the matching pattern
===== To Do =====
*
*/
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
/**
* All DokuWiki plugins to extend the parser/rendering mechanism
* need to inherit from this class
*/
class syntax_plugin_delicious extends DokuWiki_Syntax_Plugin {
/**
* return some info
*/
function getInfo(){
return array(
'author' => 'Konstantin Baierer',
'email' => 'unixprog@gmail.com',
'date' => '2007-02-22',
'name' => 'del.icio.us',
'desc' => 'displays a list of del.icio.us bookmarks',
'url' => 'http://www.dokuwiki.org/plugin:delicious',
);
}
/**
* What kind of syntax are we?
*/
function getType(){
return 'substition';
}
/**
* Where to sort in?
*/
function getSort(){
return 300;
}
/**
* Connect pattern to lexer
*/
function connectTo($mode) {
$this->Lexer->addSpecialPattern('\{\{delicious>.+?\}\}',$mode,'plugin_delicious');
}
/**
* Handle the match
* Combines the tags with OR (first if-block), NOT (second if-block) or AND
* (third if-block).
*/
function handle($match, $state, $pos, &$handler) {
$match = trim(substr($match, 12, -2));
// split into ([a|o|n]?) and tags
// note that there musn't be any questionmarks in the query, as tags get urlencoded
$query = split('\?', $match, 2);
// if there's no operand specified (i.e. no '?' to match), make it an AND search
if ($query[1] == '') {
$query[1] = $query[0];
$query[0] = 'a';
}
$junctor = strtolower(substr($query[0],0,1));
$tags = split(' ', preg_replace('/\s\s+?/', ' ', trim($query[1]) ) );
if ($junctor == 'o') {
// We want all bookmarks tagged with any of the tags given
foreach ($tags as $tag) {
$posts_for_tag = $this->parseJSON( $this->getJSON( $tag ) );
if (count($posts_for_tag) < 1) {
return array('error', "No bookmarks tagged $tag code>");
}
//if there is no element with key href, add it to the output list with key href
if (!array_key_exists($posts_for_tag['href'], $posts_pivot)) {
// add each value of each bookmark by value, as PHP4 doesn't allow to add
// arrays as elements to an existing array
foreach ($posts_for_tag as $post) {
$posts_pivot[$post['href']]['href'] = $post['href'];
$posts_pivot[$post['href']]['title'] = $post['title'];
$posts_pivot[$post['href']]['description'] = $post['description'];
$posts_pivot[$post['href']]['tags'] = $post['tags'];
}
}
}
if (count($posts_pivot) < 1) {
return array('error', "No bookmarks tagged ".implode(' OR ',$tags)." code>");
}
return $posts_pivot;
} else if ($junctor == 'n') {
// We want all bookmarks tagged $tags[0], but not tags[1..n]
$tag_pivot = array_shift($tags);
$posts_pivot = $this->parseJSON( $this->getJSON( $tag_pivot) );
if (count($posts_pivot) < 1) {
return array('error', "No bookmarks tagged $tag_pivot code>");
}
foreach ($tags as $tag) {
$posts_for_tag = $this->parseJSON( $this->getJSON( $tag ) );
if (count($posts_for_tag) < 1) {
return array('error', "No bookmarks tagged $tag code>");
}
// if there is an element with key href, unset it in the output list
foreach ($posts_for_tag as $post) {
if (array_key_exists($post['href'], $posts_pivot)) {
unset($posts_pivot[$post['href']]);
}
}
}
if (count($posts_pivot) < 1) {
return array('error', "No bookmarks tagged $tag_pivot NOT ".implode(' ', $tags)." code>");
}
return $posts_pivot;
} else {
// if we want 'and'-combined list of bookmarks, let del.icio.us do the work:
$posts_and = $this->parseJSON( $this->getJSON( implode( '+', $tags ) ) );
if (count($posts_and) < 1) {
return array('error', "No bookmarks tagged ".implode(' AND ', $tags)." code>");
}
return $posts_and;
}
}
/**
* Create output
*/
function render($mode, &$renderer, $data) {
if ($mode == 'xhtml') {
if ($data[0] == 'error') {
$renderer->doc .= "{$data[1]}";
return true;
}
$renderer->doc .= '';
foreach ($data as $link) {
$renderer->doc .= '- ';
$renderer->doc .= $this->_externallink( $link['href'],
$link['title'],
$link['class'],
'',
'',
$link['description'],
$link['tags']
);
$renderer->doc .= "
";
}
$renderer->doc .= "\n
";
return true;
} else if ($mode == 'metadata') {
// Set cache validity to expire at specified age
$this->loadConfig();
$renderer->meta['date']['valid']['age'] =
empty($renderer->meta['date']['valid']['age']) ?
$this->conf['diu_update_interval'] :
min($this->conf['diu_update_interval'], $renderer->meta['date']['valid']['age']);
}
}
/** getJSON
* Gets the JSON string containing the bookmarks, description, tags and
* maybe extended description. Returns the raw JSON string.
*
* @param string [tag]
* @returns string [del.icio.us' answer]
*/
function getJSON($tag) {
$tags = urlencode($tag); // to avoid possible encoding problems
$this->loadConfig();
$user = $this->conf['diu_user'];
$url = "http://del.icio.us/feeds/json/$user/$tag?raw&count=100";
ini_set('user_agent', 'Dokuwiki Plugin'); // set user-agent so del.icio.us doesn't ban us
$json = file_get_contents($url);
return $json;
}
/** parseJSON
* parses the raw JSON string into an array of bookmarks, keyed with the respective URL
*
* @param string [raw JSON string]
* @return array of hashes [bookmarks in an array, attributes in a hash for each]
*/
function parseJSON($json) {
preg_match_all('/
\{"u":"(.+?)", # User name (always)
(:?"n":"(.+?)",)? # Extended Description (maybe not)
"d":"(.+?)", # Title (always)
"t":\[(.+?)\]\} # Tags (always)
/x', $json, $raw_posts, PREG_SET_ORDER);
foreach ($raw_posts as $raw_post) {
$posts[$raw_post[1]]['href'] = $raw_post[1];
$posts[$raw_post[1]]['description'] = $raw_post[3];
$posts[$raw_post[1]]['title'] = preg_replace("/\\\'/","'",$raw_post[4]);
$posts[$raw_post[1]]['tags'] = preg_replace('/,/', ' ', preg_replace('/"/', '', $raw_post[5]));
}
return $posts;
}
/**
* Modified external_link()-function from /lib/plugins/base.php
* Creates the external links
*
* @author Christopher Smith
* @param strings [self-explanatory]
* @returns string [the final xhtml-link including description]
*/
function _externallink($link, $title='', $class='', $target='', $more='', $desc='', $tags='') {
global $conf;
$link = htmlentities($link);
if ($conf['relnofollow']) $more .= ' rel="nofollow"';
$class = $this->conf['diu_interwiki'] ? ' class="interwiki iw_delicious"' : ' class="urlextern"';
$text = ($title<>'') ? $title : $link;
$title = ($title<>'') ? " title='$title'" : " title='$link'";
switch ($this->conf['diu_desc']) {
case 'desc' :
if ($desc <> '') $description = "($desc)";
break;
case 'tags' :
$description = "($tags)";
break;
default:
$description = "";
break;
}
return "$text $description";
}
}
//Setup VIM: ex: et ts=4 enc=utf-8 :
==== style.css ====
I just like those round corners. :-) If you like to keep it simple, just delete the whole style.css
/**
* del.icio.us Plugin Style
* @author Konstantin Baierer
*/
ul.delicious {
border: 2px solid #666;
-moz-border-radius: 20px;
padding: 10px;
background-image: url("images/delicious.png");
background-position: 99% 10px;
background-repeat:no-repeat;
}
ul.delicious li {
list-style:none;
}
span.delicious {
font-size: 70%;
}
===== Comments / Discussion =====
Hi, about your questions.
* take a look at ''inc/cache.php''. I suspect if you use it and give your pages their own file extension you should be alright. Also have a look at how code highlighted snippets are cached, iirc correctly that code is in ''inc/p_parser_utils.php'' near the bottom. If not you'll find it by tracking through the ''code()'' code in ''inc/parser/xhtml.php''.
* you might also want to take a look at how rss feeds are handled. Given that DW caches the xhtml output of the page, you can take advantage of that and let DW handle the caching - along with the rest of the page. iirc, "All" you'll need to do is set the correct metadata parameter for page life. e.g. In your ''render()'' function handle the metadata format ...
function render($format, &$renderer, $data) {
switch ($format) {
case 'xhtml' :
/* your code for the xhtml renderer */
break;
case 'metadata' :
$this->meta['date']['valid']['age'] =
empty($this->meta['date']['valid']['age']) ?
$this->getConf('diu_update_interval') :
min($this->getConf('diu_update_interval'),$this->meta['date']['valid']['age']);
break;
default :
/* unsupported format ... do nothing */
}
}
And will need to raise a feature request for DW native RSS syntax to do the same ''min()'' check I have done here :-).
--- //[[chris@jalakai.co.uk|Christopher Smith]] 2006-12-12 19:54//
> Just wanted to tell, I'm at it. Thank you for your help. I included an extra action plugin, that uhh. Well I'm not sure yet, what it actually does or even if it works, but as I said, I'm at it. It gets somewhat complicated to check, if DW is using the cached version for exactly three hours. I tried around touching the pages (''touch -d''), but right now, it does not recache the page if I do so. Also right now, it does not even purge the cached version of the page, when I changed and saved it (besides the ''{{delicious}}''-part. \\
>But the mere fact of using '.xml' instead of '.txt' as file extension reduced the warnings significantly. Well, thanks again for the tips.
--- //[[unixprog@gmail.com|konstantin baierer]] 2006-12-19 00:56//
>> I didn't think you would need an action plugin. DW's native RSS syntax manages without one :-). For testing I would open up the metadata file and edit it. You can also try using an age of only a minute or so. Using ?do=debug will show the page's metadata too. --- //[[chris@jalakai.co.uk|Christopher Smith]] 2006-12-19 21:25//
>> I tried to install that usefull plugin, but on the pluginpage and on a page where it should run in, there is a parse error with an unexpected { in line 134 in syntax.php, i couldn't figure out the reason, so who knows this problem (and its solution)? --- //[[voisard@gmail.com|Benjamin Wasner]] 2007-01-17 17:40//
>> Same problem here. Seems like the plugin is written for PHP5 only, because it makes use of PHP5-specific functions (e.g. "simplexml_load_string") and mechanisms ("try...catch"). It would be great to have a PHP4 version as well... // [[info@jensberke.de|Jens Berke]] 2007-01-19 15:25//
>>> Sorry Sorry! :( I'll check the script and see what I can do. simplexml is just so - simple. But of course it is possible to use PHP4-compliant XML-functions. I just don't have the time right now to rewrite it (lot of exams threatening me at University). But I promise to update it as soon as I can. Anyway, thanks for trying it! :) --- //[[unixprog@gmail.com|konstantin baierer]] 2007-01-30 02:38//
>> Great plugin idea! One problem I've found however is that I'm getting the following error message: Fatal error: Call to undefined method syntax_plugin_delicious::loadConfig() in /lib/plugins/delicious/syntax.php on line 123 --- //[[sspboyd@boydstudio.ca|Stephen Boyd]] 2007-02-01 00:27//
I've rewritten the plugin using del.icio.us' [[http://del.icio.us/help/json/posts|JSON interface]] these last two days. Of course I could also rewrite it using PHP's DOMXML functions (which is PHP4 compatible) and del.icio.us XML interface, but for just getting the bookmarks, that's inconvenient to code and causes a lot of overhead traffic for the xml-tags. Moreover, no user authentication is needed to access the JSON feed, which is cool, because users don't have to store their passwords in cleartext anymore. However, the maximum of bookmarks fetched from del.icio.us using JSON is 100, but I guess, nobody wants to have a longer list of bookmarks in a wiki page anyway.
I still do some testing and bug-killing, but it should be done next week. --- //[[unixprog@gmail.com|konstantin baierer]] 2007-02-16 16:02//
> OK, done. :) Let me know if it works for PHP4 now. --- //[[unixprog@gmail.com|konstantin baierer]] 2007-02-23 02:24//
----
Hi, I've installed the Plugin at [[http://jurtenrunde.de/lieder/doku.php?id=spielplatz:test]] but I can't see any information from delicious. I have god my own account at delicious [[http://del.icio.us/Muckel1986]] but I can't see the tags. I have tested it with the dokuwiki example but I have there the same problem. I have test it with:
===== delicious =====
Ob meine Favoriten von delicious auch angezeigt werden?
{{delicious>Muckel1986}}
==== Test mit dokuwiki ====
{{delicious>dokuwiki}}
{{delicious>a?dokuwiki}}
{{delicious>o?dokuwiki}}
{{delicious>n?dokuwiki}}
I hope here ist somebody who can help me, please.
----
:!: This file is never available, please get this hosted somewhere :!:\\
And I want it. :)\\
- shawn
> sorry. hdd crash. plugin is now available again. --- //[[unixprog@gmail.com|konstantin baierer]] 2007-03-19 01:26//
Hi,
I´ve written a class to get all bookmarks into my DokuWiki. You can export all bookmarks from del.icio.us under ''settings -> Bookmarks: export / backup''. Include both tags and notes. After downloading the class turns that file either into an array or DokuWiki syntax. It creates H3's from tags and puts all bookmarks into an unordered list. It's just a quick and dirty solution but maybe someone'll find it usefull. --- //[[monitormensch@gmail.com|Kai Schaper]] 2007-07-19 09:12//
class Delicious_HTML_Parser {
private $lines;
private $linklist;
private $dw_linklist = '';
public function __construct($file) {
$this->lines = file($file);
$this->parse();
}
private function parse() {
foreach ($this->lines as $line) {
if (substr($line, 0, 4) == '') {
$line = str_replace(array('', '">'), array('', '', '"'), $line);
$parts = explode('"', $line);
$url = $parts[1];
$tags = isset($parts[7]) ? $parts[7] : 'untagged';
$description = isset($parts[8]) ? trim($parts[8]) : trim($parts[6]);
$link = ''.$description.'';
$tag_parts = explode(',', $tags);
foreach ($tag_parts as $tag) {
$this->linklist[$tag][] = array('url' => $url, 'description' => $description, 'link' => $link);
}
}
}
ksort($this->linklist);
}
public function getLinklist() {
return $this->linklist;
}
public function generateDokuWikiList() {
foreach ($this->linklist as $tag => $links) {
$num = count($links);
// Headline
$this->dw_linklist .= "==== $tag ($num) ====\n\n";
foreach ($links as $link) {
// List Item with Bookmark
$description = str_replace(array('[', ']', '|'), array('(', ')', ','), $link['description']);
$this->dw_linklist .= ' *[['.$link['url'].'|'.$description.']]'."\n";
}
$this->dw_linklist .= "\n";
}
return $this->dw_linklist;
}
}
$file = './delicious-20070719-044044.html';
$parser = new Delicious_HTML_Parser($file);
#$linklist = $parser->getLinklist();
#print_r($linklist);
$dw_linklist = $parser->generateDokuWikiList();
echo $dw_linklist;
>in witch file must I put the class and what have it to write into the dokuwiki page?
>>It's not an extension for the del.icio.us Plugin. It's just a simple stand alone script to turn your exported bookmarks into DokuWiki syntax.
=====
some hosts don't allow you to use file_get_contents, simplexml_load_string etc from remote hosts due to well deserved security concerns. Here is the hack that my host provided to avoid this using cURL.
this is at syntax.php:174, I left he old code there commented out to show where I was editing.
//* file_get_contents is commonly disabled
$ch = curl_init();
$timeout = 5; // set to zero for no timeout
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$json = curl_exec($ch);
curl_close($ch);
/*/
$json = file_get_contents($url);
//*/
They list a few other ideas here: [[http://wiki.dreamhost.com/CURL_PHP_tutorial|Dreamhost's cURL reference]]. I don't appreciate how cURL buffers you from these issues, but they do it for a living so perhaps they aren't wrong.
=====
> --- //[[danjor@infonie.fr|Jordan]] 2007-11-23 15:56//
>Hello, is there a way to make it work with a private delicious ?
>Giving the password in the conf file ?
>It would be great !!
>>I wrote a patch to get private links. But I gave up during my tests. If I want to access private links I must use the [[http://del.icio.us/help/api/|API]]. This API blocks more requests than one every second.
>>If anyway someone interested in my patch you can contact me. --- //[[dokuwiki_delicious.5.nougad@spamgourmet.com|nougad]] 2008-07-05 04:13//
=====
//[[mail@jakubsafar.cz|jakubsafar.cz]] 2008-07-28 12:33//
Hello, it seems that delicious plugin stopped working sometimes during last week. Maybe there was some change on the delicious side? Or am I alone?
> Seems delicious changed a few things about their feeds. This concerns the URL and the JSON format which now includes a "dt"-key noting the date-time the bookmark has been added. Furthermore the "n"-key which denotes the extended description is now always set even when there is now description in which case it's just an empty string (""). Most of all the feed is now UTF-8 encoded (using "\u00.." entities). There doesn't seem to be a trivial solution to decode these so I've used json_encode() which unfortunately means the patch only works with PHP >5.2. You can find it at [[http://vergiss-blackjack.de/delicious.patch]]. I haven't tested it extensively but it seems to work for my bookmarks. --- //[[georgsorst@gmx.de|Georg]] 2008-07-05 04:13//
**UPDATE, workaround:**: If there was any problem with patch, dokuwiki is capable of using delicious rss feed, see [[http://delicious.com/help/feeds|here]]. //[[mail@jakubsafar.cz|jakub]] 2008-08-20 14:37// For example:
{{rss>http://feeds.delicious.com/v2/rss/USERNAME/TAG1+TAG2+... NUMBEROFBOOKMARKS}}
==== Thank You! ====
* To [[georgsorst@gmx.de|Georg]]
* I applied your patch, and have some instructions on how to update the plugin here: http://notesmine.com/dokuwiki_delicious
* I didn't try the RSS feed, I'm using the JSON original method(s) of the plugin.
* Please contact me at [[nate@notesmine.com]] if you have any questions or suggestions. Thank you to both Georg and the originator of this plugin. :-) It RULEZ!!!!
==== "AND" doesn't work ====
With the patch described above. I submitted a hack below.
For example, if I have
{{delicious>foo bar}}
I don't get anything back. I'm using dokuwiki 2008-05-05 with php version 5.2. (I think).
I had to comment out the line that runs urlencode on the tags, because it was messing with the ''+'' that is put between the tags when using something like this:
Where you want foo+bar.
Here's the patch, just rem-out the ''$tags = urlencode($tag)'' line, and then add a line with ''$tags=$tag;''. I haven't had time to really find out why this is occurring, but I did narrow it down to the urlencode function being called.
function getJSON($tag) {
// urlencode was causing problem with AND queries to delicious
// foo+bar+baz
// $tags = urlencode($tag); // to avoid possible encoding problems
$tags=$tag;