mirror of
https://github.com/owntone/owntone-server.git
synced 2025-03-03 07:10:08 -05:00
Add support for smart playlist manipulation by date added to database. Updated mt-daapd.playlist to match
This commit is contained in:
parent
5463b63436
commit
e43caee157
@ -1,3 +1,7 @@
|
|||||||
|
2204-09-08 Ron Pedde <ron@pedde.com>
|
||||||
|
* mp3-scanner.c: decode more aac tags. Feature request #990546
|
||||||
|
* mp3-scanner.c: support for bitrate on playlsits. FR #996506
|
||||||
|
|
||||||
2004-05-21 Ron Pedde <ron@pedde.com>
|
2004-05-21 Ron Pedde <ron@pedde.com>
|
||||||
* everywhere: fixes for more conformant protocol handling,
|
* everywhere: fixes for more conformant protocol handling,
|
||||||
support for index tag, meta tag, bug fixes for configuration file
|
support for index tag, meta tag, bug fixes for configuration file
|
||||||
|
@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
|
|||||||
AC_INIT(config.h.in)
|
AC_INIT(config.h.in)
|
||||||
|
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
AM_INIT_AUTOMAKE(mt-daapd,0.2.0)
|
AM_INIT_AUTOMAKE(mt-daapd,0.2.1-cvs)
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
@ -20,13 +20,16 @@
|
|||||||
# Orchestra (string)
|
# Orchestra (string)
|
||||||
# Conductor (string)
|
# Conductor (string)
|
||||||
# Grouping (string) -- I don't even know what this is...
|
# Grouping (string) -- I don't even know what this is...
|
||||||
|
# Comment (string)
|
||||||
# Year (int)
|
# Year (int)
|
||||||
# BPM (int)
|
# BPM (int)
|
||||||
# Bitrate (int)
|
# Bitrate (int)
|
||||||
|
# Date (date)
|
||||||
#
|
#
|
||||||
# Valid operators include:
|
# Valid operators include:
|
||||||
# is, includes (string)
|
# is, includes (string)
|
||||||
# >, <, <=, >=, = (int)
|
# >, <, <=, >=, = (int)
|
||||||
|
# after, before (date)
|
||||||
#
|
#
|
||||||
# the "is" operator must exactly match the tag,
|
# the "is" operator must exactly match the tag,
|
||||||
# while the "includes" operator matches a substring.
|
# while the "includes" operator matches a substring.
|
||||||
@ -69,6 +72,52 @@
|
|||||||
# orchestra or conductor... this would probably include any
|
# orchestra or conductor... this would probably include any
|
||||||
# orchestral music. Kind of ugly, but works!
|
# orchestral music. Kind of ugly, but works!
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# DATES
|
||||||
|
#
|
||||||
|
# Dates are kind of funky. The "date" of a file is when it
|
||||||
|
# was created on the file system, or the date that it was first
|
||||||
|
# entered into the database, whichever is earlier. The date of
|
||||||
|
# a file can be matched with the terms "before" or "after".
|
||||||
|
#
|
||||||
|
# One example of a valid date is a date in yyyy-mm-dd format:
|
||||||
|
#
|
||||||
|
# "Files added after January 1, 2004" {
|
||||||
|
# date after 2004-01-01
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# There are also some special date keywords:
|
||||||
|
# "today", "yesterday", "last week", "last month", "last year"
|
||||||
|
#
|
||||||
|
# A valid date can also be made by appling an interval to a
|
||||||
|
# date. As an example, a valid date might be:
|
||||||
|
#
|
||||||
|
# 3 weeks before today
|
||||||
|
# or
|
||||||
|
# 3 weeks ago
|
||||||
|
#
|
||||||
|
# You can combine these, of course.
|
||||||
|
#
|
||||||
|
# "3 weeks before today" is the same as "2 weeks before last week"
|
||||||
|
# or "1 week after last month" or "21 days before today" or
|
||||||
|
# "20 days before yesterday" or "7 days after last month". You get
|
||||||
|
# the idea.
|
||||||
|
#
|
||||||
|
# Note that the playlists are only generated at the time that mt-daapd
|
||||||
|
# starts... so while the dates will be accurate at start time, they
|
||||||
|
# may become inaccurate with time. Yes, I know... it's on my list. :)
|
||||||
|
#
|
||||||
|
# So, examples:
|
||||||
|
#
|
||||||
|
# "Recently Added MP3s" {
|
||||||
|
# date after last month AND file includes ".mp3"
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# This matches only mp3 files added in the last 30 days.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# SUMMARY
|
||||||
|
#
|
||||||
# I expect that this language will grow over time. If you want
|
# I expect that this language will grow over time. If you want
|
||||||
# to hack on it, see src/lexer.l, src/parser.y, and src/playlist.c
|
# to hack on it, see src/lexer.l, src/parser.y, and src/playlist.c
|
||||||
#
|
#
|
||||||
@ -77,22 +126,19 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
"60's Music" {
|
"60's Music" {
|
||||||
Year > 1959 && Year < 1970
|
Year >= 1960 && Year < 1970
|
||||||
}
|
}
|
||||||
|
|
||||||
"70's Music" {
|
"Recently Added" {
|
||||||
Year > 1969 && Year < 1980
|
Date after 2 weeks ago
|
||||||
}
|
}
|
||||||
|
|
||||||
"80's Music" {
|
"Non-DRMed Music" {
|
||||||
Year > 1979 && Year < 1990
|
path not includes ".m4p"
|
||||||
}
|
}
|
||||||
|
|
||||||
"90's Music" {
|
"AAC Files" {
|
||||||
Year > 1989 && Year < 2000
|
path includes ".m4p" ||
|
||||||
|
path includes ".m4a" ||
|
||||||
|
path includes ".aac"
|
||||||
}
|
}
|
||||||
|
|
||||||
"00's Music" {
|
|
||||||
Year > 1999
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -688,6 +688,7 @@ int db_unpackrecord(datum *pdatum, MP3FILE *pmp3) {
|
|||||||
pmp3->grouping=strdup(&ppacked->data[offset]);
|
pmp3->grouping=strdup(&ppacked->data[offset]);
|
||||||
offset += ppacked->grouping_len;
|
offset += ppacked->grouping_len;
|
||||||
|
|
||||||
|
/* shouldn't this have been done when scanning? */
|
||||||
make_composite_tags(pmp3);
|
make_composite_tags(pmp3);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -726,9 +727,10 @@ int db_add(MP3FILE *pmp3) {
|
|||||||
|
|
||||||
/* dummy this up in case the client didn't */
|
/* dummy this up in case the client didn't */
|
||||||
ppacked=(MP3PACKED *)pnew->dptr;
|
ppacked=(MP3PACKED *)pnew->dptr;
|
||||||
ppacked->time_added=(int)time(NULL);
|
if(!ppacked->time_added)
|
||||||
|
ppacked->time_added=(int)time(NULL);
|
||||||
ppacked->time_modified=ppacked->time_added;
|
ppacked->time_modified=ppacked->time_added;
|
||||||
ppacked->time_played=0;
|
ppacked->time_played=0; /* do we want to keep track of this? */
|
||||||
|
|
||||||
if(gdbm_store(db_songs,dkey,*pnew,GDBM_REPLACE)) {
|
if(gdbm_store(db_songs,dkey,*pnew,GDBM_REPLACE)) {
|
||||||
DPRINTF(ERR_FATAL,"Error inserting file %s in database\n",pmp3->fname);
|
DPRINTF(ERR_FATAL,"Error inserting file %s in database\n",pmp3->fname);
|
||||||
|
50
src/lexer.l
50
src/lexer.l
@ -23,12 +23,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
extern int yydebug;
|
extern int yydebug;
|
||||||
|
time_t l_converttime(int day, int month, int year);
|
||||||
|
time_t l_convertyyyymmdd(char *date);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
@ -36,6 +39,7 @@ extern int yydebug;
|
|||||||
%option case-insensitive
|
%option case-insensitive
|
||||||
|
|
||||||
qstring \"[^\"\n]*[\"\n]
|
qstring \"[^\"\n]*[\"\n]
|
||||||
|
yyyymmdd [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -55,6 +59,24 @@ year { yylval.ival=YEAR; return(YEAR); }
|
|||||||
bpm { yylval.ival=BPM; return(BPM); }
|
bpm { yylval.ival=BPM; return(BPM); }
|
||||||
bitrate { yylval.ival=BITRATE; return(BITRATE); }
|
bitrate { yylval.ival=BITRATE; return(BITRATE); }
|
||||||
|
|
||||||
|
date { yylval.ival=DATEADDED; return(DATEADDED); }
|
||||||
|
|
||||||
|
{yyyymmdd} { yylval.ival=l_convertyyyymmdd(yytext); return(DATE); }
|
||||||
|
today { yylval.ival=time(NULL); return(DATE); }
|
||||||
|
yesterday { yylval.ival=time(NULL) - 24*3600; return(DATE); }
|
||||||
|
last\ week { yylval.ival=time(NULL) - 24*3600*7; return(DATE); }
|
||||||
|
last\ month { yylval.ival=time(NULL) - 24*3600*30; return(DATE); }
|
||||||
|
last\ year { yylval.ival=time(NULL) - 24*3600*365; return(DATE); }
|
||||||
|
|
||||||
|
days? { yylval.ival=24*3600; return(INTERVAL); }
|
||||||
|
weeks? { yylval.ival=24*3600*7; return(INTERVAL); }
|
||||||
|
months? { yylval.ival=24*3600*30; return(INTERVAL); }
|
||||||
|
years? { yylval.ival=24*3600*365; return(INTERVAL); }
|
||||||
|
|
||||||
|
ago { yylval.ival=AGO; return(AGO); }
|
||||||
|
before { yylval.ival=BEFORE; return(BEFORE); }
|
||||||
|
after { yylval.ival=AFTER; return(AFTER); }
|
||||||
|
|
||||||
is { yylval.ival=IS; return(IS); }
|
is { yylval.ival=IS; return(IS); }
|
||||||
includes { yylval.ival=INCLUDES; return(INCLUDES); }
|
includes { yylval.ival=INCLUDES; return(INCLUDES); }
|
||||||
= { yylval.ival=EQUALS; return(EQUALS); }
|
= { yylval.ival=EQUALS; return(EQUALS); }
|
||||||
@ -84,6 +106,34 @@ not |
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
time_t l_convertyyyymmdd(char *date) {
|
||||||
|
char year[5];
|
||||||
|
char month[3];
|
||||||
|
char day[3];
|
||||||
|
|
||||||
|
memset(year,0,sizeof(year));
|
||||||
|
memset(month,0,sizeof(month));
|
||||||
|
memset(day,0,sizeof(day));
|
||||||
|
|
||||||
|
strncpy(year,date,4);
|
||||||
|
strncpy(month,date+5,2);
|
||||||
|
strncpy(day,date+8,2);
|
||||||
|
|
||||||
|
DPRINTF(ERR_INFO,"Converting %d-%d-%d\n",atoi(year),atoi(month),atoi(day));
|
||||||
|
return l_converttime(atoi(day), atoi(month), atoi(year));
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t l_converttime(int day, int month, int year) {
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
memset((void*)&tm,0,sizeof(tm));
|
||||||
|
tm.tm_year = year - 1900;
|
||||||
|
tm.tm_mon = month-1;
|
||||||
|
tm.tm_mday = day;
|
||||||
|
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
int yywrap(void) {
|
int yywrap(void) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -584,6 +584,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
parseonly=1;
|
parseonly=1;
|
||||||
|
foreground=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
@ -607,7 +608,7 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.logfile) {
|
if((config.logfile) && (!parseonly)) {
|
||||||
log_setdest(config.logfile,LOGDEST_LOGFILE);
|
log_setdest(config.logfile,LOGDEST_LOGFILE);
|
||||||
} else {
|
} else {
|
||||||
if(!foreground) {
|
if(!foreground) {
|
||||||
|
@ -472,13 +472,26 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
|||||||
|
|
||||||
/* FIXME; assumes that st_ino is a u_int_32
|
/* FIXME; assumes that st_ino is a u_int_32
|
||||||
DWB: also assumes that the library is contained entirely within
|
DWB: also assumes that the library is contained entirely within
|
||||||
one file system */
|
one file system
|
||||||
|
REP: true, although linux doesn't even guarantee a unique inode
|
||||||
|
within a single device!
|
||||||
|
*/
|
||||||
mp3file.id=psb->st_ino;
|
mp3file.id=psb->st_ino;
|
||||||
|
|
||||||
/* Do the tag lookup here */
|
/* Do the tag lookup here */
|
||||||
if(!scan_gettags(mp3file.path,&mp3file) &&
|
if(!scan_gettags(mp3file.path,&mp3file) &&
|
||||||
!scan_get_fileinfo(mp3file.path,&mp3file)) {
|
!scan_get_fileinfo(mp3file.path,&mp3file)) {
|
||||||
make_composite_tags(&mp3file);
|
make_composite_tags(&mp3file);
|
||||||
|
/* fill in the time_added. I'm not sure of the logic in this.
|
||||||
|
My thinking is to use time created, but what is that? Best
|
||||||
|
guess would be earliest of st_mtime and st_ctime...
|
||||||
|
*/
|
||||||
|
mp3file.time_added=psb->st_mtime;
|
||||||
|
if(psb->st_ctime < mp3file.time_added)
|
||||||
|
mp3file.time_added=psb->st_ctime;
|
||||||
|
|
||||||
|
DPRINTF(ERR_DEBUG," Date Added: %d\n",mp3file.time_added);
|
||||||
|
|
||||||
db_add(&mp3file);
|
db_add(&mp3file);
|
||||||
pl_eval(&mp3file); /* FIXME: move to db_add? */
|
pl_eval(&mp3file); /* FIXME: move to db_add? */
|
||||||
} else {
|
} else {
|
||||||
|
45
src/parser.y
45
src/parser.y
@ -36,6 +36,7 @@ extern int yyerror(char *msg);
|
|||||||
|
|
||||||
extern PL_NODE *pl_newcharpredicate(int tag, int op, char *value);
|
extern PL_NODE *pl_newcharpredicate(int tag, int op, char *value);
|
||||||
extern PL_NODE *pl_newintpredicate(int tag, int op, int value);
|
extern PL_NODE *pl_newintpredicate(int tag, int op, int value);
|
||||||
|
extern PL_NODE *pl_newdatepredicate(int tag, int op, int value);
|
||||||
extern PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2);
|
extern PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2);
|
||||||
extern int pl_addplaylist(char *name, PL_NODE *root);
|
extern int pl_addplaylist(char *name, PL_NODE *root);
|
||||||
|
|
||||||
@ -76,17 +77,28 @@ int pl_number=2;
|
|||||||
|
|
||||||
%token <cval> ID
|
%token <cval> ID
|
||||||
%token <ival> NUM
|
%token <ival> NUM
|
||||||
|
%token <ival> DATE
|
||||||
|
|
||||||
%token <ival> YEAR
|
%token <ival> YEAR
|
||||||
%token <ival> BPM
|
%token <ival> BPM
|
||||||
%token <ival> BITRATE
|
%token <ival> BITRATE
|
||||||
|
|
||||||
|
%token <ival> DATEADDED
|
||||||
|
%token <ival> BEFORE
|
||||||
|
%token <ival> AFTER
|
||||||
|
%token <ival> AGO
|
||||||
|
%token <ival> INTERVAL
|
||||||
|
|
||||||
%type <plval> expression
|
%type <plval> expression
|
||||||
%type <plval> predicate
|
%type <plval> predicate
|
||||||
%type <ival> strtag
|
%type <ival> strtag
|
||||||
%type <ival> inttag
|
%type <ival> inttag
|
||||||
|
%type <ival> datetag
|
||||||
|
%type <ival> dateval
|
||||||
|
%type <ival> interval
|
||||||
%type <ival> strbool
|
%type <ival> strbool
|
||||||
%type <ival> intbool
|
%type <ival> intbool
|
||||||
|
%type <ival> datebool
|
||||||
%type <ival> playlist
|
%type <ival> playlist
|
||||||
|
|
||||||
%%
|
%%
|
||||||
@ -106,6 +118,10 @@ expression: expression AND expression { $$=pl_newexpr($1,$2,$3); }
|
|||||||
|
|
||||||
predicate: strtag strbool ID { $$=pl_newcharpredicate($1, $2, $3); }
|
predicate: strtag strbool ID { $$=pl_newcharpredicate($1, $2, $3); }
|
||||||
| inttag intbool NUM { $$=pl_newintpredicate($1, $2, $3); }
|
| inttag intbool NUM { $$=pl_newintpredicate($1, $2, $3); }
|
||||||
|
| datetag datebool dateval { $$=pl_newdatepredicate($1, $2, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
datetag: DATEADDED { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
inttag: YEAR
|
inttag: YEAR
|
||||||
@ -121,6 +137,21 @@ intbool: EQUALS { $$ = $1; }
|
|||||||
| NOT intbool { $$ = $2 | 0x80000000; }
|
| NOT intbool { $$ = $2 | 0x80000000; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
datebool: BEFORE { $$ = $1; }
|
||||||
|
| AFTER { $$ = $1; }
|
||||||
|
| NOT datebool { $$=$2 | 0x80000000; }
|
||||||
|
;
|
||||||
|
|
||||||
|
interval: INTERVAL { $$ = $1; }
|
||||||
|
| NUM INTERVAL { $$ = $1 * $2; }
|
||||||
|
;
|
||||||
|
|
||||||
|
dateval: DATE { $$ = $1; }
|
||||||
|
| interval BEFORE dateval { $$ = $3 - $1; }
|
||||||
|
| interval AFTER dateval { $$ = $3 + $1; }
|
||||||
|
| interval AGO { $$ = time(NULL) - $1; }
|
||||||
|
;
|
||||||
|
|
||||||
strtag: ARTIST
|
strtag: ARTIST
|
||||||
| ALBUM
|
| ALBUM
|
||||||
| GENRE
|
| GENRE
|
||||||
@ -151,6 +182,20 @@ PL_NODE *pl_newintpredicate(int tag, int op, int value) {
|
|||||||
return pnew;
|
return pnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PL_NODE *pl_newdatepredicate(int tag, int op, int value) {
|
||||||
|
PL_NODE *pnew;
|
||||||
|
|
||||||
|
pnew=(PL_NODE*)malloc(sizeof(PL_NODE));
|
||||||
|
if(!pnew)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pnew->op=op;
|
||||||
|
pnew->type=T_DATE;
|
||||||
|
pnew->arg1.ival=tag;
|
||||||
|
pnew->arg2.ival=value;
|
||||||
|
return pnew;
|
||||||
|
}
|
||||||
|
|
||||||
PL_NODE *pl_newcharpredicate(int tag, int op, char *value) {
|
PL_NODE *pl_newcharpredicate(int tag, int op, char *value) {
|
||||||
PL_NODE *pnew;
|
PL_NODE *pnew;
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "db-memory.h"
|
#include "db-memory.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
@ -71,6 +72,8 @@ void pl_dump_node(PL_NODE *pnode, int indent) {
|
|||||||
int index;
|
int index;
|
||||||
int not=0;
|
int not=0;
|
||||||
unsigned int boolarg;
|
unsigned int boolarg;
|
||||||
|
char datebuffer[40];
|
||||||
|
struct tm *ptm;
|
||||||
|
|
||||||
for(index=0;index<indent;index++) {
|
for(index=0;index<indent;index++) {
|
||||||
printf(" ");
|
printf(" ");
|
||||||
@ -122,6 +125,9 @@ void pl_dump_node(PL_NODE *pnode, int indent) {
|
|||||||
case BITRATE:
|
case BITRATE:
|
||||||
printf("BITRATE ");
|
printf("BITRATE ");
|
||||||
break;
|
break;
|
||||||
|
case DATEADDED:
|
||||||
|
printf("DATE ");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("<unknown tag> ");
|
printf ("<unknown tag> ");
|
||||||
break;
|
break;
|
||||||
@ -153,6 +159,12 @@ void pl_dump_node(PL_NODE *pnode, int indent) {
|
|||||||
case GREATEREQUAL:
|
case GREATEREQUAL:
|
||||||
printf(">= ");
|
printf(">= ");
|
||||||
break;
|
break;
|
||||||
|
case BEFORE:
|
||||||
|
printf("BEFORE ");
|
||||||
|
break;
|
||||||
|
case AFTER:
|
||||||
|
printf("AFTER ");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("<unknown boolop> ");
|
printf("<unknown boolop> ");
|
||||||
break;
|
break;
|
||||||
@ -165,6 +177,11 @@ void pl_dump_node(PL_NODE *pnode, int indent) {
|
|||||||
case T_INT:
|
case T_INT:
|
||||||
printf("%d\n",pnode->arg2.ival);
|
printf("%d\n",pnode->arg2.ival);
|
||||||
break;
|
break;
|
||||||
|
case T_DATE:
|
||||||
|
ptm=localtime((time_t*)&pnode->arg2.ival);
|
||||||
|
strftime(datebuffer,sizeof(datebuffer),"%Y-%m-%d",ptm);
|
||||||
|
printf("%s\n",datebuffer);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("<unknown type>\n");
|
printf("<unknown type>\n");
|
||||||
break;
|
break;
|
||||||
@ -299,6 +316,12 @@ int pl_eval_node(MP3FILE *pmp3, PL_NODE *pnode) {
|
|||||||
case BITRATE:
|
case BITRATE:
|
||||||
ival=pmp3->bitrate / 1024; // bitrate in Kbps
|
ival=pmp3->bitrate / 1024; // bitrate in Kbps
|
||||||
break;
|
break;
|
||||||
|
case DATEADDED:
|
||||||
|
ival=pmp3->time_added;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DPRINTF(ERR_FATAL,"Unknown token in playlist. This can't happen!\n\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolarg=(pnode->op) & 0x7FFFFFFF;
|
boolarg=(pnode->op) & 0x7FFFFFFF;
|
||||||
@ -323,6 +346,19 @@ int pl_eval_node(MP3FILE *pmp3, PL_NODE *pnode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(pnode->type==T_DATE) {
|
||||||
|
DPRINTF(ERR_DEBUG,"Comparing (datewise) %d to %d\n",ival,pnode->arg2.ival);
|
||||||
|
switch(boolarg) {
|
||||||
|
case BEFORE:
|
||||||
|
r_arg=(ival < pnode->arg2.ival);
|
||||||
|
break;
|
||||||
|
case AFTER:
|
||||||
|
r_arg=(ival > pnode->arg2.ival);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
retval=r_arg;
|
||||||
|
}
|
||||||
|
|
||||||
if(pnode->type==T_INT) {
|
if(pnode->type==T_INT) {
|
||||||
DPRINTF(ERR_DEBUG,"Comparing %d to %d\n",ival,pnode->arg2.ival);
|
DPRINTF(ERR_DEBUG,"Comparing %d to %d\n",ival,pnode->arg2.ival);
|
||||||
|
|
||||||
@ -346,7 +382,6 @@ int pl_eval_node(MP3FILE *pmp3, PL_NODE *pnode) {
|
|||||||
retval = not? !r_arg : r_arg;
|
retval = not? !r_arg : r_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* can't get here */
|
|
||||||
DPRINTF(ERR_DEBUG,"Returning %d\n",retval);
|
DPRINTF(ERR_DEBUG,"Returning %d\n",retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#define T_INT 0
|
#define T_INT 0
|
||||||
#define T_STR 1
|
#define T_STR 1
|
||||||
|
#define T_DATE 2
|
||||||
|
|
||||||
typedef struct tag_pl_node {
|
typedef struct tag_pl_node {
|
||||||
int op;
|
int op;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user