rockbox/apps/playlist_catalog.c
William Wilgus 8b7ae89b43 Playlist rework
consolidate some of the playlist create functions
remove extensions from playlist naming (you can still add it if you desire)
switch to strlcpy, strlcpy functions

Change-Id: Ibd62912da4d1f68ed5366baa887d92d4c6b1f933
2019-08-18 10:18:31 -05:00

382 lines
10 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Sebastian Henriksen, Hardeep Sidhu
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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-extra.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 "pathfuncs.h"
#include "onplay.h"
#include "playlist.h"
#include "settings.h"
#include "splash.h"
#include "tree.h"
#include "yesno.h"
#include "filetypes.h"
#include "debug.h"
#include "playlist_catalog.h"
#include "talk.h"
#include "playlist_viewer.h"
#include "bookmark.h"
/* 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 */
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 bool initialized = false;
static int initialize_catalog(void)
{
if (!initialized)
{
bool default_dir = true;
/* directory config is of the format: "dir: /path/to/dir" */
if (global_settings.playlist_catalog_dir[0] &&
strcmp(global_settings.playlist_catalog_dir,
PLAYLIST_CATALOG_DEFAULT_DIR))
{
strcpy(playlist_dir, global_settings.playlist_catalog_dir);
default_dir = false;
}
/* fall back to default directory if no or invalid config */
if (default_dir)
{
strcpy(playlist_dir, PLAYLIST_CATALOG_DEFAULT_DIR);
if (!dir_exists(playlist_dir))
mkdir(playlist_dir);
}
/* remove duplicate leading '/' */
if (playlist_dir[0] == '/' && playlist_dir[1] == '/')
strcpy(playlist_dir, &playlist_dir[1]);
playlist_dir_length = strlen(playlist_dir);
if (dir_exists(playlist_dir))
{
playlist_dir_exists = true;
memset(most_recent_playlist, 0, sizeof(most_recent_playlist));
initialized = true;
}
}
if (!playlist_dir_exists)
{
if (mkdir(playlist_dir) < 0) {
splashf(HZ*2, ID2P(LANG_CATALOG_NO_DIRECTORY), playlist_dir);
return -1;
}
else {
playlist_dir_exists = true;
memset(most_recent_playlist, 0, sizeof(most_recent_playlist));
initialized = true;
}
}
return 0;
}
void catalog_set_directory(const char* directory)
{
if (directory == NULL)
{
global_settings.playlist_catalog_dir[0] = '\0';
}
else
{
strcpy(global_settings.playlist_catalog_dir, directory);
}
initialized = false;
initialize_catalog();
}
const char* catalog_get_directory(void)
{
if (initialize_catalog() == -1)
return "";
return playlist_dir;
}
/* 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)
{
struct browse_context browse;
char selected_playlist[MAX_PATH];
int result = -1;
browse_context_init(&browse, SHOW_M3U,
BROWSE_SELECTONLY|(view? 0: BROWSE_NO_CONTEXT_MENU),
str(LANG_CATALOG), NOICON,
playlist_dir, most_recent_playlist);
browse.buf = selected_playlist;
browse.bufsize = sizeof(selected_playlist);
restart:
browse.flags &= ~BROWSE_SELECTED;
rockbox_browse(&browse);
if (browse.flags & BROWSE_SELECTED)
{
strlcpy(most_recent_playlist, selected_playlist+playlist_dir_length+1,
sizeof(most_recent_playlist));
if (view)
{
if (!bookmark_autoload(selected_playlist))
{
if (playlist_viewer_ex(selected_playlist) == PLAYLIST_VIEWER_CANCEL)
goto restart;
}
result = 0;
}
else
{
result = 0;
strlcpy(playlist, selected_playlist, MAX_PATH);
}
}
return result;
}
/* display number of tracks inserted into playlists. Used for directory
insert */
static void display_insert_count(int count)
{
static long talked_tick = 0;
if(global_settings.talk_menu && count &&
(talked_tick == 0 || TIME_AFTER(current_tick, talked_tick+5*HZ)))
{
talked_tick = current_tick;
talk_number(count, false);
talk_id(LANG_PLAYLIST_INSERT_COUNT, true);
}
splashf(0, str(LANG_PLAYLIST_INSERT_COUNT), count, str(LANG_OFF_ABORT));
}
/* 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, bool new_playlist,
const char* sel, int sel_attr)
{
int fd;
int result = -1;
if (new_playlist)
fd = open_utf8(playlist, O_CREAT|O_WRONLY|O_TRUNC);
else
fd = open(playlist, O_CREAT|O_WRONLY|O_APPEND, 0666);
if(fd < 0)
return result;
/* In case we're in the playlist directory */
reload_directory();
if ((sel_attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO)
{
/* append the selected file */
if (fdprintf(fd, "%s\n", sel) > 0)
result = 0;
}
else if ((sel_attr & FILE_ATTR_MASK) == FILE_ATTR_M3U)
{
/* append playlist */
int f, fs, i;
char buf[1024];
if(strcasecmp(playlist, sel) == 0)
goto exit;
f = open_utf8(sel, O_RDONLY);
if (f < 0)
goto exit;
i = lseek(f, 0, SEEK_CUR);
fs = filesize(f);
while (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;
const char *lines[] = {
ID2P(LANG_RECURSE_DIRECTORY_QUESTION), sel};
const 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;
}
static bool in_cat_viewer = false;
bool catalog_view_playlists(void)
{
bool retval = true;
if (in_cat_viewer)
return false;
if (initialize_catalog() == -1)
return false;
in_cat_viewer = true;
retval = (display_playlists(NULL, true) != -1);
in_cat_viewer = false;
return retval;
}
static bool in_add_to_playlist = false;
bool catalog_add_to_a_playlist(const char* sel, int sel_attr,
bool new_playlist, char *m3u8name)
{
int result;
char playlist[MAX_PATH + 7]; /* room for /.m3u8\0*/
if (in_add_to_playlist)
return false;
if (initialize_catalog() == -1)
return false;
if (new_playlist)
{
size_t len;
if (m3u8name == NULL)
{
const char *name;
/* If sel is empty, root, or playlist directory we use 'all' */
if (!sel || !strcmp(sel, "/") || !strcmp(sel, playlist_dir))
{
if (!sel || !strcmp(sel, PLAYLIST_CATALOG_DEFAULT_DIR))
sel = "/";
name = "/all";
}
else /*If sel is a folder, we prefill the text field with its name*/
name = strrchr(sel, '/');
snprintf(playlist, MAX_PATH + 1, "%s/%s",
playlist_dir,
(name!=NULL && (sel_attr & ATTR_DIRECTORY))?name+1:"");
}
else
strlcpy(playlist, m3u8name, MAX_PATH);
if (kbd_input(playlist, MAX_PATH))
return false;
len = strlen(playlist);
if(len > 4 && !strcasecmp(&playlist[len-4], ".m3u"))
strlcat(playlist, "8", sizeof(playlist));
else if(len <= 5 || strcasecmp(&playlist[len-5], ".m3u8"))
strlcat(playlist, ".m3u8", sizeof(playlist));
}
else
{
in_add_to_playlist = true;
result = display_playlists(playlist, false);
in_add_to_playlist = false;
if (result == -1)
return false;
}
if (add_to_playlist(playlist, new_playlist, sel, sel_attr) == 0)
return true;
else
return false;
}