diff options
| author | Linus Nielsen Feltzing <linus@haxx.se> | 2006-10-19 09:42:58 +0000 |
|---|---|---|
| committer | Linus Nielsen Feltzing <linus@haxx.se> | 2006-10-19 09:42:58 +0000 |
| commit | da153da0be485aa4b937d58ee209eda7fb342053 (patch) | |
| tree | 3506b6bba4935fa252250b892d023203e54f3513 /apps | |
| parent | 1645d32aa38bd61806125c8d6b1c44fa3ac0f3ca (diff) | |
| download | rockbox-da153da0be485aa4b937d58ee209eda7fb342053.zip rockbox-da153da0be485aa4b937d58ee209eda7fb342053.tar.gz rockbox-da153da0be485aa4b937d58ee209eda7fb342053.tar.bz2 rockbox-da153da0be485aa4b937d58ee209eda7fb342053.tar.xz | |
Patch #5166 by Robert Keevil - Last.fm logging
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11269 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/Makefile | 3 | ||||
| -rw-r--r-- | apps/SOURCES | 1 | ||||
| -rw-r--r-- | apps/lang/english.lang | 34 | ||||
| -rw-r--r-- | apps/main.c | 6 | ||||
| -rw-r--r-- | apps/misc.c | 2 | ||||
| -rw-r--r-- | apps/playback.c | 10 | ||||
| -rwxr-xr-x | apps/scrobbler.c | 263 | ||||
| -rw-r--r-- | apps/scrobbler.h | 24 | ||||
| -rw-r--r-- | apps/settings.c | 2 | ||||
| -rw-r--r-- | apps/settings.h | 1 | ||||
| -rw-r--r-- | apps/settings_menu.c | 23 | ||||
| -rw-r--r-- | apps/tree.c | 3 |
12 files changed, 365 insertions, 7 deletions
diff --git a/apps/Makefile b/apps/Makefile index 6214ce1..815e061 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -55,7 +55,8 @@ ifdef APPEXTRA endif 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)) OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) diff --git a/apps/SOURCES b/apps/SOURCES index dccb6f9..d759e49 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -29,6 +29,7 @@ talk.c tree.c tagtree.c filetree.c +scrobbler.c screen_access.c gui/buttonbar.c diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 8a2341b..6cd5b2d 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -3861,13 +3861,13 @@ </phrase> <phrase> id: LANG_DIRCACHE_REBOOT - desc: when activating directory cache + desc: DEPRECATED user: <source> - *: "Please reboot to enable the cache" + *: "" </source> <dest> - *: "Please reboot to enable the cache" + *: "" </dest> <voice> *: "" @@ -9940,3 +9940,31 @@ *: "Random" </voice> </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> diff --git a/apps/main.c b/apps/main.c index bd1dd7b..838a485 100644 --- a/apps/main.c +++ b/apps/main.c @@ -66,6 +66,7 @@ #include "string.h" #include "splash.h" #include "eeprom_settings.h" +#include "scrobbler.h" #if (CONFIG_CODEC == SWCODEC) #include "playback.h" @@ -252,6 +253,8 @@ void init(void) audio_preinit(); #endif + scrobbler_init(); + /* audio_init must to know the size of voice buffer so init voice first */ #if CONFIG_CODEC == SWCODEC talk_init(); @@ -455,7 +458,8 @@ void init(void) status_init(); playlist_init(); tree_init(); - + scrobbler_init(); + /* 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 */ mp3_init( global_settings.volume, diff --git a/apps/misc.c b/apps/misc.c index 87fd935..4be9e43 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -45,6 +45,7 @@ #include "font.h" #include "splash.h" #include "tagcache.h" +#include "scrobbler.h" #ifdef HAVE_MMC #include "ata_mmc.h" #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)) #endif { + scrobbler_flush_cache(); system_flush(); usb_screen(); system_restore(); diff --git a/apps/playback.c b/apps/playback.c index 486edf8..495629e 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -272,6 +272,9 @@ struct thread_entry *codec_thread_p; #ifdef PLAYBACK_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_is_playing; static volatile bool voice_codec_loaded; @@ -1630,6 +1633,8 @@ static bool codec_load_next_track(void) { struct event ev; + prev_track_elapsed = CUR_TI->id3.elapsed; + if (ci.seek_time) codec_seek_complete_callback(); @@ -2912,6 +2917,11 @@ void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) track_changed_callback = handler; } +unsigned long audio_prev_elapsed(void) +{ + return prev_track_elapsed; +} + static void audio_stop_codec_flush(void) { ci.stop_codec = true; diff --git a/apps/scrobbler.c b/apps/scrobbler.c new file mode 100755 index 0000000..68c5e9a --- /dev/null +++ b/apps/scrobbler.c @@ -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; +} diff --git a/apps/scrobbler.h b/apps/scrobbler.h new file mode 100644 index 0000000..543a30e --- /dev/null +++ b/apps/scrobbler.h @@ -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); diff --git a/apps/settings.c b/apps/settings.c index 196c432..9794568 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -665,6 +665,8 @@ static const struct bit_entry hd_bits[] = {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" }, #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. */ /* new stuff to be added at the end */ diff --git a/apps/settings.h b/apps/settings.h index 5313fe3..5fc8c7e 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -498,6 +498,7 @@ struct user_settings #ifdef CONFIG_TUNER int fm_region; #endif + bool audioscrobbler; /* Audioscrobbler logging */ }; diff --git a/apps/settings_menu.c b/apps/settings_menu.c index eabe153..0193aa0 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c @@ -56,6 +56,7 @@ #include "yesno.h" #include "list.h" #include "color_picker.h" +#include "scrobbler.h" #ifdef HAVE_LCD_BITMAP #include "peakmeter.h" @@ -1387,6 +1388,23 @@ static bool next_folder(void) 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 const struct opt_items names[] = { @@ -1605,7 +1623,7 @@ static bool dircache(void) NULL); 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) dircache_disable(); @@ -1747,8 +1765,9 @@ static bool playback_settings_menu(void) { ID2P(LANG_ID3_ORDER), id3_order }, { ID2P(LANG_NEXT_FOLDER), next_folder }, #ifdef HAVE_HEADPHONE_DETECTION - { ID2P(LANG_UNPLUG), unplug_menu } + { ID2P(LANG_UNPLUG), unplug_menu }, #endif + { ID2P(LANG_AUDIOSCROBBLER), audioscrobbler} }; bool old_shuffle = global_settings.playlist_shuffle; diff --git a/apps/tree.c b/apps/tree.c index 70b83f8..bfb6412 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -65,6 +65,7 @@ #include "yesno.h" #include "gwps-common.h" #include "eeprom_settings.h" +#include "scrobbler.h" /* gui api */ #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 */ void tree_flush(void) { + scrobbler_shutdown(); tagcache_shutdown(); playlist_shutdown(); @@ -1439,4 +1441,5 @@ void tree_restore(void) } #endif tagcache_start_scan(); + scrobbler_init(); } |