diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2023-03-29 10:58:30 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2023-10-01 11:05:29 -0400 |
commit | 7ccbd705f43553ff358d6713c8d6ac7cc9e3c343 (patch) | |
tree | cbd8b34688194715632f03e9248bb3a2e8a3dda7 /apps/playlist.c | |
parent | 781f955aa2fb813dd87986cbcc22c1676a2dd9a9 (diff) | |
download | rockbox-7ccbd705f43553ff358d6713c8d6ac7cc9e3c343.tar.gz rockbox-7ccbd705f43553ff358d6713c8d6ac7cc9e3c343.zip |
playlist: Rework playlist modified detection and dirplay
The modified state is now an explicit flag that has to be
set whenever a user-triggered modification occurs. This is
recorded in the control file to ensure it doesn't get lost
after resume. There may be some places I missed where the
modified flag should be set/cleared, but it seems to work
well enough right now.
Change-Id: I3bdba358fc495b4ca84e389ac6e7bcbef820c219
Diffstat (limited to 'apps/playlist.c')
-rw-r--r-- | apps/playlist.c | 123 |
1 files changed, 82 insertions, 41 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index 67edc5fbe5..554e1afd7e 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -31,10 +31,13 @@ | |||
31 | started and contains all the commands done to it. | 31 | started and contains all the commands done to it. |
32 | 32 | ||
33 | The first non-comment line in a control file must begin with | 33 | The first non-comment line in a control file must begin with |
34 | "P:VERSION:DIR:FILE" where VERSION is the playlist control file version, | 34 | "P:VERSION:DIR:FILE" where VERSION is the playlist control file version |
35 | DIR is the directory where the playlist is located and FILE is the | 35 | DIR is the directory where the playlist is located and FILE is the |
36 | playlist filename. For dirplay, FILE will be empty. An empty playlist | 36 | playlist filename (without the directory part). |
37 | will have both entries as null. | 37 | |
38 | When there is an on-disk playlist file, both DIR and FILE are nonempty. | ||
39 | Dynamically generated playlists (whether by the file browser, database, | ||
40 | or another means) have an empty FILE. For dirplay, DIR will be nonempty. | ||
38 | 41 | ||
39 | Control file commands: | 42 | Control file commands: |
40 | a. Add track (A:<position>:<last position>:<path to track>) | 43 | a. Add track (A:<position>:<last position>:<path to track>) |
@@ -130,9 +133,10 @@ | |||
130 | * v1 was the initial version when dynamic playlists were first implemented. | 133 | * v1 was the initial version when dynamic playlists were first implemented. |
131 | * v2 was added shortly thereafter and has been used since 2003. | 134 | * v2 was added shortly thereafter and has been used since 2003. |
132 | * v3 added the (C)lear command and is otherwise identical to v2. | 135 | * v3 added the (C)lear command and is otherwise identical to v2. |
136 | * v4 added the (F)lags command. | ||
133 | */ | 137 | */ |
134 | #define PLAYLIST_CONTROL_FILE_MIN_VERSION 2 | 138 | #define PLAYLIST_CONTROL_FILE_MIN_VERSION 2 |
135 | #define PLAYLIST_CONTROL_FILE_VERSION 3 | 139 | #define PLAYLIST_CONTROL_FILE_VERSION 4 |
136 | 140 | ||
137 | #define PLAYLIST_COMMAND_SIZE (MAX_PATH+12) | 141 | #define PLAYLIST_COMMAND_SIZE (MAX_PATH+12) |
138 | 142 | ||
@@ -431,6 +435,9 @@ static int update_control_unlocked(struct playlist_info* playlist, | |||
431 | case PLAYLIST_COMMAND_CLEAR: | 435 | case PLAYLIST_COMMAND_CLEAR: |
432 | result = write(fd, "C\n", 2); | 436 | result = write(fd, "C\n", 2); |
433 | break; | 437 | break; |
438 | case PLAYLIST_COMMAND_FLAGS: | ||
439 | result = fdprintf(fd, "F:%u:%u\n", i1, i2); | ||
440 | break; | ||
434 | default: | 441 | default: |
435 | return -1; | 442 | return -1; |
436 | } | 443 | } |
@@ -481,8 +488,7 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume) | |||
481 | 488 | ||
482 | playlist->utf8 = true; | 489 | playlist->utf8 = true; |
483 | playlist->control_created = false; | 490 | playlist->control_created = false; |
484 | playlist->modified = false; | 491 | playlist->flags = 0; |
485 | playlist->dirplay = true; | ||
486 | 492 | ||
487 | playlist->control_fd = -1; | 493 | playlist->control_fd = -1; |
488 | 494 | ||
@@ -501,6 +507,28 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume) | |||
501 | } | 507 | } |
502 | } | 508 | } |
503 | 509 | ||
510 | int update_playlist_flags_unlocked(struct playlist_info *playlist, | ||
511 | unsigned int setf, unsigned int clearf) | ||
512 | { | ||
513 | unsigned int newflags = (playlist->flags & ~clearf) | setf; | ||
514 | if (newflags == playlist->flags) | ||
515 | return 0; | ||
516 | |||
517 | playlist->flags = newflags; | ||
518 | |||
519 | if (playlist->control_fd >= 0) | ||
520 | { | ||
521 | int res = update_control_unlocked(playlist, PLAYLIST_COMMAND_FLAGS, | ||
522 | setf, clearf, NULL, NULL, NULL); | ||
523 | if (res < 0) | ||
524 | return res; | ||
525 | |||
526 | sync_control_unlocked(playlist); | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
504 | /* | 532 | /* |
505 | * Returns absolute path of track | 533 | * Returns absolute path of track |
506 | * | 534 | * |
@@ -567,28 +595,21 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length, | |||
567 | static void new_playlist_unlocked(struct playlist_info* playlist, | 595 | static void new_playlist_unlocked(struct playlist_info* playlist, |
568 | const char *dir, const char *file) | 596 | const char *dir, const char *file) |
569 | { | 597 | { |
570 | const char *fileused = file; | ||
571 | const char *dirused = dir; | ||
572 | |||
573 | empty_playlist_unlocked(playlist, false); | 598 | empty_playlist_unlocked(playlist, false); |
574 | 599 | ||
575 | if (!fileused) | 600 | /* enable dirplay for the current playlist if there's a DIR but no FILE */ |
576 | { | 601 | if (!file && dir && playlist == ¤t_playlist) |
577 | fileused = ""; | 602 | playlist->flags |= PLAYLIST_FLAG_DIRPLAY; |
578 | 603 | ||
579 | /* only the current playlist can use dirplay */ | 604 | dir = dir ?: ""; |
580 | if (dirused && playlist == ¤t_playlist) | 605 | file = file ?: ""; |
581 | playlist->dirplay = true; | ||
582 | else | ||
583 | dirused = ""; /* empty playlist */ | ||
584 | } | ||
585 | 606 | ||
586 | update_playlist_filename_unlocked(playlist, dirused, fileused); | 607 | update_playlist_filename_unlocked(playlist, dir, file); |
587 | 608 | ||
588 | if (playlist->control_fd >= 0) | 609 | if (playlist->control_fd >= 0) |
589 | { | 610 | { |
590 | update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST, | 611 | update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST, |
591 | PLAYLIST_CONTROL_FILE_VERSION, -1, dirused, fileused, NULL); | 612 | PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL); |
592 | sync_control_unlocked(playlist); | 613 | sync_control_unlocked(playlist); |
593 | } | 614 | } |
594 | } | 615 | } |
@@ -711,7 +732,6 @@ static int recreate_control_unlocked(struct playlist_info* playlist) | |||
711 | } | 732 | } |
712 | 733 | ||
713 | playlist->seed = 0; | 734 | playlist->seed = 0; |
714 | playlist->modified = true; | ||
715 | 735 | ||
716 | for (i=0; i<playlist->amount; i++) | 736 | for (i=0; i<playlist->amount; i++) |
717 | { | 737 | { |
@@ -1207,8 +1227,6 @@ static int create_and_play_dir(int direction, bool play_last) | |||
1207 | if (global_settings.playlist_shuffle) | 1227 | if (global_settings.playlist_shuffle) |
1208 | playlist_shuffle(current_tick, -1); | 1228 | playlist_shuffle(current_tick, -1); |
1209 | 1229 | ||
1210 | playlist_set_modified(NULL, false); | ||
1211 | |||
1212 | if (play_last && direction <= 0) | 1230 | if (play_last && direction <= 0) |
1213 | index = current_playlist.amount - 1; | 1231 | index = current_playlist.amount - 1; |
1214 | else | 1232 | else |
@@ -1248,7 +1266,6 @@ static int remove_all_tracks_unlocked(struct playlist_info *playlist, bool write | |||
1248 | playlist->first_index = 0; | 1266 | playlist->first_index = 0; |
1249 | playlist->amount = 1; | 1267 | playlist->amount = 1; |
1250 | playlist->indices[0] |= PLAYLIST_QUEUED; | 1268 | playlist->indices[0] |= PLAYLIST_QUEUED; |
1251 | playlist->modified = true; | ||
1252 | 1269 | ||
1253 | if (playlist->last_insert_pos == 0) | 1270 | if (playlist->last_insert_pos == 0) |
1254 | playlist->last_insert_pos = -1; | 1271 | playlist->last_insert_pos = -1; |
@@ -1423,7 +1440,6 @@ static int add_track_to_playlist_unlocked(struct playlist_info* playlist, | |||
1423 | dc_init_filerefs(playlist, insert_position, 1); | 1440 | dc_init_filerefs(playlist, insert_position, 1); |
1424 | 1441 | ||
1425 | playlist->amount++; | 1442 | playlist->amount++; |
1426 | playlist->modified = true; | ||
1427 | 1443 | ||
1428 | return insert_position; | 1444 | return insert_position; |
1429 | } | 1445 | } |
@@ -1466,7 +1482,6 @@ static int remove_track_unlocked(struct playlist_info* playlist, | |||
1466 | } | 1482 | } |
1467 | 1483 | ||
1468 | playlist->amount--; | 1484 | playlist->amount--; |
1469 | playlist->modified = true; | ||
1470 | 1485 | ||
1471 | /* update stored indices if needed */ | 1486 | /* update stored indices if needed */ |
1472 | if (position < playlist->index) | 1487 | if (position < playlist->index) |
@@ -1559,7 +1574,6 @@ static int randomise_playlist_unlocked(struct playlist_info* playlist, | |||
1559 | playlist->last_insert_pos = -1; | 1574 | playlist->last_insert_pos = -1; |
1560 | 1575 | ||
1561 | playlist->seed = seed; | 1576 | playlist->seed = seed; |
1562 | playlist->modified = true; | ||
1563 | 1577 | ||
1564 | if (write) | 1578 | if (write) |
1565 | { | 1579 | { |
@@ -1623,7 +1637,6 @@ static int sort_playlist_unlocked(struct playlist_info* playlist, | |||
1623 | 1637 | ||
1624 | /* indices have been moved so last insert position is no longer valid */ | 1638 | /* indices have been moved so last insert position is no longer valid */ |
1625 | playlist->last_insert_pos = -1; | 1639 | playlist->last_insert_pos = -1; |
1626 | playlist->modified = true; | ||
1627 | 1640 | ||
1628 | if (write && playlist->control_fd >= 0) | 1641 | if (write && playlist->control_fd >= 0) |
1629 | { | 1642 | { |
@@ -2106,7 +2119,7 @@ bool playlist_check(int steps) | |||
2106 | struct playlist_info* playlist = ¤t_playlist; | 2119 | struct playlist_info* playlist = ¤t_playlist; |
2107 | 2120 | ||
2108 | /* always allow folder navigation */ | 2121 | /* always allow folder navigation */ |
2109 | if (global_settings.next_folder && playlist->dirplay) | 2122 | if (global_settings.next_folder && playlist_allow_dirplay(playlist)) |
2110 | return true; | 2123 | return true; |
2111 | 2124 | ||
2112 | int index = get_next_index(playlist, steps, -1); | 2125 | int index = get_next_index(playlist, steps, -1); |
@@ -2650,19 +2663,39 @@ bool playlist_modified(const struct playlist_info* playlist) | |||
2650 | if (!playlist) | 2663 | if (!playlist) |
2651 | playlist = ¤t_playlist; | 2664 | playlist = ¤t_playlist; |
2652 | 2665 | ||
2653 | return playlist->modified; | 2666 | return !!(playlist->flags & PLAYLIST_FLAG_MODIFIED); |
2654 | } | 2667 | } |
2655 | 2668 | ||
2656 | /* | 2669 | /* |
2657 | * Set the playlist modified status. Useful for clearing the modified status | 2670 | * Set the playlist modified status. Should be called to set the flag after |
2658 | * after dynamically building a playlist. | 2671 | * an explicit user action that modifies the playlist. You should not clear |
2672 | * the modified flag without properly warning the user. | ||
2659 | */ | 2673 | */ |
2660 | void playlist_set_modified(struct playlist_info *playlist, bool modified) | 2674 | void playlist_set_modified(struct playlist_info* playlist, bool modified) |
2661 | { | 2675 | { |
2662 | if (!playlist) | 2676 | if (!playlist) |
2663 | playlist = ¤t_playlist; | 2677 | playlist = ¤t_playlist; |
2664 | 2678 | ||
2665 | playlist->modified = modified; | 2679 | playlist_write_lock(playlist); |
2680 | |||
2681 | if (modified) | ||
2682 | update_playlist_flags_unlocked(playlist, PLAYLIST_FLAG_MODIFIED, 0); | ||
2683 | else | ||
2684 | update_playlist_flags_unlocked(playlist, 0, PLAYLIST_FLAG_MODIFIED); | ||
2685 | |||
2686 | playlist_write_unlock(playlist); | ||
2687 | } | ||
2688 | |||
2689 | /* returns true if directory playback features should be enabled */ | ||
2690 | bool playlist_allow_dirplay(const struct playlist_info *playlist) | ||
2691 | { | ||
2692 | if (!playlist) | ||
2693 | playlist = ¤t_playlist; | ||
2694 | |||
2695 | if (playlist_modified(playlist)) | ||
2696 | return false; | ||
2697 | |||
2698 | return !!(playlist->flags & PLAYLIST_FLAG_DIRPLAY); | ||
2666 | } | 2699 | } |
2667 | 2700 | ||
2668 | /* | 2701 | /* |
@@ -2875,7 +2908,7 @@ int playlist_next(int steps) | |||
2875 | playlist->index = 0; | 2908 | playlist->index = 0; |
2876 | index = 0; | 2909 | index = 0; |
2877 | } | 2910 | } |
2878 | else if (playlist->dirplay && global_settings.next_folder) | 2911 | else if (global_settings.next_folder && playlist_allow_dirplay(playlist)) |
2879 | { | 2912 | { |
2880 | /* we switch playlists here */ | 2913 | /* we switch playlists here */ |
2881 | index = create_and_play_dir(steps, true); | 2914 | index = create_and_play_dir(steps, true); |
@@ -2926,8 +2959,8 @@ out: | |||
2926 | bool playlist_next_dir(int direction) | 2959 | bool playlist_next_dir(int direction) |
2927 | { | 2960 | { |
2928 | /* not to mess up real playlists */ | 2961 | /* not to mess up real playlists */ |
2929 | if(!current_playlist.dirplay) | 2962 | if (!playlist_allow_dirplay(¤t_playlist)) |
2930 | return false; | 2963 | return false; |
2931 | 2964 | ||
2932 | return create_and_play_dir(direction, false) >= 0; | 2965 | return create_and_play_dir(direction, false) >= 0; |
2933 | } | 2966 | } |
@@ -3184,7 +3217,7 @@ int playlist_resume(void) | |||
3184 | } | 3217 | } |
3185 | else if (str2[0] != '\0') | 3218 | else if (str2[0] != '\0') |
3186 | { | 3219 | { |
3187 | playlist->dirplay = true; | 3220 | playlist->flags |= PLAYLIST_FLAG_DIRPLAY; |
3188 | } | 3221 | } |
3189 | 3222 | ||
3190 | /* load the rest of the data */ | 3223 | /* load the rest of the data */ |
@@ -3314,6 +3347,14 @@ int playlist_resume(void) | |||
3314 | } | 3347 | } |
3315 | break; | 3348 | break; |
3316 | } | 3349 | } |
3350 | case PLAYLIST_COMMAND_FLAGS: | ||
3351 | { | ||
3352 | unsigned int setf = atoi(str1); | ||
3353 | unsigned int clearf = atoi(str2); | ||
3354 | |||
3355 | playlist->flags = (playlist->flags & ~clearf) | setf; | ||
3356 | break; | ||
3357 | } | ||
3317 | case PLAYLIST_COMMAND_COMMENT: | 3358 | case PLAYLIST_COMMAND_COMMENT: |
3318 | default: | 3359 | default: |
3319 | break; | 3360 | break; |
@@ -3364,6 +3405,9 @@ int playlist_resume(void) | |||
3364 | case 'C': | 3405 | case 'C': |
3365 | current_command = PLAYLIST_COMMAND_CLEAR; | 3406 | current_command = PLAYLIST_COMMAND_CLEAR; |
3366 | break; | 3407 | break; |
3408 | case 'F': | ||
3409 | current_command = PLAYLIST_COMMAND_FLAGS; | ||
3410 | break; | ||
3367 | case '#': | 3411 | case '#': |
3368 | current_command = PLAYLIST_COMMAND_COMMENT; | 3412 | current_command = PLAYLIST_COMMAND_COMMENT; |
3369 | break; | 3413 | break; |
@@ -3462,7 +3506,6 @@ int playlist_resume(void) | |||
3462 | } | 3506 | } |
3463 | 3507 | ||
3464 | out: | 3508 | out: |
3465 | playlist_set_modified(playlist, false); | ||
3466 | playlist_write_unlock(playlist); | 3509 | playlist_write_unlock(playlist); |
3467 | dc_thread_start(playlist, true); | 3510 | dc_thread_start(playlist, true); |
3468 | 3511 | ||
@@ -3663,7 +3706,6 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3663 | if (fd >= 0) | 3706 | if (fd >= 0) |
3664 | close(fd); | 3707 | close(fd); |
3665 | 3708 | ||
3666 | playlist->modified = false; | ||
3667 | cpu_boost(false); | 3709 | cpu_boost(false); |
3668 | 3710 | ||
3669 | return result; | 3711 | return result; |
@@ -3722,7 +3764,6 @@ int playlist_set_current(struct playlist_info* playlist) | |||
3722 | current_playlist.amount = playlist->amount; | 3764 | current_playlist.amount = playlist->amount; |
3723 | current_playlist.last_insert_pos = playlist->last_insert_pos; | 3765 | current_playlist.last_insert_pos = playlist->last_insert_pos; |
3724 | current_playlist.seed = playlist->seed; | 3766 | current_playlist.seed = playlist->seed; |
3725 | current_playlist.modified = playlist->modified; | ||
3726 | 3767 | ||
3727 | result = 0; | 3768 | result = 0; |
3728 | 3769 | ||