diff options
Diffstat (limited to 'apps/scrobbler.c')
-rw-r--r-- | apps/scrobbler.c | 195 |
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 | ||
55 | static int scrobbler_cache; | ||
56 | |||
57 | static int cache_pos; | ||
58 | static struct mp3entry scrobbler_entry; | ||
59 | static bool pending = false; | ||
60 | static bool scrobbler_initialised = false; | 55 | static bool scrobbler_initialised = false; |
56 | static int scrobbler_cache = 0; | ||
57 | static int cache_pos = 0; | ||
58 | static bool pending = false; | ||
61 | #if CONFIG_RTC | 59 | #if CONFIG_RTC |
62 | static time_t timestamp; | 60 | static time_t timestamp; |
63 | #else | 61 | #define BASE_FILENAME ".scrobbler.log" |
64 | static 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" |
69 | unsigned 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 | ||
75 | static void get_scrobbler_filename(char *path, size_t size) | 72 | static 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 | ||
173 | static void add_to_cache(unsigned long play_length) | 160 | static 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 | ||
224 | static void scrobbler_change_event(void *data) | 203 | static 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 | ||
222 | static 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 | |||
252 | int scrobbler_init(void) | 238 | int 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 | ||
274 | static void scrobbler_flush_cache(void) | 263 | static 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 | ||
290 | void scrobbler_shutdown(void) | 278 | void 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 | ||
304 | void 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 | ||
319 | bool scrobbler_is_enabled(void) | 298 | bool scrobbler_is_enabled(void) |