int scan_start() { pthread_mutex_lock(&scan_mutex); if (thread_running) { /* Signal the scan thread to restart scanning */ musicd_log(LOG_VERBOSE, "scan", "signaling to restart scan"); restart = 1; interrupted = 1; pthread_mutex_unlock(&scan_mutex); return 0; } pthread_mutex_unlock(&scan_mutex); if (!config_get_value("music-directory")) { musicd_log(LOG_WARNING, "scan", "music-directory not set, no scanning"); return 0; } thread_running = true; if (pthread_create(&scan_thread, NULL, scan_thread_func, NULL)) { musicd_perror(LOG_ERROR, "scan", "could not create thread"); return -1; } pthread_detach(scan_thread); return 0; }
static int purge_oldest_session() { session_t *p, *oldest = NULL; for (p = sessions; p; p = p->next) { if (!oldest || (p->last_request < oldest->last_request && p->refs == 0)) { oldest = p; } } if (!oldest) { /* This block shouldn't execute without a bug related to dereferencing */ musicd_log(LOG_WARNING, "session", "MAX_SESSIONS reached but all sessions in use"); return -1; } musicd_log(LOG_DEBUG, "session", "MAX_SESSIONS reached, purging %s", oldest->id); if (oldest->prev) { oldest->prev->next = oldest->next; } if (oldest->next) { oldest->next->prev = oldest->prev; } if (sessions == oldest) { sessions = oldest->next; } free(oldest->id); free(oldest); --n_sessions; return 0; }
int64_t query_index(query_t *query, int64_t id) { string_t *sql = string_new(); char *where = build_filters(query); sqlite3_stmt *stmt; int64_t result; int64_t index = 1; string_append(sql, query->format->index); string_append(sql, query->format->from); string_append(sql, query->format->join); string_append(sql, where); free(where); if (string_size(query->order) > 0) { string_appendf(sql, " ORDER BY %s", string_string(query->order)); } musicd_log(LOG_DEBUG, "query", "%s", string_string(sql)); if (sqlite3_prepare_v2(db_handle(), string_string(sql), -1, &stmt, NULL) != SQLITE_OK) { musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s", string_string(sql), db_error()); string_free(sql); return -1; } string_free(sql); bind_filters(query, stmt); while (1) { result = sqlite3_step(stmt); if (result == SQLITE_DONE) { result = 0; goto finish; } if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "query", "query_count: sqlite3_step failed"); result = -1; goto finish; } if (sqlite3_column_int64(stmt, 0) == id) { result = index; goto finish; } ++index; } finish: sqlite3_finalize(stmt); return result; }
/** * @todo FIXME More or less ugly value duplication. */ track_t *library_track_by_id(int64_t id) { sqlite3_stmt *stmt; track_t *track; int result; static const char *sql = "SELECT rowid AS id, fileid, file, cuefileid, cuefile, track, title, artistid, artist, albumid, album, start, duration, trackindex FROM tracks WHERE rowid = ?"; if (sqlite3_prepare_v2(db_handle(), sql, -1, &stmt, NULL) != SQLITE_OK) { musicd_log(LOG_ERROR, "library", "can't prepare '%s': %s", sql, db_error()); return NULL; } sqlite3_bind_int(stmt, 1, id); result = sqlite3_step(stmt); if (result == SQLITE_DONE) { return NULL; } else if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "library_track_by_id: sqlite3_step failed"); return NULL; } track = track_new(); track->id = sqlite3_column_int64(stmt, 0); track->fileid = sqlite3_column_int64(stmt, 1); track->file = strcopy((const char *)sqlite3_column_text(stmt, 2)); track->cuefileid = sqlite3_column_int64(stmt, 3); track->cuefile = strcopy((const char *)sqlite3_column_text(stmt, 4)); track->track = sqlite3_column_int(stmt, 5); track->title = strcopy((const char *)sqlite3_column_text(stmt, 6)); track->artistid = sqlite3_column_int64(stmt, 7); track->artist = strcopy((const char *)sqlite3_column_text(stmt, 8)); track->albumid = sqlite3_column_int64(stmt, 9); track->album = strcopy((const char *)sqlite3_column_text(stmt, 10)); track->start = sqlite3_column_double(stmt, 11); track->duration = sqlite3_column_double(stmt, 12); track->trackindex = sqlite3_column_double(stmt, 13); /*musicd_log(LOG_DEBUG, "library", "%" PRId64 " %s %s %d %s %s %s %lf %lf", track->id, track->file, track->cuefile, track->track, track->title, track->artist, track->album, track->start, track->duration);*/ sqlite3_finalize(stmt); return track; }
int query_tracks_next(query_t *query, track_t *track) { int result; sqlite3_stmt *stmt; if (!query) { return -1; } stmt = query->stmt; result = sqlite3_step(stmt); if (result == SQLITE_DONE) { return 1; } else if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "query", "query_tracks_next: sqlite3_step failed"); return -1; } track->id = sqlite3_column_int64(stmt, 0); track->file = (char *)sqlite3_column_text(stmt, 1); track->cuefile = (char *)sqlite3_column_text(stmt, 2); track->track = sqlite3_column_int(stmt, 3); track->title = (char *)sqlite3_column_text(stmt, 4); track->artistid = sqlite3_column_int64(stmt, 5); track->artist = (char *)sqlite3_column_text(stmt, 6); track->albumid = sqlite3_column_int64(stmt, 7); track->album = (char *)sqlite3_column_text(stmt, 8); track->start = sqlite3_column_int(stmt, 9); track->duration = sqlite3_column_int(stmt, 10); return 0; }
static lyrics_t *handle_lyrics_page(const char *page_name) { char *url, *page, *lyrics; lyrics_t *result; url = url_escape_location("http://lyrics.wikia.com", page_name); page = url_fetch(url); if (!page) { musicd_log(LOG_ERROR, "lyrics", "can't fetch lyrics page"); free(url); return NULL; } lyrics = parse_lyrics_page(page); free(page); if (!lyrics) { free(url); return NULL; } result = lyrics_new(); result->lyrics = lyrics; result->provider = strcopy("LyricWiki"); result->source = url; return result; }
void library_iterate_images_by_album (int64_t album, bool (*callback)(library_image_t *file, void *opaque), void *opaque) { static const char *sql = "SELECT images.rowid AS id, files.path AS path, files.directoryid AS directoryid FROM images JOIN files ON images.fileid = files.rowid WHERE images.albumid = ?;"; sqlite3_stmt *query; int result; library_image_t image; bool cb_result = true; if (!prepare_query(sql, &query)) { return; } sqlite3_bind_int64(query, 1, album); image.album = album; while ((result = sqlite3_step(query)) == SQLITE_ROW) { image.id = sqlite3_column_int64(query, 0); image.path = (const char*)sqlite3_column_text(query, 1); image.directory = sqlite3_column_int64(query, 2); cb_result = callback(&image, opaque); if (cb_result == false) { break; } } if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } sqlite3_finalize(query); }
session_t *session_new() { pthread_mutex_lock(&session_mutex); while (n_sessions >= MAX_SESSIONS && !purge_oldest_session()) { } session_t *session = malloc(sizeof(session_t)); memset(session, 0, sizeof(session_t)); session->id = generate_session_id(); session->refs = 1; musicd_log(LOG_DEBUG, "session", "new session %s", session->id); if (sessions) { session->next = sessions; sessions->prev = session; } sessions = session; ++n_sessions; pthread_mutex_unlock(&session_mutex); return session; }
char *library_image_path(int64_t image) { static const char *sql = "SELECT files.path AS path FROM images JOIN files ON images.fileid = files.rowid WHERE images.rowid = ?"; sqlite3_stmt *query; int result; char *path = NULL;; if (!prepare_query(sql, &query)) { return NULL; } sqlite3_bind_int64(query, 1, image); result = sqlite3_step(query); if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } if (result == SQLITE_ROW) { path = strcopy((const char *)sqlite3_column_text(query, 0)); } sqlite3_finalize(query); return path; }
static int mux_next(stream_t *stream) { int result; AVPacket packet; do { result = get_next(stream); if (result <= 0) { return result; } } while (stream->dst_size == 0); av_init_packet(&packet); packet.data = stream->dst_data; packet.size = stream->dst_size; /*packet.pts = stream->pts;*/ /* FIXME: proper PTS/DTS handling */ packet.stream_index = 0; result = av_interleaved_write_frame(stream->dst_ctx, &packet); if (result < 0) { musicd_log(LOG_ERROR, "stream", "av_interleaved_write_frame failed: %s", strerror(AVUNERROR(result))); return -1; } return 1; }
void library_iterate_directories (int64_t parent, bool (*callback)(library_directory_t *directory, void *opaque), void *opaque) { static const char *sql = "SELECT rowid, path, mtime, parentid FROM directories WHERE parentid = ?"; sqlite3_stmt *query; int result; library_directory_t directory; bool cb_result; if (!prepare_query(sql, &query)) { return; } sqlite3_bind_int64(query, 1, parent); while ((result = sqlite3_step(query)) == SQLITE_ROW) { directory.id = sqlite3_column_int64(query, 0); directory.path = (const char*)sqlite3_column_text(query, 1); directory.mtime = sqlite3_column_int64(query, 2); directory.parent = sqlite3_column_int64(query, 3); cb_result = callback(&directory, opaque); if (cb_result == false) { break; } } if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } sqlite3_finalize(query); }
char *library_directory_path(int64_t directory) { static const char *sql = "SELECT path FROM directories WHERE rowid = ?"; sqlite3_stmt *query; int result; char *path = NULL;; if (!prepare_query(sql, &query)) { return NULL; } sqlite3_bind_int64(query, 1, directory); result = sqlite3_step(query); if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } if (result == SQLITE_ROW) { path = strcopy((const char *)sqlite3_column_text(query, 0)); } sqlite3_finalize(query); return path; }
void library_iterate_files_by_directory (int64_t directory, bool (*callback)(library_file_t *file)) { static const char *sql = "SELECT rowid, path, mtime, directoryid FROM files WHERE directoryid = ?"; sqlite3_stmt *query; int result; library_file_t file; bool cb_result = true; if (!prepare_query(sql, &query)) { return; } sqlite3_bind_int64(query, 1, directory); while ((result = sqlite3_step(query)) == SQLITE_ROW) { file.id = sqlite3_column_int64(query, 0); file.path = (const char*)sqlite3_column_text(query, 1); file.mtime = sqlite3_column_int64(query, 2); file.directory = sqlite3_column_int64(query, 3); cb_result = callback(&file); if (cb_result == false) { break; } } if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } sqlite3_finalize(query); }
int query_albums_next(query_t *query, query_album_t *album) { int result; sqlite3_stmt *stmt; if (!query) { return -1; } stmt = query->stmt; result = sqlite3_step(stmt); if (result == SQLITE_DONE) { return 1; } else if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "query", "query_albums_next: sqlite3_step failed"); return -1; } album->albumid = sqlite3_column_int64(stmt, 0); album->album = (char *)sqlite3_column_text(stmt, 1); album->image = sqlite3_column_int64(stmt, 2); album->tracks = sqlite3_column_int64(stmt, 3); return 0; }
int query_artists_next(query_t *query, query_artist_t *artist) { int result; sqlite3_stmt *stmt; if (!query) { return -1; } stmt = query->stmt; result = sqlite3_step(stmt); if (result == SQLITE_DONE) { return 1; } else if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "query", "query_artists_next: sqlite3_step failed"); return -1; } artist->artistid = sqlite3_column_int64(stmt, 0); artist->artist = (char *)sqlite3_column_text(stmt, 1); return 0; }
/** * LyricsWiki fetching */ lyrics_t *lyrics_fetch(const track_t *track) { char *url, *page, *page_name, *artist; char *p; lyrics_t *lyrics; /* Try the exact page */ page_name = stringf("%s:%s", track->artist, track->title); lyrics = handle_lyrics_page(page_name); free(page_name); if (lyrics) { return lyrics; } /* Try finding the exact song from API search and try that exact page */ artist = url_escape(track->artist); url = stringf( "http://lyrics.wikia.com/api.php?func=getArtist&artist=%s&fmt=text", artist); free(artist); page = url_fetch(url); free(url); if (!page) { musicd_log(LOG_ERROR, "lyrics", "can't fetch artist search"); return NULL; } page_name = find_lyrics_page_name(page, track->title); if (page_name) { lyrics = handle_lyrics_page(page_name); free(page_name); if (lyrics) { goto finish; } } /* Try finding the exact artist name and use that like in the first step */ p = strchr(page, ':'); if (p) { *p = '\0'; page_name = stringf("%s:%s", page, track->title); lyrics = handle_lyrics_page(page_name); free(page_name); if (lyrics) { goto finish; } } finish: free(page); return lyrics; }
static bool prepare_query(const char *sql, sqlite3_stmt **query) { if (sqlite3_prepare_v2(db_handle(), sql, -1, query, NULL) != SQLITE_OK) { musicd_log(LOG_ERROR, "library", "can't prepare '%s': %s", sql, db_error()); return false; } return true; }
static void scan() { const char *raw_path = config_to_path("music-directory"); char *path; time_t now; if (raw_path == NULL) { musicd_log(LOG_INFO, "scan", "music-directory not set, not scanning"); return; } path = strcopy(raw_path); /* Strip possible trailing / */ if (path[strlen(path) - 1] == '/') { path[strlen(path) - 1] = '\0'; } last_scan = db_meta_get_int("last-scan"); now = time(NULL); musicd_log(LOG_INFO, "scan", "starting"); signal(SIGINT, scan_signal_handler); scan_directory(path, 0); free(path); signal(SIGINT, NULL); if (interrupted) { musicd_log(LOG_INFO, "scan", "interrupted"); return; } musicd_log(LOG_INFO, "scan", "finished"); db_meta_set_int("last-scan", now); }
static bool execute(sqlite3_stmt *query) { int result = sqlite3_step(query); if (result == SQLITE_DONE || result == SQLITE_ROW) { result = true; } else { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sqlite3_sql(query)); result = false; } sqlite3_finalize(query); return result; }
int64_t query_count(query_t *query) { string_t *sql = string_new(); char *where = build_filters(query); sqlite3_stmt *stmt; int64_t result; string_append(sql, query->format->count); string_append(sql, query->format->from); string_append(sql, query->format->join); string_append(sql, where); free(where); musicd_log(LOG_DEBUG, "query", "%s", string_string(sql)); if (sqlite3_prepare_v2(db_handle(), string_string(sql), -1, &stmt, NULL) != SQLITE_OK) { musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s", string_string(sql), db_error()); string_free(sql); return -1; } string_free(sql); bind_filters(query, stmt); result = sqlite3_step(stmt); if (result != SQLITE_ROW) { musicd_log(LOG_ERROR, "query", "query_count: sqlite3_step failed"); result = -1; goto finish; } result = sqlite3_column_int64(stmt, 0); finish: sqlite3_finalize(stmt); return result; }
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; }
int query_start(query_t *query) { string_t *sql = string_new(); char *where = build_filters(query); sqlite3_stmt *stmt; string_append(sql, query->format->body); string_append(sql, query->format->from); string_append(sql, query->format->join); string_append(sql, where); free(where); if (string_size(query->order) > 0) { string_appendf(sql, " ORDER BY %s", string_string(query->order)); } if (query->limit > 0 || query->offset > 0) { string_appendf(sql, " LIMIT %" PRId64 " OFFSET %" PRId64 "", query->limit, query->offset); } musicd_log(LOG_DEBUG, "query", "%s", string_string(sql)); if (sqlite3_prepare_v2(db_handle(), string_string(sql), -1, &stmt, NULL) != SQLITE_OK) { musicd_log(LOG_ERROR, "query", "can't prepare '%s': %s", string_string(sql), db_error()); string_free(sql); return -1; } string_free(sql); bind_filters(query, stmt); query->stmt = stmt; return 0; }
static int64_t execute_scalar(sqlite3_stmt *query) { int64_t result = sqlite3_step(query); if (result == SQLITE_ROW) { result = sqlite3_column_int(query, 0); } else if (result == SQLITE_DONE) { result = 0; } else { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sqlite3_sql(query)); result = -1; } sqlite3_finalize(query); return result; }
lyrics_t *library_lyrics(int64_t track, time_t *time) { static const char *sql = "SELECT lyrics, provider, source, mtime FROM lyrics WHERE trackid = ?"; sqlite3_stmt *query; int result; lyrics_t *lyrics; if (time) { *time = 0; } if (!prepare_query(sql, &query)) { return NULL; } sqlite3_bind_int64(query, 1, track); result = sqlite3_step(query); if (result != SQLITE_DONE && result != SQLITE_ROW) { musicd_log(LOG_ERROR, "library", "sqlite3_step failed for '%s'", sql); } if (result == SQLITE_ROW) { if (time) { *time = sqlite3_column_int64(query, 3); } if (!sqlite3_column_text(query, 0)) { return NULL; } lyrics = lyrics_new(); lyrics->lyrics = strcopy((const char *)sqlite3_column_text(query, 0)); if (sqlite3_column_text(query, 1)) { lyrics->provider = strcopy((const char *)sqlite3_column_text(query, 1)); } if (sqlite3_column_text(query, 2)) { lyrics->source = strcopy((const char *)sqlite3_column_text(query, 2)); } return lyrics; } return NULL; }
static int read_data(client_t *client) { char buffer[1025]; int n; n = read(client->fd, buffer, 1024); if (n == 0) { musicd_log(LOG_INFO, "client", "%s: exiting", client->address); return -1; } if (n < 0) { if (errno == EWOULDBLOCK) { /* No data available right now, ignore */ return 0; } musicd_perror(LOG_INFO, "client", "%s: can't read", client->address); return -1; } string_nappend(client->inbuf, buffer, n); return n; }
static int read_next(stream_t *stream) { int result; while (1) { av_free_packet(&stream->src_packet); result = av_read_frame(stream->src_ctx, &stream->src_packet); if (result < 0) { if (result == AVERROR_EOF) { /* end of file */ return 0; } musicd_log(LOG_ERROR, "stream", "av_read_frame failed: %s", strerror(AVUNERROR(result))); return 0; } if (stream->src_packet.stream_index != 0) { continue; } break; } if (stream->src_packet.pts * av_q2d(stream->src_ctx->streams[0]->time_base) > stream->track->start + stream->track->duration) { if (stream->track->cuefile) { /* Accurate end of track */ return 0; } else { /* Miscalculated track length */ } } return 1; }
static int encode_next(stream_t *stream) { int result, got_packet; AVFrame *frame = stream->encode_frame; AVPacket *packet = &stream->encode_packet; while (av_audio_fifo_size(stream->src_buf) < stream->encoder->frame_size) { result = decode_next(stream); if (result <= 0) { return result; } } av_audio_fifo_read(stream->src_buf, (void **)frame->extended_data, stream->encoder->frame_size); av_free_packet(packet); result = avcodec_encode_audio2(stream->encoder, packet, frame, &got_packet); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't encode: %s", strerror(AVUNERROR(result))); return -1; } if (!got_packet) { return 1; } stream->dst_data = packet->data; stream->dst_size = packet->size; return 1; }
/** * @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; }
int client_process(client_t *client) { int result; while ((result = read_data(client)) > 0) { } if (result < 0) { return result; } if (!client->protocol) { /* The client has no protocol detected yet */ find_protocol(client); if (!client->protocol) { musicd_log(LOG_ERROR, "client", "%s: unknown protocol, terminating", client->address); return -1; } musicd_log(LOG_DEBUG, "client", "%s: protocol is '%s'", client->address, client->protocol->name); /* Actually open the client to be processed with detected protocol */ client->self = client->protocol->open(client); } if (client->state == CLIENT_STATE_WAIT_TASK) { /* Client was waiting for task to finish and now the task manager signaled * through the pipe. */ client->state = CLIENT_STATE_NORMAL; task_free(client->wait_task); if (client->wait_callback(client->self, client->wait_data) < 0) { return -1; } } /* (Try to) purge the entire outgoing buffer. */ if (string_size(client->outbuf) > 0) { /* There is outgoing data in buffer, try to write */ result = write_data(client); if (result < 0) { return result; } } if (client->state == CLIENT_STATE_DRAIN) { if (string_size(client->outbuf) == 0) { /* Client was draining, and now it is done - terminate */ return -1; } } /* If there was nothing to write but we have unprocessed data, process it. */ if (string_size(client->inbuf) > 0) { result = client->protocol->process(client->self, string_string(client->inbuf), string_size(client->inbuf)); if (result < 0) { return result; } string_remove_front(client->inbuf, result); } else if (client->state == CLIENT_STATE_FEED && string_size(client->outbuf) == 0) { /* There wasn't anything to process, we can push data to the client and the * outgoing buffer is empty. */ result = client->protocol->feed(client->self); if (result < 0) { return result; } } return 0; }
int main(int argc, char* argv[]) { musicd_start_time = time(NULL); config_init(); config_set_hook("log-level", log_level_changed); config_set_hook("log-time-format", log_time_format_changed); config_set("log-level", "debug"); config_set_hook("directory", directory_changed); config_set("config", "~/.musicd.conf"); config_set("directory", "~/.musicd"); config_set("bind", "any"); config_set("port", "6800"); config_set_hook("image-prefix", scan_image_prefix_changed); config_set("image-prefix", "front,cover,jacket"); config_set("server-name", "musicd server"); if (config_load_args(argc, argv)) { musicd_log(LOG_FATAL, "main", "invalid command line arguments"); print_usage(argv[0]); return -1; } if (config_get_value("help")) { print_usage(argv[0]); return 0; } if (config_get_value("version")) { print_version(); return 0; } if (!config_to_bool("no-config") && config_load_file(config_to_path("config"))) { musicd_log(LOG_FATAL, "main", "could not read config file"); return -1; } /* Reload command line arguments - this is because the config file might have * overwritten them, and the command line has the highest priority. */ config_load_args(argc, argv); confirm_directory(); musicd_log(LOG_INFO, "main", "musicd version %s", MUSICD_VERSION_STRING); srand(time(NULL)); av_register_all(); avcodec_register_all(); av_lockmgr_register(&musicd_av_lockmgr); av_log_set_level(AV_LOG_QUIET); if (db_open()) { musicd_log(LOG_FATAL, "library", "can't open database"); return -1; } if (library_open()) { musicd_log(LOG_FATAL, "main", "could not open library"); return -1; } if (cache_open()) { musicd_log(LOG_FATAL, "main", "could not open cache"); return -1; } if (server_start()) { musicd_log(LOG_FATAL, "main", "could not start server"); return -1; } signal(SIGUSR1, start_scan_signal); scan_start(); while (1) { sleep(1); } return 0; }