Development/Tutorials/Plasma4/ComicPlugin: Difference between revisions

From KDE TechBase
(Initial version of the comic plugin tutorial -- WIP)
 
(Add a code example and more description of the functions.)
Line 71: Line 71:
<code ini>
<code ini>
Name[de]=Mein Comic
Name[de]=Mein Comic
Comment[de]Mein Comic
Comment[de]=Mein Comic
</code>
</code>


Line 86: Line 86:


===Available functions===
===Available functions===
There are two available functions that you can use straight away:
There are different functions that you can use or can (have to) add:
* function init()
 
* function pageRetrieved(id, data)
<code javascript>
function init()
comic.pageRequest(url, id)
function pageRetrieved(id, data)
</code>
 
You can in fact add other functions if you need them.


====init()====
====init()====
'''init()''' is being called by the dataengine, so you need to include it.
'''init()''' is being called by the dataengine, so you need to include it.


====pageRetrieved(id, data)====
====pageRequest(url, id)====
'''pageRetrieved''' is only called if you ask the dataengine to download something for you. ''data'' is the downloaded data in a byte stream converted to unicode, while ''id'' defines what data has been downloaded. There are three different ids:
Ask the dataengine to download '''url''' for you. '''id''' specifies of what type the download is. There are three different ids:
* comic.Page
* comic.Page
* comic.User
* comic.User
* comic.Image
* comic.Image
Both ''comic.Page'' and ''comic.User'' are intended to be used for downloading web-pages (so only text), while ''comic.Image'' is used for the actual comic image.
Both ''comic.Page'' and ''comic.User'' are intended to be used for downloading web-pages (so only text) -- it is not really important which one you use -- while ''comic.Image'' is used for the actual comic image.
 
If the download was successful the dataengine will call pageRetrieved.
 
====pageRetrieved(id, data)====
'''pageRetrieved''' is only called if you asked the dataengine to download something for you. ''data'' is the downloaded data in a byte stream converted to unicode, while ''id'' defines what data has been downloaded.


You can in fact add other functions if you need them.
Here you could search in the data for the url to the comic strip, the title of the comic, the comic's author, the next identifier etc.
So you only need to implement that function if you want to find something in data or if you want to modify the image.


===Available objects===
===Available objects===
In this section all available objects are listed and described.
In this section all (NOT YET) available objects are listed and described.
Only comic.identifier and some other identifiers in special
Only comic.identifier and some other identifiers in special
cases -- as discussed below -- have something assigned to them initially.
cases -- as discussed below -- have something assigned to them initially.
Line 168: Line 180:
Here you have to set everything you want to use yourself, nothing is set
Here you have to set everything you want to use yourself, nothing is set
automatically.
automatically.
===Examples===
==number==
This example shows the implementation of the comic plugin for xkcd.com
<code javascript>
/*
*  Copyright (C) 2007 Tobias Koenig <[email protected]>
*  Copyright (C) 2009 Matthias Fuchs <[email protected]>
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU Library General Public License version 2 as
*  published by the Free Software Foundation
*
*  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 Library General Public
*  License along with this program; if not, write to the
*  Free Software Foundation, Inc.,
*  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
function init()
{
    comic.comicAuthor = "Randall Munroe";
    comic.websiteUrl = "http://xkcd.com/";
    comic.shopUrl = "http://store.xkcd.com/";
    comic.requestPage(comic.websiteUrl, comic.User);
}
function pageRetrieved(id, data)
{
    //find the most recent strip
    if (id == comic.User) {
        var re = new RegExp("Permanent link to this comic: http://xkcd.com/(\\d+)/");
        var match = re.exec(data);
        if ( match != null ) {
            comic.lastIdentifier = match[1];
            comic.websiteUrl += comic.identifier + "/";
            comic.requestPage(comic.websiteUrl, comic.Page);
        } else {
            comic.error();
        }
    }
    if (id == comic.Page) {
        var re = new RegExp("<img src=\"(http://imgs.xkcd.com/comics/[^\"]+)\"");
        var match = re.exec(data);
        if (match != null) {
            comic.requestPage(match[1], comic.Image);
        } else {
            comic.error();
            return;
        }
        //find the tooltip and the strip title of the comic
        re = new RegExp("src=\"http://imgs.xkcd.com/comics/.+\" title=\"([^\"]+)\" alt=\"([^\"]+)\"");
        match = re.exec(data);
        if (match != null) {
            comic.additionalText = match[1];
            comic.title = match[2];
        }
    }
}
</code>





Revision as of 02:32, 1 February 2009

Note: this tutorial is not finished yet

Abstract

This tutorial will describe how to create your own plugin ("add comics") for the comic plasmoid. You need at least KDE 4.2 to be able to create plugins.

In general you can create plugins in any language supported by Kross, though this tutorial will focus on QtScript (JavaScript, ECMAScript), as this is supported by any KDE installation out of the box.

Keep in mind that not all supported features are discussed here.

Type of comics

There are three different types of comics that are supported by the comic dataengine.

  1. date
  2. number
  3. string

That is the way the comics are identified, like "garfield:2000-01-01" or "xkcd:100", string can be anything.

Sometimes the website your comic is published on neither have an easy way to get a date or a number to a comic strip or that would not help to access the strip, in that case you should use string.

The idea of this is that the type should be enough to get the comic e.g. "xkcd:100". The first part tells what plugin should be loaded and the last part tells your plugin what comic strip should be loaded. Your plugin won't get more information from the dataengine on the request than that.

Package Structure

The comic plugins are provided as packages that can be uploaded to www.kde-files.org and easily downloaded from that place directly from the applet.

First create a folder you want to work in. Than you need a structure like the following:

  • ./metadata.desktop
  • ./icon.png
  • ./contents/code/main.es

Later you need to zip the files to a ".comic"-package, you can do that with e.g.

zip -r my_comic.comic contents/code/main.es metadata.desktop icon.png

where "my_comic" is the name of the comic you want to add.

The metadata.desktop file

Every comic plugin needs a metadata.desktop file like the following:

[Desktop Entry] Name=My Comic Comment=My Comic Type=Service X-KDE-ServiceTypes=Plasma/Comic Icon=icon.png

X-KDE-Library=plasma_comic_krossprovider X-KDE-PluginInfo-Author=Your Name X-KDE-PluginInfo-Email=Your email-adress X-KDE-PluginInfo-Name=my_comic X-KDE-PluginInfo-Version=0.1 X-KDE-PluginInfo-Website=http://plasma.kde.org/ X-KDE-PluginInfo-License=GPLv2 X-KDE-PluginInfo-EnabledByDefault=true X-KDE-PlasmaComicProvider-SuffixType=Date In the "Name" and "Comment" section add the name of the comic you want to add. It will show up in the comic list (that is not the "Get New Comics..."-dialog) under that name. You could also translate the name of the comic to different languages e.g.

Name[de]=Mein Comic Comment[de]=Mein Comic

You only need "Icon" if you have an icon for your comic -- like a favicon -- that you want to add. Here it is called "icon.png"

X-KDE-PluginInfo-Name is very important, as that is the name of your plugin. The comic dataengine will use this name to identify what comic plugin should be loaded. You need that if you test your plugin with the plasmaengineexplorer. There is no white-space allowed in the name.

X-KDE-PlasmaComicProvider-SuffixType is the type of the comic as discussed the section above.

The Code

In the first two sections I am discussing what functions and objects are available, if you want skip these sections and use them only as reference if needed.

Available functions

There are different functions that you can use or can (have to) add:

function init() comic.pageRequest(url, id) function pageRetrieved(id, data)

You can in fact add other functions if you need them.

init()

init() is being called by the dataengine, so you need to include it.

pageRequest(url, id)

Ask the dataengine to download url for you. id specifies of what type the download is. There are three different ids:

  • comic.Page
  • comic.User
  • comic.Image

Both comic.Page and comic.User are intended to be used for downloading web-pages (so only text) -- it is not really important which one you use -- while comic.Image is used for the actual comic image.

If the download was successful the dataengine will call pageRetrieved.

pageRetrieved(id, data)

pageRetrieved is only called if you asked the dataengine to download something for you. data is the downloaded data in a byte stream converted to unicode, while id defines what data has been downloaded.

Here you could search in the data for the url to the comic strip, the title of the comic, the comic's author, the next identifier etc. So you only need to implement that function if you want to find something in data or if you want to modify the image.

Available objects

In this section all (NOT YET) available objects are listed and described. Only comic.identifier and some other identifiers in special cases -- as discussed below -- have something assigned to them initially.

comic.comicAuthor = "Randall Munroe"; //the author or authors of the comic strip comic.websiteUrl = "http://xkcd.com/42/"; //the address to the page where the strip is comic.shopUrl = "http://store.xkcd.com/"; //if there is a shop for the comic comic.title = "Geico"; //the title of the comic strip, can be also the chapter etc. comic.additionalText = "David did this"; //additional text, that will be shown as tooltip in the comic applet.

Identifier

There are five "identifier" objects, that react differently depending on the type of the comic.

comic.identifier //the identifier of the recent comic strip comic.firstIdentifier //the first comic strip e.g. number 1 comic.lastIdentifier //the last (most recent) comic strip e.g. number 42 comic.previousIdentifier //the previous identifier of the current strip e.g. number 40 comic.nextIdentifier //the next identifier of the current strip e.g. 41

comic.identifier is the identifier the dataengine is being asked for, so it is already set, though you can assign something different to it if needed.

date
number

comic.identifier will either be a specific number, or if no number has been specified by the caller of the dataengine it will be "0". (As a result of that you can not have a comic that is identified by number "0", if there would be one you have to shift everything see EXAMPLE.)

comic.firstIdentifier //if not specified will be "1" comic.lastIdentifier //has to be manually specified

If comic.identifier is 0 and you assigning something to comic.lastIdentifier, then comic.identifier will be reassigned that number automatically e.g.:

comic.identifier = 0; print(comic.identifier); //0 comic.lastIdentifier = 42; print(comic.identifier); //now it would be 42

comic.lastIdentifier = 100; print(comic.identifier); //still 42 In any case comic.identifier will be in the specified range.

If you do not set both (!) comic.previousIdentifier and comic.nextIdentifier then they will be set automatically according to this rules:

  • comic.previousIdentifier = comic.identifier - 1;
  • comic.previousIdentifier never will be smaller than comic.firstIdentifier
  • comic.nextIdentifier = comic.identifier + 1;
  • comic.nextIdentifier never will be larger than comic.lastIdentifier

You should set the identifiers yourself if the comic is _not_ end-to-end e.g. 1,4,5,9 ... If you are not sure also set the identifiers yourself.

string

Here you have to set everything you want to use yourself, nothing is set automatically.

Examples

number

This example shows the implementation of the comic plugin for xkcd.com /*

*   Copyright (C) 2007 Tobias Koenig <[email protected]>
*   Copyright (C) 2009 Matthias Fuchs <[email protected]>
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU Library General Public License version 2 as
*   published by the Free Software Foundation
*
*   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 Library General Public
*   License along with this program; if not, write to the
*   Free Software Foundation, Inc.,
*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

function init() {

   comic.comicAuthor = "Randall Munroe";
   comic.websiteUrl = "http://xkcd.com/";
   comic.shopUrl = "http://store.xkcd.com/";
   comic.requestPage(comic.websiteUrl, comic.User);

}

function pageRetrieved(id, data) {

   //find the most recent strip
   if (id == comic.User) {
       var re = new RegExp("Permanent link to this comic: http://xkcd.com/(\\d+)/");
       var match = re.exec(data);
       if ( match != null ) {
           comic.lastIdentifier = match[1];
           comic.websiteUrl += comic.identifier + "/";
           comic.requestPage(comic.websiteUrl, comic.Page);
       } else {
           comic.error();
       }
   }
   if (id == comic.Page) {
       var re = new RegExp("<img src=\"(http://imgs.xkcd.com/comics/[^\"]+)\"");
       var match = re.exec(data);
       if (match != null) {
           comic.requestPage(match[1], comic.Image);
       } else {
           comic.error();
           return;
       }
       //find the tooltip and the strip title of the comic
       re = new RegExp("src=\"http://imgs.xkcd.com/comics/.+\" title=\"([^\"]+)\" alt=\"([^\"]+)\"");
       match = re.exec(data);
       if (match != null) {
           comic.additionalText = match[1];
           comic.title = match[2];
       }
   }

}


Testing the plugin

To test the plugin you need to install it first:

plasmapkg -t comic -i my_comic.comic

If your comic does not show up in the comic list you have to type

kbuildsyoca4

and then it should be there. That will install the plugin to

~/.kde4/share/apps/plasma/comics/my_comic # maybe ".kde" in your case

Now best is you directly work on

~/.kde4/share/apps/plasma/comics/my_comic/contents/code/main.es

as you do not have to have reinstall the plugin if you change something. If you are finished and changed something on the main.es file simply store the main.es in your original folder and use the zip-command mentioned above to update the package.

To test your plugin type

plasmoidviewer comic

and choose your plugin. That way you will see debug-output. Alternatively you could use the plasmaengineexplorer

plasmaengineexplorer

there choose comic and type in your comic identifier e.g.

garfield:

or

garfield:2000-01-01

Debugging the plugin

Often it happens that your plugin won't work the first try and the following debuggin can be painful as there is not that much output unless you use some tricks.

Add print-statements in your main.es file to see what the values of different variables are and where your plugin stops working. Here are some examples:

if ( id == comic.page ) {

   print("****in comic.page");
   ...
   print("****a");
   ...
   print("****b");
   ...
   print("****id: " + comic.identifier);

}

I add "****" in the print to find the output more easily.

Publishing on kde-files.org

First you should deinstall the plugin by plasmapkg -t comic -r my_comic and then you need an account on www.kde-files.org. If you have done all that go to the "Plasma Comics" section and contribute your plugin. It will show up in the "Get New Comics..."-Dialog after a while.