last

git clone git://oldgit.suckless.org/last/
Log | Files | Refs

commit fc70639523ebd14acd776a5bb14cedc198de81cc
parent 184d2e480ecd07edc897e77c42b6028eb7b26c6d
Author: Kris Maglione <jg@suckless.org>
Date:   Mon, 24 Aug 2009 13:56:37 -0400

Minor changes, what I don't know.

Diffstat:
http.c | 9++++++---
last.c | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
pass | 16++++++++++++++++
player.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
posix.c | 7+++++--
util.c | 7++++---
6 files changed, 143 insertions(+), 45 deletions(-)

diff --git a/http.c b/http.c @@ -66,10 +66,11 @@ hconv(Fmt *f) { for(p=s; (c = *p); p++) { if(c & 0x80 || !isprint(c) || isspace(c)) break; + if(c == '%' && !(f->flags & FmtComma)) + break; switch(c) { default: continue; - case '%': case '<': case '>': case '{': @@ -85,6 +86,7 @@ hconv(Fmt *f) { case '+': break; } + break; } if(p != s) ret += fmtprint(f, "%.*s", p-s, s); @@ -92,7 +94,7 @@ hconv(Fmt *f) { if(c == ' ') ret += fmtstrcpy(f, "+"); else - ret += fmtprint(f, "%%%02X", c); + ret += fmtprint(f, "%%%02uX", (uchar)c); p++; } } @@ -122,11 +124,12 @@ Hconv(Fmt *f) { case '\\': break; } + break; } if(p != s) ret += fmtprint(f, "%.*s", p-s, s); if(c) { - ret += fmtprint(f, "%%%02X", c); + ret += fmtprint(f, "%%%02uX", (uchar)c); p++; } } diff --git a/last.c b/last.c @@ -1,10 +1,13 @@ #define EXTERN +#define _GNU_SOURCE #include <u.h> #include <libc.h> #include <auth.h> #include <bio.h> #include <mp.h> #include <libsec.h> +#include <signal.h> +#include <string.h> #include <thread.h> #include "last.h" @@ -52,8 +55,9 @@ struct Assoc { Rartist, "Conlon Nancarrow", Rartist, "Iannis Xenakis", Rartist, "Olivier Messiaen", + Rartist, "Mauricio Kagel", Ralbum, "Music Box", - 0, 0, + 0, }; char* @@ -66,9 +70,15 @@ erespval(int i) { } void -exitsall(char *err) { - if(err) +exitsall(char *err, ...) { + va_list ap; + + if(err) { + va_start(ap, err); + err = vsmprint(err, ap); + va_end(ap); print("threadexitsall(%s)\n", err); + } threadexitsall(err); } @@ -125,7 +135,10 @@ get(char *path, char *fmt, ...) { if(debug['a'] && !debug['h']) print("GET %q %s\n", host, uri); - b = httpget(host, uri); + do { + b = httpget(host, uri); + rerrstr(buf, sizeof buf); + }while(b == nil && strcasestr(buf, "interrupted")); free(uri); if(b == nil) { resp[Rresponse] = smprint("get fails: %r"); @@ -177,6 +190,24 @@ rpc(const char *cmd, const char *fmt, ...) { return i; } +void +erpc(const char *cmd, const char *fmt, ...) { + VFmt v; + + v.fmt = query(nil, fmt); + va_start(v.args, fmt); + if(get("%s/%s.php", "session=%h %V", basepath, cmd, session, &v)) + sysfatal("rpc %s: %r\n", cmd); + va_end(v.args); + free(v.fmt); +} + +int +skip(char *cmd) { + skipping = 1; + return rpc("control", "command=%h", cmd); +} + static void printresp(void) { char *s; @@ -203,8 +234,7 @@ getmeta(void) { do { if(n > 50) exitsall("meta"); - if(rpc("np", "")) - exitsall("rpc np"); + erpc("np", ""); }while(resp[Rstreaming] == nil || strcmp(resp[Rstreaming], "true")); s = resp[Rtrackduration]; @@ -215,7 +245,7 @@ getmeta(void) { print("\n"); print("Station: %R\n", Rstation); - print("Atrist: %R <%R>\n", Rartist, Rartist_url); + print("Artist: %R <%R>\n", Rartist, Rartist_url); print("Album: %R\n", Ralbum); print("Track: %R\n", Rtrack); print("Duration: %d:%02d\n", sec/60, sec%60); @@ -223,14 +253,13 @@ getmeta(void) { print("\n"); print("> "); - label("Playing \"%R\" by %R", Rtrack, Rartist); + label("Playing “%R” by %R", Rtrack, Rartist); for(a=junk; a->str; a++) if(resp[a->field] && cistrstr(resp[a->field], a->str)) { print("Junk %s; banning.\n", respnam[a->field]); - rpc("control", "command=ban"); + skip("ban"); printresp(); - skipping = 1; break; } } @@ -246,7 +275,7 @@ userinfo(char **user, char **pass) { if(up == nil) sysfatal("no username/password: %r"); - md5(up->passwd, strlen(up->passwd), digest, nil); + md5((uchar*)up->passwd, strlen(up->passwd), digest, nil); for(i=0; i < MD5dlen; i++) sprint(buf+2*i, "%02x", digest[i]);; @@ -274,6 +303,9 @@ threadmain(int argc, char *argv[]) { fmtinstall('R', Rconv); quotefmtinstall(); + signal(SIGCHLD, SIG_IGN); + notifyoff("sys: child"); + label("Wait..."); httpinit(); @@ -297,7 +329,11 @@ threadmain(int argc, char *argv[]) { label("Stopped."); Binit(&in, 0, OREAD); - while(print("> "), s = Brdline(&in, '\n')) { + while(print("> "), Bgetc(&in) != Beof) { + Bungetc(&in); + s = Brdline(&in, '\n'); + if(s == nil) + continue; s[BLINELEN(&in)-1] = '\0'; q = tok(&s); if(!strcmp(q, "start")) { @@ -306,18 +342,28 @@ threadmain(int argc, char *argv[]) { if(!strcmp(q, "stop")) { endstream(); }else + if(!strcmp(q, "info")) { + getmeta(); + }else if(!strcmp(q, "skip") || !strcmp(q, "ban")) { - skipping = 1; label("Skipping..."); - rpc("control", "command=%h", q); + skip(q); printresp(); }else if(!strcmp(q, "love")) { rpc("control", "command=love"); printresp(); }else + if(!strcmp(q, "artist")) { + rpc("adjust", "url=%h%h", "lastfm://artist/", s); + printresp(); + }else + if(!strcmp(q, "tag")) { + rpc("adjust", "url=%h%h", "lastfm://globaltags/", s); + printresp(); + }else if(!strcmp(q, "station")) { - rpc("adjust", "url=%h", s); + rpc("adjust", "url=%,h", s); printresp(); }else if(!strcmp(q, "time")) { diff --git a/pass b/pass @@ -0,0 +1,16 @@ +#!/bin/rc +. 9.rc + +echo Enter your last.fm login credentials. +echo -n Username: '' +username=`{read} +echo -n Password: '' +stty -echo +pass=`{read} +stty echo + +9p read factotum/ctl >/dev/null >[2=1] || 9 factotum & + +echo 'delkey dom=last.fm' | 9p write factotum/ctl >[2]/dev/null +echo 'key user='$"username' !password='$"pass' dom=last.fm proto=pass' | 9p write factotum/ctl >/dev/null >[2=1] + diff --git a/player.c b/player.c @@ -25,7 +25,9 @@ playerproc(void *v) { fd[0] = dup(fdin, -1); fd[1] = open("/dev/null", OWRITE); fd[2] = open("/dev/null", OWRITE); + notedisable("alarm"); cpid = threadspawn(fd, player[0], player); + noteenable("alarm"); do{ m = recvp(cwait); i = 0; @@ -65,12 +67,29 @@ tgetc(Biobuf *b) { #define GETC(bp) \ ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:tgetc((bp))) +static int +scan(int c, char *str) { + char *s; + + s=str; + do { + if(*s++ != c) + break; + if(*s == '\0') + return 1; + }while((c = GETC(stream)) != Beof); + while(--s > str) + Bungetc(stream); + return 0; +} + static void proxyproc(void *v) { char errbuf[16]; - int c, i; + int c, i, j, bytes; qlock(&lk); + j = 0; while(playing) { label("Starting stream."); if(debug['p']) @@ -82,34 +101,37 @@ proxyproc(void *v) { if(stream) break; if(i++ > 5) { - fprint(2, "can't get stream: %r\n"); + msg("Can't get stream: %r\n"); playing = 0; } rerrstr(errbuf, sizeof errbuf); - }while(playing && !strcmp(errbuf, "interrupted")); + }while(playing && !strcasestr(errbuf, "interrupted")); c = 0; + bytes = 0; while(playing && (c = GETC(stream)) != Beof) { - if(c == 'S') { - i = 0; - if(i++, 'Y' == GETC(stream)) - if(i++, 'N' == GETC(stream)) - if(i++, 'C' == GETC(stream)) { - if(debug['v']) - msg("SYNC\n"); - skipping = 0; - getmeta(); - continue; + if(scan(c, "SYNC")) { + if(debug['v']) + msg("SYNC\n"); + skipping = 0; + getmeta(); + }else + if(scan(c, "HTTP/1.0 ")) { + msg("Stream died: %.*s\n", Blinelen(stream)-1, Brdline(stream, '\n')); + playing = 0; + }else { + bytes++; + if(!skipping) + BPUTC(&playerin, c); + else { + playerin.ocount = -playerin.bsize; + /* Waited too long, probably won't actually skip. + * Just start a new stream. + */ + /* 8192 is arbitrary. */ + if(skipping++ > 8192) + break; } - while(i--) - Bungetc(stream); - } - if(!skipping) - BPUTC(&playerin, c); - else { - playerin.ocount = -playerin.bsize; - if(skipping++ > 8192) - break; } } if(debug['p'] && !playing) @@ -117,6 +139,12 @@ proxyproc(void *v) { if(c == Beof) msg("Stream died\n"); Bterm(stream); + if(bytes > 2048) + j = 0; + else if(j++ > 15) { + msg("Stream won't stay open\n"); + playing = 0; + } } qunlock(&lk); } @@ -139,6 +167,7 @@ endstream(void) { return; playing = 0; + postnote(PNGROUP, getpid(), "alarm"); qlock(&lk); qunlock(&lk); diff --git a/posix.c b/posix.c @@ -6,7 +6,10 @@ void noblock(int fd) { - if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) + int old; + + old = fcntl(fd, F_GETFL, 0); + if(fcntl(fd, F_SETFL, old | O_NONBLOCK) == -1) sysfatal("Can't set O_NONBLOCK for %d: %r", fd); } @@ -24,7 +27,7 @@ label(const char *fmt, ...) { print("\033];LastFM: %V\007", &v); va_end(v.args); - return; + /* return; */ if(status == nil) { home = getenv("HOME"); diff --git a/util.c b/util.c @@ -7,7 +7,7 @@ static void eat(char **s, int (*p)(int), int r) { char *q; - for(q=*s; p(*q) == r; q++) + for(q=*s; *q && p(*q) == r; q++) ; *s = q; } @@ -19,6 +19,8 @@ tok(char **s) { eat(s, isspace, 1); p = *s; eat(s, isspace, 0); + if(**s) + *(*s)++ = '\0'; eat(s, isspace, 1); return p; } @@ -28,10 +30,9 @@ printfile(char *file, const char *fmt, ...) { va_list ap; int fd; - fd = open(file, OWRITE); + fd = open(file, OWRITE|ONONBLOCK); if(fd < 0) return; - noblock(fd); va_start(ap, fmt); vfprint(fd, (char*)fmt, ap);