mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-22 19:45:43 -04:00
Start of smart playlists
This commit is contained in:
parent
a98bdfbf66
commit
377356bd06
@ -8,6 +8,8 @@ AM_INIT_AUTOMAKE(mt-daapd,0.1.0)
|
|||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
AC_PROG_YACC
|
||||||
|
AC_PROG_LEX
|
||||||
|
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
|
|
||||||
|
BUILT_SOURCES=parser.h
|
||||||
|
AM_YFLAGS=-d
|
||||||
|
|
||||||
sbin_PROGRAMS = mt-daapd
|
sbin_PROGRAMS = mt-daapd
|
||||||
|
|
||||||
if COND_REND_POSIX
|
if COND_REND_POSIX
|
||||||
@ -17,7 +21,8 @@ endif
|
|||||||
mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
|
mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
|
||||||
webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \
|
webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \
|
||||||
daap-proto.c daap-proto.h daap.c daap.h db-memory.c db-memory.h \
|
daap-proto.c daap-proto.h daap.c daap.h db-memory.c db-memory.h \
|
||||||
mp3-scanner.h mp3-scanner.c $(RENDSRC)
|
mp3-scanner.h mp3-scanner.c playlist.c playlist.h \
|
||||||
|
lexer.l parser.y $(RENDSRC)
|
||||||
|
|
||||||
EXTRA_DIST = mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c \
|
EXTRA_DIST = mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c \
|
||||||
mdns/mDNSUNP.c rend-howl.c rend-posix.c rend-osx.c
|
mdns/mDNSUNP.c rend-howl.c rend-posix.c rend-osx.c
|
||||||
|
84
src/lexer.l
Normal file
84
src/lexer.l
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
%{
|
||||||
|
|
||||||
|
/* $Id$
|
||||||
|
*
|
||||||
|
* Simple playlist lexer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "playlist.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
extern int yydebug;
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option yylineno
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
[\n\t ]+
|
||||||
|
|
||||||
|
artist { yylval.ival=TOK_ARTIST; return(TOK_ARTIST); }
|
||||||
|
album { yylval.ival=TOK_ALBUM; return(TOK_ALBUM); }
|
||||||
|
genre { yylval.ival=TOK_GENRE; return(TOK_GENRE); }
|
||||||
|
|
||||||
|
is |
|
||||||
|
= { yylval.ival=TOK_IS; return(TOK_IS); }
|
||||||
|
|
||||||
|
includes |
|
||||||
|
=~ |
|
||||||
|
~= { yylval.ival=TOK_INCLUDES; return(TOK_INCLUDES); }
|
||||||
|
|
||||||
|
or |
|
||||||
|
\|\| { yylval.ival=TOK_OR; return(TOK_OR); }
|
||||||
|
|
||||||
|
and |
|
||||||
|
&& { yylval.ival=TOK_AND; return(TOK_AND); }
|
||||||
|
|
||||||
|
not |
|
||||||
|
! { yylval.ival=1; return(TOK_NOT); }
|
||||||
|
|
||||||
|
|
||||||
|
\"[A-Za-z0-9 ]*\" { yylval.cval=strdup(yytext); return(TOK_ID); }
|
||||||
|
|
||||||
|
. { return yytext[0]; }
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
int yywrap(void) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyerror(char *msg) {
|
||||||
|
printf("\nParser Error: Line %d: %s\n",yylineno, msg);
|
||||||
|
printf("Wish I could be more helpful. :(\n\n");
|
||||||
|
printf("If you know how to generate good yacc errors, please\n");
|
||||||
|
printf("Let me know!\n\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
FILE *fin;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
yydebug=1;
|
||||||
|
|
||||||
|
fin=fopen(argv[1],"r");
|
||||||
|
if(!fin) {
|
||||||
|
perror("fopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
yyin=fin;
|
||||||
|
result=yyparse();
|
||||||
|
printf("Parsed... result = %d\n", result);
|
||||||
|
|
||||||
|
pl_dump();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
116
src/parser.y
Normal file
116
src/parser.y
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
%{
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "playlist.h"
|
||||||
|
|
||||||
|
#define YYERROR_VERBOSE 1
|
||||||
|
|
||||||
|
/* Forwards */
|
||||||
|
|
||||||
|
extern PL_NODE *pl_newpredicate(int tag, int op, char *value);
|
||||||
|
extern PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2);
|
||||||
|
extern int pl_addplaylist(char *name, PL_NODE *root);
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%left TOK_OR TOK_AND
|
||||||
|
|
||||||
|
%union {
|
||||||
|
unsigned int ival;
|
||||||
|
char *cval;
|
||||||
|
PL_NODE *plval;
|
||||||
|
}
|
||||||
|
|
||||||
|
%token <ival> TOK_ARTIST
|
||||||
|
%token <ival> TOK_ALBUM
|
||||||
|
%token <ival> TOK_GENRE
|
||||||
|
|
||||||
|
%token <ival> TOK_IS
|
||||||
|
%token <ival> TOK_INCLUDES
|
||||||
|
|
||||||
|
%token <ival> TOK_OR
|
||||||
|
%token <ival> TOK_AND
|
||||||
|
%token <ival> TOK_NOT
|
||||||
|
|
||||||
|
%token <cval> TOK_ID
|
||||||
|
|
||||||
|
%type <plval> expression
|
||||||
|
%type <plval> predicate
|
||||||
|
%type <ival> idtag
|
||||||
|
%type <ival> boolarg
|
||||||
|
%type <cval> value
|
||||||
|
%type <ival> playlist
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
playlistlist: playlist
|
||||||
|
| playlistlist playlist
|
||||||
|
;
|
||||||
|
|
||||||
|
playlist: TOK_ID '{' expression '}' { $$ = pl_addplaylist($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
expression: expression TOK_AND expression { $$=pl_newexpr($1,$2,$3); }
|
||||||
|
| expression TOK_OR expression { $$=pl_newexpr($1,$2,$3); }
|
||||||
|
| '(' expression ')' { $$=$2; }
|
||||||
|
| predicate
|
||||||
|
;
|
||||||
|
|
||||||
|
predicate: idtag boolarg value { $$=pl_newpredicate($1, $2, $3); }
|
||||||
|
|
||||||
|
idtag: TOK_ARTIST
|
||||||
|
| TOK_ALBUM
|
||||||
|
| TOK_GENRE
|
||||||
|
;
|
||||||
|
|
||||||
|
boolarg: TOK_IS
|
||||||
|
| TOK_INCLUDES
|
||||||
|
| TOK_NOT boolarg { $$=$2 | 0x80000000; }
|
||||||
|
;
|
||||||
|
|
||||||
|
value: TOK_ID
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
PL_NODE *pl_newpredicate(int tag, int op, char *value) {
|
||||||
|
PL_NODE *pnew;
|
||||||
|
|
||||||
|
pnew=(PL_NODE*)malloc(sizeof(PL_NODE));
|
||||||
|
if(!pnew)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pnew->op=op;
|
||||||
|
pnew->arg1.ival=tag;
|
||||||
|
pnew->arg2.cval=value;
|
||||||
|
return pnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2) {
|
||||||
|
PL_NODE *pnew;
|
||||||
|
|
||||||
|
pnew=(PL_NODE*)malloc(sizeof(PL_NODE));
|
||||||
|
if(!pnew)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pnew->op=op;
|
||||||
|
pnew->arg1.plval=arg1;
|
||||||
|
pnew->arg2.plval=arg2;
|
||||||
|
return pnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pl_addplaylist(char *name, PL_NODE *root) {
|
||||||
|
SMART_PLAYLIST *pnew;
|
||||||
|
|
||||||
|
pnew=(SMART_PLAYLIST *)malloc(sizeof(SMART_PLAYLIST));
|
||||||
|
if(!pnew)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pnew->next=pl_smart.next;
|
||||||
|
pnew->name=name;
|
||||||
|
pnew->root=root;
|
||||||
|
pl_smart.next=pnew;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
92
src/playlist.c
Normal file
92
src/playlist.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "playlist.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
/* Globals */
|
||||||
|
SMART_PLAYLIST pl_smart = { NULL, NULL, NULL };
|
||||||
|
|
||||||
|
/* Forwards */
|
||||||
|
void pl_dump(void);
|
||||||
|
void pl_dump_node(PL_NODE *pnode, int indent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pl_dump
|
||||||
|
*
|
||||||
|
* Dump the playlist list for debugging
|
||||||
|
*/
|
||||||
|
void pl_dump(void) {
|
||||||
|
SMART_PLAYLIST *pcurrent=pl_smart.next;
|
||||||
|
|
||||||
|
while(pcurrent) {
|
||||||
|
printf("Playlist %s:\n",pcurrent->name);
|
||||||
|
pl_dump_node(pcurrent->root,1);
|
||||||
|
pcurrent=pcurrent->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pl_dump_node
|
||||||
|
*
|
||||||
|
* recursively dump a node
|
||||||
|
*/
|
||||||
|
void pl_dump_node(PL_NODE *pnode, int indent) {
|
||||||
|
int index;
|
||||||
|
int not=0;
|
||||||
|
unsigned int boolarg;
|
||||||
|
|
||||||
|
for(index=0;index<indent;index++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pnode->op == TOK_AND) {
|
||||||
|
printf("AND\n");
|
||||||
|
} else if (pnode->op == TOK_OR) {
|
||||||
|
printf("OR\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if((pnode->op == TOK_AND) || (pnode->op == TOK_OR)) {
|
||||||
|
pl_dump_node(pnode->arg1.plval,indent+1);
|
||||||
|
pl_dump_node(pnode->arg2.plval,indent+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pnode->arg1.ival) {
|
||||||
|
case TOK_ARTIST:
|
||||||
|
printf("ARTIST ");
|
||||||
|
break;
|
||||||
|
case TOK_ALBUM:
|
||||||
|
printf("ALBUM ");
|
||||||
|
break;
|
||||||
|
case TOK_GENRE:
|
||||||
|
printf("GENRE ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf ("<unknown tag> ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolarg=(pnode->op) & 0x7FFFFFFF;
|
||||||
|
if(pnode->op & 0x80000000)
|
||||||
|
not=1;
|
||||||
|
|
||||||
|
switch(boolarg) {
|
||||||
|
case TOK_IS:
|
||||||
|
printf("%s",not? "IS " : "IS NOT ");
|
||||||
|
break;
|
||||||
|
case TOK_INCLUDES:
|
||||||
|
printf("%s",not? "INCLUDES " : "DOES NOT INCLUDE ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("<unknown boolop> ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s\n",pnode->arg2.cval);
|
||||||
|
return;
|
||||||
|
}
|
32
src/playlist.h
Normal file
32
src/playlist.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PL_H_
|
||||||
|
#define _PL_H_
|
||||||
|
|
||||||
|
typedef struct tag_pl_node {
|
||||||
|
int op;
|
||||||
|
union {
|
||||||
|
int ival;
|
||||||
|
struct tag_pl_node *plval;
|
||||||
|
} arg1;
|
||||||
|
union {
|
||||||
|
char *cval;
|
||||||
|
struct tag_pl_node *plval;
|
||||||
|
} arg2;
|
||||||
|
} PL_NODE;
|
||||||
|
|
||||||
|
typedef struct tag_smart_playlist {
|
||||||
|
char *name;
|
||||||
|
PL_NODE *root;
|
||||||
|
struct tag_smart_playlist *next;
|
||||||
|
} SMART_PLAYLIST;
|
||||||
|
|
||||||
|
extern SMART_PLAYLIST pl_smart;
|
||||||
|
extern void pl_dump(void);
|
||||||
|
|
||||||
|
#endif /* _PL_H_ */
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user