<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>xscDevBlog - LastSharp &#38; Co. &#187; Lapicon</title>
	<atom:link href="http://dev.xscheme.de/category/projects/lapicon/feed/" rel="self" type="application/rss+xml" />
	<link>http://dev.xscheme.de</link>
	<description>Der xscheme-DevelopmentBlog</description>
	<lastBuildDate>Sun, 23 May 2010 11:40:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Inside Last.FM: Silent Authentication für API 2.0</title>
		<link>http://dev.xscheme.de/2009/07/inside-lastfm-silent-authentication/</link>
		<comments>http://dev.xscheme.de/2009/07/inside-lastfm-silent-authentication/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 21:47:06 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Lapicon]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[lastfm]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=774</guid>
		<description><![CDATA[Update (17.07.2009): Das hier ist (abgesehen von den &#8220;Skills&#8221;, die ich dabei gebraucht hab) wohl ziemlich überflüssig, wenn man die API-Methode auth.getMobileSession mal genauer betrachtet. Wieder was gelernt: RTFM!
Da im Moment anscheinend wieder Änderungen am Last.FM-Webservice gemacht werden, die dazu geführt haben, dass LastSharp höchstens noch mithilfe der &#8220;Modifizierten Verbindung&#8221; (unter &#8220;Erweiterte Einstellungen&#8221; &#62;&#62; &#8220;Verschiedenes&#8221;) [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update (17.07.2009):</strong> Das hier ist (abgesehen von den &#8220;Skills&#8221;, die ich dabei gebraucht hab) wohl ziemlich überflüssig, wenn man die API-Methode auth.getMobileSession mal genauer betrachtet. Wieder was gelernt: RTFM!</p>
<p>Da im Moment anscheinend wieder Änderungen am Last.FM-Webservice gemacht werden, die dazu geführt haben, dass LastSharp höchstens noch mithilfe der &#8220;Modifizierten Verbindung&#8221; (unter &#8220;Erweiterte Einstellungen&#8221; &gt;&gt; &#8220;Verschiedenes&#8221;) funktioniert, habe ich mir mal das <a href="http://www.lastfm.de/api/radio">Radio-API</a> angesehen, das ja anscheinend die Zukunft des Radiostreamings bei Last.FM ist. Was mich daran allerdings stört, ist die umständliche Anmeldeprozedur: Token holen, Browser öffnen, auf Authentifizierung warten, Session holen.</p>
<p>Der Umweg über den Browser ist einfach unschön, weshalb ich nach einer Lösung gesucht habe, die <strong>den Login sowie die anschließende Bestätigung eines Users im Hintergrund simuliert</strong>, sodass er das eigentliche Programm nicht verlassen muss.</p>
<p><span id="more-774"></span></p>
<p><em>Funktionen, die Authentication-Token und -Session holen, werden im folgenden als gegeben betrachetet, z.B. durch LastFmLib.Net. </em></p>
<p>Wir brauchen nun also zwei Funktionen, die das Abschicken des Login-Formulars und das Klicken auf den &#8220;Zulassen&#8221;-Button vortäuschen. Beide Operationen produzieren eine HTTP-POST-Anfrage, funktionieren aber nur, wenn auch die richtigen Cookies vorhanden sind. (Das hat mich einige Zeit gekostet und dabei war die Lösung so einfach&#8230;) Es bietet sich an, die POST-Anfrage in eine Hilfsfunktion <em>ExecutePOST</em> zu packen, hier z.B. in C#:<br />
(Namespace <em>System.Net</em> muss eingebunden sein)</p>
<pre name="code" class="c-sharp">// Löst das Cookie Problem: Immer denselben Container verwenden!
private static CookieContainer GlobalCookies = new CookieContainer();

// Sendet eine POST-Anfrage
public static void ExecutePOST(string uri, string data) {
    try
    {
        // Bereite die Anfrage vor
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.Method = "POST";
        request.CookieContainer = GlobalCookies; // !!
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;

        // Schreiben der Daten
        ASCIIEncoding enc = new ASCIIEncoding();
        byte[] bdata = enc.GetBytes(bodyData);
        Stream str = req.GetRequestStream();
        str.Write(bdata, 0, bdata.Length);
        str.Close();

        // Schicke Anfrage ab und verwirf die Antwort
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        response.Close();
    }
    catch { }
}</pre>
<p>Will man überprüfen, ob die gewünschte Operation erfolgreich war, würde es sich vermutlich anbieten, die Antwort auszuwerten, aber darauf verzichte ich jetzt aus Zeitgründen.</p>
<p>Nächster Schritt ist die Untersuchung der Formulare auf der Last.FM-Seite, damit man weiß, welche Daten an welche Adresse gesendet werden müssen:</p>
<ul>
<li>Login: <strong>https://www.last.fm/login/</strong>
<ul>
<li>refererKey (leer)</li>
<li>backto (&#8220;/&#8221;)</li>
<li>username (Benutzername)</li>
<li>password (Passwort)</li>
</ul>
</li>
<li>Zulassen: <strong>http://www.last.fm/api/grantAccess</strong>
<ul>
<li>api_key (Last.FM schickt den sogar zweimal, wir deshalb sicherheitshalber auch&#8230;)</li>
<li>token (Authentication-Token)</li>
<li>referer (&#8220;/&#8221;)</li>
</ul>
</li>
</ul>
<p>Also, die beiden verbleibenden Funktionen in C#:</p>
<pre name="code" class="c-sharp">    // Lasse ein Programm zu
    public static void GrantAccess(string token)
    {
        ExecutePOST(
            "http://www.last.fm/api/grantAccess",
            "api_key=" + apiKey + "&amp;api_key=" + apiKey + "&amp;token=" + token + "&amp;referer=/"
        );
    }

    // Melde den User bei Last.FM an
    public static void Login(string username, string password)
    {
        ExecutePOST(
            "https://www.last.fm/login/",
            "refererKey=&amp;backto=/&amp;username=" + Uri.EscapeDataString(username) +
            "&amp;password=" + Uri.EscapeDataString(password)
        );
    }</pre>
<p>Um jetzt eine gesamte Anmeldung zu simulieren, müsste man nun folgendes machen:</p>
<pre name="code" class="c-sharp">public static void Authenticate(string username, string password)
{
    string token = GetToken(); // irgendeine externe Funktion
    Login(username, password);
    GrantAccess(token);
    string session = GetSession(); // irgendeine externe Funktion
    // Mache etwas...
}</pre>
<p>Das war&#8217;s auch schon. Wie gesagt fehlt hier ein Test, ob die Anmeldung erfolgreich war, aber irgendwie lässt sich das bestimmt einfach überprüfen. (Vllt. liefert Last.FM ja im Hintergrund einen HTTP-Error, der im Browser nicht auffällt?)</p>
<p>Jedenfalls, wenn jemand die <strong>Authentifizierung für das Last.FM-API 2.0 im Hintergrund</strong> ablaufen lassen will, ist das hier der Weg. Ich hoffe, es hilft.</p>
<p>Die Verwendung des Radio-APIs in LastSharp werde ich übrigens so lang wie möglich hinauszögern, da hier wieder einmal diverse Standards (HTTP, XML, &#8230;) unsachgemäß ausgelegt werden&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/07/inside-lastfm-silent-authentication/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zwischenstand: Universal Version Description (UVD) / Entwickler gesucht</title>
		<link>http://dev.xscheme.de/2009/05/zwischenstand-universal-version-description-uvd-entwickler-gesucht/</link>
		<comments>http://dev.xscheme.de/2009/05/zwischenstand-universal-version-description-uvd-entwickler-gesucht/#comments</comments>
		<pubDate>Wed, 13 May 2009 14:17:12 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Batch]]></category>
		<category><![CDATA[Codeschnipsel]]></category>
		<category><![CDATA[Fundstücke]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Lapicon]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Theorie]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=755</guid>
		<description><![CDATA[Ich möchte an dieser Stelle einmal auf den aktuellen Stand des hier begonnenen Projekts verweisen, der sich wie folgt darstellt: Ich habe das UVD-Format weiter ausgearbeitet und angepasst und damit begonnen, eine C#-Bibliothek zu schreiben, die dessen Verarbeitung dient.
Als Beispiel sei die UVD von LastSharp gegeben, die wir im folgenden Codebeispiel mithilfe einer XSL-Transformation (DescriptionPage.xsl) [...]]]></description>
			<content:encoded><![CDATA[<p>Ich möchte an dieser Stelle einmal auf den aktuellen Stand des <a href="http://dev.xscheme.de/2009/05/universal-version-description-uvd/">hier</a> begonnenen Projekts verweisen, der sich wie folgt darstellt: Ich habe das UVD-Format weiter ausgearbeitet und angepasst und damit begonnen, eine C#-Bibliothek zu schreiben, die dessen Verarbeitung dient.</p>
<p>Als Beispiel sei die <a href="http://dev.xscheme.de/uvd/lastsharp.uvd.xml">UVD von LastSharp</a> gegeben, die wir im folgenden Codebeispiel mithilfe einer XSL-Transformation (<a href="http://dev.xscheme.de/uvd/DescriptionPage.xsl">DescriptionPage.xsl</a>) in eine HTML-Datei verwandeln. Das soll illustrieren, wie einfach die Verwendung von UVD sein kann, wenn entsprechende Bibliotheken vorhanden sind:</p>
<pre class="c-sharp:collapse" name="code">UVD lastsharp = UVD.Create("http://dev.xscheme.de/uvd/lastsharp.uvd.xml");
lastsharp.Save("c:/lastsharp.htm", "http://dev.xscheme.de/uvd/DescriptionPage.xsl");</pre>
<p>Nun haben wir eine Datei &#8220;lastsharp.htm&#8221;, die <a href="http://dev.xscheme.de/uvd/lastsharp.htm">hier</a> eingesehen werden kann und Beschreibungen in verschiedenen Sprachen und Längen bietet, Downloadlinks, etc&#8230; Außerdem sind (wie man bei der Ansicht des Quelltextes feststellen kann) auch die META-Tags zu Schlüsselwörtern und Beschreibungen bereits gesetzt, sodass die Seite auch für Suchmaschinen verwendbar ist.</p>
<p><span id="more-755"></span>Das UVD-Objekt (s. Code) bietet noch weitere Möglichkeiten, aber ich möchte nun auf den Update-Mechanismus zu sprechen kommen, den man mithilfe von UVD implementieren kann. Eine UVD kann einen Verweis auf die vorhergehende Version, sowie Informationen zum inkrementellen Update (lösche Datei X, aktualisiere Datei Y, &#8230;) enthalten, sodass man durch Untersuchen der Versionsgeschichte jede Version auf den neuesten Stand bringen kann.</p>
<p>Wir verwenden die folgenden (sinnlosen) Dateien zur Demonstration: <a href="http://dev.xscheme.de/uvd/updatetest1.xml">Version 1.2</a> &gt;&gt; <a href="http://dev.xscheme.de/uvd/updatetest2.xml">Version 1.1</a> &gt;&gt; <a href="http://dev.xscheme.de/uvd/updatetest3.xml">Version 1.0</a>. Mithilfe der UVDs läuft ein Update von Version 1.0 auf 1.2 folgendermaßen ab:</p>
<ol>
<li>Extrahiere aus der UVD zu Version 1.2 die URL zu Version 1.1!</li>
<li>Speichere die Update-Informationen in der UVD zu Version 1.1!</li>
<li>Führe nacheinander die Update-Schritte (1.0 &gt;&gt; 1.1) und (1.1 &gt;&gt; 1.2) aus!</li>
</ol>
<p>Die Bibliothek, an der ich gerade arbeite, verwendet hierfür sog. Update-Profile, die festlegen, welche Sprache und welches Betriebssystem für das Update berücksichtigt werden soll. Code:</p>
<pre class="c-sharp:collapse" name="code">UVD version12 = UVD.Create("http://dev.xscheme.de/uvd/updatetest1.xml");
UVDVersion currentVs = new UVDVersion(1, 0); // aktuelle Version
UpdateProfile profile = new UpdateProfile(); // OS und Sprache egal
Update u = profile.CreateUpdate(currentVs, version12);
foreach(UpdateSegment s in u)
{
    Console.WriteLine(s.ToString());
}
u.Execute("c:/program/"); // Programmverzeichnis muss angegeben werden!</pre>
<p>Das liefert folgende Ausgabe:</p>
<pre>[Add: file3.txt] http://www.download.de
[Execute: file3.txt]
[Remove: file4.txt]
[Add: file1.txt] http://www.download.de
[Update: file2.txt] http://www.download.de
[Execute: file3.txt]</pre>
<p>Anschließend werden genau diese Schritte ausgeführt. Bei der Erstellung des Updates wird im übrigen mehr oder weniger intelligent vorgegangen: wenn eine Datei in Version 1.2 gelöscht wird, wird sie in Version 1.1 gar nicht erst hinzugefügt. Und warum eine Datei hinzufügen, wenn sie irgendwann später überschrieben wird? Dieses Verhalten lässt sich über das Update-Profil festlegen. Wenn deaktiviert, lautet die Ausgabe:</p>
<pre><span style="text-decoration: underline;">[Add: file4.txt] http://www.download.de</span>
<span style="text-decoration: underline;">[Add: file2.txt] http://www.download.de</span>
[Add: file3.txt] http://www.download.de
[Execute: file3.txt]
<span style="text-decoration: underline;">[Remove: file4.txt]</span>
[Add: file1.txt] http://www.download.de
<span style="text-decoration: underline;">[Update: file2.txt] http://www.download.de</span>
[Execute: file3.txt]</pre>
<p>Soviel dazu. Was jetzt noch wichtig ist, ist die Übertragung der Bibliothek auf andere Programmiersprachen. <strong>Deswegen suche ich Entwickler, die mit mir gemeinsam UVD auf Java, PHP, etc&#8230; portieren.</strong> Bei Interesse einfach eine E-Mail schreiben an <a href="mailto:Yannick_Scherer@gmx.net">Yannick_Scherer@gmx.net</a>! Aber man sollte sich bewusst sein, dass das einiges an Arbeit bedeutet.</p>
<p>Mehr habe ich vorerst nicht vorzuweisen&#8230; Außer vielleicht das ultimative &#8220;einzeilige&#8221; Update (mit einer sinnvollen Datei funktioniert es dann auch&#8230;):</p>
<pre class="c-sharp:collapse" name="code">new UpdateProfile()
       .CreateUpdate(new UVDVersion(1, 0), UVD.Create("http://dev.xscheme.de/uvd/updatetest1.xml"))
       .Execute("c:/program/");</pre>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/05/zwischenstand-universal-version-description-uvd-entwickler-gesucht/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wie verwende ich Lapicon in meinem eigenen Programm? (.NET)</title>
		<link>http://dev.xscheme.de/2009/04/lapicon-in-eigenem-programm-verwenden/</link>
		<comments>http://dev.xscheme.de/2009/04/lapicon-in-eigenem-programm-verwenden/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 19:43:55 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Lapicon]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[rest]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=677</guid>
		<description><![CDATA[Lapicon (Loose API Connection Language) kann (ab Version 1.0.10) auf einfache Art und Weise im eigenen Programm verwendet werden.
Um zu lernen, wie das geht, entwickeln wir hier (mit C#, aber eine Übertragung auf andere .NET-Sprachen dürfte jeder einigermaßen versierte Programmierer hinbekommen) ein Mini-Programm, das in einem Fenster zwei Eingabefelder für &#8220;Interpret&#8221; und &#8220;Titel&#8221; bereitstellt und [...]]]></description>
			<content:encoded><![CDATA[<p><strong><a href="http://dev.xscheme.de/lapicon">Lapicon</a></strong> (Loose API Connection Language) kann (ab Version 1.0.10) auf einfache Art und Weise im eigenen Programm verwendet werden.</p>
<p>Um zu lernen, wie das geht, entwickeln wir hier (mit C#, aber eine Übertragung auf andere .NET-Sprachen dürfte jeder einigermaßen versierte Programmierer hinbekommen) ein Mini-Programm, das in einem Fenster zwei Eingabefelder für &#8220;Interpret&#8221; und &#8220;Titel&#8221; bereitstellt und das zugehörige Album findet. Ich gebe zu, keine bahnbrechende Idee, aber zur Demonstration reicht&#8217;s.  <span id="more-677"></span></p>
<p>Zuallererst erstellen wir ein neues Projekt vom Typ &#8220;Windows Forms Anwendung&#8221; mit beliebigem Namen und erstellen einen Verweis auf Lapicon.  Das geht folgendermaßen:</p>
<ol>
<li>Rechtsklick auf &#8220;Veweise&#8221; im Projektmappen-Explorer, dann Klick auf &#8220;Verweis hinzufügen&#8230;&#8221;:<img class="size-full wp-image-678 alignnone" title="Lapicon Tutorial: Verweis hinzufügen" src="http://dev.xscheme.de/wp-content/uploads/2009/04/lapiconassemblytut1.png" alt="Lapicon Tutorial: Verweis hinzufügen" width="343" height="189" /></li>
<li>Unter &#8220;Durchsuchen&#8221; die Datei &#8220;Lapicon.exe&#8221; suchen und auswählen. Klick auf &#8220;OK&#8221;.<img class="alignnone size-full wp-image-679" title="Lapicon Tutorial: Lapicon.exe einbinden" src="http://dev.xscheme.de/wp-content/uploads/2009/04/lapiconassemblytut2.png" alt="Lapicon Tutorial: Lapicon.exe einbinden" width="504" height="232" /></li>
</ol>
<p>Jetzt kann die Programmentwicklung losgehen. Wir erstellen ein Fenster, das in etwa so aussieht:</p>
<p style="text-align: center;"><img class="size-full wp-image-680 aligncenter" title="Lapicon Tutorial: Fenster" src="http://dev.xscheme.de/wp-content/uploads/2009/04/lapiconassemblytut3.png" alt="Lapicon Tutorial: Fenster" width="322" height="160" /></p>
<p>Jetzt geht es an die Implementierung der Funktionen. Alle Lapicon-Funktionen werden durch das Objekt &#8220;LapiconProcessor&#8221; im Namespace &#8220;Lapicon&#8221; bereitgestellt. Da &#8220;LapiconProcessor&#8221; ein ziemlich langer Name ist und Programmierer von Haus aus faul sind, fügen wir folgendes Statement an den Anfang des Codes unseres Fensters (Rechtsklick auf das Fenster &gt;&gt; &#8220;Code anzeigen&#8221;) ein:</p>
<pre>using L = Lapicon.LapiconProcessor;</pre>
<p>Damit kürzen wir das Objekt &#8220;LapiconProcessor&#8221; als &#8220;L&#8221; ab und können ab sofort in unserem Code darauf zugreifen. Zuallererst ist unsere Anwendung ja auf das Last.FM-API ausgelegt, d.h. beim Laden der Anwendung würde es sich anbieten, Lapicon für dieses API zu konfigurieren. Hierfür verwenden wir das &#8220;Load&#8221;-Ereignis des Fensters, indem wir an irgendeine freie Stelle (im Fensterentwurf) doppelklicken. Anschließend ergänzen wir den so erstellten Code folgendermaßen:</p>
<pre>private void AlbumFinderForm_Load(object sender, EventArgs e)
{
<span style="color: #ff9900;"><span style="color: #000000;">   // Lapicon: Initialisierung für Last.FM (entspricht L.Process("#lastfm"))</span></span>
<span style="color: #ff9900;">   L.LastFMInit();<span style="color: #000000;"> </span></span>
}</pre>
<p>Jetzt müssen wir noch festlegen, was passiert, wenn wir auf den Button klicken. Also erstellen wir mit einem Doppelklick darauf das &#8220;Click&#8221;-Event und verwenden die verschiedenen Lapicon-Funktionen, um eine Anfrage an Last.FM zu senden und das Ergebnis in einer MessageBox anzuzeigen. Die wichtigsten Lapicon-Funktionen sind:</p>
<ul>
<li><strong>Process(&#8220;statement1&#8243;, &#8220;statement2&#8243;, &#8230;) </strong>führt die angegebenen Lapicon-Befehle nacheinander aus.</li>
<li><strong>Var(&#8220;var&#8221;)</strong> liefert den Wert einer Variablen.</li>
<li><strong>Var(&#8220;var&#8221;, &#8220;wert&#8221;)</strong> speichert &#8220;wert&#8221; in der Variable &#8220;var&#8221;.</li>
<li><strong>VarExists(&#8220;var&#8221;)</strong> liefert &#8220;true&#8221;, wenn eine Variable existiert.</li>
<li><strong>List(&#8220;var&#8221;)</strong> liefert eine Liste.</li>
<li><strong>ListCreate(&#8220;var&#8221;)</strong> erstellt eine Liste.</li>
<li><strong>List(&#8220;var&#8221;, &#8220;wert&#8221;)</strong> fügt &#8220;wert&#8221; zur Liste hinzu.</li>
<li><strong>ListExists(&#8220;var&#8221;)</strong> liefert &#8220;true&#8221;, wenn eine Liste existiert.</li>
</ul>
<p>Mehr braucht man meistens nicht. Unser Click-Event wird demnach folgendermaßen aussehen:</p>
<pre class="c-sharp" name="code">private void btFindAlbum_Click(object sender, EventArgs e)
{
    // Interpret und Titel
    string artist = txtArtist.Text.Trim();
    string track = txtTrack.Text.Trim();

    // Wenn eins von beidem leer ist: nicht weitermachen
    if (artist == "" || track == "") return;

    // Ansonsten: Album (und richtig geschriebene Infos) holen
    L.Process(
        "[track.getInfo : track=" + track + "&amp;artist=" + artist + "]",
        "store track/album/title in album",
        "store track/artist/name in artist",
        "store track/name in track"
    );

    // Ausgabe oder Fehler
    if (L.Var("album") == "")
    {
        MessageBox.Show(
            "Kein Album zu diesen Eingaben gefunden!",
            "Kein Album",
            MessageBoxButtons.OK,
            MessageBoxIcon.Exclamation);
    }
    else
    {
        MessageBox.Show(
            "Gefundene Informationen:\n\n" +
               "   " + L.Var("artist") + " - " + L.Var("track") + "\n" +
               "   Album: " + L.Var("album"),
            "Album gefunden!",
            MessageBoxButtons.OK,
            MessageBoxIcon.Information);
    }
}</pre>
<p>Das war auch schon alles. Mit &#8220;Process&#8221; wird die Anfrage abgeschickt und die nötigen Daten gesichert, mit &#8220;Var&#8221; erfolgt die Verwendung der Daten. Und schon ist das Programm <em>good to go</em>:</p>
<p><img class="alignnone size-full wp-image-681" title="Lapicon Tutorial: Fertiges Programm" src="http://dev.xscheme.de/wp-content/uploads/2009/04/lapiconassemblytut4.png" alt="Lapicon Tutorial: Fertiges Programm" width="486" height="305" /></p>
<p>Viel einfacher geht es wirklich nicht mehr. Ich hoffe, damit allen, die Interesse an Lapicon haben, ein Stück weiter geholfen zu haben.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/04/lapicon-in-eigenem-programm-verwenden/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wie baue ich mir ein Script mit Lapicon?</title>
		<link>http://dev.xscheme.de/2009/04/kurzanleitung-zu-lapicon/</link>
		<comments>http://dev.xscheme.de/2009/04/kurzanleitung-zu-lapicon/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 00:06:07 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Lapicon]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[lastfm]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[webservice]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=635</guid>
		<description><![CDATA[Lapicon (Loose API Connection Language) ist ein Interpreter für eine Scriptsprache, die auf den ersten Blick Ähnlichkeiten mit dem Windows-Eigenen Batch hat und dafür gedacht ist, mit Webservern in Verbindung zu treten, die ihre Daten als XML bereitstellen und REST-Anfragen über HTTP-GET unterstützen. Soweit die Theorie.
Praktisch gesehen ist Lapicon eine einfache Möglichkeit, Webservices zu verwenden. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dev.xscheme.de/lapicon"><strong>Lapicon</strong></a> (Loose API Connection Language) ist ein Interpreter für eine Scriptsprache, die auf den ersten Blick Ähnlichkeiten mit dem Windows-Eigenen <em>Batch</em> hat und dafür gedacht ist, mit Webservern in Verbindung zu treten, die ihre Daten als XML bereitstellen und REST-Anfragen über HTTP-GET unterstützen. Soweit die Theorie.</p>
<p>Praktisch gesehen ist Lapicon eine einfache Möglichkeit, <strong>Webservices zu verwenden</strong>. Und geeignete gibt es (wie die Google-Suche nach &#8220;REST-API&#8221; schon bald zeigt) einige:</p>
<ul>
<li>Last.FM (http://www.last.fm/api)</li>
<li>Flickr (http://www.flickr.com/services/api/)</li>
<li>Twitter (http://apiwiki.twitter.com/Twitter-API-Documentation)</li>
<li>Wuala (http://www.wuala.com/de/api)</li>
<li>&#8230;</li>
</ul>
<p>Aber wie geht man nun vor, wenn man Lapicon für irgendeines dieser APIs verwenden will? Diese Frage will ich in diesem Artikel beantworten, anhand zweier Beispiele: den Skripts DownloadAlbumAfterSearch.lpc und Lyrics.lpc aus dem Paket <strong>DarkSharpScripts</strong>, das ab Version 1.0.9 von Lapicon im Verzeichnis &#8220;packages&#8221; zu finden ist. Das erste Script sucht anhand einer Eingabe alle in Frage kommenden Alben und lässt den User eines auswählen, das anschließend komplett von Last.FM heruntergeladen wird (wenn möglich). Und das zweite findet mithilfe der <a href="http://lyricwiki.org/Main_Page">LyricWiki</a> (noch eine Seite, die REST-Anfragen unterstützt!) den Songtext zu einem vom User eingegebenen Musiktitel.</p>
<p><span id="more-635"></span><strong></strong></p>
<p><strong>Schritt 0: Den einfachen Scriptstart ermöglichen</strong></p>
<p>Damit man möglichst einfach Lapicon-Scripts starten kann, sollte man eine Datei mit der Endung &#8220;.lpc&#8221; anlegen und unter Windows darauf doppelklicken und anschließend über &#8220;Programm aus Liste auswählen&#8221; &gt;&gt; &#8220;Durchsuchen&#8230;&#8221; die Lapicon.exe als Standardprogramm festlegen. Dann lassen sich Scripts per Doppelklick starten.</p>
<p><strong>Schritt 1: Grundeinstellungen</strong></p>
<p>Zuallererst muss Lapicon mitgeteilt werden, wohin es Anfragen schicken soll, wie diese Anfragen aussehen sollen und wie es mit den Antworten umzugehen hat. Man stelle sich folgende Fragen:</p>
<ol>
<li>Wie lautet die URL, an die die Anfragen gehen sollen? (Findet man meistens auf der API-Seite.)</li>
<li>Brauche ich irgendwelche Daten für die Anfrage, die immer vorhanden sein müssen? (Beispielsweise bei Last.FM: ein API-Schlüssel.)</li>
<li>Wie ist das Format der Anfrage-URL? &#8220;URL?Parameter&#8221; oder &#8220;URL/Parameter1/Parameter2&#8243;?</li>
<li>Wie sieht die Antwort aus? Welcher XML-Knoten ist die Wurzel? Sind irgendwelche Namespaces enthalten?</li>
<li>Werden mir Informationen bereitgestellt, ob Fehler aufgetreten sind, und wo finde ich sie?</li>
</ol>
<p>Jetzt geht es ans Konfigurieren von Lapicon, hier am Beispiel Last.FM:</p>
<pre>// s.o. Punkt 1: die Basis-URL
#base http://ws.audioscrobbler.com/2.0/

// s.o. Punkt 2: API-Key muss immer mitgesendet werden
#static api_key ce59c153ff5e3003c74df5b618aeccac

// s.o. Punkt 3: Die Anfrage hat das Format "URL?Parameter" (ansonsten: #noquery)
#query

// s.o. Punkt 4: Wurzel ist der "lfm"-Knoten; wir brauchen die Namespaces "xspf" und "lastfm"
#rootnode
#namespace xspf http://xspf.org/ns/0/
#namespace lastfm http://www.audioscrobbler.net/dtd/xspf-lastfm

// s.o. Punkt 5: wenn kein Fehler aufgetreten ist, steht im Attribut "status" des "lfm"-Knotens "ok"
#errornode lfm/@status
#noerrorvalue ok</pre>
<p>Für &#8220;#rootnode&#8221; und &#8220;#errornode&#8221;, sowie später für Anfragen, wird Kenntnis von XPath benötigt. Es sei an dieser Stelle auf den <a href="http://de.wikipedia.org/wiki/XPATH">Wikipedia-Artikel zum Thema</a> verwiesen.</p>
<p>Da Last.FM als eines der Hauptanwendungsfelder für Lapicon gedacht war, lässt sich das oben geschriebene abkürzen:</p>
<pre>#lastfm</pre>
<p>Und schon ist Lapicon bereit dafür, zu arbeiten.</p>
<p><strong>Schritt 2: Wie soll das Programm ablaufen?</strong></p>
<p>Es ist immer wichtig, sich klarzumachen, was man jetzt eigentlich vorhat. Was also soll unser Script machen? Welche Daten brauchen wir dafür? Welche Anfragen müssen wir senden und welche Teile der Antworten verwenden?</p>
<p>Wir schreiben ein Script, das Alben sucht und anschließend komplett herunterlädt, also soll es folgende Schritte ausführen:</p>
<ol>
<li>Eingabe des Suchstrings</li>
<li>Verwendung der Funktion <a href="http://www.last.fm/api/show/?service=357">album.search</a> des Last.FM-APIs um eine Suche durchzuführen. Aus der Antwort lesen wir die Titel, Interpreten und IDs der einzelnen Alben aus.</li>
<li>Ausgabe einer nummerierten Liste mit Interpreten und Albumtitel</li>
<li>Eingabe der Nummer des gewünschten Albums</li>
<li>Verwendung der Funktion <a href="http://www.last.fm/api/show/?service=271">playlist.fetch</a>, um an die Tracks des Albums zu kommen. (Mit zwei nicht dokumentierten Parametern.) Wir verwenden die URLs und die Titel der Tracks.</li>
<li>Erstellen des Ausgabeverzeichnisses nach dem Muster &#8220;Interpret/Album&#8221;</li>
<li>Schleife, die einen Track nach dem anderen herunterlädt.</li>
<li>Ende.</li>
</ol>
<p><strong>Schritt 3: Implementierung</strong></p>
<p>Das Originalscript setzt zuerst die Last.FM-Einstellungen fest, dann lädt es die DarkSharpScripts-Konfigurationsdatei, die im selben Verzeichnis liegt:</p>
<pre>// Use Last.FM
#lastfm

// Include
inc(&lt;script directory&gt;/Config.DarkSharpScripts.lpc)</pre>
<p>Anschließend folgt die Eingabe des Suchstrings und eine Prüfung, ob auch wirklich etwas eingegeben wurde:</p>
<pre>// Search
def query &lt;&lt; Suchen
echo

[if &lt;query&gt; is not empty]</pre>
<p>Die Zeile &#8220;def query &lt;&lt; Suchen&#8221; bewirkt, dass der User eine Eingabezeile mit der Beschriftung &#8220;[in] Suchen:&#8221; vor sich hat. Drückt er die Enter-Taste wird alles eingegebene in der Variable &#8220;query&#8221; gespeichert. Um auf den Wert dieses Variable wiederum zuzugreifen, muss man sie in spitze Klammern setzen: &#8220;&lt;query&gt;&#8221;. Alles, was jetzt folgt, wird demnach nur ausgeführt, wenn der Wert von &#8220;query&#8221; nicht leer ist:</p>
<pre>   [album.search : album=&lt;query&gt;&amp;limit=&lt;DS_SearchLimit&gt;]*
   store* results/albummatches/album/name in albumTitles
   store* results/albummatches/album/artist in albumCreators
   store* results/albummatches/album/id in albumIDs

   // Choose
   f:displayAlbum n
      echo [&lt;n&gt;] &lt;albumCreators[&lt;n&gt;]&gt; - &lt;albumTitles[&lt;n&gt;]&gt;
   f:end
   forall* albumTitles index t: displayAlbum(&lt;t&gt;)
   echo</pre>
<p>Das Konstrukt in eckigen Klammern ist die Anfrage an Last.FM. Vor dem Doppelpunkt steht die Funktion, die aufgerufen werden soll, dahinter ihre Argumente &#8211; in diesem Fall &#8220;album&#8221; und &#8220;limit&#8221; mit den Werten der Variablen &#8220;query&#8221; und &#8220;DS_SearchLimit&#8221; (letztere aus der Konfigurationsdatei; sie legt fest, wie viele Suchergebnisse maximal angezeigt werden). Die Sternchen signalisieren, dass nun nicht ein einzelner Wert gespeichert werden soll, sondern eine Reihe von Werten in einer Liste. &#8220;store* results/albummatches/album/name in albumTitles&#8221; beispielsweise speichert alle Werte, die über diesen XPath (&#8220;results/&#8230;&#8221;) zu erreichen sind, in der Liste &#8220;albumTitles&#8221;.</p>
<p>Was dann folgt, ist eine Funktion, die genau einen Wert (die Variable &#8220;n&#8221;) als Argument erhält. Sie gibt anhand der beiden Listen &#8220;albumTitles&#8221; und &#8220;albumCreators&#8221; das n-te Album (wobei n bei 0 beginnt) aus. Hier sieht man den Zugriff auf einzelne Listenelemente: &lt;albumTitles[0]&gt; wäre z.B. der Titel des ersten gefundenen Albums, falls vorhanden.</p>
<p>Diese Funktion wird nun für jedes Element der Liste &#8220;albumTitles&#8221; aufgerufen, immer mit dem aktuellen Index als Argument. (Neben der gezeigten Version der &#8220;forall*&#8221;-Schleife gibt es noch eine weitere, die nicht den Index, sondern den Wert als Variable liefert: &#8220;forall* list as element: &#8230;&#8221;)</p>
<p>Jetzt kann der User eingeben, welches Album er haben will, anschließend wird die Playlist mit den einzelnen Titel geladen:</p>
<pre>   def nr &lt;&lt; Nummer des Albums
   echo

   // Album Info
   def albumID = &lt;albumIDs[&lt;nr&gt;]&gt;
   def albumName = file(&lt;albumTitles[&lt;nr&gt;]&gt;)
   def albumCreator = file(&lt;albumCreators[&lt;nr&gt;]&gt;)

   // Playlist Info
   [playlist.fetch : playlistURL=lastfm://playlist/album/&lt;albumID&gt;&amp;streaming=1&amp;fod=1]*
   store* xspf:playlist/xspf:trackList/xspf:track/xspf:title in trackTitles
   store* xspf:playlist/xspf:trackList/xspf:track/xspf:location in trackLocation</pre>
<p>Die Zeile &#8220;def albumName = file(&#8230;)&#8221; speichert in der Variable &#8220;albumName&#8221; einen bereinigten, für Dateinamen geeigneten String. Jetzt haben wir die URLs und Titel der Tracks, die wir herunterladen wollen. Und genau das macht der folgende Abschnitt &#8211; wieder nach dem Prinzip: &#8220;Lade die Datei mit dem Index &#8220;index&#8221; herunter!&#8221;</p>
<pre>   [if &lt;trackLocation length&gt; != 0]

      // Directory
      def dir = &lt;DS_AlbumsPath&gt;&lt;albumCreator&gt;/&lt;albumName&gt;
      mkdir &lt;dir&gt;

      // Download Function
      f:dl index
         def title = file(&lt;trackTitles[&lt;index&gt;]&gt;)
         def nindex
         nindex ::= &lt;index&gt;+1
         echo Downloading(&lt;nindex&gt;/&lt;trackLocation length&gt;) &lt;albumCreator&gt; - &lt;title&gt;...
         def fn = &lt;dir&gt;/&lt;nindex&gt; - &lt;albumCreator&gt; - &lt;title&gt;.mp3
         lpc(&lt;script directory&gt;/ResolveAndDownload.lpc) with &lt;trackLocation[&lt;index&gt;]&gt;|&lt;fn&gt;
         mp3Gain(&lt;fn&gt;)
      f:end

      // Download
      forall* trackTitles as t: dl(&lt;trackTitles counter&gt;)
      //
      wait

   [else]

      wait Album nicht herunterladbar

   [endif]

[else]

   wait Keine Sucheingabe

[endif]</pre>
<p>Wir sehen einiges Neues hier: die Funktion &#8220;mkdir&#8221; erstellt ein Verzeichnis, die Zuweisung mit &#8220;::=&#8221; löst eine Berechnung aus (damit &#8220;nindex&#8221; um 1 größer ist als &#8220;index&#8221;) und dann das Konstrukt &#8220;lpc(&#8230;) with &#8230;&#8221;. Hier geschieht folgendes: Lapicon ruft das Script ResolveAndDownload.lpc auf, das im selben Verzeichnis liegt, und zwar mit den <span style="text-decoration: underline;">Kommandozeilenargumenten</span> &lt;trackLocation[&lt;index&gt;]&gt; und &lt;fn&gt;. Dieses kleine Hilfsscript macht nichts anderes, als die übergebene URL (das erste Argument) mithilfe von HTTP aufzulösen und dann herunterzuladen. Das zweite Argument ist der Name der heruntergeladenen Datei. Es sollte sich also eigentlich von selbst erschließen:</p>
<pre>// Data
def url = &lt;cmd 1&gt;
def file = &lt;cmd 2&gt;

// Resolve
def rurl

#error off
rurl = resolve &lt;url&gt;
#error on

[if &lt;rurl&gt; is not empty]

   down &lt;rurl&gt; &gt;&gt; &lt;file&gt;

[else]

   echo Resolving URL "&lt;url&gt;" failed...
   echo
   wait Taste drücken zum Beenden
   exit

[endif]</pre>
<p>Die Funktion &#8220;mp3Gain&#8221;, die nach dem &#8220;lpc&#8221;-Statement kommt, ist in der Konfigurationsdatei definiert und ruft ein Hilfsprogramm auf, das wiederum mit der mp3Gain.exe,  die im selben Verzeichnis liegt, die Musikdatei normalisiert:</p>
<pre>// MP3-Gain
f:mp3Gain file

   [if &lt;file&gt; is not empty]

      echo Normalisieren...
      shell: &lt;script directory&gt;/ExecuteMp3Gain.bat | "&lt;file&gt;"

   [endif]

f:end</pre>
<p>Eine genaue Übersicht über alle von Lapicon unterstützen Funktionen findet sich in der Datei Lapicon.txt oder auf SourceForge: <a href="http://lastsharp.svn.sourceforge.net/viewvc/lastsharp/branches/Lapicon/Lapicon.txt?view=markup&amp;pathrev=65">http://lastsharp.svn.sourceforge.net/viewvc/lastsharp/branches/Lapicon/Lapicon.txt?view=markup&amp;pathrev=65</a></p>
<p><strong>Beispiel 2: Lyrics.lpc</strong></p>
<pre>// -------------------------------------------------------------------
// DarkSharp.Lyrics
//   Downloads lyrics
//   Copyright (c) 2009 Yannick Scherer
// -------------------------------------------------------------------
// Lyricwiki
#base http://lyricwiki.org/api.php
#rootnode LyricsResult
#static func getSong
#static fmt xml

// Config
inc(&lt;script directory&gt;/Config.DarkSharpScripts.lpc)

// Input
def artist &lt;&lt; Interpret
def track &lt;&lt; Titel

// Get Lyrics from Lyricwiki
[artist=&lt;artist&gt;&amp;song=&lt;track&gt;] store lyrics in lyrics

[if &lt;lyrics&gt; is not empty]
   // Clean
   artist = file(&lt;artist&gt;)
   track = file(&lt;track&gt;)
   // Save
   mkdir &lt;DS_LyricsPath&gt;
   echo crlf(&lt;lyrics&gt;) &gt;&gt;&gt; &lt;DS_LyricsPath&gt;&lt;artist&gt; - &lt;track&gt;.txt
[else]
   echo Keine Lyrics gefunden!
[endif]

echo
wait</pre>
<p>Anmerkungen hierzu: man kann Anfragen auch in einer Zeile und/oder ohne Angabe der Funktion schreiben. Letzteres ist immer dann notwendig, wenn der Parameter, der die Funktion enthält, nicht &#8220;method&#8221; heißt.</p>
<p>Des weiteren sieht man eine Dateiausgabe: zuerst wird mit &#8220;artist = file(&lt;artist&gt;)&#8221; der Interpret und anschließend der Titel bereinigt, dann wird ein Verzeichnis erstellt und anschließend eine Ausgabe in eine Datei getätigt. Das Einschließen der Lyrics in &#8220;crlf(&#8230;)&#8221; bewirkt, dass Zeilenumbrüche richtig umgesetzt werden; das Verwenden von &#8220;&gt;&gt;&gt;&#8221; statt &#8220;&gt;&gt;&#8221; zwingt Lapicon, eine evtl. vorhandene Datei zu überschreiben, anstatt an deren Ende etwas anzuhängen.</p>
<p>Das Nachvollziehen der Grundeinstellungen bleibt jedem selbst überlassen.</p>
<p>Ich hoffe, damit konnte ich ein wenig helfen, wenn es um die Arbeit mit Lapicon geht!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/04/kurzanleitung-zu-lapicon/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>[Release] Lapicon 1.0.5</title>
		<link>http://dev.xscheme.de/2009/04/release-lapicon-105/</link>
		<comments>http://dev.xscheme.de/2009/04/release-lapicon-105/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 14:15:42 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[Lapicon]]></category>
		<category><![CDATA[webservice]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=605</guid>
		<description><![CDATA[Ich habe vor einiger Zeit bereits einmal Lapicon erwähnt. Der Name steht für &#8220;Loose API Connection Language&#8221; und bezeichnet eine Scriptsprache, die Ähnlichkeiten mit Batch aufweist und dafür gedacht ist, mit XML-basierten WebServices zu interagieren.
Das klingt jetzt extrem technisch, das gebe ich zu, aber im Prinzip ist es ganz einfach: das Last.FM-API beispielsweise kann über [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe vor einiger Zeit bereits einmal <strong>Lapicon</strong> erwähnt. Der Name steht für &#8220;<strong>L</strong>oose <strong>API</strong> <strong>Con</strong>nection Language&#8221; und bezeichnet eine Scriptsprache, die Ähnlichkeiten mit Batch aufweist und dafür gedacht ist, mit XML-basierten WebServices zu interagieren.</p>
<p>Das klingt jetzt extrem technisch, das gebe ich zu, aber im Prinzip ist es ganz einfach: das Last.FM-API beispielsweise kann über Adressen der Form</p>
<pre>http://ws.audioscrobbler.com/2.0/?method=[Funktion]&amp;api_key=[APIKey]&amp;[sonstige Parameter]</pre>
<p>aufgerufen werden. Daraufhin wird eine Antwort gesendet, die folgende Form hat:</p>
<pre>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;lfm status="ok"&gt;
(...)
&lt;/lfm&gt;</pre>
<p>Will man diese Antworten nun auswerten, müsste man sie als Programmierer zuerst per Hand auseinandernehmen oder auf entsprechende Bibliotheken zurückgreifen. Hinzu kommt natürlich der Aufwand beim Erstellen der Anfrage, beim Fehler abfangen, etc&#8230; Meist hat man dann mehr Daten gesammelt, als man eigentlich benötigt, hatte einen Haufen Schreibaufwand und weiß, bei der nächsten Anfrage geht&#8217;s wieder von vorne los. Lapicon übernimmt das alles und ermöglicht so eine gezielte Abfrage und Ausgabe von Daten in drei Zeilen.</p>
<p><span id="more-605"></span>Ein Lapicon-Script, dass beispielsweise die Last.FM-ID eines Titels abruft, wäre das folgende:</p>
<pre>#lastfm
[track.getInfo : artist=the+kooks&amp;track=see+the+sun] store track/id in trackID
echo ID: &lt;trackID&gt;</pre>
<p>Hierbei wäre der gewünschte Track im Code verankert. Genauso gut könnten wir auch den User entscheiden lassen, was er haben will:</p>
<pre>#lastfm
read Interpret to artist
read Titel to track
[track.getInfo : artist=&lt;artist&gt;&amp;track=&lt;track&gt;] store track/id in trackID
echo ID: &lt;trackID&gt;</pre>
<p>So einfach kann es gehen. Eine genaue Beschreibung des gesamten Befehlssatzes findet man in der Lapicon.txt, die sich im Paket oder <a href="http://lastsharp.svn.sourceforge.net/viewvc/lastsharp/branches/Lapicon/Lapicon.txt?view=markup">hier</a> findet. Ich werde aber demnächst noch eine Kurzeinführung verfassen.</p>
<p>Außerdem habe ich ein paar Lapicon-Scripts geschrieben, die es ermöglichen einzelne Tracks bis hin zu ganzen Alben anonym von Last.FM herunterladen. Dieses Paket, <strong>DarkSharpScripts,</strong> wird ebenfalls demnächst zum Download bereit stehen. Ich warte damit allerdings noch bis zur Veröffentlichung von LeSharp, da dort das kleine Programm <strong>Pico</strong> (Path to ID3 Converter) enthalten ist, dass anhand eines Dateipfades ID3-Tags nachträgt. Somit die richtige Ergänzung für die Lapicon-MP3s, die ohne Tags daherkommen.</p>
<p>Ich würde mich freuen, wenn irgendwer Lapicon ausprobieren würde. Am einfachsten geht das übrigens, wenn man eine Datei mit der Endung &#8220;.lpc&#8221; erstellt, unter Windows darauf doppelklickt und den Lapicon-Interpreter als Standardanwendung auswählt. Dann kann man die Scripts ab sofort per Doppelklick starten.</p>
<p>Download (SourceForge): <a href="https://sourceforge.net/project/showfiles.php?group_id=255668&amp;package_id=319513&amp;release_id=677641">https://sourceforge.net/project/showfiles.php?group_id=255668&amp;package_id=319513&amp;release_id=677641</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/04/release-lapicon-105/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Lapicon: Loose API Connection Language</title>
		<link>http://dev.xscheme.de/2009/03/lapicon-1/</link>
		<comments>http://dev.xscheme.de/2009/03/lapicon-1/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 01:11:19 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[Lapicon]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=566</guid>
		<description><![CDATA[Im Moment arbeite ich an einem kleinen Tool mit dem Arbeitstitel &#8220;LessSharp&#8221;, dass sich &#8211; ähnlich wie Lea, deren Funktionen es womöglich übernehmen wird, aber das weiß ich noch nicht &#8211; aus der Grauzone LastSharps erhebt und auf ganz legalem Wege nützlich sein soll. Als kleines Nebenprodukt ist Lapicon entstanden &#8211; ein Interpreter für eine [...]]]></description>
			<content:encoded><![CDATA[<p>Im Moment arbeite ich an einem kleinen Tool mit dem Arbeitstitel &#8220;LessSharp&#8221;, dass sich &#8211; ähnlich wie Lea, deren Funktionen es womöglich übernehmen wird, aber das weiß ich noch nicht &#8211; aus der Grauzone LastSharps erhebt und auf ganz legalem Wege nützlich sein soll. Als kleines Nebenprodukt ist <strong>Lapicon</strong> entstanden &#8211; ein Interpreter für eine Batch-ähnliche Skriptsprache, die dafür gedacht ist, <strong>einfache Last.FM-API-Anfragen zu senden</strong>.</p>
<p><span id="more-566"></span>Hier ein Beispiel, dass die Top-Tags zu einem bestimmten Titel auflistet:</p>
<pre>// LastFM verwenden
#lastfm

// Interpret und Titel vom User erfragen
def artist = read Interpret
def track = read Titel

// Absenden
[track.getInfo : artist=&lt;artist&gt;&amp;track=&lt;track&gt;]* store track/toptags/tag/name in tags

// Ausgeben
forall* tags as tag: echo &lt;tag&gt;

// Fenster offen halten
def dummy = read Enter druecken...</pre>
<p>Damit lassen sich Last.FM-API-Anfragen einfach und schnell versenden und die Antworten gezielt auswerten. Natürlich ist das alles noch nicht ausgereift, aber mit ein bisschen Arbeit wird da schon noch etwas draus. Wer allerdings jetzt schon damit herumspielen möchte, findet Lapicon hier:</p>
<p><span style="text-decoration: line-through;"><a href="http://dev.xscheme.de/wp-content/uploads/2009/03/lapicon-10.rar">Download Lapicon 1.0</a></span> (nicht aktuell, beim Download die beigefügten Beispiele beachten!)<span style="text-decoration: line-through;"><br />
</span></p>
<p>Ich möchte an dieser Stelle mal meinen Zeitplan offenlegen:</p>
<ul>
<li>Reise nach Peru: 25.03.-15.04.</li>
<li>LastSharp 0.4.1: um den 25. April</li>
<li>&#8220;LessSharp&#8221; oder wie auch immer es heißen wird: Mitte Mai</li>
</ul>
<p>Alles weitere sieht man dann schon&#8230;</p>
<p><strong>UPDATE (23.03.2009): </strong>Beispiel auf aktuellen Stand des Programms angepasst.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/03/lapicon-1/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
