summaryrefslogtreecommitdiff
path: root/apps/playlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playlist.c')
-rw-r--r--apps/playlist.c123
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
510int 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,
567static void new_playlist_unlocked(struct playlist_info* playlist, 595static 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 == &current_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 == &current_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 = &current_playlist; 2119 struct playlist_info* playlist = &current_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 = &current_playlist; 2664 playlist = &current_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 */
2660void playlist_set_modified(struct playlist_info *playlist, bool modified) 2674void playlist_set_modified(struct playlist_info* playlist, bool modified)
2661{ 2675{
2662 if (!playlist) 2676 if (!playlist)
2663 playlist = &current_playlist; 2677 playlist = &current_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 */
2690bool playlist_allow_dirplay(const struct playlist_info *playlist)
2691{
2692 if (!playlist)
2693 playlist = &current_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:
2926bool playlist_next_dir(int direction) 2959bool 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(&current_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
3464out: 3508out:
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