Example #1
0
File: library.c Project: EQ4/musicd
int64_t library_track_add(track_t *track, int64_t directory)
{
  static const char *sql =
    "INSERT INTO tracks (fileid, file, cuefileid, cuefile, track, title, artistid, artist, albumid, album, start, duration, trackindex) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

  sqlite3_stmt *query;

  if (!prepare_query(sql, &query)) {
    return -1;
  }

  track->fileid = library_file(track->file, directory);
  if (track->cuefile) {
    track->cuefileid = library_file(track->cuefile, directory);
  }

  if (track->artist) {
    track->artistid = field_rowid_create("artists", "name", track->artist);
  }
  if (track->album) {
    track->albumid = field_rowid_create("albums", "name", track->album);
  }

  sqlite3_bind_int64(query, 1, track->fileid);
  sqlite3_bind_text(query, 2, track->file, -1, NULL);
  sqlite3_bind_int64(query, 3, track->cuefileid);
  sqlite3_bind_text(query, 4, track->cuefile, -1, NULL);
  sqlite3_bind_int(query, 5, track->track);
  sqlite3_bind_text(query, 6, track->title, -1, NULL);
  sqlite3_bind_int64(query, 7, track->artistid);
  sqlite3_bind_text(query, 8, track->artist, -1, NULL);
  sqlite3_bind_int64(query, 9, track->albumid);
  sqlite3_bind_text(query, 10, track->album, -1, NULL);
  sqlite3_bind_double(query, 11, track->start);
  sqlite3_bind_double(query, 12, track->duration);
  sqlite3_bind_double(query, 13, track->trackindex);

  if (!execute(query)) {
    return -1;
  }

  if (track->album) {
    increment_album_tracks(track->albumid);
  }

  return sqlite3_last_insert_rowid(db_handle());
}
Example #2
0
File: scan.c Project: EQ4/musicd
static int64_t scan_file(const char *path, int64_t directory)
{
  const char *extension;
  int64_t file = 0;
  track_t **tracks;
  int i;

  for (extension = path + strlen(path);
    *(extension) != '.' && extension != path; --extension) { }
  ++extension;
    
  if (!strcasecmp(extension, "cue")) {
    /* CUE sheet */
    musicd_log(LOG_DEBUG, "scan", "cue: %s", path);
    cue_read(path, directory);
  } else if(FreeImage_GetFIFFromFilename(path) != FIF_UNKNOWN) {
    /* Image file */
    if (FreeImage_GetFileType(path, 0) != FIF_UNKNOWN) {
      musicd_log(LOG_DEBUG, "scan", "image: %s", path);
      file = library_file(path, directory);
      library_image_add(file);
    }
  } else {
    tracks = tracks_from_path(path);
    /* Try tracks */
    if (!tracks) {
      return file;
    }
    for (i = 0; tracks[i]; ++i) {
      musicd_log(LOG_DEBUG, "scan", "track: %s", path);
      library_track_add(tracks[i], directory);
      scan_track_added();
      file = library_file(path, 0);
    }
    tracks_free(tracks);
  } 
  return file;
}
Example #3
0
static void import_unix_dlopen(environment_t* r)
{
  /*
   * This is the only library we don't load dynamically from a scheme
   * file.  But we should load it dynamically from HERE via dlopen.
   *
   * Just ignore dlclose for now, the OS will take care of that as well
   * when process exit (we'll deal with resource handling like that later)
   * (TODO)
   */
  static void *lib = dlopen(library_file("libunix-dlopen.so").c_str(),
                       RTLD_LAZY | RTLD_GLOBAL);

  if ( lib == NULL )
    raise(runtime_exception(format("(unix dlopen): %s", dlerror())));

  /*
   * Exported name on left, dlsym name on right
   */
  const char* sym[] = {
    "dlclose",         "proc_dlclose",
    "dlerror",         "proc_dlerror",
    "dlopen",          "proc_dlopen",
    "dlopen-internal", "proc_dlopen_internal",
    "dlopen-self",     "proc_dlopen_self",
    "dlsym",           "proc_dlsym",
    "dlsym-syntax",    "proc_dlsym_syntax",
    NULL};

  for ( const char** s = sym; *s; s += 2 ) {
    void *f = dlsym(lib, *(s+1));

    if ( f == NULL )
      raise(runtime_exception(format("(unix dlopen): %s", dlerror())));

    r->define(*s, reinterpret_cast<lambda_t>(f));
  }
}
Example #4
0
File: cue.c Project: EQ4/musicd
/**
 * @todo FIXME Multiple files in same cue sheet
 * @todo FIXME Rewrite this garbage
 */
bool cue_read(const char *cuepath, int64_t directory)
{
  bool result = true;
  
  FILE *file;
  char *directory_path, *path, *path2;
  
  bool header_read = false;
  
  char album[512], albumartist[512];
  char line[1024], instr[16], string1[512], *ptr;
  
  int64_t track_file;
  
  struct stat status;
  
  //char file[strlen(path) + 1024 + 2], cuefile[strlen(path) + 1024 + 2];
  
  int i;
  
  int index, mins, secs, frames;
  /* Track is stored in prev_track until index of the following track is known.
   * This is mandatory for figuring out the track's length. Last track's
   * length is calculated from file's total length. */
  track_t *prev_track = NULL, *track = NULL, *file_track = NULL;
  
  file = fopen(cuepath, "r");
  if (!file) {
    musicd_perror(LOG_ERROR, "cue", "can't open file %s", cuepath);
    return false;
  }
  
  directory_path = malloc(strlen(cuepath));
  
  /* Extract directory path. */
  for (i = strlen(cuepath) - 1; i > 0 && cuepath[i] != '/'; --i) { }
  strncpy(directory_path, cuepath, i);
  directory_path[i] = '\0';
  
  /* Directory + 256 4-byte UTF-8 characters + '/' + '\0', more than needed. */
  path = malloc(strlen(directory_path) + 1024 + 2);
  path2 = malloc(strlen(directory_path) + 1024 + 2);
  
  album[0] = '\0';
  albumartist[0] = '\0';
  
  /* Check for BOM, seek back if not found. */
  fread(line, 1, 3, file);
  if (line[0] != (char)0xef
   || line[1] != (char)0xbb
   || line[2] != (char)0xbf) {
    fseek(file, 0, SEEK_SET);
  }

  while (read_line(file, line, sizeof(line))) {
    /* Read instruction, up to 15 characters. */
    if (sscanf(line, "%15s", instr) < 1) {
      continue;
    }
    
    
    /* Skip comments. */
    if (!strcmp(instr, "REM")) {
      continue;
    }
    
    ptr = line + strlen(instr) + 1;
    if (ptr[0] == '"') {
      ptr += read_string(ptr, string1) + 1;
    }
    
    if (!strcmp(instr, "PERFORMER")) {
      /*musicd_log(LOG_DEBUG, "cue", "performer: %s", string1);*/
      if (!header_read) {
        strcpy(albumartist, string1);
      } else if (track) {
        free(track->artist);
        track->artist = strcopy(string1);
      }
    } else if (!strcmp(instr, "TITLE")) {
      /*musicd_log(LOG_DEBUG, "cue", "title: %s", string1);*/
      if (!header_read) {
        strcpy(album, string1);
      } else if (track) {
        free(track->title);
        track->title = strcopy(string1);
      }
    } else if (!strcmp(instr, "FILE")) {
      if (file_track) {
        musicd_log(LOG_WARNING, "cue", "multiple FILEs in a single cue sheet"
                                       "(%s) is currently unsupported, sorry",
                                        cuepath);
        break;
      }
      
      header_read = true;
      
      sprintf(path, "%s/%s", directory_path, string1);
      
      if (stat(path, &status)) {
        result = false;
        break;
      }
      
      /* Prioritizing: if there are multiple cue sheets and a cue sheet with
       * same base name as the track file exists, it is used for the track.
       * otherwise, sheet with highest mtime will result to be selected.
       */
      for (i = strlen(path) - 1; i > 0 && path[i] != '.'; --i) { }
      strncpy(path2, path, i);
      strcpy(path2 + i, ".cue");
      
      if (strcmp(path2, cuepath) && stat(path2, &status) == 0) {
        musicd_log(LOG_DEBUG, "cue",
                   "multiple cue sheets for '%s', trying '%s'",
                   path, path2);
        if (cue_read(path2, directory)) {
          break;
        }
      }
      
      file_track = track_from_path(path);
      if (!file_track) {
        break;
      }
      
      track_file = library_file(path, 0);
      if (track_file > 0) {
        /* File already exists, clear associated tracks. */
        library_file_clear(track_file);
      } else {
        track_file = library_file(path, directory);
        if (track_file <= 0) {
          /* Some error... */
          break;
        }
      }
      
      library_file_mtime_set(track_file, status.st_mtime);
      
      musicd_log(LOG_DEBUG, "cue", "audio: %s", path);
      continue;
    }
    
    
    if (!file_track) {
      continue;
    }
    
    if (!strcmp(instr, "TRACK")) {
      sscanf(ptr, "%d %s", &index, string1);
      /*musicd_log(LOG_DEBUG, "cue", "track: %d '%s'", index, string1);*/
      if (track) {
        if (!prev_track) {
          prev_track = track;
        } else {
          prev_track->duration = track->start - prev_track->start;
          library_track_add(prev_track, directory);
          scan_track_added();
          track_free(prev_track);
          prev_track = track;
        }
      }
      
      track = track_new();
      track->cuefile = strcopy(cuepath);
      track->file = strcopy(path);
      track->track = index;
      /* Set artist same as the album artist and replace if track spefific
       * artist is later defined. */
      track->artist = strcopy(albumartist);
      track->album = strcopy(album);
      track->albumartist = strcopy(albumartist);
    }
    
    if (!strcmp(instr, "INDEX")) {
      sscanf(ptr, "%d %d:%d:%d", &index, &mins, &secs, &frames);
      /*musicd_log(LOG_DEBUG, "cue", "index: %d %2.2d:%2.2d.%2.2d", index, mins, secs, frames);*/
      if (index == 1) {
        /* One frame is 1/75 seconds */
        track->start = mins * 60.0 + secs + frames / 75.0;
      }
    }    
    
  }
  
  if (prev_track) {
    prev_track->duration = track->start - prev_track->start;
    library_track_add(prev_track, directory);
    scan_track_added();
    track_free(prev_track);
  }
  if (track) {
    track->duration = file_track->duration - track->start;
    library_track_add(track, directory);
    scan_track_added();
    track_free(track);
  }
  
  track_free(file_track);
  
  fclose(file);
  
  free(directory_path);
  
  free(path);
  free(path2);
  
  return result;
}
Example #5
0
File: scan.c Project: EQ4/musicd
/**
 * Iterates through directory. Subdirectories will be scanned using
 * scan_directory.
 */
static void iterate_directory(const char *dirpath, int dir_id)
{
  struct stat status;
  DIR *dir;
  struct dirent *entry;
  
  int64_t file;
  time_t file_mtime;
  
  char *path;
  
  if (!(dir = opendir(dirpath))) {
    /* Probably no read access - ok, we just omit. */
    musicd_perror(LOG_WARNING, "scan", "could not open directory %s", dirpath);
    return;
  }
  
  /* + 256 4-bit UTF-8 characters + / and \0 
   * More than enough on every platform really in use. */
  path = malloc(strlen(dirpath) + 1024 + 2);
  
  errno = 0;
  while ((entry = readdir(dir))) {
    if (interrupted) {
      break;
    }
    
    /* Omit hidden files and most importantly . and .. */
    if (entry->d_name[0] == '.') {
      goto next;
    }
    
    sprintf(path, "%s/%s", dirpath, entry->d_name);

    if (stat(path, &status)) {
      goto next;
    }
      
    if (S_ISDIR(status.st_mode)) {
      scan_directory(path, dir_id);
      goto next;
    }
    if (!S_ISREG(status.st_mode)) {
      goto next;
    }
    
    file = library_file(path, 0);
    if (file > 0) {
      file_mtime = library_file_mtime(file);
      if (file_mtime == status.st_mtime) {
        goto next;
      }
    }
    
    file = scan_file(path, dir_id);
    if (file) {
      library_file_mtime_set(file, status.st_mtime);
    }

  next:
    errno = 0;
  }
  
  closedir(dir);
  
  if (errno) {
    /* It was possible to open the directory but we can't iterate it anymore?
     * Something's fishy. */
    musicd_perror(LOG_ERROR, "scan", "could not iterate directory %s", path);
  }
  free(path);
}
Example #6
0
static void import_scheme_file(environment_t *r, const char* file)
{
  import(r, exports_import); // add (import)
  import(r, library_file(file));
}
Example #7
0
void load_library_index()
{
  if ( library_map != NULL )
    return;

  std::string filename = library_file(library_index_file);
  environment_t *env = null_environment();
  program_t *p = parse(slurp(open_file(filename)), env);

  cons_t *index = p->root;

  if ( !pairp(index) || !symbolp(caar(index)) )
    invalid_index_format(filename + ": no list with symbols");

  for ( ; !nullp(index); index = cdr(index) ) {
    if ( symbol_name(caar(index)) == "define-library-index" ) {
      if ( library_map != NULL )
        invalid_index_format(filename + ": only one define-library-index allowed");

      if ( !listp(cdar(index)) ) {
        invalid_index_format(filename
          + ": define-library-index is not a list");
      }

      size_t len = length(cdar(index));
      library_map = (library_map_t*) malloc((1+len)*sizeof(library_map_t));

      size_t i = 0;
      for ( cons_t *lib = cdar(index); !nullp(lib); lib = cdr(lib), ++i ) {
        cons_t *name = caar(lib);
        cons_t *file = cadar(lib);

        if ( !listp(name) || !stringp(file) )
          invalid_index_format(filename + ": not list/string pair");

        library_map[i].library_name = strdup(sprint(name).c_str());
        library_map[i].source_file = strdup(file->string);
      }

      // important to signal end of list:
      library_map[i].library_name = NULL;
      library_map[i].source_file = NULL;

      continue;
    } else if ( symbol_name(caar(index)) == "define-repl-imports" ) {
      if ( repl_libraries != NULL )
        invalid_index_format(filename + ": only one define-repl-imports allowed");

      if ( !listp(cdar(index)) ) {
        invalid_index_format(filename
          + ": define-repl-imports is not a list");
      }

      size_t len = length(cdar(index));
      repl_libraries = (const char**) malloc((1+len)*sizeof(char*));

      const char **s = repl_libraries;
      for ( cons_t *lib = cdar(index); !nullp(lib); lib = cdr(lib), ++s ) {
        cons_t *name = car(lib);
        *s = strdup(sprint(name).c_str());
      }
      *s = NULL;
      continue;
    } else
      invalid_index_format(filename + ": unknown label "
        + sprint(caar(index)));
  }
}