Patch #5179 by Sebastian Henriksen and Hardeep Sidhu - Playlist catalog

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10232 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Linus Nielsen Feltzing 2006-07-18 13:54:12 +00:00
parent d4100c4cb1
commit da0525f54f
8 changed files with 832 additions and 120 deletions

View File

@ -13,6 +13,7 @@ menu.c
misc.c
onplay.c
playlist.c
playlist_catalog.c
playlist_menu.c
playlist_viewer.c
plugin.c

View File

@ -8571,3 +8571,88 @@
*: "Export modifications"
</voice>
</phrase>
<phrase>
id: LANG_CATALOG
desc: in onplay menu
user:
<source>
*: "Playlist catalog"
</source>
<dest>
*: "Playlist catalog"
</dest>
<voice>
*: "Playlist catalog"
</voice>
</phrase>
<phrase>
id: LANG_CATALOG_ADD_TO
desc: in onplay playlist catalog submenu
user:
<source>
*: "Add to playlist"
</source>
<dest>
*: "Add to playlist"
</dest>
<voice>
*: "Add to playlist"
</voice>
</phrase>
<phrase>
id: LANG_CATALOG_ADD_TO_NEW
desc: in onplay playlist catalog submenu
user:
<source>
*: "Add to new playlist"
</source>
<dest>
*: "Add to new playlist"
</dest>
<voice>
*: "Add to new playlist"
</voice>
</phrase>
<phrase>
id: LANG_CATALOG_VIEW
desc: in onplay playlist catalog submenu
user:
<source>
*: "View catalog"
</source>
<dest>
*: "View catalog"
</dest>
<voice>
*: "View catalog"
</voice>
</phrase>
<phrase>
id: LANG_CATALOG_NO_DIRECTORY
desc: error message when playlist catalog directory doesn't exist
user:
<source>
*: "%s doesn't exist"
</source>
<dest>
*: "%s doesn't exist"
</dest>
<voice>
*: ""
</voice>
</phrase>
<phrase>
id: LANG_CATALOG_NO_PLAYLISTS
desc: error message when no playlists for playlist catalog
user:
<source>
*: "No playlists"
</source>
<dest>
*: "No playlists"
</dest>
<voice>
*: ""
</voice>
</phrase>

View File

@ -63,6 +63,7 @@
#include "eq_menu.h"
#endif
#include "playlist_menu.h"
#include "playlist_catalog.h"
static int context;
static char* selected_file = NULL;
@ -222,6 +223,50 @@ static bool view_playlist(void)
return result;
}
bool cat_add_to_a_playlist(void)
{
return catalog_add_to_a_playlist(selected_file, selected_file_attr,
false);
}
bool cat_add_to_a_new_playlist(void)
{
return catalog_add_to_a_playlist(selected_file, selected_file_attr, true);
}
static bool cat_playlist_options(void)
{
struct menu_item items[3];
int m, i=0, result;
bool ret = false;
if ((audio_status() & AUDIO_STATUS_PLAY && context == CONTEXT_WPS) ||
context == CONTEXT_TREE)
{
if (context == CONTEXT_WPS)
{
items[i].desc = ID2P(LANG_CATALOG_VIEW);
items[i].function = catalog_view_playlists;
i++;
}
items[i].desc = ID2P(LANG_CATALOG_ADD_TO);
items[i].function = cat_add_to_a_playlist;
i++;
items[i].desc = ID2P(LANG_CATALOG_ADD_TO_NEW);
items[i].function = cat_add_to_a_new_playlist;
i++;
}
m = menu_init( items, i, NULL, NULL, NULL, NULL );
result = menu_show(m);
if(result >= 0)
ret = items[result].function();
menu_exit(m);
return ret;
}
/* Sub-menu for playlist options */
static bool playlist_options(void)
{
@ -773,9 +818,9 @@ static int onplay_callback(int key, int menu)
int onplay(char* file, int attr, int from)
{
#if CONFIG_CODEC == SWCODEC
struct menu_item items[13]; /* increase this if you add entries! */
struct menu_item items[14]; /* increase this if you add entries! */
#else
struct menu_item items[11];
struct menu_item items[12];
#endif
int m, i=0, result;
#ifdef HAVE_LCD_COLOR
@ -803,6 +848,9 @@ int onplay(char* file, int attr, int from)
items[i].desc = ID2P(LANG_PLAYLIST);
items[i].function = playlist_options;
i++;
items[i].desc = ID2P(LANG_CATALOG);
items[i].function = cat_playlist_options;
i++;
}
if (context == CONTEXT_WPS)

View File

@ -133,6 +133,13 @@
#define PLAYLIST_DISPLAY_COUNT 10
struct directory_search_context {
struct playlist_info* playlist;
int position;
bool queue;
int count;
};
static bool changing_dir = false;
static struct playlist_info current_playlist;
@ -151,9 +158,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
static int add_track_to_playlist(struct playlist_info* playlist,
const char *filename, int position,
bool queue, int seek_pos);
static int add_directory_to_playlist(struct playlist_info* playlist,
const char *dirname, int *position,
bool queue, int *count, bool recurse);
static int directory_search_callback(char* filename, void* context);
static int remove_track_from_playlist(struct playlist_info* playlist,
int position, bool write);
static int randomise_playlist(struct playlist_info* playlist,
@ -681,121 +686,46 @@ static int add_track_to_playlist(struct playlist_info* playlist,
}
/*
* Insert directory into playlist. May be called recursively.
* Callback for playlist_directory_tracksearch to insert track into
* playlist.
*/
static int add_directory_to_playlist(struct playlist_info* playlist,
const char *dirname, int *position,
bool queue, int *count, bool recurse)
static int directory_search_callback(char* filename, void* context)
{
char buf[MAX_PATH+1];
unsigned char *count_str;
int result = 0;
int num_files = 0;
int i;
struct entry *files;
struct tree_context* tc = tree_get_context();
int dirfilter = *(tc->dirfilter);
struct directory_search_context* c =
(struct directory_search_context*) context;
int insert_pos;
/* use the tree browser dircache to load files */
*(tc->dirfilter) = SHOW_ALL;
insert_pos = add_track_to_playlist(c->playlist, filename, c->position,
c->queue, -1);
if (ft_load(tc, dirname) < 0)
{
gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
*(tc->dirfilter) = dirfilter;
if (insert_pos < 0)
return -1;
}
files = (struct entry*) tc->dircache;
num_files = tc->filesindir;
/* we've overwritten the dircache so tree browser will need to be
reloaded */
reload_directory();
if (queue)
count_str = str(LANG_PLAYLIST_QUEUE_COUNT);
else
count_str = str(LANG_PLAYLIST_INSERT_COUNT);
for (i=0; i<num_files; i++)
(c->count)++;
/* Make sure tracks are inserted in correct order if user requests
INSERT_FIRST */
if (c->position == PLAYLIST_INSERT_FIRST || c->position >= 0)
c->position = insert_pos + 1;
if (((c->count)%PLAYLIST_DISPLAY_COUNT) == 0)
{
/* user abort */
if (button_get(false) == SETTINGS_CANCEL)
{
result = -1;
break;
}
unsigned char* count_str;
if (files[i].attr & ATTR_DIRECTORY)
{
if (recurse)
{
/* recursively add directories */
snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name);
result = add_directory_to_playlist(playlist, buf, position,
queue, count, recurse);
if (result < 0)
break;
if (c->queue)
count_str = str(LANG_PLAYLIST_QUEUE_COUNT);
else
count_str = str(LANG_PLAYLIST_INSERT_COUNT);
/* we now need to reload our current directory */
if(ft_load(tc, dirname) < 0)
{
result = -1;
break;
}
files = (struct entry*) tc->dircache;
num_files = tc->filesindir;
if (!num_files)
{
result = -1;
break;
}
}
else
continue;
}
else if ((files[i].attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
{
int insert_pos;
snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name);
insert_pos = add_track_to_playlist(playlist, buf, *position,
queue, -1);
if (insert_pos < 0)
{
result = -1;
break;
}
(*count)++;
/* Make sure tracks are inserted in correct order if user requests
INSERT_FIRST */
if (*position == PLAYLIST_INSERT_FIRST || *position >= 0)
*position = insert_pos + 1;
if ((*count%PLAYLIST_DISPLAY_COUNT) == 0)
{
display_playlist_count(*count, count_str);
if (*count == PLAYLIST_DISPLAY_COUNT &&
(audio_status() & AUDIO_STATUS_PLAY) &&
playlist->started)
audio_flush_and_reload_tracks();
}
/* let the other threads work */
yield();
}
display_playlist_count(c->count, count_str);
if ((c->count) == PLAYLIST_DISPLAY_COUNT &&
(audio_status() & AUDIO_STATUS_PLAY) &&
c->playlist->started)
audio_flush_and_reload_tracks();
}
/* restore dirfilter */
*(tc->dirfilter) = dirfilter;
return result;
return 0;
}
/*
@ -2811,9 +2741,9 @@ int playlist_insert_directory(struct playlist_info* playlist,
const char *dirname, int position, bool queue,
bool recurse)
{
int count = 0;
int result;
unsigned char *count_str;
struct directory_search_context context;
if (!playlist)
playlist = &current_playlist;
@ -2829,18 +2759,23 @@ int playlist_insert_directory(struct playlist_info* playlist,
else
count_str = str(LANG_PLAYLIST_INSERT_COUNT);
display_playlist_count(count, count_str);
display_playlist_count(0, count_str);
context.playlist = playlist;
context.position = position;
context.queue = queue;
context.count = 0;
cpu_boost(true);
result = add_directory_to_playlist(playlist, dirname, &position, queue,
&count, recurse);
result = playlist_directory_tracksearch(dirname, recurse,
directory_search_callback, &context);
sync_control(playlist, false);
cpu_boost(false);
display_playlist_count(count, count_str);
display_playlist_count(context.count, count_str);
if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
audio_flush_and_reload_tracks();
@ -3403,3 +3338,98 @@ int playlist_save(struct playlist_info* playlist, char *filename)
return result;
}
/*
* Search specified directory for tracks and notify via callback. May be
* called recursively.
*/
int playlist_directory_tracksearch(const char* dirname, bool recurse,
int (*callback)(char*, void*),
void* context)
{
char buf[MAX_PATH+1];
int result = 0;
int num_files = 0;
int i;
struct entry *files;
struct tree_context* tc = tree_get_context();
int old_dirfilter = *(tc->dirfilter);
if (!callback)
return -1;
/* use the tree browser dircache to load files */
*(tc->dirfilter) = SHOW_ALL;
if (ft_load(tc, dirname) < 0)
{
gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
*(tc->dirfilter) = old_dirfilter;
return -1;
}
files = (struct entry*) tc->dircache;
num_files = tc->filesindir;
/* we've overwritten the dircache so tree browser will need to be
reloaded */
reload_directory();
for (i=0; i<num_files; i++)
{
/* user abort */
if (button_get(false) == SETTINGS_CANCEL)
{
result = -1;
break;
}
if (files[i].attr & ATTR_DIRECTORY)
{
if (recurse)
{
/* recursively add directories */
snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name);
result = playlist_directory_tracksearch(buf, recurse,
callback, context);
if (result < 0)
break;
/* we now need to reload our current directory */
if(ft_load(tc, dirname) < 0)
{
result = -1;
break;
}
files = (struct entry*) tc->dircache;
num_files = tc->filesindir;
if (!num_files)
{
result = -1;
break;
}
}
else
continue;
}
else if ((files[i].attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
{
snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name);
if (callback(buf, context) != 0)
{
result = -1;
break;
}
/* let the other threads work */
yield();
}
}
/* restore dirfilter */
*(tc->dirfilter) = old_dirfilter;
return result;
}

View File

@ -158,5 +158,8 @@ char *playlist_get_name(const struct playlist_info* playlist, char *buf,
int playlist_get_track_info(struct playlist_info* playlist, int index,
struct playlist_track_info* info);
int playlist_save(struct playlist_info* playlist, char *filename);
int playlist_directory_tracksearch(const char* dirname, bool recurse,
int (*callback)(char*, void*),
void* context);
#endif /* __PLAYLIST_H__ */

504
apps/playlist_catalog.c Normal file
View File

@ -0,0 +1,504 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Sebastian Henriksen, Hardeep Sidhu
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "action.h"
#include "dir.h"
#include "file.h"
#include "filetree.h"
#include "kernel.h"
#include "keyboard.h"
#include "lang.h"
#include "list.h"
#include "misc.h"
#include "onplay.h"
#include "playlist.h"
#include "settings.h"
#include "splash.h"
#include "sprintf.h"
#include "tree.h"
#include "yesno.h"
#define PLAYLIST_CATALOG_CFG ROCKBOX_DIR "/playlist_catalog.config"
#define PLAYLIST_CATALOG_DEFAULT_DIR "/Playlists"
#define MAX_PLAYLISTS 400
#define PLAYLIST_DISPLAY_COUNT 10
/* Use for recursive directory search */
struct add_track_context {
int fd;
int count;
};
/* keep track of most recently used playlist */
static char most_recent_playlist[MAX_PATH];
/* directory where our playlists our stored (configured in
PLAYLIST_CATALOG_CFG) */
static char playlist_dir[MAX_PATH];
static int playlist_dir_length;
static bool playlist_dir_exists = false;
/* Retrieve playlist directory from config file and verify it exists */
static int initialize_catalog(void)
{
static bool initialized = false;
if (!initialized)
{
int f;
DIR* dir;
bool default_dir = true;
f = open(PLAYLIST_CATALOG_CFG, O_RDONLY);
if (f >= 0)
{
char buf[MAX_PATH+5];
while (read_line(f, buf, sizeof(buf)))
{
char* name;
char* value;
/* directory config is of the format: "dir: /path/to/dir" */
if (settings_parseline(buf, &name, &value) &&
!strncasecmp(name, "dir:", strlen(name)) &&
strlen(value) > 0)
{
strncpy(playlist_dir, value, strlen(value));
default_dir = false;
}
}
close(f);
}
/* fall back to default directory if no or invalid config */
if (default_dir)
strncpy(playlist_dir, PLAYLIST_CATALOG_DEFAULT_DIR,
sizeof(playlist_dir));
playlist_dir_length = strlen(playlist_dir);
dir = opendir(playlist_dir);
if (dir)
{
playlist_dir_exists = true;
closedir(dir);
memset(most_recent_playlist, 0, sizeof(most_recent_playlist));
initialized = true;
}
}
if (!playlist_dir_exists)
{
gui_syncsplash(HZ*2, true, str(LANG_CATALOG_NO_DIRECTORY),
playlist_dir);
return -1;
}
return 0;
}
/* Use the filetree functions to retrieve the list of playlists in the
directory */
static int create_playlist_list(char** playlists, int num_items,
int* num_playlists)
{
int result = -1;
int num_files = 0;
int index = 0;
int i;
bool most_recent = false;
struct entry *files;
struct tree_context* tc = tree_get_context();
int dirfilter = *(tc->dirfilter);
*num_playlists = 0;
/* use the tree browser dircache to load only playlists */
*(tc->dirfilter) = SHOW_PLAYLIST;
if (ft_load(tc, playlist_dir) < 0)
{
gui_syncsplash(HZ*2, true, str(LANG_CATALOG_NO_DIRECTORY),
playlist_dir);
goto exit;
}
files = (struct entry*) tc->dircache;
num_files = tc->filesindir;
/* we've overwritten the dircache so tree browser will need to be
reloaded */
reload_directory();
/* if it exists, most recent playlist will always be index 0 */
if (most_recent_playlist[0] != '\0')
{
index = 1;
most_recent = true;
}
for (i=0; i<num_files && index<num_items; i++)
{
if (files[i].attr & TREE_ATTR_M3U)
{
if (most_recent && !strncmp(files[i].name, most_recent_playlist,
sizeof(most_recent_playlist)))
{
playlists[0] = files[i].name;
most_recent = false;
}
else
{
playlists[index] = files[i].name;
index++;
}
}
}
*num_playlists = index;
/* we couldn't find the most recent playlist, shift all playlists up */
if (most_recent)
{
for (i=0; i<index-1; i++)
playlists[i] = playlists[i+1];
(*num_playlists)--;
most_recent_playlist[0] = '\0';
}
result = 0;
exit:
*(tc->dirfilter) = dirfilter;
return result;
}
/* Callback for gui_synclist */
static char* playlist_callback_name(int selected_item, void* data,
char* buffer)
{
char** playlists = (char**) data;
strncpy(buffer, playlists[selected_item], MAX_PATH);
return buffer;
}
/* Display all playlists in catalog. Selected "playlist" is returned.
If "view" mode is set then we're not adding anything into playlist. */
static int display_playlists(char* playlist, bool view)
{
int result = -1;
int num_playlists = 0;
int lastbutton = BUTTON_NONE;
bool exit = false;
char temp_buf[MAX_PATH];
char* playlists[MAX_PLAYLISTS];
struct gui_synclist playlist_lists;
if (create_playlist_list(playlists, sizeof(playlists),
&num_playlists) != 0)
return -1;
if (num_playlists <= 0)
{
gui_syncsplash(HZ*2, true, str(LANG_CATALOG_NO_PLAYLISTS));
return -1;
}
if (!playlist)
playlist = temp_buf;
gui_synclist_init(&playlist_lists, playlist_callback_name, playlists,
false, 1);
gui_synclist_set_nb_items(&playlist_lists, num_playlists);
gui_synclist_draw(&playlist_lists);
while (!exit)
{
int button = button_get_w_tmo(HZ/2);
char* sel_file;
gui_synclist_do_button(&playlist_lists, button);
sel_file = playlists[gui_synclist_get_sel_pos(&playlist_lists)];
switch (button)
{
case TREE_EXIT:
#ifdef TREE_RC_EXIT
case TREE_RC_EXIT:
#endif
#ifdef TREE_OFF
case TREE_OFF:
#endif
exit = true;
break;
#ifdef TREE_ENTER
case TREE_ENTER:
case TREE_ENTER | BUTTON_REPEAT:
#endif
#ifdef TREE_RC_RUN
case TREE_RC_RUN:
#endif
case TREE_RUN:
#ifdef TREE_RUN_PRE
if (((button == TREE_RUN)
#ifdef TREE_RC_RUN_PRE
|| (button == TREE_RC_RUN))
&& ((lastbutton != TREE_RC_RUN_PRE)
#endif
&& (lastbutton != TREE_RUN_PRE)))
break;
#endif
if (view)
{
/* In view mode, selecting a playlist starts playback */
if (playlist_create(playlist_dir, sel_file) != -1)
{
if (global_settings.playlist_shuffle)
playlist_shuffle(current_tick, -1);
playlist_start(0, 0);
}
}
else
{
/* we found the playlist we want to add to */
snprintf(playlist, MAX_PATH, "%s/%s", playlist_dir,
sel_file);
}
result = 0;
exit = true;
break;
case TREE_CONTEXT:
#ifdef TREE_CONTEXT2
case TREE_CONTEXT2:
#endif
#ifdef TREE_RC_CONTEXT
case TREE_RC_CONTEXT:
#endif
/* context menu only available in view mode */
if (view)
{
snprintf(playlist, MAX_PATH, "%s/%s", playlist_dir,
sel_file);
if (onplay(playlist, TREE_ATTR_M3U,
CONTEXT_TREE) != ONPLAY_OK)
{
result = 0;
exit = true;
}
else
gui_synclist_draw(&playlist_lists);
}
break;
case BUTTON_NONE:
gui_syncstatusbar_draw(&statusbars, false);
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
{
result = -1;
exit = true;
}
break;
}
lastbutton = button;
}
return result;
}
/* display number of tracks inserted into playlists. Used for directory
insert */
static void display_insert_count(int count)
{
gui_syncsplash(0, true, str(LANG_PLAYLIST_INSERT_COUNT), count,
#if CONFIG_KEYPAD == PLAYER_PAD
str(LANG_STOP_ABORT)
#else
str(LANG_OFF_ABORT)
#endif
);
}
/* Add specified track into playlist. Callback from directory insert */
static int add_track_to_playlist(char* filename, void* context)
{
struct add_track_context* c = (struct add_track_context*) context;
if (fdprintf(c->fd, "%s\n", filename) <= 0)
return -1;
(c->count)++;
if (((c->count)%PLAYLIST_DISPLAY_COUNT) == 0)
display_insert_count(c->count);
return 0;
}
/* Add "sel" file into specified "playlist". How to insert depends on type
of file */
static int add_to_playlist(const char* playlist, char* sel, int sel_attr)
{
int fd;
int result = -1;
fd = open(playlist, O_CREAT|O_WRONLY|O_APPEND);
if(fd < 0)
return result;
/* In case we're in the playlist directory */
reload_directory();
if ((sel_attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
{
/* append the selected file */
if (fdprintf(fd, "%s\n", sel) > 0)
result = 0;
}
else if ((sel_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)
{
/* append playlist */
int f, fs, i;
char buf[1024];
if(strcasecmp(playlist, sel) == 0)
goto exit;
f = open(sel, O_RDONLY);
if (f < 0)
goto exit;
fs = filesize(f);
for (i=0; i<fs;)
{
int n;
n = read(f, buf, sizeof(buf));
if (n < 0)
break;
if (write(fd, buf, n) < 0)
break;
i += n;
}
if (i >= fs)
result = 0;
close(f);
}
else if (sel_attr & ATTR_DIRECTORY)
{
/* search directory for tracks and append to playlist */
bool recurse = false;
char *lines[] = {
(char *)str(LANG_RECURSE_DIRECTORY_QUESTION),
sel
};
struct text_message message={lines, 2};
struct add_track_context context;
if (global_settings.recursive_dir_insert != RECURSE_ASK)
recurse = (bool)global_settings.recursive_dir_insert;
else
{
/* Ask if user wants to recurse directory */
recurse = (gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES);
}
context.fd = fd;
context.count = 0;
display_insert_count(0);
result = playlist_directory_tracksearch(sel, recurse,
add_track_to_playlist, &context);
display_insert_count(context.count);
}
exit:
close(fd);
return result;
}
bool catalog_view_playlists(void)
{
if (initialize_catalog() == -1)
return false;
if (display_playlists(NULL, true) == -1)
return false;
return true;
}
bool catalog_add_to_a_playlist(char* sel, int sel_attr, bool new_playlist)
{
char playlist[MAX_PATH];
if (initialize_catalog() == -1)
return false;
if (new_playlist)
{
snprintf(playlist, MAX_PATH, "%s/", playlist_dir);
if (kbd_input(playlist, MAX_PATH))
return false;
if(strlen(playlist) <= 4 ||
strcasecmp(&playlist[strlen(playlist)-4], ".m3u"))
strcat(playlist, ".m3u");
}
else
{
if (display_playlists(playlist, false) == -1)
return false;
}
if (add_to_playlist(playlist, sel, sel_attr) == 0)
{
strncpy(most_recent_playlist, playlist+playlist_dir_length+1,
sizeof(most_recent_playlist));
return true;
}
else
return false;
}

39
apps/playlist_catalog.h Normal file
View File

@ -0,0 +1,39 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Sebastian Henriksen, Hardeep Sidhu
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _PLAYLIST_CATALOG_H_
#define _PLAYLIST_CATALOG_H_
/*
* View list of playlists in catalog.
* ret : true if no error
*/
bool catalog_view_playlists(void);
/*
* Add something to a playlist (new or select from list of playlists in
* catalog).
* sel : the path of the music file, playlist or directory to add
* sel_attr : the attributes that tell what type of file we're adding
* new_playlist : whether we want to create a new playlist or add to an
* existing one.
* ret : true if the file was successfully added
*/
bool catalog_add_to_a_playlist(char* sel, int sel_attr, bool new_playlist);
#endif

View File

@ -28,6 +28,7 @@
#include "playlist_viewer.h"
#include "talk.h"
#include "lang.h"
#include "playlist_catalog.h"
#include "playlist_menu.h"
static bool save_playlist(void)
@ -61,11 +62,12 @@ bool playlist_menu(void)
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_CREATE_PLAYLIST), create_playlist },
{ ID2P(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
{ ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
{ ID2P(LANG_RECURSE_DIRECTORY), recurse_directory },
{ ID2P(LANG_WARN_ERASEDYNPLAYLIST_MENU), warnon_option},
{ ID2P(LANG_CREATE_PLAYLIST), create_playlist },
{ ID2P(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
{ ID2P(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
{ ID2P(LANG_CATALOG), catalog_view_playlists },
{ ID2P(LANG_RECURSE_DIRECTORY), recurse_directory },
{ ID2P(LANG_WARN_ERASEDYNPLAYLIST_MENU), warnon_option },
};
m = menu_init( items, sizeof items / sizeof(struct menu_item), NULL,