shithub: mpl

Download patch

ref: fde5a0286017c96a4c127b45ba69af27b61c4835
parent: f0bb0451afe4b3d4719c6b2446dfa8034c9eb4fc
author: Jacob Moody <[email protected]>
date: Tue Sep 17 10:06:26 EDT 2019

Parse folder of albums instead of just one, and draw >1 to the screen if possible
Fix playback on native 9front install
Fallback to file name if MP3 IDV1 tags are not found
Do case insesitive check on vorbis tag keys

--- a/dec.c
+++ b/dec.c
@@ -50,6 +50,12 @@
 	if(afd < 0)
 		sysfatal("could not open audio device");
 	bufsize = iounit(afd);
+	/*
+	* On native plan9 installs this will return 0,
+	* so we default to the default iosize.
+	*/
+	if(bufsize == 0)
+		bufsize = 8192;
 	buf = emalloc(bufsize);
 
 	for(;;){
--- a/dir.c
+++ b/dir.c
@@ -62,10 +62,9 @@
 	return nil;
 }
 
-Album*
-dir2album(char *path)
+void
+dir2album(Album *a, char *path)
 {
-	Album *a;
 	Dir *files;
 	int fd;
 	long n;
@@ -78,21 +77,23 @@
 
 	fd = open(path, OREAD);
 	if(fd < 0)
-		return nil;
+		return;
 
 	n = dirreadall(fd, &files);
 	close(fd);
 	if(n <= 0)
-		return nil;
+		return;
 
-	a = emalloc(sizeof(Album));
-
 	/* Do a single pass to find cover.^(jp^(eg g) png) */
 	for(i=0;i<n;i++){
-		dot = strstr(path, "cover.");
-		if(dot == nil)
-			continue;
-		dot+=1;
+		dot = cistrstr(files[i].name, "cover.");
+		if(dot == nil){
+			dot = cistrstr(files[i].name, "folder.");
+			if(dot == nil)
+				continue;
+		}
+		dot = strrchr(dot, '.');
+		dot++;
 		snprint(buf, 512, "%s/%s", path, files[i].name);
 		fd = open(buf, OREAD);
 		if(fd<0)
@@ -101,8 +102,10 @@
 		a->cover = convpic(fd, dot);
 		if(a->cover != nil){
 			needpic = 0;
+			close(fd);
 			break;
 		}
+		close(fd);
 	}
 
 	/* Greedy alloc to start, we will trim down later */
@@ -146,5 +149,42 @@
 	a->songs = realloc(a->songs, sizeof(Song*) * songcount);
 
 	free(files);
-	return a;
+	return;
+}
+
+int
+parselibrary(Album **als, char *path)
+{
+	Dir *files;
+	int fd;
+	uint n, i;
+	uint numdirs = 0;
+	uint alcount = 0;
+	char buf[512];
+
+	fd = open(path, OREAD);
+	if(fd < 0)
+		return 0;
+
+	n = dirreadall(fd, &files);
+	close(fd);
+	if(n <= 0)
+		return 0;
+
+	for(i=0;i<n;i++)
+		if(files[i].qid.type&QTDIR)
+			numdirs++;
+
+	*als = emalloc(sizeof(Album)*numdirs);
+	for(i=0;i<n;i++)
+		if(files[i].qid.type&QTDIR){
+			snprint(buf, 512, "%s/%s", path, files[i].name);
+			dir2album(*als+alcount, buf);
+			if(*als+alcount != nil)
+				alcount++;
+		}
+
+	*als = realloc(*als, sizeof(Album)*alcount);
+
+	return alcount;
 }
\ No newline at end of file
--- a/draw.c
+++ b/draw.c
@@ -133,16 +133,18 @@
 	return i;
 }
 
-void
-drawalbum(Album *a, Image *textcolor, Image *active, int cursong)
+Point
+drawalbum(Album *a, Image *textcolor, Image *active, Point start, int cursong)
 {
 	uint i;
-	Point p = screen->r.min;
 	Font *f = screen->display->defaultfont;
 	Rune *tracktitle = nil;
+	Point p = start;
 
-	draw(screen, screen->r, a->cover, nil, ZP);
-	p.x += a->cover->r.max.x;
+	if(a->cover != nil){
+		draw(screen, Rpt(p, addpt(p, a->cover->r.max)), a->cover, nil, ZP);
+		p.x += a->cover->r.max.x;
+	}
 
 	runestring(screen, p, textcolor, ZP, f, a->name);
 	p.y += f->height * 2;
@@ -162,5 +164,19 @@
 		runestring(screen, p, i == cursong ? active : textcolor, ZP, f, tracktitle);
 		p.y += f->height;
 	}
+	start.y+=256;
+	return start;
 }
 
+void
+drawlibrary(Album *start, Album *stop, Album *cur, Image *textcolor, Image *active, int cursong)
+{
+	Point p = screen->r.min;
+	int height = screen->r.max.y - screen->r.min.y;
+	Album *screenstop = start+(height/256)-1;
+	stop = screenstop < stop ? screenstop : stop;
+	stop+=1;
+
+	for(;start!=stop;start++)
+		p = drawalbum(start, textcolor, active, p, start ==  cur ? cursong : -1);
+}
\ No newline at end of file
--- a/fncs.h
+++ b/fncs.h
@@ -10,6 +10,7 @@
 u64int	lebtoi(uchar*,int);
 void	kill(int);
 void	killgrp(int);
+int		runecstrcmp(Rune*,Rune*);
 
 /* id3.c */
 ID3v1*	readid3(int);
@@ -22,9 +23,11 @@
 FlacMeta*	readflacmeta(int, int);
 
 /* draw.c */
-void	drawalbum(Album*, Image*, Image*, int);
+Point	drawalbum(Album*, Image*, Image*, Point, int);
 Image*	convpic(int, char*);
 Image*	convpicbuf(uchar*, uvlong, char*);
+void	drawlibrary(Album*, Album*, Album*, Image*, Image*, int);
 
 /* dir.c */
-Album*	dir2album(char*);
\ No newline at end of file
+void	dir2album(Album*,char*);
+int		parselibrary(Album**,char*);
\ No newline at end of file
--- a/id3.c
+++ b/id3.c
@@ -6,6 +6,19 @@
 #include "dat.h"
 #include "fncs.h"
 
+/* If we can't read the tag, at least default to file names */
+void
+fillnotag(ID3v1 *id, int fd)
+{
+	char buf[512];
+	char *slash, *dot;
+	fd2path(fd, buf, 512);
+	slash = strrchr(buf, '/');
+	dot = strrchr(buf, '.');
+	*dot = '\0';
+	id->title = runesmprint("%s", slash+1);
+}
+
 ID3v1*
 readid3(int fd)
 {
@@ -23,11 +36,13 @@
 
 	if(pread(fd, buf, 128, length-128) != 128)
 		return nil;
-	
-	if(memcmp(buf, "TAG", 3) != 0)
-		return nil;
 
 	id = emalloc(sizeof(ID3v1));
+
+	if(memcmp(buf, "TAG", 3) != 0){
+		fillnotag(id, fd);
+		return id;
+	}
 
 	memcpy(fieldbuf, buf+3, 30);
 	fieldbuf[30] = '\0';
--- a/mpl.c
+++ b/mpl.c
@@ -23,7 +23,7 @@
 Channel		*queuein;
 Channel		*queueout;
 Channel		*ctl;
-Album		*a;
+Album		*start, *cur, *stop;
 int			cursong;
 int			decpid;
 
@@ -49,7 +49,7 @@
 		quit("eresized: Can't reattach to window");
 
 	draw(screen, screen->r, background, nil, ZP);
-	drawalbum(a, black, red, cursong);
+	drawlibrary(cur, stop, cur, black, red, cursong);
 	flushimage(display, Refnone);
 }
 
@@ -56,9 +56,19 @@
 char*
 nextsong(void)
 {
-	cursong = cursong < 0 ? a->nsong-1 : cursong;
-	cursong = cursong > a->nsong-1 ? 0 : cursong;
-	return a->songs[cursong]->path;
+	if(cursong < 0){
+		cur--;
+		if(cur < start)
+			cur = stop;
+		cursong = cur->nsong-1;
+	}
+	if(cursong > cur->nsong-1){
+		cur++;
+		if(cur > stop)
+			cur = start;
+		cursong = 0;
+	}
+	return cur->songs[cursong]->path;
 }
 
 void
@@ -109,6 +119,7 @@
 	Mouse mouse;
 	Rune kbd;
 	int resize[2];
+	int nalbum;
 	cursong = 0;
 	queuein = queueout = ctl = nil;
 
@@ -129,13 +140,13 @@
 	black = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlack);
 	background = allocimagemix(display, DPaleyellow, DPalegreen);
 
-	a = dir2album(argv[1]);
-	if(a == nil)
-		quit("nil album");
-	if(a->nsong == 0)
-		quit("no songs");
+	nalbum = parselibrary(&start, argv[1]);
+	if(nalbum == 0)
+		quit("No songs found");
+	cur = start;
+	stop = start+(nalbum-1);
 	spawndec(&queuein, &ctl, &queueout);
-	send(queuein, &(a->songs[0]->path));
+	send(queuein, &(cur->songs[0]->path));
 	handleaction('w');
 
 	Alt alts[] = {
--- a/util.c
+++ b/util.c
@@ -69,4 +69,22 @@
 		sysfatal("could not write to note");
 	close(nfd);
 	free(note);
+}
+
+int
+runecstrcmp(Rune *s1, Rune *s2)
+{
+	Rune c1, c2;
+
+	for(;;) {
+		c1 = tolowerrune(*s1++);
+		c2 = tolowerrune(*s2++);
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			return 0;
+	}
 }
\ No newline at end of file
--- a/vorbis.c
+++ b/vorbis.c
@@ -11,15 +11,15 @@
 {
 	uint i;
 	for(i=0;i<v->ncom;i++){
-		if(runestrcmp(v->key[i], L"ALBUM") == 0){
+		if(runecstrcmp(v->key[i], L"album") == 0){
 			v->album = v->val[i];
 			continue;
 		}
-		if(runestrcmp(v->key[i], L"TITLE") == 0){
+		if(runecstrcmp(v->key[i], L"title") == 0){
 			v->title = v->val[i];
 			continue;
 		}
-		if(runestrcmp(v->key[i], L"ARTIST") == 0){
+		if(runecstrcmp(v->key[i], L"artist") == 0){
 			v->artist = v->val[i];
 			continue;
 		}