1/* 2 * Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org> 3 * 4 * Rewritten from mt-daapd code: 5 * Copyright (C) 2003 Ron Pedde (ron@pedde.com) 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22#ifdef HAVE_CONFIG_H 23# include <config.h> 24#endif 25 26#include <stdio.h> 27#include <unistd.h> 28#include <stdlib.h> 29#include <string.h> 30#include <ctype.h> 31#include <limits.h> 32#include <sys/param.h> 33#include <sys/types.h> 34#include <sys/stat.h> 35#include <errno.h> 36 37#include "logger.h" 38#include "db.h" 39#include "filescanner.h" 40#include "misc.h" 41 42 43void 44scan_m3u_playlist(char *file) 45{ 46 FILE *fp; 47 struct playlist_info *pli; 48 struct stat sb; 49 char buf[PATH_MAX]; 50 char rel_entry[PATH_MAX]; 51 char *pl_base; 52 char *entry; 53 char *filename; 54 char *ptr; 55 size_t len; 56 int pl_id; 57 int ret; 58 59 DPRINTF(E_INFO, L_SCAN, "Processing static playlist: %s\n", file); 60 61 ret = stat(file, &sb); 62 if (ret < 0) 63 { 64 DPRINTF(E_LOG, L_SCAN, "Could not stat() '%s': %s\n", file, strerror(errno)); 65 66 return; 67 } 68 69 filename = strrchr(file, '/'); 70 if (!filename) 71 filename = file; 72 else 73 filename++; 74 75 pli = db_pl_fetch_bypath(file); 76 77 if (pli) 78 { 79 DPRINTF(E_DBG, L_SCAN, "Playlist found, updating\n"); 80 81 pl_id = pli->id; 82 83 free_pli(pli, 0); 84 85 db_pl_ping(pl_id); 86 db_pl_clear_items(pl_id); 87 } 88 else 89 pl_id = 0; 90 91 fp = fopen(file, "r"); 92 if (!fp) 93 { 94 DPRINTF(E_WARN, L_SCAN, "Could not open playlist '%s': %s\n", file, strerror(errno)); 95 96 return; 97 } 98 99 if (pl_id == 0) 100 { 101 /* Get only the basename, to be used as the playlist name */ 102 ptr = strrchr(filename, '.'); 103 if (ptr) 104 *ptr = '\0'; 105 106 /* Safe: filename is a subset of file which is <= PATH_MAX already */ 107 strncpy(buf, filename, sizeof(buf)); 108 109 /* Restore the full filename */ 110 if (ptr) 111 *ptr = '.'; 112 113 ret = db_pl_add(buf, file, &pl_id); 114 if (ret < 0) 115 { 116 DPRINTF(E_LOG, L_SCAN, "Error adding m3u playlist '%s'\n", file); 117 118 return; 119 } 120 121 DPRINTF(E_INFO, L_SCAN, "Added playlist as id %d\n", pl_id); 122 } 123 124 ptr = strrchr(file, '/'); 125 if (!ptr) 126 { 127 DPRINTF(E_WARN, L_SCAN, "Could not determine playlist base path\n"); 128 129 return; 130 } 131 132 *ptr = '\0'; 133 pl_base = strdup(file); 134 *ptr = '/'; 135 136 if (!pl_base) 137 { 138 DPRINTF(E_WARN, L_SCAN, "Out of memory\n"); 139 140 return; 141 } 142 143 while (fgets(buf, sizeof(buf), fp) != NULL) 144 { 145 len = strlen(buf); 146 if (buf[len - 1] != '\n') 147 { 148 DPRINTF(E_WARN, L_SCAN, "Entry exceeds PATH_MAX, discarding\n"); 149 150 while (fgets(buf, sizeof(buf), fp) != NULL) 151 { 152 if (buf[strlen(buf) - 1] == '\n') 153 break; 154 } 155 156 continue; 157 } 158 159 if ((buf[0] == ';') || (buf[0] == '#') || (buf[0] == '\n')) 160 continue; 161 162 while (isspace(buf[len - 1])) 163 { 164 len--; 165 buf[len] = '\0'; 166 } 167 168 /* Absolute vs. relative path */ 169 if (buf[0] == '/') 170 { 171 entry = buf; 172 } 173 else 174 { 175 ret = snprintf(rel_entry, sizeof(rel_entry),"%s/%s", pl_base, buf); 176 if ((ret < 0) || (ret >= sizeof(rel_entry))) 177 { 178 DPRINTF(E_WARN, L_SCAN, "Skipping entry, PATH_MAX exceeded\n"); 179 180 continue; 181 } 182 183 entry = rel_entry; 184 } 185 186 filename = m_realpath(entry); 187 if (!filename) 188 { 189 DPRINTF(E_WARN, L_SCAN, "Could not determine real path for '%s': %s\n", entry, strerror(errno)); 190 191 continue; 192 } 193 194 ret = db_pl_add_item_bypath(pl_id, filename); 195 if (ret < 0) 196 DPRINTF(E_WARN, L_SCAN, "Could not add %s to playlist\n", filename); 197 198 free(filename); 199 } 200 201 free(pl_base); 202 203 if (!feof(fp)) 204 { 205 DPRINTF(E_LOG, L_SCAN, "Error reading playlist '%s': %s\n", file, strerror(errno)); 206 207 fclose(fp); 208 return; 209 } 210 211 fclose(fp); 212 213 DPRINTF(E_INFO, L_SCAN, "Done processing playlist\n"); 214} 215