Patch #5166 by Robert Keevil - Last.fm logging
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11269 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1645d32aa3
commit
da153da0be
17 changed files with 414 additions and 9 deletions
|
@ -55,7 +55,8 @@ ifdef APPEXTRA
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(DEFINES) -DTARGET_ID=$(TARGET_ID) \
|
CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(DEFINES) -DTARGET_ID=$(TARGET_ID) \
|
||||||
-DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE}
|
-DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} \
|
||||||
|
-DTARGET_NAME=\"$(ARCHOS)\"
|
||||||
|
|
||||||
OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
|
OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
|
||||||
OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2))
|
OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2))
|
||||||
|
|
|
@ -29,6 +29,7 @@ talk.c
|
||||||
tree.c
|
tree.c
|
||||||
tagtree.c
|
tagtree.c
|
||||||
filetree.c
|
filetree.c
|
||||||
|
scrobbler.c
|
||||||
|
|
||||||
screen_access.c
|
screen_access.c
|
||||||
gui/buttonbar.c
|
gui/buttonbar.c
|
||||||
|
|
|
@ -3861,13 +3861,13 @@
|
||||||
</phrase>
|
</phrase>
|
||||||
<phrase>
|
<phrase>
|
||||||
id: LANG_DIRCACHE_REBOOT
|
id: LANG_DIRCACHE_REBOOT
|
||||||
desc: when activating directory cache
|
desc: DEPRECATED
|
||||||
user:
|
user:
|
||||||
<source>
|
<source>
|
||||||
*: "Please reboot to enable the cache"
|
*: ""
|
||||||
</source>
|
</source>
|
||||||
<dest>
|
<dest>
|
||||||
*: "Please reboot to enable the cache"
|
*: ""
|
||||||
</dest>
|
</dest>
|
||||||
<voice>
|
<voice>
|
||||||
*: ""
|
*: ""
|
||||||
|
@ -9940,3 +9940,31 @@
|
||||||
*: "Random"
|
*: "Random"
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_AUDIOSCROBBLER
|
||||||
|
desc: "Last.fm Log" in the playback menu
|
||||||
|
user:
|
||||||
|
<source>
|
||||||
|
*: "Last.fm Log"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "Last.fm Log"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "Last.fm Log"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_PLEASE_REBOOT
|
||||||
|
desc: when activating an option that requires a reboot
|
||||||
|
user:
|
||||||
|
<source>
|
||||||
|
*: "Please reboot to enable"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "Please reboot to enable"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: ""
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "splash.h"
|
#include "splash.h"
|
||||||
#include "eeprom_settings.h"
|
#include "eeprom_settings.h"
|
||||||
|
#include "scrobbler.h"
|
||||||
|
|
||||||
#if (CONFIG_CODEC == SWCODEC)
|
#if (CONFIG_CODEC == SWCODEC)
|
||||||
#include "playback.h"
|
#include "playback.h"
|
||||||
|
@ -252,6 +253,8 @@ void init(void)
|
||||||
audio_preinit();
|
audio_preinit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
scrobbler_init();
|
||||||
|
|
||||||
/* audio_init must to know the size of voice buffer so init voice first */
|
/* audio_init must to know the size of voice buffer so init voice first */
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
talk_init();
|
talk_init();
|
||||||
|
@ -455,7 +458,8 @@ void init(void)
|
||||||
status_init();
|
status_init();
|
||||||
playlist_init();
|
playlist_init();
|
||||||
tree_init();
|
tree_init();
|
||||||
|
scrobbler_init();
|
||||||
|
|
||||||
/* No buffer allocation (see buffer.c) may take place after the call to
|
/* No buffer allocation (see buffer.c) may take place after the call to
|
||||||
audio_init() since the mpeg thread takes the rest of the buffer space */
|
audio_init() since the mpeg thread takes the rest of the buffer space */
|
||||||
mp3_init( global_settings.volume,
|
mp3_init( global_settings.volume,
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "splash.h"
|
#include "splash.h"
|
||||||
#include "tagcache.h"
|
#include "tagcache.h"
|
||||||
|
#include "scrobbler.h"
|
||||||
#ifdef HAVE_MMC
|
#ifdef HAVE_MMC
|
||||||
#include "ata_mmc.h"
|
#include "ata_mmc.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -625,6 +626,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
|
||||||
if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED))
|
if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
scrobbler_flush_cache();
|
||||||
system_flush();
|
system_flush();
|
||||||
usb_screen();
|
usb_screen();
|
||||||
system_restore();
|
system_restore();
|
||||||
|
|
|
@ -272,6 +272,9 @@ struct thread_entry *codec_thread_p;
|
||||||
#ifdef PLAYBACK_VOICE
|
#ifdef PLAYBACK_VOICE
|
||||||
extern struct codec_api ci_voice;
|
extern struct codec_api ci_voice;
|
||||||
|
|
||||||
|
/* Play time of the previous track */
|
||||||
|
unsigned long prev_track_elapsed;
|
||||||
|
|
||||||
static volatile bool voice_thread_start;
|
static volatile bool voice_thread_start;
|
||||||
static volatile bool voice_is_playing;
|
static volatile bool voice_is_playing;
|
||||||
static volatile bool voice_codec_loaded;
|
static volatile bool voice_codec_loaded;
|
||||||
|
@ -1630,6 +1633,8 @@ static bool codec_load_next_track(void)
|
||||||
{
|
{
|
||||||
struct event ev;
|
struct event ev;
|
||||||
|
|
||||||
|
prev_track_elapsed = CUR_TI->id3.elapsed;
|
||||||
|
|
||||||
if (ci.seek_time)
|
if (ci.seek_time)
|
||||||
codec_seek_complete_callback();
|
codec_seek_complete_callback();
|
||||||
|
|
||||||
|
@ -2912,6 +2917,11 @@ void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
|
||||||
track_changed_callback = handler;
|
track_changed_callback = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long audio_prev_elapsed(void)
|
||||||
|
{
|
||||||
|
return prev_track_elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
static void audio_stop_codec_flush(void)
|
static void audio_stop_codec_flush(void)
|
||||||
{
|
{
|
||||||
ci.stop_codec = true;
|
ci.stop_codec = true;
|
||||||
|
|
263
apps/scrobbler.c
Executable file
263
apps/scrobbler.c
Executable file
|
@ -0,0 +1,263 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Robert Keevil
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/*
|
||||||
|
Audioscrobbler spec at:
|
||||||
|
http://www.audioscrobbler.net/wiki/Portable_Player_Logging
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
#include "sprintf.h"
|
||||||
|
#include "playback.h"
|
||||||
|
#include "logf.h"
|
||||||
|
#include "id3.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
#include "ata.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RTC
|
||||||
|
#include "time.h"
|
||||||
|
#include "timefuncs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "scrobbler.h"
|
||||||
|
|
||||||
|
#define SCROBBLER_VERSION "1.0"
|
||||||
|
|
||||||
|
#ifdef CONFIG_RTC
|
||||||
|
#define SCROBBLER_FILE "/.scrobbler.log"
|
||||||
|
#else
|
||||||
|
#define SCROBBLER_FILE "/.scrobbler-timeless.log"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* increment this on any code change that effects output */
|
||||||
|
/* replace with CVS Revision keyword? */
|
||||||
|
#define SCROBBLER_REVISION "1.0"
|
||||||
|
|
||||||
|
#define SCROBBLER_MAX_CACHE 32
|
||||||
|
/* longest entry I've had is 323, add a safety margin */
|
||||||
|
#define SCROBBLER_CACHE_LEN 512
|
||||||
|
|
||||||
|
static char* scrobbler_cache;
|
||||||
|
|
||||||
|
static int scrobbler_fd = -1;
|
||||||
|
static int cache_pos;
|
||||||
|
static struct mp3entry scrobbler_entry;
|
||||||
|
static bool pending = false;
|
||||||
|
static bool scrobbler_initialised = false;
|
||||||
|
#ifdef CONFIG_RTC
|
||||||
|
static time_t timestamp;
|
||||||
|
#else
|
||||||
|
static unsigned long timestamp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Crude work-around for Archos Sims - return a set amount */
|
||||||
|
#if (CONFIG_CODEC != SWCODEC) && defined(SIMULATOR)
|
||||||
|
unsigned long audio_prev_elapsed(void)
|
||||||
|
{
|
||||||
|
return 120000;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void write_cache(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* If the file doesn't exist, create it.
|
||||||
|
Check at each write since file may be deleted at any time */
|
||||||
|
scrobbler_fd = open(SCROBBLER_FILE, O_RDONLY);
|
||||||
|
if(scrobbler_fd < 0)
|
||||||
|
{
|
||||||
|
scrobbler_fd = open(SCROBBLER_FILE, O_RDWR | O_CREAT);
|
||||||
|
if(scrobbler_fd >= 0)
|
||||||
|
{
|
||||||
|
fdprintf(scrobbler_fd, "#AUDIOSCROBBLER/%s\n", SCROBBLER_VERSION);
|
||||||
|
fdprintf(scrobbler_fd, "#TZ/UNKNOWN\n");
|
||||||
|
#ifdef CONFIG_RTC
|
||||||
|
fdprintf(scrobbler_fd, "#CLIENT/Rockbox %s %s\n",
|
||||||
|
TARGET_NAME, SCROBBLER_REVISION);
|
||||||
|
#else
|
||||||
|
fdprintf(scrobbler_fd, "#CLIENT/Rockbox %s %s Timeless\n",
|
||||||
|
TARGET_NAME, SCROBBLER_REVISION);
|
||||||
|
#endif
|
||||||
|
close(scrobbler_fd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: cannot create log file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(scrobbler_fd);
|
||||||
|
scrobbler_fd = -1;
|
||||||
|
|
||||||
|
/* write the cache entries */
|
||||||
|
scrobbler_fd = open(SCROBBLER_FILE, O_WRONLY | O_APPEND);
|
||||||
|
if(scrobbler_fd >= 0)
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: writing %d entries", cache_pos);
|
||||||
|
|
||||||
|
for ( i=0; i < cache_pos; i++ )
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: write %d", i);
|
||||||
|
fdprintf(scrobbler_fd, "%s", scrobbler_cache+(SCROBBLER_CACHE_LEN*i));
|
||||||
|
}
|
||||||
|
close(scrobbler_fd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: error writing file");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear even if unsuccessful - don't want to overflow the buffer */
|
||||||
|
cache_pos = 0;
|
||||||
|
scrobbler_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_to_cache(void)
|
||||||
|
{
|
||||||
|
/* using HAVE_MMC to check for Ondios - anything better to use? */
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
#if defined(IPOD_NANO) || defined(HAVE_MMC)
|
||||||
|
if ( cache_pos >= SCROBBLER_MAX_CACHE )
|
||||||
|
#else
|
||||||
|
if ( ( cache_pos >= SCROBBLER_MAX_CACHE ) || ( ata_disk_is_active() ) )
|
||||||
|
#endif
|
||||||
|
#endif /* !SIMULATOR */
|
||||||
|
write_cache();
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
char rating = 'S'; /* Skipped */
|
||||||
|
|
||||||
|
logf("SCROBBLER: add_to_cache[%d]", cache_pos);
|
||||||
|
|
||||||
|
if ( audio_prev_elapsed() >
|
||||||
|
(scrobbler_entry.length/2) )
|
||||||
|
rating = 'L'; /* Listened */
|
||||||
|
|
||||||
|
if (scrobbler_entry.tracknum > 0)
|
||||||
|
{
|
||||||
|
ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
|
||||||
|
SCROBBLER_CACHE_LEN,
|
||||||
|
"%s\t%s\t%s\t%d\t%d\t%c\t%ld\n",
|
||||||
|
scrobbler_entry.artist,
|
||||||
|
scrobbler_entry.album?scrobbler_entry.album:"",
|
||||||
|
scrobbler_entry.title,
|
||||||
|
scrobbler_entry.tracknum,
|
||||||
|
(int)scrobbler_entry.length/1000,
|
||||||
|
rating,
|
||||||
|
(long)timestamp);
|
||||||
|
} else {
|
||||||
|
ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
|
||||||
|
SCROBBLER_CACHE_LEN,
|
||||||
|
"%s\t%s\t%s\t\t%d\t%c\t%ld\n",
|
||||||
|
scrobbler_entry.artist,
|
||||||
|
scrobbler_entry.album?scrobbler_entry.album:"",
|
||||||
|
scrobbler_entry.title,
|
||||||
|
(int)scrobbler_entry.length/1000,
|
||||||
|
rating,
|
||||||
|
(long)timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ret >= SCROBBLER_CACHE_LEN )
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: entry too long:");
|
||||||
|
logf("SCROBBLER: %s", scrobbler_entry.path);
|
||||||
|
} else
|
||||||
|
cache_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrobbler_change_event(struct mp3entry *id)
|
||||||
|
{
|
||||||
|
/* add entry using the previous scrobbler_entry and timestamp */
|
||||||
|
if (pending)
|
||||||
|
add_to_cache();
|
||||||
|
|
||||||
|
/* check if track was resumed > %50 played
|
||||||
|
check for blank artist or track name */
|
||||||
|
if ((id->elapsed > (id->length/2)) ||
|
||||||
|
(!id->artist ) || (!id->title ) )
|
||||||
|
{
|
||||||
|
pending = false;
|
||||||
|
logf("SCROBBLER: skipping file %s", id->path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: add pending");
|
||||||
|
copy_mp3entry(&scrobbler_entry, id);
|
||||||
|
#ifdef CONFIG_RTC
|
||||||
|
timestamp = mktime(get_time());
|
||||||
|
#else
|
||||||
|
timestamp = 0;
|
||||||
|
#endif
|
||||||
|
pending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int scrobbler_init(void)
|
||||||
|
{
|
||||||
|
logf("SCROBBLER: init %d", global_settings.audioscrobbler);
|
||||||
|
|
||||||
|
if(!global_settings.audioscrobbler)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
|
||||||
|
|
||||||
|
audio_set_track_changed_event(&scrobbler_change_event);
|
||||||
|
cache_pos = 0;
|
||||||
|
pending = false;
|
||||||
|
scrobbler_initialised = true;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrobbler_flush_cache(void)
|
||||||
|
{
|
||||||
|
if (scrobbler_initialised)
|
||||||
|
{
|
||||||
|
/* Add any pending entries to the cache */
|
||||||
|
if(pending)
|
||||||
|
add_to_cache();
|
||||||
|
|
||||||
|
/* Write the cache to disk if needed */
|
||||||
|
if (cache_pos)
|
||||||
|
write_cache();
|
||||||
|
|
||||||
|
pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrobbler_shutdown(void)
|
||||||
|
{
|
||||||
|
scrobbler_flush_cache();
|
||||||
|
|
||||||
|
if (scrobbler_initialised)
|
||||||
|
{
|
||||||
|
audio_set_track_changed_event(NULL);
|
||||||
|
scrobbler_initialised = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scrobbler_is_enabled(void)
|
||||||
|
{
|
||||||
|
return scrobbler_initialised;
|
||||||
|
}
|
24
apps/scrobbler.h
Normal file
24
apps/scrobbler.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Robert Keevil
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void scrobbler_change_event(struct mp3entry *id);
|
||||||
|
int scrobbler_init(void);
|
||||||
|
void scrobbler_flush_cache(void);
|
||||||
|
void scrobbler_shutdown(void);
|
||||||
|
bool scrobbler_is_enabled(void);
|
|
@ -665,6 +665,8 @@ static const struct bit_entry hd_bits[] =
|
||||||
{2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
|
{2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{1, S_O(audioscrobbler), false, "Last.fm Logging", off_on},
|
||||||
|
|
||||||
/* If values are just added to the end, no need to bump the version. */
|
/* If values are just added to the end, no need to bump the version. */
|
||||||
/* new stuff to be added at the end */
|
/* new stuff to be added at the end */
|
||||||
|
|
||||||
|
|
|
@ -498,6 +498,7 @@ struct user_settings
|
||||||
#ifdef CONFIG_TUNER
|
#ifdef CONFIG_TUNER
|
||||||
int fm_region;
|
int fm_region;
|
||||||
#endif
|
#endif
|
||||||
|
bool audioscrobbler; /* Audioscrobbler logging */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "yesno.h"
|
#include "yesno.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "color_picker.h"
|
#include "color_picker.h"
|
||||||
|
#include "scrobbler.h"
|
||||||
|
|
||||||
#ifdef HAVE_LCD_BITMAP
|
#ifdef HAVE_LCD_BITMAP
|
||||||
#include "peakmeter.h"
|
#include "peakmeter.h"
|
||||||
|
@ -1387,6 +1388,23 @@ static bool next_folder(void)
|
||||||
INT, names, 3, NULL );
|
INT, names, 3, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool audioscrobbler(void)
|
||||||
|
{
|
||||||
|
bool result = set_bool_options(str(LANG_AUDIOSCROBBLER),
|
||||||
|
&global_settings.audioscrobbler,
|
||||||
|
STR(LANG_ON),
|
||||||
|
STR(LANG_OFF),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!scrobbler_is_enabled() && global_settings.audioscrobbler)
|
||||||
|
gui_syncsplash(HZ*2, true, str(LANG_PLEASE_REBOOT));
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
scrobbler_shutdown();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static bool codepage_setting(void)
|
static bool codepage_setting(void)
|
||||||
{
|
{
|
||||||
static const struct opt_items names[] = {
|
static const struct opt_items names[] = {
|
||||||
|
@ -1605,7 +1623,7 @@ static bool dircache(void)
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (!dircache_is_enabled() && global_settings.dircache)
|
if (!dircache_is_enabled() && global_settings.dircache)
|
||||||
gui_syncsplash(HZ*2, true, str(LANG_DIRCACHE_REBOOT));
|
gui_syncsplash(HZ*2, true, str(LANG_PLEASE_REBOOT));
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
dircache_disable();
|
dircache_disable();
|
||||||
|
@ -1747,8 +1765,9 @@ static bool playback_settings_menu(void)
|
||||||
{ ID2P(LANG_ID3_ORDER), id3_order },
|
{ ID2P(LANG_ID3_ORDER), id3_order },
|
||||||
{ ID2P(LANG_NEXT_FOLDER), next_folder },
|
{ ID2P(LANG_NEXT_FOLDER), next_folder },
|
||||||
#ifdef HAVE_HEADPHONE_DETECTION
|
#ifdef HAVE_HEADPHONE_DETECTION
|
||||||
{ ID2P(LANG_UNPLUG), unplug_menu }
|
{ ID2P(LANG_UNPLUG), unplug_menu },
|
||||||
#endif
|
#endif
|
||||||
|
{ ID2P(LANG_AUDIOSCROBBLER), audioscrobbler}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool old_shuffle = global_settings.playlist_shuffle;
|
bool old_shuffle = global_settings.playlist_shuffle;
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "yesno.h"
|
#include "yesno.h"
|
||||||
#include "gwps-common.h"
|
#include "gwps-common.h"
|
||||||
#include "eeprom_settings.h"
|
#include "eeprom_settings.h"
|
||||||
|
#include "scrobbler.h"
|
||||||
|
|
||||||
/* gui api */
|
/* gui api */
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
@ -1378,6 +1379,7 @@ void ft_play_filename(char *dir, char *file)
|
||||||
/* These two functions are called by the USB and shutdown handlers */
|
/* These two functions are called by the USB and shutdown handlers */
|
||||||
void tree_flush(void)
|
void tree_flush(void)
|
||||||
{
|
{
|
||||||
|
scrobbler_shutdown();
|
||||||
tagcache_shutdown();
|
tagcache_shutdown();
|
||||||
playlist_shutdown();
|
playlist_shutdown();
|
||||||
|
|
||||||
|
@ -1439,4 +1441,5 @@ void tree_restore(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
tagcache_start_scan();
|
tagcache_start_scan();
|
||||||
|
scrobbler_init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,3 +130,38 @@ int set_time(const struct tm *tm)
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mktime() code taken from lynx-2.8.5 source, written
|
||||||
|
by Philippe De Muyter <phdm@macqel.be> */
|
||||||
|
time_t mktime(struct tm *t)
|
||||||
|
{
|
||||||
|
short month, year;
|
||||||
|
time_t result;
|
||||||
|
static int m_to_d[12] =
|
||||||
|
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
||||||
|
|
||||||
|
month = t->tm_mon;
|
||||||
|
year = t->tm_year + month / 12 + 1900;
|
||||||
|
month %= 12;
|
||||||
|
if (month < 0)
|
||||||
|
{
|
||||||
|
year -= 1;
|
||||||
|
month += 12;
|
||||||
|
}
|
||||||
|
result = (year - 1970) * 365 + (year - 1969) / 4 + m_to_d[month];
|
||||||
|
result = (year - 1970) * 365 + m_to_d[month];
|
||||||
|
if (month <= 1)
|
||||||
|
year -= 1;
|
||||||
|
result += (year - 1968) / 4;
|
||||||
|
result -= (year - 1900) / 100;
|
||||||
|
result += (year - 1600) / 400;
|
||||||
|
result += t->tm_mday;
|
||||||
|
result -= 1;
|
||||||
|
result *= 24;
|
||||||
|
result += t->tm_hour;
|
||||||
|
result *= 60;
|
||||||
|
result += t->tm_min;
|
||||||
|
result *= 60;
|
||||||
|
result += t->tm_sec;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
|
@ -141,6 +141,7 @@ void audio_set_spdif_power_setting(bool on);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
unsigned long audio_get_spdif_sample_rate(void);
|
unsigned long audio_get_spdif_sample_rate(void);
|
||||||
|
unsigned long audio_prev_elapsed(void);
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
/* audio encoder functions (defined in playback.c) */
|
/* audio encoder functions (defined in playback.c) */
|
||||||
int audio_get_encoder_id(void);
|
int audio_get_encoder_id(void);
|
||||||
|
|
|
@ -20,8 +20,7 @@ struct tm
|
||||||
int tm_isdst;
|
int tm_isdst;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(SIMULATOR) && !defined(_TIME_T_DEFINED) && !defined(_TIME_T_DECLARED)
|
#if !defined(_TIME_T_DEFINED) && !defined(_TIME_T_DECLARED)
|
||||||
/* for non-win32 simulators */
|
|
||||||
typedef long time_t;
|
typedef long time_t;
|
||||||
|
|
||||||
/* this define below is used by the mingw headers to prevent duplicate
|
/* this define below is used by the mingw headers to prevent duplicate
|
||||||
|
|
|
@ -27,5 +27,6 @@
|
||||||
struct tm *get_time(void);
|
struct tm *get_time(void);
|
||||||
int set_time(const struct tm *tm);
|
int set_time(const struct tm *tm);
|
||||||
bool valid_time(const struct tm *tm);
|
bool valid_time(const struct tm *tm);
|
||||||
|
time_t mktime(struct tm *t);
|
||||||
|
|
||||||
#endif /* _TIMEFUNCS_H_ */
|
#endif /* _TIMEFUNCS_H_ */
|
||||||
|
|
|
@ -108,6 +108,9 @@ static struct trackdata trackdata[MAX_TRACK_ENTRIES];
|
||||||
static unsigned int current_track_counter = 0;
|
static unsigned int current_track_counter = 0;
|
||||||
static unsigned int last_track_counter = 0;
|
static unsigned int last_track_counter = 0;
|
||||||
|
|
||||||
|
/* Play time of the previous track */
|
||||||
|
unsigned long prev_track_elapsed;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
static int track_read_idx = 0;
|
static int track_read_idx = 0;
|
||||||
static int track_write_idx = 0;
|
static int track_write_idx = 0;
|
||||||
|
@ -1056,6 +1059,9 @@ static void track_change(void)
|
||||||
{
|
{
|
||||||
DEBUGF("Track change\n");
|
DEBUGF("Track change\n");
|
||||||
|
|
||||||
|
struct trackdata *track = get_trackdata(0);
|
||||||
|
prev_track_elapsed = track->id3.elapsed;
|
||||||
|
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
/* Reset the AVC */
|
/* Reset the AVC */
|
||||||
sound_set_avc(-1);
|
sound_set_avc(-1);
|
||||||
|
@ -1072,6 +1078,11 @@ static void track_change(void)
|
||||||
current_track_counter++;
|
current_track_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long audio_prev_elapsed(void)
|
||||||
|
{
|
||||||
|
return prev_track_elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void hexdump(const unsigned char *buf, int len)
|
void hexdump(const unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue