/** * Consume 'locate' (updatedb) output results and feed into search results. */ static void fa_locate_searcher (fa_search_t *fas) { char buf[PATH_MAX]; char iconpath[PATH_MAX]; regex_t preg; prop_t *entries[2] = {NULL, NULL}; prop_t *nodes[2] = {NULL, NULL}; int t, i; if (fa_create_paths_regex(&preg) == -1) return fa_search_destroy(fas); snprintf(iconpath, sizeof(iconpath), "%s/resources/fileaccess/fs_icon.png", showtime_dataroot()); /* Consume 'locate' results. */ while (1) { char url[PATH_MAX+strlen("file://")]; prop_t *p, *metadata; const char *type; struct fa_stat fs; int ctype; prop_courier_poll(fas->fas_pc); if (!fas->fas_run) break; if (!fgets(buf, sizeof(buf), fas->fas_fp)) break; if (!*buf || *buf == '\n') continue; buf[strlen(buf)-1] = '\0'; /* Ignore dot-files/dirs. */ if (strstr(buf, "/.")) continue; if (regexec(&preg, buf, 0, NULL, 0)) { TRACE(TRACE_DEBUG, "FA", "Searcher: %s: \"%s\" not matching regex: SKIP", fas->fas_query, buf); continue; } /* Probe media type. * * FIXME: We might want to hide matching files under a matching directory, * or the other way around. * E..g: * Metallica/ * 01-Metallica-Song1.mp3 * 02-Metallica-Song1.mp3 * * Should either hide Metallica/ or 01-Metallica-Song1..2.. * But that would require the 'locate' output to be sorted, is it? * Its also problematic where a sub set of the tracks matches * the directory name. Then what should we show?. * * There is also the problem with: * Scrubs S01E01/ * Scrubs_s01e01.avi * Sample/ * Scrubs_s01e01_sample.avi * Which will show as four separate entries, less than optimal. * * For now we provide all matches, directories and files, * matching on the entire path (not just the basename). */ snprintf(url, sizeof(url), "file://%s", buf); if (fa_stat(url, &fs, NULL, 0)) continue; metadata = prop_create_root("metadata"); if(fs.fs_type == CONTENT_DIR) { ctype = CONTENT_DIR; prop_set_string(prop_create(metadata, "title"), basename(buf)); } else { metadata_t *md = fa_probe_metadata(url, NULL, 0); if(md != NULL) { ctype = md->md_contenttype; metadata_destroy(md); } else { ctype = CONTENT_UNKNOWN; } } if (ctype == CONTENT_UNKNOWN) continue; switch(ctype) { case CONTENT_AUDIO: t = 0; break; case CONTENT_VIDEO: case CONTENT_DVD: t = 1; break; default: continue; } if(nodes[t] == NULL) if(search_class_create(fas->fas_nodes, &nodes[t], &entries[t], t ? "Local video files" : "Local audio files", iconpath)) break; prop_add_int(entries[t], 1); if ((type = content2type(ctype)) == NULL) continue; /* Unlikely.. */ p = prop_create_root(NULL); if (prop_set_parent(metadata, p)) prop_destroy(metadata); prop_set_string(prop_create(p, "url"), url); prop_set_string(prop_create(p, "type"), type); if(prop_set_parent(p, nodes[t])) { prop_destroy(p); break; } } for(i = 0; i < 2; i++) { if(nodes[i]) prop_ref_dec(nodes[i]); if(entries[i]) prop_ref_dec(entries[i]); } TRACE(TRACE_DEBUG, "FA", "Searcher: %s: Done", fas->fas_query); fa_search_destroy(fas); regfree(&preg); }
static void file_open_file(prop_t *page, const char *url, fa_stat_t *fs) { char errbuf[200]; metadata_t *md; void *db = metadb_get(); md = metadb_metadata_get(db, url, fs->fs_mtime); metadb_close(db); if(md == NULL) md = fa_probe_metadata(url, errbuf, sizeof(errbuf), NULL); if(md == NULL) { nav_open_errorf(page, _("Unable to open file: %s"), errbuf); return; } if(md->md_redirect != NULL) url = md->md_redirect; prop_t *meta = prop_create_root("metadata"); metadata_to_proptree(md, meta, 0); switch(md->md_contenttype) { case CONTENT_ARCHIVE: case CONTENT_ALBUM: file_open_browse(page, url, fs->fs_mtime); break; case CONTENT_AUDIO: if(!file_open_audio(page, url)) { break; } playqueue_play(url, meta, 0); playqueue_open(page); meta = NULL; break; case CONTENT_VIDEO: case CONTENT_DVD: backend_open_video(page, url, 0); break; case CONTENT_IMAGE: file_open_image(page, meta); meta = NULL; break; case CONTENT_PLUGIN: plugin_open_file(page, url); break; default: nav_open_errorf(page, _("Can't handle content type %d"), md->md_contenttype); break; } prop_destroy(meta); metadata_destroy(md); }