merge
This commit is contained in:
commit
ebaddcf030
7 changed files with 195 additions and 18 deletions
177
sys/man/1/zuke
Normal file
177
sys/man/1/zuke
Normal 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).
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(type != Tunknown){
|
||||
ctx->found |= 1<<type;
|
||||
ctx->num++;
|
||||
}
|
||||
if(*s)
|
||||
if(*s){
|
||||
ctx->tag(ctx, type, k, s, offset, size, f);
|
||||
if(type != Tunknown){
|
||||
ctx->found |= 1<<type;
|
||||
ctx->num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue