diff options
Diffstat (limited to 'apps/playlist.c')
-rw-r--r-- | apps/playlist.c | 551 |
1 files changed, 289 insertions, 262 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index 652f805aea..b82736bbac 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -111,6 +111,7 @@ | |||
111 | #include "dircache.h" | 111 | #include "dircache.h" |
112 | #endif | 112 | #endif |
113 | #include "logf.h" | 113 | #include "logf.h" |
114 | #include "panic.h" | ||
114 | 115 | ||
115 | #if 0//def ROCKBOX_HAS_LOGDISKF | 116 | #if 0//def ROCKBOX_HAS_LOGDISKF |
116 | #undef DEBUGF | 117 | #undef DEBUGF |
@@ -679,101 +680,6 @@ static void display_playlist_count(int count, const unsigned char *fmt, | |||
679 | } | 680 | } |
680 | 681 | ||
681 | /* | 682 | /* |
682 | * recreate the control file based on current playlist entries | ||
683 | */ | ||
684 | static int recreate_control_unlocked(struct playlist_info* playlist) | ||
685 | { | ||
686 | const char file_suffix[] = "_temp\0"; | ||
687 | char temp_file[MAX_PATH + sizeof(file_suffix)]; | ||
688 | int temp_fd = -1; | ||
689 | int i; | ||
690 | int result = 0; | ||
691 | |||
692 | temp_file[0] = 0; | ||
693 | |||
694 | if(playlist->control_fd >= 0) | ||
695 | { | ||
696 | char* dir = playlist->filename; | ||
697 | char* file = playlist->filename+playlist->dirlen; | ||
698 | char c = playlist->filename[playlist->dirlen-1]; | ||
699 | |||
700 | pl_close_control(playlist); | ||
701 | |||
702 | snprintf(temp_file, sizeof(temp_file), "%s%s", | ||
703 | playlist->control_filename, file_suffix); | ||
704 | |||
705 | if (rename(playlist->control_filename, temp_file) < 0) | ||
706 | return -1; | ||
707 | |||
708 | temp_fd = open(temp_file, O_RDONLY); | ||
709 | if (temp_fd < 0) | ||
710 | return -1; | ||
711 | |||
712 | playlist->control_fd = open(playlist->control_filename, | ||
713 | O_CREAT|O_RDWR|O_TRUNC, 0666); | ||
714 | if (playlist->control_fd < 0) | ||
715 | { | ||
716 | close(temp_fd); | ||
717 | return -1; | ||
718 | } | ||
719 | |||
720 | playlist->filename[playlist->dirlen-1] = '\0'; | ||
721 | |||
722 | update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST, | ||
723 | PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL); | ||
724 | |||
725 | playlist->filename[playlist->dirlen-1] = c; | ||
726 | |||
727 | if (result < 0) | ||
728 | { | ||
729 | close(temp_fd); | ||
730 | return result; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | playlist->seed = 0; | ||
735 | |||
736 | for (i=0; i<playlist->amount; i++) | ||
737 | { | ||
738 | if (playlist->indices[i] & PLAYLIST_INSERT_TYPE_MASK) | ||
739 | { | ||
740 | bool queue = playlist->indices[i] & PLAYLIST_QUEUED; | ||
741 | char inserted_file[MAX_PATH+1]; | ||
742 | |||
743 | lseek(temp_fd, playlist->indices[i] & PLAYLIST_SEEK_MASK, | ||
744 | SEEK_SET); | ||
745 | read_line(temp_fd, inserted_file, sizeof(inserted_file)); | ||
746 | |||
747 | result = fdprintf(playlist->control_fd, "%c:%d:%d:", | ||
748 | queue?'Q':'A', i, playlist->last_insert_pos); | ||
749 | if (result > 0) | ||
750 | { | ||
751 | /* save the position in file where name is written */ | ||
752 | int seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR); | ||
753 | |||
754 | result = fdprintf(playlist->control_fd, "%s\n", | ||
755 | inserted_file); | ||
756 | |||
757 | playlist->indices[i] = | ||
758 | (playlist->indices[i] & ~PLAYLIST_SEEK_MASK) | seek_pos; | ||
759 | } | ||
760 | |||
761 | if (result < 0) | ||
762 | break; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | close(temp_fd); | ||
767 | remove(temp_file); | ||
768 | fsync(playlist->control_fd); | ||
769 | |||
770 | if (result < 0) | ||
771 | return result; | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | /* | ||
777 | * calculate track offsets within a playlist file | 683 | * calculate track offsets within a playlist file |
778 | */ | 684 | */ |
779 | static int add_indices_to_playlist(struct playlist_info* playlist, | 685 | static int add_indices_to_playlist(struct playlist_info* playlist, |
@@ -3560,173 +3466,6 @@ void playlist_resume_track(int start_index, unsigned int crc, | |||
3560 | playlist_start(0, 0, 0); | 3466 | playlist_start(0, 0, 0); |
3561 | } | 3467 | } |
3562 | 3468 | ||
3563 | /* save the current dynamic playlist to specified file. The | ||
3564 | * temp_buffer (if not NULL) is used as a scratchpad when loading indices | ||
3565 | * (slow if not used). */ | ||
3566 | int playlist_save(struct playlist_info* playlist, char *filename, | ||
3567 | void* temp_buffer, size_t temp_buffer_size) | ||
3568 | { | ||
3569 | int fd; | ||
3570 | int i, index; | ||
3571 | int count = 0; | ||
3572 | char path[MAX_PATH+1]; | ||
3573 | char tmp_buf[MAX_PATH+1]; | ||
3574 | int result = 0; | ||
3575 | int *seek_buf; | ||
3576 | bool reparse; | ||
3577 | ssize_t pathlen; | ||
3578 | |||
3579 | ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); | ||
3580 | seek_buf = temp_buffer; | ||
3581 | |||
3582 | /* without temp_buffer, or when it's depleted, and we overwrite the current | ||
3583 | * playlist then the newly saved playlist has to be reparsed. With | ||
3584 | * sufficient temp_buffer the indicies be remembered and added without | ||
3585 | * reparsing */ | ||
3586 | reparse = temp_buffer_size == 0; | ||
3587 | |||
3588 | if (!playlist) | ||
3589 | playlist = ¤t_playlist; | ||
3590 | |||
3591 | if (playlist->amount <= 0) | ||
3592 | return -1; | ||
3593 | |||
3594 | /* use current working directory as base for pathname */ | ||
3595 | pathlen = format_track_path(path, filename, sizeof(path), PATH_ROOTSTR); | ||
3596 | if (pathlen < 0) | ||
3597 | return -1; | ||
3598 | |||
3599 | /* Use temporary pathname and overwrite/rename later */ | ||
3600 | if (strlcat(path, "_temp", sizeof(path)) >= sizeof (path)) | ||
3601 | return -1; | ||
3602 | |||
3603 | if (is_m3u8_name(path)) | ||
3604 | { | ||
3605 | fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); | ||
3606 | } | ||
3607 | else | ||
3608 | { | ||
3609 | /* some applications require a BOM to read the file properly */ | ||
3610 | fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0666); | ||
3611 | } | ||
3612 | |||
3613 | if (fd < 0) | ||
3614 | { | ||
3615 | notify_access_error(); | ||
3616 | return -1; | ||
3617 | } | ||
3618 | |||
3619 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), false); | ||
3620 | |||
3621 | cpu_boost(true); | ||
3622 | |||
3623 | index = playlist->first_index; | ||
3624 | for (i=0; i<playlist->amount; i++) | ||
3625 | { | ||
3626 | /* user abort */ | ||
3627 | if (action_userabort(TIMEOUT_NOBLOCK)) | ||
3628 | { | ||
3629 | result = -1; | ||
3630 | break; | ||
3631 | } | ||
3632 | |||
3633 | /* Don't save queued files */ | ||
3634 | if (!(playlist->indices[index] & PLAYLIST_QUEUED)) | ||
3635 | { | ||
3636 | if (get_track_filename(playlist, index, tmp_buf, sizeof(tmp_buf))) | ||
3637 | { | ||
3638 | result = -1; | ||
3639 | break; | ||
3640 | } | ||
3641 | |||
3642 | if (!reparse) | ||
3643 | seek_buf[count] = filesize(fd); | ||
3644 | |||
3645 | if (fdprintf(fd, "%s\n", tmp_buf) < 0) | ||
3646 | { | ||
3647 | notify_access_error(); | ||
3648 | result = -1; | ||
3649 | break; | ||
3650 | } | ||
3651 | |||
3652 | count++; | ||
3653 | /* when our temp buffer is depleted we have to fall | ||
3654 | * back to reparsing the playlist (slow) */ | ||
3655 | if (count*sizeof(int) >= temp_buffer_size) | ||
3656 | reparse = true; | ||
3657 | |||
3658 | if ((count % PLAYLIST_DISPLAY_COUNT) == 0) | ||
3659 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), | ||
3660 | false); | ||
3661 | |||
3662 | yield(); | ||
3663 | } | ||
3664 | |||
3665 | index = (index+1)%playlist->amount; | ||
3666 | } | ||
3667 | |||
3668 | close(fd); | ||
3669 | fd = -1; | ||
3670 | |||
3671 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); | ||
3672 | |||
3673 | if (result >= 0) | ||
3674 | { | ||
3675 | strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */ | ||
3676 | |||
3677 | dc_thread_stop(playlist); | ||
3678 | playlist_write_lock(playlist); | ||
3679 | |||
3680 | if (!rename(path, tmp_buf)) | ||
3681 | { | ||
3682 | fd = open_utf8(tmp_buf, O_RDONLY); | ||
3683 | if (fd >= 0 && fsamefile(fd, playlist->fd) > 0) | ||
3684 | { | ||
3685 | /* Replace the current playlist with the new one and update | ||
3686 | indices */ | ||
3687 | close(playlist->fd); | ||
3688 | playlist->fd = fd; | ||
3689 | fd = -1; | ||
3690 | |||
3691 | if (!reparse) | ||
3692 | { | ||
3693 | index = playlist->first_index; | ||
3694 | for (i=0, count=0; i<playlist->amount; i++) | ||
3695 | { | ||
3696 | if (!(playlist->indices[index] & PLAYLIST_QUEUED)) | ||
3697 | { | ||
3698 | playlist->indices[index] = seek_buf[count]; | ||
3699 | count++; | ||
3700 | } | ||
3701 | index = (index+1)%playlist->amount; | ||
3702 | } | ||
3703 | } | ||
3704 | else | ||
3705 | { | ||
3706 | NOTEF("reparsing current playlist (slow)"); | ||
3707 | playlist->amount = 0; | ||
3708 | add_indices_to_playlist(playlist, temp_buffer, | ||
3709 | temp_buffer_size); | ||
3710 | } | ||
3711 | |||
3712 | /* we need to recreate control because inserted tracks are | ||
3713 | now part of the playlist and shuffle has been invalidated */ | ||
3714 | result = recreate_control_unlocked(playlist); | ||
3715 | } | ||
3716 | } | ||
3717 | |||
3718 | playlist_write_unlock(playlist); | ||
3719 | dc_thread_start(playlist, true); | ||
3720 | } | ||
3721 | |||
3722 | if (fd >= 0) | ||
3723 | close(fd); | ||
3724 | |||
3725 | cpu_boost(false); | ||
3726 | |||
3727 | return result; | ||
3728 | } | ||
3729 | |||
3730 | /* | 3469 | /* |
3731 | * Set the specified playlist as the current. | 3470 | * Set the specified playlist as the current. |
3732 | * NOTE: You will get undefined behaviour if something is already playing so | 3471 | * NOTE: You will get undefined behaviour if something is already playing so |
@@ -3938,3 +3677,291 @@ int playlist_update_resume_info(const struct mp3entry* id3) | |||
3938 | 3677 | ||
3939 | return 0; | 3678 | return 0; |
3940 | } | 3679 | } |
3680 | |||
3681 | static int pl_get_tempname(const char *filename, char *buf, size_t bufsz) | ||
3682 | { | ||
3683 | if (strlcpy(buf, filename, bufsz) >= bufsz) | ||
3684 | return -1; | ||
3685 | |||
3686 | if (strlcat(buf, "_temp", bufsz) >= bufsz) | ||
3687 | return -1; | ||
3688 | |||
3689 | return 0; | ||
3690 | } | ||
3691 | |||
3692 | /* | ||
3693 | * Save all non-queued tracks to an M3U playlist with the given filename. | ||
3694 | * On success, the playlist is updated to point to the new playlist file. | ||
3695 | * On failure, the playlist filename is unchanged, but playlist indices | ||
3696 | * may be trashed; the current playlist should be reloaded. | ||
3697 | * | ||
3698 | * Returns 0 on success, < 0 on error, and > 0 if user canceled. | ||
3699 | */ | ||
3700 | static int pl_save_playlist(struct playlist_info* playlist, | ||
3701 | const char *filename, | ||
3702 | char *tmpbuf, size_t tmpsize) | ||
3703 | { | ||
3704 | int fd, index, num_saved; | ||
3705 | off_t offset; | ||
3706 | int ret, err; | ||
3707 | |||
3708 | if (pl_get_tempname(filename, tmpbuf, tmpsize)) | ||
3709 | return -1; | ||
3710 | |||
3711 | /* | ||
3712 | * We always save playlists as UTF-8. Add a BOM only when | ||
3713 | * saving to the .m3u file extension. | ||
3714 | */ | ||
3715 | if (is_m3u8_name(filename)) | ||
3716 | fd = open(tmpbuf, O_CREAT|O_WRONLY|O_TRUNC, 0666); | ||
3717 | else | ||
3718 | fd = open_utf8(tmpbuf, O_CREAT|O_WRONLY|O_TRUNC); | ||
3719 | |||
3720 | if (fd < 0) | ||
3721 | return -1; | ||
3722 | |||
3723 | offset = lseek(fd, 0, SEEK_CUR); | ||
3724 | index = playlist->first_index; | ||
3725 | num_saved = 0; | ||
3726 | |||
3727 | display_playlist_count(num_saved, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); | ||
3728 | |||
3729 | for (int i = 0; i < playlist->amount; ++i, ++index) | ||
3730 | { | ||
3731 | if (index == playlist->amount) | ||
3732 | index = 0; | ||
3733 | |||
3734 | /* TODO: Disabled for now, as we can't restore the playlist state yet */ | ||
3735 | if (false && action_userabort(TIMEOUT_NOBLOCK)) | ||
3736 | { | ||
3737 | err = 1; | ||
3738 | goto error; | ||
3739 | } | ||
3740 | |||
3741 | /* Do not save queued files to playlist. */ | ||
3742 | if (playlist->indices[index] & PLAYLIST_QUEUED) | ||
3743 | continue; | ||
3744 | |||
3745 | if (get_track_filename(playlist, index, tmpbuf, tmpsize)) | ||
3746 | { | ||
3747 | err = -2; | ||
3748 | goto error; | ||
3749 | } | ||
3750 | |||
3751 | /* Update seek offset so it points into the new file. */ | ||
3752 | playlist->indices[index] &= ~PLAYLIST_INSERT_TYPE_MASK; | ||
3753 | playlist->indices[index] &= ~PLAYLIST_SEEK_MASK; | ||
3754 | playlist->indices[index] |= offset; | ||
3755 | |||
3756 | ret = fdprintf(fd, "%s\n", tmpbuf); | ||
3757 | if (ret < 0) | ||
3758 | { | ||
3759 | err = -3; | ||
3760 | goto error; | ||
3761 | } | ||
3762 | |||
3763 | offset += ret; | ||
3764 | num_saved++; | ||
3765 | |||
3766 | if ((num_saved % PLAYLIST_DISPLAY_COUNT) == 0) | ||
3767 | display_playlist_count(num_saved, ID2P(LANG_PLAYLIST_SAVE_COUNT), false); | ||
3768 | } | ||
3769 | |||
3770 | display_playlist_count(num_saved, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); | ||
3771 | close(fd); | ||
3772 | pl_close_playlist(playlist); | ||
3773 | |||
3774 | pl_get_tempname(filename, tmpbuf, tmpsize); | ||
3775 | if (rename(tmpbuf, filename)) | ||
3776 | return -4; | ||
3777 | |||
3778 | strcpy(tmpbuf, filename); | ||
3779 | char *dir = tmpbuf; | ||
3780 | char *file = strrchr(tmpbuf, '/') + 1; | ||
3781 | file[-1] = '\0'; | ||
3782 | |||
3783 | update_playlist_filename_unlocked(playlist, dir, file); | ||
3784 | return 0; | ||
3785 | |||
3786 | error: | ||
3787 | close(fd); | ||
3788 | pl_get_tempname(filename, tmpbuf, tmpsize); | ||
3789 | remove(tmpbuf); | ||
3790 | return err; | ||
3791 | } | ||
3792 | |||
3793 | /* | ||
3794 | * Update the control file after saving the playlist under a new name. | ||
3795 | * A new control file is generated, containing the new playlist filename. | ||
3796 | * Queued tracks are copied to the new control file. | ||
3797 | * | ||
3798 | * On success, the new control file replaces the old control file. | ||
3799 | * On failure, indices may be trashed and the playlist should be | ||
3800 | * reloaded. This may not be possible if the playlist was overwritten. | ||
3801 | */ | ||
3802 | static int pl_save_update_control(struct playlist_info* playlist, | ||
3803 | char *tmpbuf, size_t tmpsize) | ||
3804 | { | ||
3805 | int old_fd, index; | ||
3806 | int err; | ||
3807 | char c; | ||
3808 | bool any_queued = false; | ||
3809 | |||
3810 | /* Nothing to update if we don't have any control file */ | ||
3811 | if (!playlist->control_created) | ||
3812 | return 0; | ||
3813 | |||
3814 | if (pl_get_tempname(playlist->control_filename, tmpbuf, tmpsize)) | ||
3815 | return -1; | ||
3816 | |||
3817 | /* Close the existing control file, reopen it as read-only */ | ||
3818 | pl_close_control(playlist); | ||
3819 | old_fd = open(playlist->control_filename, O_RDONLY); | ||
3820 | if (old_fd < 0) | ||
3821 | return -2; | ||
3822 | |||
3823 | /* Create new control file, pointing it at a tempfile */ | ||
3824 | playlist->control_fd = open(tmpbuf, O_CREAT|O_RDWR|O_TRUNC, 0666); | ||
3825 | if (playlist->control_fd < 0) | ||
3826 | { | ||
3827 | close(old_fd); | ||
3828 | return -3; | ||
3829 | } | ||
3830 | |||
3831 | /* Write out playlist filename */ | ||
3832 | c = playlist->filename[playlist->dirlen-1]; | ||
3833 | playlist->filename[playlist->dirlen-1] = '\0'; | ||
3834 | |||
3835 | err = update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST, | ||
3836 | PLAYLIST_CONTROL_FILE_VERSION, -1, | ||
3837 | playlist->filename, | ||
3838 | &playlist->filename[playlist->dirlen], NULL); | ||
3839 | |||
3840 | playlist->filename[playlist->dirlen-1] = c; | ||
3841 | |||
3842 | if (err <= 0) | ||
3843 | return -4; | ||
3844 | |||
3845 | index = playlist->first_index; | ||
3846 | for (int i = 0; i < playlist->amount; ++i, ++index) | ||
3847 | { | ||
3848 | if (index == playlist->amount) | ||
3849 | index = 0; | ||
3850 | |||
3851 | /* We only need to update queued files */ | ||
3852 | if (!(playlist->indices[index] & PLAYLIST_QUEUED)) | ||
3853 | continue; | ||
3854 | |||
3855 | /* Read filename from old control file */ | ||
3856 | lseek(old_fd, playlist->indices[index] & PLAYLIST_SEEK_MASK, SEEK_SET); | ||
3857 | read_line(old_fd, tmpbuf, tmpsize); | ||
3858 | |||
3859 | /* Write it out to the new control file */ | ||
3860 | int seekpos; | ||
3861 | err = update_control_unlocked(playlist, PLAYLIST_COMMAND_QUEUE, | ||
3862 | i, playlist->last_insert_pos, | ||
3863 | tmpbuf, NULL, &seekpos); | ||
3864 | if (err <= 0) | ||
3865 | return -5; | ||
3866 | |||
3867 | /* Update seek offset for the new control file. */ | ||
3868 | playlist->indices[index] &= ~PLAYLIST_SEEK_MASK; | ||
3869 | playlist->indices[index] |= seekpos; | ||
3870 | any_queued = true; | ||
3871 | } | ||
3872 | |||
3873 | /* Preserve modified state */ | ||
3874 | if (playlist_modified(playlist)) | ||
3875 | { | ||
3876 | if (any_queued) | ||
3877 | { | ||
3878 | err = update_control_unlocked(playlist, PLAYLIST_COMMAND_FLAGS, | ||
3879 | PLAYLIST_FLAG_MODIFIED, 0, NULL, NULL, NULL); | ||
3880 | if (err <= 0) | ||
3881 | return -6; | ||
3882 | } | ||
3883 | else | ||
3884 | { | ||
3885 | playlist->flags &= ~PLAYLIST_FLAG_MODIFIED; | ||
3886 | } | ||
3887 | } | ||
3888 | |||
3889 | /* Clear dirplay flag, since we now point at a playlist */ | ||
3890 | playlist->flags &= ~PLAYLIST_FLAG_DIRPLAY; | ||
3891 | |||
3892 | /* Reset shuffle seed */ | ||
3893 | playlist->seed = 0; | ||
3894 | |||
3895 | pl_close_control(playlist); | ||
3896 | close(old_fd); | ||
3897 | remove(playlist->control_filename); | ||
3898 | |||
3899 | /* TODO: Check for errors? The old control file is gone by this point... */ | ||
3900 | pl_get_tempname(playlist->control_filename, tmpbuf, tmpsize); | ||
3901 | rename(tmpbuf, playlist->control_filename); | ||
3902 | |||
3903 | playlist->control_fd = open(playlist->control_filename, O_RDWR); | ||
3904 | playlist->control_created = (playlist->control_fd >= 0); | ||
3905 | return 0; | ||
3906 | } | ||
3907 | |||
3908 | int playlist_save(struct playlist_info* playlist, char *filename) | ||
3909 | { | ||
3910 | char save_path[MAX_PATH+1]; | ||
3911 | char tmpbuf[MAX_PATH+1]; | ||
3912 | ssize_t pathlen; | ||
3913 | int rc = 0; | ||
3914 | |||
3915 | if (!playlist) | ||
3916 | playlist = ¤t_playlist; | ||
3917 | |||
3918 | pathlen = format_track_path(save_path, filename, sizeof(save_path), PATH_ROOTSTR); | ||
3919 | if (pathlen < 0) | ||
3920 | return -1; | ||
3921 | |||
3922 | cpu_boost(true); | ||
3923 | dc_thread_stop(playlist); | ||
3924 | playlist_write_lock(playlist); | ||
3925 | |||
3926 | if (playlist->amount <= 0) | ||
3927 | { | ||
3928 | rc = -1; | ||
3929 | goto error; | ||
3930 | } | ||
3931 | |||
3932 | rc = pl_save_playlist(playlist, save_path, tmpbuf, sizeof(tmpbuf)); | ||
3933 | if (rc < 0) | ||
3934 | { | ||
3935 | // TODO: If we fail here, we just need to reparse the old playlist file | ||
3936 | panicf("Failed to save playlist: %d", rc); | ||
3937 | goto error; | ||
3938 | } | ||
3939 | |||
3940 | /* User cancelled? */ | ||
3941 | if (rc > 0) | ||
3942 | goto error; | ||
3943 | |||
3944 | rc = pl_save_update_control(playlist, tmpbuf, sizeof(tmpbuf)); | ||
3945 | if (rc) | ||
3946 | { | ||
3947 | // TODO: If we fail here, then there are two possibilities depending on | ||
3948 | // whether we overwrote the old playlist file: | ||
3949 | // | ||
3950 | // - if it still exists, we could reparse it + old control file | ||
3951 | // - otherwise, we need to selectively reload the old control file | ||
3952 | // and somehow make use of the new playlist file | ||
3953 | // | ||
3954 | // The latter case poses other issues though, like what happens after we | ||
3955 | // resume, because replaying the old control file over the new playlist | ||
3956 | // won't work properly. We could simply choose to reset the control file, | ||
3957 | // seeing as by this point it only contains transient data (queued tracks). | ||
3958 | panicf("Failed to update control file: %d", rc); | ||
3959 | goto error; | ||
3960 | } | ||
3961 | |||
3962 | error: | ||
3963 | playlist_write_unlock(playlist); | ||
3964 | dc_thread_start(playlist, true); | ||
3965 | cpu_boost(false); | ||
3966 | return rc; | ||
3967 | } | ||