summaryrefslogtreecommitdiff
path: root/apps/scrobbler.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/scrobbler.c')
-rw-r--r--apps/scrobbler.c195
1 files changed, 87 insertions, 108 deletions
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index be60cc15af..efd028327c 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -52,50 +52,40 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
52/* longest entry I've had is 323, add a safety margin */ 52/* longest entry I've had is 323, add a safety margin */
53#define SCROBBLER_CACHE_LEN 512 53#define SCROBBLER_CACHE_LEN 512
54 54
55static int scrobbler_cache;
56
57static int cache_pos;
58static struct mp3entry scrobbler_entry;
59static bool pending = false;
60static bool scrobbler_initialised = false; 55static bool scrobbler_initialised = false;
56static int scrobbler_cache = 0;
57static int cache_pos = 0;
58static bool pending = false;
61#if CONFIG_RTC 59#if CONFIG_RTC
62static time_t timestamp; 60static time_t timestamp;
63#else 61#define BASE_FILENAME ".scrobbler.log"
64static unsigned long timestamp; 62#define HDR_STR_TIMELESS
65#endif 63#define get_timestamp() ((long)timestamp)
66 64#define record_timestamp() ((void)(timestamp = mktime(get_time())))
67/* Crude work-around for Archos Sims - return a set amount */ 65#else /* !CONFIG_RTC */
68#if (CONFIG_CODEC != SWCODEC) && (CONFIG_PLATFORM & PLATFORM_HOSTED) 66#define HDR_STR_TIMELESS " Timeless"
69unsigned long audio_prev_elapsed(void) 67#define BASE_FILENAME ".scrobbler-timeless.log"
70{ 68#define get_timestamp() (0l)
71 return 120000; 69#define record_timestamp() ({})
72} 70#endif /* CONFIG_RTC */
73#endif
74 71
75static void get_scrobbler_filename(char *path, size_t size) 72static void get_scrobbler_filename(char *path, size_t size)
76{ 73{
77 int used; 74 int used;
78
79#if CONFIG_RTC
80 const char *base_filename = ".scrobbler.log";
81#else
82 const char *base_filename = ".scrobbler-timeless.log";
83#endif
84
85/* Get location of USB mass storage area */ 75/* Get location of USB mass storage area */
86#ifdef APPLICATION 76#ifdef APPLICATION
87#if (CONFIG_PLATFORM & PLATFORM_MAEMO) 77#if (CONFIG_PLATFORM & PLATFORM_MAEMO)
88 used = snprintf(path, size, "/home/user/MyDocs/%s", base_filename); 78 used = snprintf(path, size, "/home/user/MyDocs/%s", BASE_FILENAME);
89#elif (CONFIG_PLATFORM & PLATFORM_ANDROID) 79#elif (CONFIG_PLATFORM & PLATFORM_ANDROID)
90 used = snprintf(path, size, "/sdcard/%s", base_filename); 80 used = snprintf(path, size, "/sdcard/%s", BASE_FILENAME);
91#elif defined (SAMSUNG_YPR0) 81#elif defined (SAMSUNG_YPR0)
92 used = snprintf(path, size, "%s/%s", HOME_DIR, base_filename); 82 used = snprintf(path, size, "%s/%s", HOME_DIR, BASE_FILENAME);
93#else /* SDL/unknown RaaA build */ 83#else /* SDL/unknown RaaA build */
94 used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, base_filename); 84 used = snprintf(path, size, "%s/%s", ROCKBOX_DIR, BASE_FILENAME);
95#endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */ 85#endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */
96 86
97#else 87#else
98 used = snprintf(path, size, "/%s", base_filename); 88 used = snprintf(path, size, "/%s", BASE_FILENAME);
99#endif 89#endif
100 90
101 if (used >= (int)size) 91 if (used >= (int)size)
@@ -121,12 +111,9 @@ static void write_cache(void)
121 if(fd >= 0) 111 if(fd >= 0)
122 { 112 {
123 fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n" 113 fdprintf(fd, "#AUDIOSCROBBLER/" SCROBBLER_VERSION "\n"
124 "#TZ/UNKNOWN\n" 114 "#TZ/UNKNOWN\n" "#CLIENT/Rockbox "
125#if CONFIG_RTC 115 TARGET_NAME SCROBBLER_REVISION
126 "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION "\n"); 116 HDR_STR_TIMELESS "\n");
127#else
128 "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION " Timeless\n");
129#endif
130 117
131 close(fd); 118 close(fd);
132 } 119 }
@@ -170,51 +157,43 @@ static void scrobbler_flush_callback(void *data)
170 write_cache(); 157 write_cache();
171} 158}
172 159
173static void add_to_cache(unsigned long play_length) 160static void add_to_cache(const struct mp3entry *id)
174{ 161{
175 if ( cache_pos >= SCROBBLER_MAX_CACHE ) 162 if ( cache_pos >= SCROBBLER_MAX_CACHE )
176 write_cache(); 163 write_cache();
177 164
178 int ret;
179 char rating = 'S'; /* Skipped */ 165 char rating = 'S'; /* Skipped */
180 char* scrobbler_buf = core_get_data(scrobbler_cache); 166 char* scrobbler_buf = core_get_data(scrobbler_cache);
181 167
182 logf("SCROBBLER: add_to_cache[%d]", cache_pos); 168 logf("SCROBBLER: add_to_cache[%d]", cache_pos);
183 169
184 if ( play_length > (scrobbler_entry.length/2) ) 170 if (id->elapsed > id->length / 2)
185 rating = 'L'; /* Listened */ 171 rating = 'L'; /* Listened */
186 172
187 if (scrobbler_entry.tracknum > 0) 173 char tracknum[11] = { "" };
188 { 174
189 ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos), 175 if (id->tracknum > 0)
190 SCROBBLER_CACHE_LEN, 176 snprintf(tracknum, sizeof (tracknum), "%d", id->tracknum);
191 "%s\t%s\t%s\t%d\t%d\t%c\t%ld\t%s\n", 177
192 scrobbler_entry.artist, 178 int ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos),
193 scrobbler_entry.album?scrobbler_entry.album:"", 179 SCROBBLER_CACHE_LEN,
194 scrobbler_entry.title, 180 "%s\t%s\t%s\t%s\t%d\t%c\t%ld\t%s\n",
195 scrobbler_entry.tracknum, 181 id->artist,
196 (int)scrobbler_entry.length/1000, 182 id->album ?: "",
197 rating, 183 id->title,
198 (long)timestamp, 184 tracknum,
199 scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:""); 185 (int)(id->length / 1000),
200 } else { 186 rating,
201 ret = snprintf(scrobbler_buf+(SCROBBLER_CACHE_LEN*cache_pos), 187 get_timestamp(),
202 SCROBBLER_CACHE_LEN, 188 id->mb_track_id ?: "");
203 "%s\t%s\t%s\t\t%d\t%c\t%ld\t%s\n",
204 scrobbler_entry.artist,
205 scrobbler_entry.album?scrobbler_entry.album:"",
206 scrobbler_entry.title,
207 (int)scrobbler_entry.length/1000,
208 rating,
209 (long)timestamp,
210 scrobbler_entry.mb_track_id?scrobbler_entry.mb_track_id:"");
211 }
212 189
213 if ( ret >= SCROBBLER_CACHE_LEN ) 190 if ( ret >= SCROBBLER_CACHE_LEN )
214 { 191 {
215 logf("SCROBBLER: entry too long:"); 192 logf("SCROBBLER: entry too long:");
216 logf("SCROBBLER: %s", scrobbler_entry.path); 193 logf("SCROBBLER: %s", id->path);
217 } else { 194 }
195 else
196 {
218 cache_pos++; 197 cache_pos++;
219 register_storage_idle_func(scrobbler_flush_callback); 198 register_storage_idle_func(scrobbler_flush_callback);
220 } 199 }
@@ -223,15 +202,11 @@ static void add_to_cache(unsigned long play_length)
223 202
224static void scrobbler_change_event(void *data) 203static void scrobbler_change_event(void *data)
225{ 204{
226 struct mp3entry *id = (struct mp3entry*)data; 205 struct mp3entry *id = ((struct track_event *)data)->id3;
227 /* add entry using the previous scrobbler_entry and timestamp */
228 if (pending)
229 add_to_cache(audio_prev_elapsed());
230 206
231 /* check if track was resumed > %50 played 207 /* check if track was resumed > %50 played
232 check for blank artist or track name */ 208 check for blank artist or track name */
233 if ((id->elapsed > (id->length/2)) || 209 if (id->elapsed > id->length / 2 || !id->artist || !id->title)
234 (!id->artist ) || (!id->title ) )
235 { 210 {
236 pending = false; 211 pending = false;
237 logf("SCROBBLER: skipping file %s", id->path); 212 logf("SCROBBLER: skipping file %s", id->path);
@@ -239,81 +214,85 @@ static void scrobbler_change_event(void *data)
239 else 214 else
240 { 215 {
241 logf("SCROBBLER: add pending"); 216 logf("SCROBBLER: add pending");
242 copy_mp3entry(&scrobbler_entry, id); 217 record_timestamp();
243#if CONFIG_RTC
244 timestamp = mktime(get_time());
245#else
246 timestamp = 0;
247#endif
248 pending = true; 218 pending = true;
249 } 219 }
250} 220}
251 221
222static void scrobbler_finish_event(void *data)
223{
224 struct track_event *te = (struct track_event *)data;
225
226 /* add entry using the currently ending track */
227 if (pending && (te->flags & TEF_CURRENT)
228#if CONFIG_CODEC == SWCODEC
229 && !(te->flags & TEF_REWIND)
230#endif
231 )
232 {
233 pending = false;
234 add_to_cache(te->id3);
235 }
236}
237
252int scrobbler_init(void) 238int scrobbler_init(void)
253{ 239{
254 logf("SCROBBLER: init %d", global_settings.audioscrobbler); 240 if (scrobbler_initialised)
241 return 1;
255 242
256 if(!global_settings.audioscrobbler) 243 scrobbler_cache = core_alloc("scrobbler",
257 return -1; 244 SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
258 245
259 scrobbler_cache = core_alloc("scrobbler", SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
260 if (scrobbler_cache <= 0) 246 if (scrobbler_cache <= 0)
261 { 247 {
262 logf("SCROOBLER: OOM"); 248 logf("SCROOBLER: OOM");
263 return -1; 249 return -1;
264 } 250 }
265 251
266 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event);
267 cache_pos = 0; 252 cache_pos = 0;
268 pending = false; 253 pending = false;
254
269 scrobbler_initialised = true; 255 scrobbler_initialised = true;
270 256
257 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, scrobbler_change_event);
258 add_event(PLAYBACK_EVENT_TRACK_FINISH, false, scrobbler_finish_event);
259
271 return 1; 260 return 1;
272} 261}
273 262
274static void scrobbler_flush_cache(void) 263static void scrobbler_flush_cache(void)
275{ 264{
276 if (scrobbler_initialised)
277 {
278 /* Add any pending entries to the cache */ 265 /* Add any pending entries to the cache */
279 if(pending) 266 if (pending)
280 add_to_cache(audio_prev_elapsed()); 267 {
281
282 /* Write the cache to disk if needed */
283 if (cache_pos)
284 write_cache();
285
286 pending = false; 268 pending = false;
269 if (audio_status())
270 add_to_cache(audio_current_track());
287 } 271 }
272
273 /* Write the cache to disk if needed */
274 if (cache_pos)
275 write_cache();
288} 276}
289 277
290void scrobbler_shutdown(void) 278void scrobbler_shutdown(bool poweroff)
291{ 279{
280 if (!scrobbler_initialised)
281 return;
282
283 remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
284 remove_event(PLAYBACK_EVENT_TRACK_FINISH, scrobbler_finish_event);
285
292 scrobbler_flush_cache(); 286 scrobbler_flush_cache();
293 287
294 if (scrobbler_initialised) 288 if (!poweroff)
295 { 289 {
296 remove_event(PLAYBACK_EVENT_TRACK_CHANGE, scrobbler_change_event);
297 scrobbler_initialised = false;
298 /* get rid of the buffer */ 290 /* get rid of the buffer */
299 core_free(scrobbler_cache); 291 core_free(scrobbler_cache);
300 scrobbler_cache = 0; 292 scrobbler_cache = 0;
301 } 293 }
302}
303 294
304void scrobbler_poweroff(void) 295 scrobbler_initialised = false;
305{
306 if (scrobbler_initialised && pending)
307 {
308 if ( audio_status() )
309 add_to_cache(audio_current_track()->elapsed);
310 else
311 add_to_cache(audio_prev_elapsed());
312
313 /* scrobbler_shutdown is called later, the cache will be written
314 * make sure the final track isn't added twice when that happens */
315 pending = false;
316 }
317} 296}
318 297
319bool scrobbler_is_enabled(void) 298bool scrobbler_is_enabled(void)