diff options
Diffstat (limited to 'apps/plugins/lua_scripts/random_playlist.lua')
-rw-r--r-- | apps/plugins/lua_scripts/random_playlist.lua | 125 |
1 files changed, 87 insertions, 38 deletions
diff --git a/apps/plugins/lua_scripts/random_playlist.lua b/apps/plugins/lua_scripts/random_playlist.lua index 9d300025ac..b4fd216981 100644 --- a/apps/plugins/lua_scripts/random_playlist.lua +++ b/apps/plugins/lua_scripts/random_playlist.lua | |||
@@ -20,6 +20,19 @@ | |||
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | ]] | 22 | ]] |
23 | --[[ random_playlist | ||
24 | This script opens the users database file containg track path + filenames | ||
25 | first it reads the database file making an index of tracks | ||
26 | [for large playlists it only saves an index every [10|100|1000] tracks. | ||
27 | tracks will be incrementally loaded along with the results of the entries | ||
28 | traversed but the garbage collector will erase them when needed] | ||
29 | |||
30 | next tracks are choosen at random and added either to an in-ram playlist | ||
31 | using plugin functions OR | ||
32 | to a on disk playlist using a table as a write buffer | ||
33 | the user can also choose to play the playlist in either case | ||
34 | ]] | ||
35 | |||
23 | require ("actions") | 36 | require ("actions") |
24 | require("dbgettags") | 37 | require("dbgettags") |
25 | get_tags = nil -- unneeded | 38 | get_tags = nil -- unneeded |
@@ -29,6 +42,7 @@ local playlistpath = "/Playlists" | |||
29 | local max_tracks = 500; -- size of playlist to create | 42 | local max_tracks = 500; -- size of playlist to create |
30 | local min_repeat = 500; -- this many songs before a repeat | 43 | local min_repeat = 500; -- this many songs before a repeat |
31 | local play_on_success = true; | 44 | local play_on_success = true; |
45 | local playlist_name = "random_playback.m3u8" | ||
32 | --program vars | 46 | --program vars |
33 | local playlist_handle | 47 | local playlist_handle |
34 | local t_playlistbuf -- table for playlist write buffer | 48 | local t_playlistbuf -- table for playlist write buffer |
@@ -63,12 +77,15 @@ local function text_extent(msg, font) | |||
63 | return rb.font_getstringsize(msg, font) | 77 | return rb.font_getstringsize(msg, font) |
64 | end | 78 | end |
65 | 79 | ||
66 | local function _setup_random_playlist(tag_entries, play, min_repeat, trackcount) | 80 | local function _setup_random_playlist(tag_entries, play, savepl, min_repeat, trackcount) |
67 | -- Setup string tables | 81 | -- Setup string tables |
68 | local tPLAYTEXT = {"Play? [ %s ] (up/dn)", "true = play tracks on success"} | 82 | local tPLAYTEXT = {"Play? [ %s ] (up/dn)", "true = play tracks on success"} |
83 | local tSAVETEXT = {"Save to disk? [ %s ] (up/dn)", | ||
84 | "true = tracks saved to", | ||
85 | playlist_name}; | ||
69 | local tREPEATTEXT = {"Repeat hist? [ %d ] (up/dn)","higher = less repeated songs"} | 86 | local tREPEATTEXT = {"Repeat hist? [ %d ] (up/dn)","higher = less repeated songs"} |
70 | local tPLSIZETEXT = {"Find [ %d ] tracks? (up/dn)", | 87 | local tPLSIZETEXT = {"Find [ %d ] tracks? (up/dn)", |
71 | "Warning overwrites dynamic playlist", | 88 | "Warning may overwrite dynamic playlist", |
72 | "Press back to cancel"}; | 89 | "Press back to cancel"}; |
73 | -- how many lines can we fit on the screen? | 90 | -- how many lines can we fit on the screen? |
74 | local res, w, h = text_extent("I") | 91 | local res, w, h = text_extent("I") |
@@ -125,6 +142,22 @@ local function _setup_random_playlist(tag_entries, play, min_repeat, trackcount) | |||
125 | end | 142 | end |
126 | end | 143 | end |
127 | 144 | ||
145 | -- Save the playlist to disk true/false? | ||
146 | function setup_get_save() | ||
147 | action = ask_user_action(tdesc, | ||
148 | string.format(tSAVETEXT[1], tostring(savepl)), | ||
149 | tSAVETEXT[2], tSAVETEXT[3]); | ||
150 | if action == ADD_BUTTON then | ||
151 | savepl = true | ||
152 | elseif action == SUB_BUTTON then | ||
153 | savepl = false | ||
154 | elseif action == OK_BUTTON then | ||
155 | ask = setup_get_play; | ||
156 | setup_get_save = nil | ||
157 | action = 0 | ||
158 | end | ||
159 | end | ||
160 | |||
128 | -- Repeat song buffer list of previously added tracks 0-?? | 161 | -- Repeat song buffer list of previously added tracks 0-?? |
129 | function setup_get_repeat() | 162 | function setup_get_repeat() |
130 | if min_repeat >= trackcount then min_repeat = trackcount - 1 end | 163 | if min_repeat >= trackcount then min_repeat = trackcount - 1 end |
@@ -139,7 +172,7 @@ local function _setup_random_playlist(tag_entries, play, min_repeat, trackcount) | |||
139 | min_repeat = min_repeat - increment | 172 | min_repeat = min_repeat - increment |
140 | if min_repeat < 0 then min_repeat = 0 end | 173 | if min_repeat < 0 then min_repeat = 0 end |
141 | elseif action == OK_BUTTON then | 174 | elseif action == OK_BUTTON then |
142 | ask = setup_get_play; | 175 | ask = setup_get_save; |
143 | setup_get_repeat = nil | 176 | setup_get_repeat = nil |
144 | action = 0 | 177 | action = 0 |
145 | end | 178 | end |
@@ -173,9 +206,11 @@ local function _setup_random_playlist(tag_entries, play, min_repeat, trackcount) | |||
173 | if action == CANCEL_BUTTON then rb.lcd_scroll_stop(); return nil end | 206 | if action == CANCEL_BUTTON then rb.lcd_scroll_stop(); return nil end |
174 | until (action == OK_BUTTON) | 207 | until (action == OK_BUTTON) |
175 | 208 | ||
176 | return play, min_repeat, trackcount; | 209 | return play, savepl, min_repeat, trackcount; |
177 | end | 210 | end |
178 | 211 | --[[ manually create a playlist | |
212 | playlist is created initially by creating a new file (or erasing old) | ||
213 | and adding the BOM]] | ||
179 | --deletes existing file and creates a new playlist | 214 | --deletes existing file and creates a new playlist |
180 | local function playlist_create(filename) | 215 | local function playlist_create(filename) |
181 | local filehandle = io.open(filename, "w+") --overwrite | 216 | local filehandle = io.open(filename, "w+") --overwrite |
@@ -184,47 +219,42 @@ local function playlist_create(filename) | |||
184 | return false | 219 | return false |
185 | end | 220 | end |
186 | t_playlistbuf = {} | 221 | t_playlistbuf = {} |
187 | filehandle:write("\239\187\191") -- Write BOM --"\xEF\xBB\xBF" | 222 | filehandle:write("\239\187\191") -- Write BOM --"\xEF\xBB\xBF" |
188 | playlist_handle = filehandle | 223 | playlist_handle = filehandle |
189 | return true | 224 | return true |
190 | --os.remove( playlistpath .. "/" .. playlist) | ||
191 | --rb.playlist("remove_all_tracks") | ||
192 | --rb.playlist("create", playlistpath .. "/", playlist) | ||
193 | end | 225 | end |
194 | 226 | ||
195 | -- writes track path to a buffer must be flushed | 227 | -- writes track path to a buffer must be later flushed to playlist file |
196 | local function playlist_write(trackpath) | 228 | local function playlist_insert(trackpath) |
197 | t_playlistbuf[#t_playlistbuf + 1] = trackpath | 229 | local bufp = #t_playlistbuf + 1 |
198 | t_playlistbuf[#t_playlistbuf + 1] = "\n" | 230 | t_playlistbuf[bufp] = trackpath |
199 | --[[if rb.playlist("insert_track", str) < 0 then | 231 | bufp = bufp + 1 |
200 | rb.splash(rb.HZ, sPLAYLISTERROR) | 232 | t_playlistbuf[bufp] = "\n" |
201 | break; -- ERROR, PLAYLIST FULL? | 233 | return bufp |
202 | end]] | ||
203 | end | 234 | end |
204 | 235 | ||
205 | -- flushes playlist buffer to file | 236 | -- flushes playlist buffer to file |
206 | local function playlist_flush() | 237 | local function playlist_flush() |
207 | playlist_handle:write(table.concat(t_playlistbuf)) | 238 | playlist_handle:write(table.concat(t_playlistbuf)) |
208 | t_playlistbuf = {} | 239 | t_playlistbuf = {} |
209 | --[[if rb.playlist("insert_track", str) < 0 then | ||
210 | rb.splash(rb.HZ, sPLAYLISTERROR) | ||
211 | break; -- ERROR, PLAYLIST FULL? | ||
212 | end]] | ||
213 | end | 240 | end |
214 | 241 | ||
215 | -- closes playlist file descriptor | 242 | -- closes playlist file descriptor |
216 | local function playlist_finalize() | 243 | local function playlist_finalize() |
217 | playlist_handle:close() | 244 | playlist_handle:close() |
245 | return true | ||
218 | end | 246 | end |
219 | 247 | ||
220 | --[[ Given the filenameDB file [database] | 248 | --[[ Given the filenameDB file [database] |
221 | creates a random dynamic playlist with a default savename of [playlist] | 249 | creates a random dynamic playlist with a default savename of [playlist] |
222 | containing [trackcount] tracks, played on completion if [play] is true]] | 250 | containing [trackcount] tracks, played on completion if [play] is true]] |
223 | local function create_random_playlist(database, playlist, trackcount, play) | 251 | local function create_random_playlist(database, playlist, trackcount, play, savepl) |
224 | if not database or not playlist or not trackcount then return end | 252 | if not database or not playlist or not trackcount then return end |
225 | if not play then play = false end | 253 | if not play then play = false end |
254 | if not savepl then savepl = false end | ||
226 | 255 | ||
227 | local playlist_handle | 256 | local playlist_handle |
257 | local playlistisfinalized = false | ||
228 | local file = io.open('/' .. database or "", "r") --read | 258 | local file = io.open('/' .. database or "", "r") --read |
229 | if not file then rb.splash(100, string.format(sERROROPENFMT, database)) return end | 259 | if not file then rb.splash(100, string.format(sERROROPENFMT, database)) return end |
230 | 260 | ||
@@ -258,11 +288,25 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
258 | end | 288 | end |
259 | 289 | ||
260 | local tag_entries = bytesLE_n(tagcache_entries) | 290 | local tag_entries = bytesLE_n(tagcache_entries) |
261 | if tag_entries > 50000 then play = false end | ||
262 | 291 | ||
263 | play, min_repeat, trackcount = _setup_random_playlist( | 292 | play, savepl, min_repeat, trackcount = _setup_random_playlist( |
264 | tag_entries, play, min_repeat, trackcount); | 293 | tag_entries, play, savepl, min_repeat, trackcount); |
265 | _setup_random_playlist = nil | 294 | _setup_random_playlist = nil |
295 | |||
296 | if savepl == false then | ||
297 | -- Use the rockbox playlist functions to add tracks to in-ram playlist | ||
298 | playlist_create = function(filename) | ||
299 | return (rb.playlist("create", playlistpath .. "/", playlist) >= 0) | ||
300 | end | ||
301 | playlist_insert = function(str) | ||
302 | return rb.playlist("insert_track", str) | ||
303 | end | ||
304 | playlist_flush = function() end | ||
305 | playlist_finalize = function() | ||
306 | return (rb.playlist("amount") >= trackcount) | ||
307 | end | ||
308 | end | ||
309 | if not playlist_create(playlistpath .. "/" .. playlist) then return end | ||
266 | collectgarbage("collect") | 310 | collectgarbage("collect") |
267 | 311 | ||
268 | -- how many lines can we fit on the screen? | 312 | -- how many lines can we fit on the screen? |
@@ -344,7 +388,7 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
344 | end | 388 | end |
345 | 389 | ||
346 | get_index() --init get_index fn | 390 | get_index() --init get_index fn |
347 | -- Playlist insert loop | 391 | -- Playlist insert loop |
348 | while true do | 392 | while true do |
349 | str = nil | 393 | str = nil |
350 | tries = 0 | 394 | tries = 0 |
@@ -365,7 +409,11 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
365 | tracks = tracks + 1 | 409 | tracks = tracks + 1 |
366 | show_progress() | 410 | show_progress() |
367 | push_lru(idxp) -- add to repeat list | 411 | push_lru(idxp) -- add to repeat list |
368 | playlist_write(str) | 412 | if playlist_insert(str) < 0 then |
413 | rb.sleep(rb.HZ) --rb playlist fn display own message wait for that | ||
414 | rb.splash(rb.HZ, sPLAYLISTERROR) | ||
415 | break; -- ERROR, PLAYLIST FULL? | ||
416 | end | ||
369 | end | 417 | end |
370 | 418 | ||
371 | if tracks >= trackcount then | 419 | if tracks >= trackcount then |
@@ -384,7 +432,7 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
384 | function build_anchor_index() | 432 | function build_anchor_index() |
385 | -- index every n files | 433 | -- index every n files |
386 | ANCHOR_INTV = 1 -- for small db we can put all the entries in ram | 434 | ANCHOR_INTV = 1 -- for small db we can put all the entries in ram |
387 | local ent = tag_entries / 1000 -- more than 10,000 will be incrementally loaded | 435 | local ent = tag_entries / 100 -- more than 1000 will be incrementally loaded |
388 | while ent >= 10 do -- need to reduce the size of the anchor index? | 436 | while ent >= 10 do -- need to reduce the size of the anchor index? |
389 | ent = ent / 10 | 437 | ent = ent / 10 |
390 | ANCHOR_INTV = ANCHOR_INTV * 10 | 438 | ANCHOR_INTV = ANCHOR_INTV * 10 |
@@ -442,8 +490,6 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
442 | track_index = anchor_index | 490 | track_index = anchor_index |
443 | anchor_index = nil | 491 | anchor_index = nil |
444 | end | 492 | end |
445 | |||
446 | if not playlist_create(playlistpath .. "/" .. playlist) then return end | ||
447 | --[[ --profiling | 493 | --[[ --profiling |
448 | local starttime = rb.current_tick(); | 494 | local starttime = rb.current_tick(); |
449 | get_tracks_random() | 495 | get_tracks_random() |
@@ -453,16 +499,19 @@ local function create_random_playlist(database, playlist, trackcount, play) | |||
453 | if (false) then | 499 | if (false) then |
454 | --]] | 500 | --]] |
455 | get_tracks_random() | 501 | get_tracks_random() |
456 | playlist_finalize(playlist_handle) | 502 | playlistisfinalized = playlist_finalize(playlist_handle) |
457 | end | 503 | end |
458 | 504 | ||
459 | file:close() | 505 | file:close() |
460 | collectgarbage("collect") | 506 | collectgarbage("collect") |
461 | if trackcount and play == true then | 507 | if trackcount and play == true and playlistisfinalized == true then |
462 | rb.audio("stop") | 508 | rb.audio("stop") |
463 | rb.yield() | 509 | rb.yield() |
464 | rb.playlist("create", playlistpath .. "/", "dynamic_playlist.m3u8") | 510 | if savepl == true then |
465 | rb.playlist("insert_playlist", playlistpath .. "/" .. playlist) | 511 | rb.playlist("create", playlistpath .. "/", playlist) |
512 | rb.playlist("insert_playlist", playlistpath .. "/" .. playlist) | ||
513 | rb.sleep(rb.HZ) | ||
514 | end | ||
466 | rb.playlist("start", 0, 0, 0) | 515 | rb.playlist("start", 0, 0, 0) |
467 | end | 516 | end |
468 | 517 | ||
@@ -482,13 +531,13 @@ local function main() | |||
482 | rb.lcd_update() | 531 | rb.lcd_update() |
483 | collectgarbage("collect") | 532 | collectgarbage("collect") |
484 | create_random_playlist(rb.ROCKBOX_DIR .. "/database_4.tcd", | 533 | create_random_playlist(rb.ROCKBOX_DIR .. "/database_4.tcd", |
485 | "random_playback.m3u8", max_tracks, play_on_success); | 534 | playlist_name, max_tracks, play_on_success); |
486 | rb.splash(rb.HZ * 2, sGOODBYE) | ||
487 | -- Restore user backlight settings | 535 | -- Restore user backlight settings |
488 | rb.backlight_use_settings() | 536 | rb.backlight_use_settings() |
489 | if rb.cpu_boost then rb.cpu_boost(false) end | 537 | if rb.cpu_boost then rb.cpu_boost(false) end |
490 | 538 | rb.sleep(rb.HZ) | |
491 | --[[ | 539 | rb.splash(rb.HZ * 2, sGOODBYE) |
540 | --[[ | ||
492 | local used, allocd, free = rb.mem_stats() | 541 | local used, allocd, free = rb.mem_stats() |
493 | local lu = collectgarbage("count") | 542 | local lu = collectgarbage("count") |
494 | local fmt = function(t, v) return string.format("%s: %d Kb\n", t, v /1024) end | 543 | local fmt = function(t, v) return string.format("%s: %d Kb\n", t, v /1024) end |