This commit is contained in:
cinap_lenrek 2021-05-05 01:51:20 +02:00
commit ebaddcf030
7 changed files with 195 additions and 18 deletions

177
sys/man/1/zuke Normal file
View file

@ -0,0 +1,177 @@
.TH ZUKE 1
.SH NAME
mkplist, zuke \- graphical music player
.SH SYNOPSIS
.B audio/mkplist
.I directory/file/URL [...]
.br
.B audio/zuke
[
.B -s
] [
.B -c
.I columns
]
.SH DESCRIPTION
.PP
.I Zuke
is a graphical music player that reads a playlist from standard input
and presents an interface to play music. Playlists are generated
by
.IR mkplist ,
which accepts files, directories, and URLs as its arguments,
and writes the resulting playlist to standard output.
.PP
Formats supported by
.I zuke
are: MP3, OGG/Vorbis, FLAC, and WAV. With additional programs, Opus,
modules and M4A (AAC) can be played.
.I Zuke
also supports network streams, such as IceCast.
Option
.B -s
enables ``shuffle'' mode on start.
.PP
The columns (and their order) displayed can be changed by passing the
following letters along
.B -c
option:
.RS
.TF "c"
.TP
.B A
Artist
.TP
.B a
Album
.TP
.B b
File basename
.TP
.B t
Title
.TP
.B D
Duration
.TP
.B d
Date
.TP
.B T
Track number
.TP
.B p
Full file path
.PD
.RE
.PP
By default, artist, album, title, and duration are displayed, which
corresponds to
.B "-c AatD."
.PP
.I Zuke
can be controlled with a mouse, keyboard, and plumber. Button 1
selects a track, button 2 plays a track. Clicking on the seek bar
changes the playback position accordingly. On the right of the seek
bar, current position, track duration and volume are displayed. ``∫''
is shown if shuffle mode is enabled.
.PP
.I Zuke
provides a number of keyboard controls:
.RS
.TF "p c Space"
.TP
.B -
Lower volume.
.TP
.B + =
Increase volume.
.TP
.B ← →
Seek 10 seconds back/forward.
.TP
.B , .
Seek 60 seconds back/forward.
.TP
.B ↑ ↓ Pgup Pgdown Home End
Move within the playlist.
.TP
.B o i
Jump to current track.
.TP
.B Enter
Play selected track.
.TP
.B > b
Skip to next track.
.TP
.B < z
Skip to previous track.
.TP
.B v
Stop
.TP
.B p c Space
Pause/Resume.
.TP
.B s
Toggle ``shuffle''.
.TP
.B q Del
Quit.
.TP
.B /
Search forward.
.TP
.B ?
Search backwards.
.TP
.B n
Repeat search forward.
.TP
.B N
Repeat search backwards.
.RE
.PD
.PP
.I Zuke
can be controlled by emulating key presses via the plumber port
.IR audio .
.PP
Files present in the current playlist can be plumbed too, and will be
played immediately.
.SH EXAMPLES
Generate a playlist:
.IP
.EX
audio/mkplist /usr/glenda/music \\
file.mp3 \\
http://stream.nauticradio.net:14280/ > music.plist
.EE
.PP
Playing a playlist:
.IP
.EX
audio/zuke < music.plist
.EE
.PP
Append to a playlist:
.IP
.EX
audio/mkplist /n/moremusic >> music.plist
.EE
.PP
Skip to the next track using plumber:
.IP
.EX
plumb -d audio 'key >'
.EE
.SH SEE ALSO
.IR play (1)
.SH SOURCE
.B /sys/src/cmd/audio/zuke
.br
.B /sys/src/cmd/audio/libtags
.SH HISTORY
.I Zuke
first appeared in 9front (April, 2021).

View file

@ -3,12 +3,12 @@
int
tagit(Tagctx *ctx)
{
char d[4+26+1], o[26*UTFmax+1];
uchar d[4+26+1], o[26*2+1];
if(ctx->read(ctx, d, 4+26) != 4+26 || memcmp(d, "IMPM", 4) != 0)
return -1;
d[4+26] = 0;
if(cp437toutf8(o, sizeof(o), d+4, 26) > 0)
if(iso88591toutf8(o, sizeof(o), d+4, 26) > 0)
txtcb(ctx, Ttitle, "", o);
return 0;

View file

@ -16,6 +16,7 @@ static char *variants[] =
"CD81",
"OCTA",
"OKTA",
"10CH",
"16CN",
"32CN",
nil,
@ -24,7 +25,7 @@ static char *variants[] =
int
tagmod(Tagctx *ctx)
{
char d[20], o[20*UTFmax+1];
uchar d[20], o[20*2+1];
int i;
if(ctx->seek(ctx, 1080, 0) != 1080)
@ -41,7 +42,7 @@ tagmod(Tagctx *ctx)
return -1;
if(ctx->read(ctx, d, 20) != 20)
return -1;
if(cp437toutf8(o, sizeof(o), d, 20) > 0)
if(iso88591toutf8(o, sizeof(o), d, 20) > 0)
txtcb(ctx, Ttitle, "", o);
return 0;

View file

@ -41,19 +41,20 @@ tagscallcb(Tagctx *ctx, int type, const char *k, char *s, int offset, int size,
char *e;
if(f == nil && size == 0){
while(*s <= ' ' && *s)
while((uchar)*s <= ' ' && *s)
s++;
e = s + strlen(s);
while(e != s && e[-1] <= ' ')
while(e != s && (uchar)e[-1] <= ' ')
e--;
*e = 0;
}
if(*s){
ctx->tag(ctx, type, k, s, offset, size, f);
if(type != Tunknown){
ctx->found |= 1<<type;
ctx->num++;
}
if(*s)
ctx->tag(ctx, type, k, s, offset, size, f);
}
}
int

View file

@ -41,4 +41,4 @@ void cbvorbiscomment(Tagctx *ctx, char *k, char *v);
void tagscallcb(Tagctx *ctx, int type, const char *k, char *s, int offset, int size, Tagread f);
#define txtcb(ctx, type, k, s) tagscallcb(ctx, type, k, (const char*)s, 0, 0, nil)
#define txtcb(ctx, type, k, s) tagscallcb(ctx, type, k, (char*)s, 0, 0, nil)

View file

@ -3,12 +3,11 @@
int
tagxm(Tagctx *ctx)
{
char d[17+20+1], o[20*UTFmax+1], *s;
char d[17+20+1], o[20*UTFmax+1];
if(ctx->read(ctx, d, 17+20) != 17+20 || memcmp(d, "Extended Module: ", 17) != 0)
if(ctx->read(ctx, d, 17+20) != 17+20 || cistrncmp(d, "Extended Module: ", 17) != 0)
return -1;
d[17+20] = 0;
for(s = d+17; *s == ' '; s++);
if(cp437toutf8(o, sizeof(o), d+17, 20) > 0)
txtcb(ctx, Ttitle, "", o);

View file

@ -175,10 +175,9 @@ addchild(Mesg *p, Mesg *m, int d)
assert(m->parent == nil);
for(q = p; q != nil; q = q->parent){
if(ideq(m->messageid, q->messageid)){
fprint(2, "wonky message replies to self\n");
/* some messages refer to themselves */
if(ideq(m->messageid, q->messageid))
return 0;
}
if(m->time > q->time)
q->time = m->time;
}