static void xmms_medialib_property_remove (xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *source, const gchar *key, xmms_error_t *error) { const char *sources[2] = { source, NULL }; s4_sourcepref_t *sp; s4_resultset_t *set; const s4_result_t *res; s4_val_t *song_id; sp = s4_sourcepref_create (sources); song_id = s4_val_new_int (entry); set = xmms_medialib_filter (session, "song_id", song_id, S4_COND_PARENT, sp, key, S4_FETCH_DATA); res = s4_resultset_get_result (set, 0, 0); if (res != NULL) { xmms_medialib_session_property_unset (session, entry, key, s4_result_get_val (res), source); } s4_resultset_free (set); s4_sourcepref_unref (sp); s4_val_free (song_id); }
static xmms_fetch_spec_t * xmms_fetch_spec_new_organize (xmmsv_t *fetch, xmms_fetch_info_t *info, s4_sourcepref_t *prefs, xmms_error_t *err) { xmms_fetch_spec_t *spec; xmmsv_dict_iter_t *it; s4_sourcepref_t *sp; xmmsv_t *org_data; gint org_idx; if (!xmmsv_dict_get (fetch, "data", &org_data)) { xmms_error_set (err, XMMS_ERROR_INVAL, "Required field 'data' not set in organize."); return NULL; } if (xmmsv_get_type (org_data) != XMMSV_TYPE_DICT) { xmms_error_set (err, XMMS_ERROR_INVAL, "Field 'data' in organize must be a dict."); return NULL; } sp = normalize_source_preferences (fetch, prefs, err); if (xmms_error_iserror (err)) { return NULL; } spec = g_new0 (xmms_fetch_spec_t, 1); spec->type = FETCH_ORGANIZE; spec->data.organize.count = xmmsv_dict_get_size (org_data); spec->data.organize.keys = g_new0 (const char *, spec->data.organize.count); spec->data.organize.data = g_new0 (xmms_fetch_spec_t *, spec->data.organize.count); org_idx = 0; xmmsv_get_dict_iter (org_data, &it); while (xmmsv_dict_iter_valid (it)) { xmms_fetch_spec_t *orgee; const gchar *str; xmmsv_t *entry; xmmsv_dict_iter_pair (it, &str, &entry); orgee = xmms_fetch_spec_new (entry, info, sp, err); if (xmms_error_iserror (err)) { xmms_fetch_spec_free (spec); spec = NULL; break; } spec->data.organize.keys[org_idx] = str; spec->data.organize.data[org_idx] = orgee; org_idx++; xmmsv_dict_iter_next (it); } xmmsv_dict_iter_explicit_destroy (it); s4_sourcepref_unref (sp); return spec; }
/** * @internal */ static xmms_medialib_entry_t xmms_medialib_get_id (xmms_medialib_session_t *session, const char *url, xmms_error_t *error) { s4_sourcepref_t *sourcepref; s4_resultset_t *set; s4_val_t *value; const s4_result_t *res; gint32 id = 0; sourcepref = xmms_medialib_session_get_source_preferences (session); value = s4_val_new_string (url); set = xmms_medialib_filter (session, XMMS_MEDIALIB_ENTRY_PROPERTY_URL, value, 0, sourcepref, "song_id", S4_FETCH_PARENT); s4_val_free (value); s4_sourcepref_unref (sourcepref); res = s4_resultset_get_result (set, 0, 0); if (res != NULL) { s4_val_get_int (s4_result_get_val (res), &id); } s4_resultset_free (set); return id; }
static xmms_fetch_spec_t * xmms_fetch_spec_new_metadata (xmmsv_t *fetch, xmms_fetch_info_t *info, s4_sourcepref_t *prefs, xmms_error_t *err) { xmms_fetch_spec_t *ret = NULL; s4_sourcepref_t *sp; const gchar *key; xmmsv_t *gets, *fields; gint i, size, aggregate, get; aggregate = normalize_aggregate_function (fetch, err); if (xmms_error_iserror (err)) { return NULL; } fields = normalize_metadata_fields (fetch, err); if (xmms_error_iserror (err)) { return NULL; } gets = normalize_metadata_get (fetch, err); if (xmms_error_iserror (err)) { return NULL; } sp = normalize_source_preferences (fetch, prefs, err); if (xmms_error_iserror (err)) { xmmsv_unref (gets); return NULL; } ret = g_new0 (xmms_fetch_spec_t, 1); ret->type = FETCH_METADATA; ret->data.metadata.aggr_func = aggregate; for (i = 0; i < 4 && xmmsv_list_get_int (gets, i, &get); i++) { ret->data.metadata.get[i] = get; } ret->data.metadata.get_size = i; if (fields != NULL) { size = xmmsv_list_get_size (fields); ret->data.metadata.col_count = size; ret->data.metadata.cols = g_new (gint32, size); for (i = 0; xmmsv_list_get_string (fields, i, &key); i++) { ret->data.metadata.cols[i] = xmms_fetch_info_add_key (info, fetch, key, sp); } } else { /* No fields requested, fetching all available */ ret->data.metadata.col_count = 1; ret->data.metadata.cols = g_new0 (gint32, 1); ret->data.metadata.cols[0] = xmms_fetch_info_add_key (info, fetch, NULL, sp); } s4_sourcepref_unref (sp); xmmsv_unref (gets); return ret; }
gint xmms_medialib_session_property_set (xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *key, const s4_val_t *value, const gchar *source) { const gchar *sources[2] = { source, NULL }; const s4_result_t *res; s4_condition_t *cond; s4_fetchspec_t *spec; s4_resultset_t *set; s4_sourcepref_t *sp; s4_val_t *song_id; gint result; GHashTable *events; song_id = s4_val_new_int (entry); sp = s4_sourcepref_create (sources); cond = s4_cond_new_filter (S4_FILTER_EQUAL, "song_id", song_id, sp, S4_CMP_CASELESS, S4_COND_PARENT); spec = s4_fetchspec_create (); s4_fetchspec_add (spec, key, sp, S4_FETCH_DATA); set = s4_query (session->trans, spec, cond); s4_cond_free (cond); s4_fetchspec_free (spec); res = s4_resultset_get_result (set, 0, 0); if (res != NULL) { const s4_val_t *old_value = s4_result_get_val (res); s4_del (session->trans, "song_id", song_id, key, old_value, source); } s4_resultset_free (set); s4_sourcepref_unref (sp); result = s4_add (session->trans, "song_id", song_id, key, value, source); s4_val_free (song_id); if (strcmp (key, XMMS_MEDIALIB_ENTRY_PROPERTY_URL) == 0) { events = xmms_medialib_session_get_table (&session->added); } else { events = xmms_medialib_session_get_table (&session->updated); } g_hash_table_insert (events, GINT_TO_POINTER (entry), GINT_TO_POINTER (entry)); return result; }
static void xmms_medialib_destroy (xmms_object_t *object) { xmms_medialib_t *mlib = (xmms_medialib_t *) object; XMMS_DBG ("Deactivating medialib object."); s4_sourcepref_unref (mlib->default_sp); s4_close (mlib->s4); xmms_medialib_unregister_ipc_commands (); }
/** * Frees a condition and operands recursively * * @param cond The condition to free */ void s4_cond_free (s4_condition_t *cond) { if (cond->type == S4_COND_COMBINER) { g_ptr_array_free (cond->u.combine.operands, TRUE); free (cond); } else if (cond->type == S4_COND_FILTER) { if (cond->u.filter.free_func != NULL) cond->u.filter.free_func (cond->u.filter.funcdata); if (cond->u.filter.sp != NULL) s4_sourcepref_unref (cond->u.filter.sp); if (!cond->u.filter.const_key && cond->u.filter.key != NULL) free ((char*)cond->u.filter.key); free (cond); } }
/** * Frees a fetchspec * @param spec The fetchspec to free */ void s4_fetchspec_free (s4_fetchspec_t *spec) { int i; for (i = 0; i < spec->array->len; i++) { fetch_data_t *data = &g_array_index (spec->array, fetch_data_t, i); if (data->pref != NULL) { s4_sourcepref_unref (data->pref); } if (data->key != NULL && !data->const_key) { free ((void*)data->key); } } g_array_free (spec->array, TRUE); free (spec); }
/** * Queries the medialib and returns an xmmsv_t with the info requested * * @param coll The collection to find * @param fetch Specifies what to fetch * @return An xmmsv_t with the structure requested in fetch */ xmmsv_t * xmms_medialib_query (xmms_medialib_session_t *session, xmmsv_t *coll, xmmsv_t *fetch, xmms_error_t *err) { s4_sourcepref_t *sourcepref; s4_resultset_t *set; xmmsv_t *ret; xmms_fetch_info_t *info; xmms_fetch_spec_t *spec; xmms_error_reset (err); sourcepref = xmms_medialib_session_get_source_preferences (session); info = xmms_fetch_info_new (sourcepref); spec = xmms_fetch_spec_new (fetch, info, sourcepref, err); s4_sourcepref_unref (sourcepref); if (spec == NULL) { xmms_fetch_spec_free (spec); xmms_fetch_info_free (info); return NULL; } set = xmms_medialib_query_recurs (session, coll, info); ret = xmms_medialib_query_to_xmmsv (set, spec); s4_resultset_free (set); xmms_fetch_spec_free (spec); xmms_fetch_info_free (info); if (ret == NULL) { if (err) { xmms_error_set (err, XMMS_ERROR_NOENT, "Failed to retrieve query " "result. This is probably a bug in xmms2d."); } return NULL; } xmms_medialib_session_track_garbage (session, ret); return ret; }
static void xmms_medialib_client_rehash (xmms_medialib_t *medialib, xmms_medialib_entry_t entry, xmms_error_t *error) { xmms_medialib_session_t *session; do { session = xmms_medialib_session_begin (medialib); if (xmms_medialib_check_id (session, entry)) { xmms_medialib_entry_status_set (session, entry, XMMS_MEDIALIB_ENTRY_STATUS_REHASH); } else if (entry == 0) { s4_sourcepref_t *sourcepref; s4_resultset_t *set; s4_val_t *status; gint i; sourcepref = xmms_medialib_session_get_source_preferences (session); status = s4_val_new_int (XMMS_MEDIALIB_ENTRY_STATUS_OK); set = xmms_medialib_filter (session, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS, status, 0, sourcepref, "song_id", S4_FETCH_PARENT); s4_val_free (status); s4_sourcepref_unref (sourcepref); for (i = 0; i < s4_resultset_get_rowcount (set); i++) { const s4_result_t *res; res = s4_resultset_get_result (set, i, 0); for (; res != NULL; res = s4_result_next (res)) { xmms_medialib_entry_t item; s4_val_get_int (s4_result_get_val (res), &item); xmms_medialib_entry_status_set (session, item, XMMS_MEDIALIB_ENTRY_STATUS_REHASH); } } s4_resultset_free (set); } else { xmms_error_set (error, XMMS_ERROR_NOENT, "No such entry"); } } while (!xmms_medialib_session_commit (session)); }
static s4_resultset_t * not_resolved_set (xmms_medialib_session_t *session) { s4_condition_t *cond1, *cond2, *cond; s4_sourcepref_t *sourcepref; s4_fetchspec_t *spec; s4_resultset_t *ret; s4_val_t *v1, *v2; sourcepref = xmms_medialib_session_get_source_preferences (session); v1 = s4_val_new_int (XMMS_MEDIALIB_ENTRY_STATUS_NEW); v2 = s4_val_new_int (XMMS_MEDIALIB_ENTRY_STATUS_REHASH); cond1 = s4_cond_new_filter (S4_FILTER_EQUAL, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS, v1, sourcepref, S4_CMP_CASELESS, 0); cond2 = s4_cond_new_filter (S4_FILTER_EQUAL, XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS, v2, sourcepref, S4_CMP_CASELESS, 0); cond = s4_cond_new_combiner (S4_COMBINE_OR); s4_cond_add_operand (cond, cond1); s4_cond_add_operand (cond, cond2); spec = s4_fetchspec_create (); s4_fetchspec_add (spec, "song_id", sourcepref, S4_FETCH_PARENT); ret = xmms_medialib_session_query (session, spec, cond); s4_sourcepref_unref (sourcepref); s4_fetchspec_free (spec); s4_cond_free (cond); s4_cond_free (cond1); s4_cond_free (cond2); s4_val_free (v1); s4_val_free (v2); return ret; }
/** * Return a fresh unused medialib id. * * The first id starts at 1 as 0 is considered reserved for other use. */ static int32_t xmms_medialib_get_new_id (xmms_medialib_session_t *session) { gint32 highest = 0; s4_fetchspec_t *fs; s4_condition_t *cond; s4_resultset_t *set; s4_sourcepref_t *sourcepref; sourcepref = xmms_medialib_session_get_source_preferences (session); cond = s4_cond_new_custom_filter (highest_id_filter, &highest, NULL, "song_id", sourcepref, 0, 1, S4_COND_PARENT); s4_sourcepref_unref (sourcepref); fs = s4_fetchspec_create (); set = xmms_medialib_session_query (session, fs, cond); s4_resultset_free (set); s4_cond_free (cond); s4_fetchspec_free (fs); return highest + 1; }
static s4_val_t * xmms_medialib_entry_property_get (xmms_medialib_session_t *session, xmms_medialib_entry_t entry, const gchar *property) { s4_sourcepref_t *sourcepref; const s4_result_t *res; s4_resultset_t *set; s4_val_t *ret = NULL; s4_val_t *song_id; g_return_val_if_fail (property, NULL); song_id = s4_val_new_int (entry); if (strcmp (property, XMMS_MEDIALIB_ENTRY_PROPERTY_ID) == 0) { /* only resolving attributes other than 'id' */ return song_id; } sourcepref = xmms_medialib_session_get_source_preferences (session); set = xmms_medialib_filter (session, "song_id", song_id, S4_COND_PARENT, sourcepref, property, S4_FETCH_DATA); s4_sourcepref_unref (sourcepref); res = s4_resultset_get_result (set, 0, 0); if (res != NULL) { ret = s4_val_copy (s4_result_get_val (res)); } s4_resultset_free (set); s4_val_free (song_id); return ret; }
/** * Decodes a cluster fetch specification from a dictionary. * The 'cluster-by' must be one of 'id', 'position' or 'value'. If set * to 'value', then an additional 'cluster-field' will be used to specify * which meta data attribute to cluster on. */ static xmms_fetch_spec_t * xmms_fetch_spec_new_cluster (xmmsv_t *fetch, xmms_fetch_info_t *info, s4_sourcepref_t *prefs, xmms_error_t *err) { xmmsv_t *cluster_by, *cluster_field, *cluster_data; xmms_fetch_spec_t *data, *spec = NULL; s4_sourcepref_t *sp; const gchar *value = NULL; const gchar *field = NULL; const gchar *fallback = NULL; gint cluster_type; if (!xmmsv_dict_get (fetch, "cluster-by", &cluster_by)) { cluster_by = xmmsv_new_string ("value"); xmmsv_dict_set (fetch, "cluster-by", cluster_by); xmmsv_unref (cluster_by); } if (!xmmsv_dict_entry_get_string (fetch, "cluster-by", &value)) { const gchar *message = "'cluster-by' must be a string."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } xmmsv_get_string (cluster_by, &value); if (!cluster_by_from_string (value, &cluster_type)) { const gchar *message = "'cluster-by' must be 'id', 'position', or 'value'."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } if (cluster_type == CLUSTER_BY_VALUE) { if (!xmmsv_dict_entry_get_string (fetch, "cluster-field", &field)) { const gchar *message = "'cluster-field' must if 'cluster-by' is 'value'."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } } if (!xmmsv_dict_get (fetch, "data", &cluster_data)) { const gchar *message = "Required field 'data' not set in cluster."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } if (xmmsv_dict_entry_get_type (fetch, "cluster-fallback") == XMMSV_TYPE_NONE) { fallback = NULL; } else if (!xmmsv_dict_entry_get_string (fetch, "cluster-fallback", &fallback)) { const gchar *message = "Optional field 'default' must be a string."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } sp = normalize_source_preferences (fetch, prefs, err); if (xmms_error_iserror (err)) { return NULL; } data = xmms_fetch_spec_new (cluster_data, info, sp, err); if (xmms_error_iserror (err)) { s4_sourcepref_unref (sp); return NULL; } spec = g_new0 (xmms_fetch_spec_t, 1); spec->data.cluster.data = data; spec->data.cluster.type = cluster_type; spec->data.cluster.fallback = fallback; switch (spec->data.cluster.type) { case CLUSTER_BY_ID: spec->data.cluster.column = xmms_fetch_info_add_song_id(info, cluster_field); break; case CLUSTER_BY_VALUE: xmmsv_dict_get (fetch, "cluster-field", &cluster_field); spec->data.cluster.column = xmms_fetch_info_add_key (info, cluster_field, field, sp); break; case CLUSTER_BY_POSITION: /* do nothing */ break; default: g_assert_not_reached (); } s4_sourcepref_unref (sp); return spec; }