mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-24 13:13:17 -05: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.
|
||||
AC_PROG_CC
|
||||
AC_PROG_YACC
|
||||
AC_PROG_LEX
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
# $Id$
|
||||
#
|
||||
|
||||
BUILT_SOURCES=parser.h
|
||||
AM_YFLAGS=-d
|
||||
|
||||
sbin_PROGRAMS = mt-daapd
|
||||
|
||||
if COND_REND_POSIX
|
||||
@ -17,7 +21,8 @@ endif
|
||||
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 \
|
||||
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 \
|
||||
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