summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/Makefile3
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/lang/english.lang34
-rw-r--r--apps/main.c6
-rw-r--r--apps/misc.c2
-rw-r--r--apps/playback.c10
-rwxr-xr-xapps/scrobbler.c263
-rw-r--r--apps/scrobbler.h24
-rw-r--r--apps/settings.c2
-rw-r--r--apps/settings.h1
-rw-r--r--apps/settings_menu.c23
-rw-r--r--apps/tree.c3
12 files changed, 365 insertions, 7 deletions
diff --git a/apps/Makefile b/apps/Makefile
index 6214ce138b..815e061d3c 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -55,7 +55,8 @@ ifdef APPEXTRA
55endif 55endif
56 56
57CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(DEFINES) -DTARGET_ID=$(TARGET_ID) \ 57CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(DEFINES) -DTARGET_ID=$(TARGET_ID) \
58 -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} 58 -DAPPSVERSION=\"$(VERSION)\" $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} \
59 -DTARGET_NAME=\"$(ARCHOS)\"
59 60
60OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC)) 61OBJS2 := $(OBJDIR)/lang.o $(patsubst %.c, $(OBJDIR)/%.o, $(SRC))
61OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) 62OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2))
diff --git a/apps/SOURCES b/apps/SOURCES
index dccb6f95ac..d759e49a6f 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -29,6 +29,7 @@ talk.c
29tree.c 29tree.c
30tagtree.c 30tagtree.c
31filetree.c 31filetree.c
32scrobbler.c
32 33
33screen_access.c 34screen_access.c
34gui/buttonbar.c 35gui/buttonbar.c
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 8a2341b204..6cd5b2d533 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3861,13 +3861,13 @@
3861</phrase> 3861</phrase>
3862<phrase> 3862<phrase>
3863 id: LANG_DIRCACHE_REBOOT 3863 id: LANG_DIRCACHE_REBOOT
3864 desc: when activating directory cache 3864 desc: DEPRECATED
3865 user: 3865 user:
3866 <source> 3866 <source>
3867 *: "Please reboot to enable the cache" 3867 *: ""
3868 </source> 3868 </source>
3869 <dest> 3869 <dest>
3870 *: "Please reboot to enable the cache" 3870 *: ""
3871 </dest> 3871 </dest>
3872 <voice> 3872 <voice>
3873 *: "" 3873 *: ""
@@ -9940,3 +9940,31 @@
9940 *: "Random" 9940 *: "Random"
9941 </voice> 9941 </voice>
9942</phrase> 9942</phrase>
9943<phrase>
9944 id: LANG_AUDIOSCROBBLER
9945 desc: "Last.fm Log" in the playback menu
9946 user:
9947 <source>
9948 *: "Last.fm Log"
9949 </source>
9950 <dest>
9951 *: "Last.fm Log"
9952 </dest>
9953 <voice>
9954 *: "Last.fm Log"
9955 </voice>
9956</phrase>
9957<phrase>
9958 id: LANG_PLEASE_REBOOT
9959 desc: when activating an option that requires a reboot
9960 user:
9961 <source>
9962 *: "Please reboot to enable"
9963 </source>
9964 <dest>
9965 *: "Please reboot to enable"
9966 </dest>
9967 <voice>
9968 *: ""
9969 </voice>
9970</phrase>
diff --git a/apps/main.c b/apps/main.c
index bd1dd7b03c..838a4859d2 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -66,6 +66,7 @@
66#include "string.h" 66#include "string.h"
67#include "splash.h" 67#include "splash.h"
68#include "eeprom_settings.h" 68#include "eeprom_settings.h"
69#include "scrobbler.h"
69 70
70#if (CONFIG_CODEC == SWCODEC) 71#if (CONFIG_CODEC == SWCODEC)
71#include "playback.h" 72#include "playback.h"
@@ -252,6 +253,8 @@ void init(void)
252 audio_preinit(); 253 audio_preinit();
253#endif 254#endif
254 255
256 scrobbler_init();
257
255 /* audio_init must to know the size of voice buffer so init voice first */ 258 /* audio_init must to know the size of voice buffer so init voice first */
256#if CONFIG_CODEC == SWCODEC 259#if CONFIG_CODEC == SWCODEC
257 talk_init(); 260 talk_init();
@@ -455,7 +458,8 @@ void init(void)
455 status_init(); 458 status_init();
456 playlist_init(); 459 playlist_init();
457 tree_init(); 460 tree_init();
458 461 scrobbler_init();
462
459 /* No buffer allocation (see buffer.c) may take place after the call to 463 /* No buffer allocation (see buffer.c) may take place after the call to
460 audio_init() since the mpeg thread takes the rest of the buffer space */ 464 audio_init() since the mpeg thread takes the rest of the buffer space */
461 mp3_init( global_settings.volume, 465 mp3_init( global_settings.volume,
diff --git a/apps/misc.c b/apps/misc.c
index 87fd93513e..4be9e43fd9 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -45,6 +45,7 @@
45#include "font.h" 45#include "font.h"
46#include "splash.h" 46#include "splash.h"
47#include "tagcache.h" 47#include "tagcache.h"
48#include "scrobbler.h"
48#ifdef HAVE_MMC 49#ifdef HAVE_MMC
49#include "ata_mmc.h" 50#include "ata_mmc.h"
50#endif 51#endif
@@ -625,6 +626,7 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
625 if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED)) 626 if (!mmc_touched() || (mmc_remove_request() == SYS_MMC_EXTRACTED))
626#endif 627#endif
627 { 628 {
629 scrobbler_flush_cache();
628 system_flush(); 630 system_flush();
629 usb_screen(); 631 usb_screen();
630 system_restore(); 632 system_restore();
diff --git a/apps/playback.c b/apps/playback.c
index 486edf80b2..495629e5ea 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -272,6 +272,9 @@ struct thread_entry *codec_thread_p;
272#ifdef PLAYBACK_VOICE 272#ifdef PLAYBACK_VOICE
273extern struct codec_api ci_voice; 273extern struct codec_api ci_voice;
274 274
275/* Play time of the previous track */
276unsigned long prev_track_elapsed;
277
275static volatile bool voice_thread_start; 278static volatile bool voice_thread_start;
276static volatile bool voice_is_playing; 279static volatile bool voice_is_playing;
277static volatile bool voice_codec_loaded; 280static volatile bool voice_codec_loaded;
@@ -1630,6 +1633,8 @@ static bool codec_load_next_track(void)
1630{ 1633{
1631 struct event ev; 1634 struct event ev;
1632 1635
1636 prev_track_elapsed = CUR_TI->id3.elapsed;
1637
1633 if (ci.seek_time) 1638 if (ci.seek_time)
1634 codec_seek_complete_callback(); 1639 codec_seek_complete_callback();
1635 1640
@@ -2912,6 +2917,11 @@ void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
2912 track_changed_callback = handler; 2917 track_changed_callback = handler;
2913} 2918}
2914 2919
2920unsigned long audio_prev_elapsed(void)
2921{
2922 return prev_track_elapsed;
2923}
2924
2915static void audio_stop_codec_flush(void) 2925static void audio_stop_codec_flush(void)
2916{ 2926{
2917 ci.stop_codec = true; 2927 ci.stop_codec = true;
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
new file mode 100755
index 0000000000..68c5e9addf
--- /dev/null
+++ b/apps/scrobbler.c
@@ -0,0 +1,263 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Robert Keevil
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19/*
20Audioscrobbler spec at:
21http://www.audioscrobbler.net/wiki/Portable_Player_Logging
22*/
23
24#include "file.h"
25#include "sprintf.h"
26#include "playback.h"
27#include "logf.h"
28#include "id3.h"
29#include "kernel.h"
30#include "audio.h"
31#include "buffer.h"
32#include "settings.h"
33
34#ifndef SIMULATOR
35#include "ata.h"
36#endif
37
38#ifdef CONFIG_RTC
39#include "time.h"
40#include "timefuncs.h"
41#endif
42
43#include "scrobbler.h"
44
45#define SCROBBLER_VERSION "1.0"
46
47#ifdef CONFIG_RTC
48#define SCROBBLER_FILE "/.scrobbler.log"
49#else
50#define SCROBBLER_FILE "/.scrobbler-timeless.log"
51#endif
52
53/* increment this on any code change that effects output */
54/* replace with CVS Revision keyword? */
55#define SCROBBLER_REVISION "1.0"
56
57#define SCROBBLER_MAX_CACHE 32
58/* longest entry I've had is 323, add a safety margin */
59#define SCROBBLER_CACHE_LEN 512
60
61static char* scrobbler_cache;
62
63static int scrobbler_fd = -1;
64static int cache_pos;
65static struct mp3entry scrobbler_entry;
66static bool pending = false;
67static bool scrobbler_initialised = false;
68#ifdef CONFIG_RTC
69static time_t timestamp;
70#else
71static unsigned long timestamp;
72#endif
73
74/* Crude work-around for Archos Sims - return a set amount */
75#if (CONFIG_CODEC != SWCODEC) && defined(SIMULATOR)
76unsigned long audio_prev_elapsed(void)
77{
78 return 120000;
79}
80#endif
81
82static void write_cache(void)
83{
84 int i;
85
86 /* If the file doesn't exist, create it.
87 Check at each write since file may be deleted at any time */
88 scrobbler_fd = open(SCROBBLER_FILE, O_RDONLY);
89 if(scrobbler_fd < 0)
90 {
91 scrobbler_fd = open(SCROBBLER_FILE, O_RDWR | O_CREAT);
92 if(scrobbler_fd >= 0)
93 {
94 fdprintf(scrobbler_fd, "#AUDIOSCROBBLER/%s\n", SCROBBLER_VERSION);
95 fdprintf(scrobbler_fd, "#TZ/UNKNOWN\n");
96#ifdef CONFIG_RTC
97 fdprintf(scrobbler_fd, "#CLIENT/Rockbox %s %s\n",
98 TARGET_NAME, SCROBBLER_REVISION);
99#else
100 fdprintf(scrobbler_fd, "#CLIENT/Rockbox %s %s Timeless\n",
101 TARGET_NAME, SCROBBLER_REVISION);
102#endif
103 close(scrobbler_fd);
104 }
105 else
106 {
107 logf("SCROBBLER: cannot create log file");
108 }
109 }
110 close(scrobbler_fd);
111 scrobbler_fd = -1;
112
113 /* write the cache entries */
114 scrobbler_fd = open(SCROBBLER_FILE, O_WRONLY | O_APPEND);
115 if(scrobbler_fd >= 0)
116 {
117 logf("SCROBBLER: writing %d entries", cache_pos);
118
119 for ( i=0; i < cache_pos; i++ )
120 {
121 logf("SCROBBLER: write %d", i);
122 fdprintf(scrobbler_fd, "%s", scrobbler_cache+(SCROBBLER_CACHE_LEN*i));
123 }
124 close(scrobbler_fd);
125 }
126 else
127 {
128 logf("SCROBBLER: error writing file");
129 }
130
131 /* clear even if unsuccessful - don't want to overflow the buffer */
132 cache_pos = 0;
133 scrobbler_fd = -1;
134}
135
136static void add_to_cache(void)
137{
138/* using HAVE_MMC to check for Ondios - anything better to use? */
139#ifndef SIMULATOR
140#if defined(IPOD_NANO) || defined(HAVE_MMC)
141 if ( cache_pos >= SCROBBLER_MAX_CACHE )
142#else
143 if ( ( cache_pos >= SCROBBLER_MAX_CACHE ) || ( ata_disk_is_active() ) )
144#endif
145#endif /* !SIMULATOR */
146 write_cache();
147
148 int ret;
149 char rating = 'S'; /* Skipped */
150
151 logf("SCROBBLER: add_to_cache[%d]", cache_pos);
152
153 if ( audio_prev_elapsed() >
154 (scrobbler_entry.length/2) )
155 rating = 'L'; /* Listened */
156
157 if (scrobbler_entry.tracknum > 0)
158 {
159 ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
160 SCROBBLER_CACHE_LEN,
161 "%s\t%s\t%s\t%d\t%d\t%c\t%ld\n",
162 scrobbler_entry.artist,
163 scrobbler_entry.album?scrobbler_entry.album:"",
164 scrobbler_entry.title,
165 scrobbler_entry.tracknum,
166 (int)scrobbler_entry.length/1000,
167 rating,
168 (long)timestamp);
169 } else {
170 ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
171 SCROBBLER_CACHE_LEN,
172 "%s\t%s\t%s\t\t%d\t%c\t%ld\n",
173 scrobbler_entry.artist,
174 scrobbler_entry.album?scrobbler_entry.album:"",
175 scrobbler_entry.title,
176 (int)scrobbler_entry.length/1000,
177 rating,
178 (long)timestamp);
179 }
180
181 if ( ret >= SCROBBLER_CACHE_LEN )
182 {
183 logf("SCROBBLER: entry too long:");
184 logf("SCROBBLER: %s", scrobbler_entry.path);
185 } else
186 cache_pos++;
187}
188
189void scrobbler_change_event(struct mp3entry *id)
190{
191 /* add entry using the previous scrobbler_entry and timestamp */
192 if (pending)
193 add_to_cache();
194
195 /* check if track was resumed > %50 played
196 check for blank artist or track name */
197 if ((id->elapsed > (id->length/2)) ||
198 (!id->artist ) || (!id->title ) )
199 {
200 pending = false;
201 logf("SCROBBLER: skipping file %s", id->path);
202 }
203 else
204 {
205 logf("SCROBBLER: add pending");
206 copy_mp3entry(&scrobbler_entry, id);
207#ifdef CONFIG_RTC
208 timestamp = mktime(get_time());
209#else
210 timestamp = 0;
211#endif
212 pending = true;
213 }
214}
215
216int scrobbler_init(void)
217{
218 logf("SCROBBLER: init %d", global_settings.audioscrobbler);
219
220 if(!global_settings.audioscrobbler)
221 return -1;
222
223 scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
224
225 audio_set_track_changed_event(&scrobbler_change_event);
226 cache_pos = 0;
227 pending = false;
228 scrobbler_initialised = true;
229
230 return 1;
231}
232
233void scrobbler_flush_cache(void)
234{
235 if (scrobbler_initialised)
236 {
237 /* Add any pending entries to the cache */
238 if(pending)
239 add_to_cache();
240
241 /* Write the cache to disk if needed */
242 if (cache_pos)
243 write_cache();
244
245 pending = false;
246 }
247}
248
249void scrobbler_shutdown(void)
250{
251 scrobbler_flush_cache();
252
253 if (scrobbler_initialised)
254 {
255 audio_set_track_changed_event(NULL);
256 scrobbler_initialised = false;
257 }
258}
259
260bool scrobbler_is_enabled(void)
261{
262 return scrobbler_initialised;
263}
diff --git a/apps/scrobbler.h b/apps/scrobbler.h
new file mode 100644
index 0000000000..543a30ed13
--- /dev/null
+++ b/apps/scrobbler.h
@@ -0,0 +1,24 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Robert Keevil
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20void scrobbler_change_event(struct mp3entry *id);
21int scrobbler_init(void);
22void scrobbler_flush_cache(void);
23void scrobbler_shutdown(void);
24bool scrobbler_is_enabled(void);
diff --git a/apps/settings.c b/apps/settings.c
index 196c432c8f..97945682df 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -665,6 +665,8 @@ static const struct bit_entry hd_bits[] =
665 {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" }, 665 {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
666#endif 666#endif
667 667
668 {1, S_O(audioscrobbler), false, "Last.fm Logging", off_on},
669
668 /* If values are just added to the end, no need to bump the version. */ 670 /* If values are just added to the end, no need to bump the version. */
669 /* new stuff to be added at the end */ 671 /* new stuff to be added at the end */
670 672
diff --git a/apps/settings.h b/apps/settings.h
index 5313fe37b1..5fc8c7e5f5 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -498,6 +498,7 @@ struct user_settings
498#ifdef CONFIG_TUNER 498#ifdef CONFIG_TUNER
499 int fm_region; 499 int fm_region;
500#endif 500#endif
501 bool audioscrobbler; /* Audioscrobbler logging */
501 502
502}; 503};
503 504
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index eabe153810..0193aa0102 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -56,6 +56,7 @@
56#include "yesno.h" 56#include "yesno.h"
57#include "list.h" 57#include "list.h"
58#include "color_picker.h" 58#include "color_picker.h"
59#include "scrobbler.h"
59 60
60#ifdef HAVE_LCD_BITMAP 61#ifdef HAVE_LCD_BITMAP
61#include "peakmeter.h" 62#include "peakmeter.h"
@@ -1387,6 +1388,23 @@ static bool next_folder(void)
1387 INT, names, 3, NULL ); 1388 INT, names, 3, NULL );
1388} 1389}
1389 1390
1391static bool audioscrobbler(void)
1392{
1393 bool result = set_bool_options(str(LANG_AUDIOSCROBBLER),
1394 &global_settings.audioscrobbler,
1395 STR(LANG_ON),
1396 STR(LANG_OFF),
1397 NULL);
1398
1399 if (!scrobbler_is_enabled() && global_settings.audioscrobbler)
1400 gui_syncsplash(HZ*2, true, str(LANG_PLEASE_REBOOT));
1401
1402 if(!result)
1403 scrobbler_shutdown();
1404
1405 return result;
1406}
1407
1390static bool codepage_setting(void) 1408static bool codepage_setting(void)
1391{ 1409{
1392 static const struct opt_items names[] = { 1410 static const struct opt_items names[] = {
@@ -1605,7 +1623,7 @@ static bool dircache(void)
1605 NULL); 1623 NULL);
1606 1624
1607 if (!dircache_is_enabled() && global_settings.dircache) 1625 if (!dircache_is_enabled() && global_settings.dircache)
1608 gui_syncsplash(HZ*2, true, str(LANG_DIRCACHE_REBOOT)); 1626 gui_syncsplash(HZ*2, true, str(LANG_PLEASE_REBOOT));
1609 1627
1610 if (!result) 1628 if (!result)
1611 dircache_disable(); 1629 dircache_disable();
@@ -1747,8 +1765,9 @@ static bool playback_settings_menu(void)
1747 { ID2P(LANG_ID3_ORDER), id3_order }, 1765 { ID2P(LANG_ID3_ORDER), id3_order },
1748 { ID2P(LANG_NEXT_FOLDER), next_folder }, 1766 { ID2P(LANG_NEXT_FOLDER), next_folder },
1749#ifdef HAVE_HEADPHONE_DETECTION 1767#ifdef HAVE_HEADPHONE_DETECTION
1750 { ID2P(LANG_UNPLUG), unplug_menu } 1768 { ID2P(LANG_UNPLUG), unplug_menu },
1751#endif 1769#endif
1770 { ID2P(LANG_AUDIOSCROBBLER), audioscrobbler}
1752 }; 1771 };
1753 1772
1754 bool old_shuffle = global_settings.playlist_shuffle; 1773 bool old_shuffle = global_settings.playlist_shuffle;
diff --git a/apps/tree.c b/apps/tree.c
index 70b83f8934..bfb6412bfe 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -65,6 +65,7 @@
65#include "yesno.h" 65#include "yesno.h"
66#include "gwps-common.h" 66#include "gwps-common.h"
67#include "eeprom_settings.h" 67#include "eeprom_settings.h"
68#include "scrobbler.h"
68 69
69/* gui api */ 70/* gui api */
70#include "list.h" 71#include "list.h"
@@ -1378,6 +1379,7 @@ void ft_play_filename(char *dir, char *file)
1378/* These two functions are called by the USB and shutdown handlers */ 1379/* These two functions are called by the USB and shutdown handlers */
1379void tree_flush(void) 1380void tree_flush(void)
1380{ 1381{
1382 scrobbler_shutdown();
1381 tagcache_shutdown(); 1383 tagcache_shutdown();
1382 playlist_shutdown(); 1384 playlist_shutdown();
1383 1385
@@ -1439,4 +1441,5 @@ void tree_restore(void)
1439 } 1441 }
1440#endif 1442#endif
1441 tagcache_start_scan(); 1443 tagcache_start_scan();
1444 scrobbler_init();
1442} 1445}