Change i2c config on e200. Seems to speed things up somewhat.
[kugel-rb.git] / apps / scrobbler.c
blob07ba016a518f459665768bc257c8d10b67485ac7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Robert Keevil
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 Audioscrobbler spec at:
21 http://www.audioscrobbler.net/wiki/Portable_Player_Logging
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 #include "ata_idle_notify.h"
35 #if CONFIG_RTC
36 #include "time.h"
37 #include "timefuncs.h"
38 #endif
40 #include "scrobbler.h"
42 #define SCROBBLER_VERSION "1.0"
44 #if CONFIG_RTC
45 #define SCROBBLER_FILE "/.scrobbler.log"
46 #else
47 #define SCROBBLER_FILE "/.scrobbler-timeless.log"
48 #endif
50 /* increment this on any code change that effects output */
51 #define SCROBBLER_REVISION " $Revision$"
53 #define SCROBBLER_MAX_CACHE 32
54 /* longest entry I've had is 323, add a safety margin */
55 #define SCROBBLER_CACHE_LEN 512
57 static char* scrobbler_cache;
59 static int scrobbler_fd = -1;
60 static int cache_pos;
61 static struct mp3entry scrobbler_entry;
62 static bool pending = false;
63 static bool scrobbler_initialised = false;
64 static bool scrobbler_ata_callback = false;
65 #if CONFIG_RTC
66 static time_t timestamp;
67 #else
68 static unsigned long timestamp;
69 #endif
71 /* Crude work-around for Archos Sims - return a set amount */
72 #if (CONFIG_CODEC != SWCODEC) && defined(SIMULATOR)
73 unsigned long audio_prev_elapsed(void)
75 return 120000;
77 #endif
79 static void write_cache(void)
81 int i;
83 scrobbler_ata_callback = false;
85 /* If the file doesn't exist, create it.
86 Check at each write since file may be deleted at any time */
87 scrobbler_fd = open(SCROBBLER_FILE, O_RDONLY);
88 if(scrobbler_fd < 0)
90 scrobbler_fd = open(SCROBBLER_FILE, O_RDWR | O_CREAT);
91 if(scrobbler_fd >= 0)
93 fdprintf(scrobbler_fd, "#AUDIOSCROBBLER/%s\n", SCROBBLER_VERSION);
94 fdprintf(scrobbler_fd, "#TZ/UNKNOWN\n");
95 #if CONFIG_RTC
96 fdprintf(scrobbler_fd,
97 "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION "\n");
98 #else
99 fdprintf(scrobbler_fd,
100 "#CLIENT/Rockbox " TARGET_NAME SCROBBLER_REVISION " Timeless\n");
101 #endif
102 close(scrobbler_fd);
104 else
106 logf("SCROBBLER: cannot create log file");
109 close(scrobbler_fd);
110 scrobbler_fd = -1;
112 /* write the cache entries */
113 scrobbler_fd = open(SCROBBLER_FILE, O_WRONLY | O_APPEND);
114 if(scrobbler_fd >= 0)
116 logf("SCROBBLER: writing %d entries", cache_pos);
118 for ( i=0; i < cache_pos; i++ )
120 logf("SCROBBLER: write %d", i);
121 fdprintf(scrobbler_fd, "%s", scrobbler_cache+(SCROBBLER_CACHE_LEN*i));
123 close(scrobbler_fd);
125 else
127 logf("SCROBBLER: error writing file");
130 /* clear even if unsuccessful - don't want to overflow the buffer */
131 cache_pos = 0;
132 scrobbler_fd = -1;
135 static bool scrobbler_flush_callback(void)
137 if (scrobbler_initialised && cache_pos)
138 write_cache();
139 return true;
142 static void add_to_cache(void)
144 if ( cache_pos >= SCROBBLER_MAX_CACHE )
145 write_cache();
147 int ret;
148 char rating = 'S'; /* Skipped */
150 logf("SCROBBLER: add_to_cache[%d]", cache_pos);
152 if ( audio_prev_elapsed() >
153 (scrobbler_entry.length/2) )
154 rating = 'L'; /* Listened */
156 if (scrobbler_entry.tracknum > 0)
158 ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
159 SCROBBLER_CACHE_LEN,
160 "%s\t%s\t%s\t%d\t%d\t%c\t%ld\n",
161 scrobbler_entry.artist,
162 scrobbler_entry.album?scrobbler_entry.album:"",
163 scrobbler_entry.title,
164 scrobbler_entry.tracknum,
165 (int)scrobbler_entry.length/1000,
166 rating,
167 (long)timestamp);
168 } else {
169 ret = snprintf(scrobbler_cache+(SCROBBLER_CACHE_LEN*cache_pos),
170 SCROBBLER_CACHE_LEN,
171 "%s\t%s\t%s\t\t%d\t%c\t%ld\n",
172 scrobbler_entry.artist,
173 scrobbler_entry.album?scrobbler_entry.album:"",
174 scrobbler_entry.title,
175 (int)scrobbler_entry.length/1000,
176 rating,
177 (long)timestamp);
180 if ( ret >= SCROBBLER_CACHE_LEN )
182 logf("SCROBBLER: entry too long:");
183 logf("SCROBBLER: %s", scrobbler_entry.path);
184 } else {
185 cache_pos++;
186 if (!scrobbler_ata_callback)
187 scrobbler_ata_callback = register_ata_idle_func(scrobbler_flush_callback);
192 void scrobbler_change_event(struct mp3entry *id)
194 /* add entry using the previous scrobbler_entry and timestamp */
195 if (pending)
196 add_to_cache();
198 /* check if track was resumed > %50 played
199 check for blank artist or track name */
200 if ((id->elapsed > (id->length/2)) ||
201 (!id->artist ) || (!id->title ) )
203 pending = false;
204 logf("SCROBBLER: skipping file %s", id->path);
206 else
208 logf("SCROBBLER: add pending");
209 copy_mp3entry(&scrobbler_entry, id);
210 #if CONFIG_RTC
211 timestamp = mktime(get_time());
212 #else
213 timestamp = 0;
214 #endif
215 pending = true;
219 int scrobbler_init(void)
221 logf("SCROBBLER: init %d", global_settings.audioscrobbler);
223 if(!global_settings.audioscrobbler)
224 return -1;
226 scrobbler_cache = buffer_alloc(SCROBBLER_MAX_CACHE*SCROBBLER_CACHE_LEN);
228 audio_set_track_changed_event(&scrobbler_change_event);
229 cache_pos = 0;
230 pending = false;
231 scrobbler_initialised = true;
233 return 1;
236 void scrobbler_flush_cache(void)
238 if (scrobbler_initialised)
240 /* Add any pending entries to the cache */
241 if(pending)
242 add_to_cache();
244 /* Write the cache to disk if needed */
245 if (cache_pos)
246 write_cache();
248 pending = false;
252 void scrobbler_shutdown(void)
254 #ifndef SIMULATOR
255 if (scrobbler_ata_callback)
256 unregister_ata_idle_func(scrobbler_flush_callback, false);
257 #endif
259 scrobbler_flush_cache();
261 if (scrobbler_initialised)
263 audio_set_track_changed_event(NULL);
264 scrobbler_initialised = false;
268 bool scrobbler_is_enabled(void)
270 return scrobbler_initialised;