static gboolean queue_track_to_scrobble (gpointer data) { AUDDBG("The playing track is going to be ENQUEUED!\n."); gchar *tab_remover; char *queuepath = g_strconcat(aud_get_path(AUD_PATH_USER_DIR),"/scrobbler.log", NULL); char *artist = tuple_get_str(playing_track, FIELD_ARTIST); char *title = tuple_get_str(playing_track, FIELD_TITLE); char *album = tuple_get_str(playing_track, FIELD_ALBUM); tab_remover = remove_tabs(artist); str_unref(artist); artist = tab_remover; tab_remover = remove_tabs(title); str_unref(title); title = tab_remover; tab_remover = remove_tabs(album); str_unref(album); album = tab_remover; tab_remover = NULL; int number = tuple_get_int(playing_track, FIELD_TRACK_NUMBER); int length = tuple_get_int(playing_track, FIELD_LENGTH) / 1000; //artist, title and timestamp are required for a successful scrobble if ( artist != NULL && strlen(artist) > 0 && title != NULL && strlen(title) > 0) { pthread_mutex_lock(&log_access_mutex); FILE *f = fopen(queuepath, "a"); if (f == NULL) { perror("fopen"); } else { //This isn't exactly the scrobbler.log format because the header //is missing, but we're sticking to it anyway... //See http://www.audioscrobbler.net/wiki/Portable_Player_Logging if (fprintf(f, "%s\t%s\t%s\t%i\t%i\t%s\t%"G_GINT64_FORMAT"\n", artist, (album == NULL ? "" : album), title, number, length, "L", timestamp ) < 0) { perror("fprintf"); } else { pthread_mutex_lock(&communication_mutex); pthread_cond_signal(&communication_signal); pthread_mutex_unlock(&communication_mutex); } fclose(f); } pthread_mutex_unlock(&log_access_mutex); } g_free(queuepath); g_free(artist); g_free(title); g_free(album); cleanup_current_track(); return FALSE; }
static void decode_rva (Tuple * tuple, const guchar * data, gint size) { const gchar * domain; gint channel, adjustment, adjustment_unit, peak, peak_unit; if (memchr (data, 0, size) == NULL) return; domain = (const gchar *) data; TAGDBG ("RVA domain: %s\n", domain); size -= strlen (domain) + 1; data += strlen (domain) + 1; while (size > 0) { if (! decode_rva_block (& data, & size, & channel, & adjustment, & adjustment_unit, & peak, & peak_unit)) break; if (channel != 1) /* specific channel? */ continue; if (tuple_get_value_type (tuple, FIELD_GAIN_GAIN_UNIT, NULL) == TUPLE_INT) adjustment = adjustment * (gint64) tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL) / adjustment_unit; else tuple_associate_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL, adjustment_unit); if (peak_unit) { if (tuple_get_value_type (tuple, FIELD_GAIN_PEAK_UNIT, NULL) == TUPLE_INT) peak = peak * (gint64) tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL) / peak_unit; else tuple_associate_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL, peak_unit); } if (! strcasecmp (domain, "album")) { tuple_associate_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL, adjustment); if (peak_unit) tuple_associate_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL, peak); } else if (! strcasecmp (domain, "track")) { tuple_associate_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL, adjustment); if (peak_unit) tuple_associate_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL, peak); } } }
static int tuple_compare_int (const Tuple * a, const Tuple * b, int field) { if (tuple_get_value_type (a, field, NULL) != TUPLE_INT) return (tuple_get_value_type (b, field, NULL) != TUPLE_INT) ? 0 : -1; if (tuple_get_value_type (b, field, NULL) != TUPLE_INT) return 1; int int_a = tuple_get_int (a, field, NULL); int int_b = tuple_get_int (b, field, NULL); return (int_a < int_b) ? -1 : (int_a > int_b); }
Tuple * xs_probe_for_tuple(const char *filename, VFSFile *fd) { Tuple *tuple; xs_tuneinfo_t *info; int tune = -1; pthread_mutex_lock(&xs_status_mutex); if (!xs_sidplayfp_probe(fd)) { pthread_mutex_unlock(&xs_status_mutex); return NULL; } pthread_mutex_unlock(&xs_status_mutex); /* Get information from URL */ tuple = tuple_new_from_filename (filename); tune = tuple_get_int (tuple, FIELD_SUBSONG_NUM); /* Get tune information from emulation engine */ pthread_mutex_lock(&xs_status_mutex); info = xs_sidplayfp_getinfo (filename); pthread_mutex_unlock(&xs_status_mutex); if (info == NULL) return tuple; xs_get_song_tuple_info(tuple, info, tune); if (xs_cfg.subAutoEnable && info->nsubTunes > 1 && ! tune) xs_fill_subtunes(tuple, info); xs_tuneinfo_free(info); return tuple; }
static void mlp_hook_playback_begin(gpointer hook_data, gpointer user_data) { gint playlist = mlp_playlist_get_playing(); gint pos = mlp_playlist_get_position(playlist); if (mlp_playlist_entry_get_length (playlist, pos, FALSE) < 30) { AUDDBG(" *** not submitting due to entry->length < 30"); return; } gchar * filename = mlp_playlist_entry_get_filename (playlist, pos); if (ishttp (filename)) { AUDDBG(" *** not submitting due to HTTP source"); str_unref (filename); return; } str_unref (filename); sc_idle(m_scrobbler); if (submit_tuple) tuple_unref (submit_tuple); submit_tuple = mlp_playlist_entry_get_tuple (playlist, pos, FALSE); if (! submit_tuple) return; sc_addentry(m_scrobbler, submit_tuple, tuple_get_int(submit_tuple, FIELD_LENGTH, NULL) / 1000); if (!track_timeout) track_timeout = g_timeout_add_seconds(1, sc_timeout, NULL); }
static void insert_vorbis_comment (FLAC__StreamMetadata * meta, const char * name, const Tuple * tuple, int field) { TupleValueType type = tuple_field_get_type (field); if (tuple_get_value_type (tuple, field, NULL) != type) return; char * temp; switch (type) { case TUPLE_INT:; int ival = tuple_get_int (tuple, field, NULL); temp = g_strdup_printf ("%s=%d", name, ival); break; case TUPLE_STRING:; char * sval = tuple_get_str (tuple, field, NULL); temp = g_strdup_printf ("%s=%s", name, sval); str_unref (sval); default: return; } FLAC__StreamMetadata_VorbisComment_Entry comment; comment.length = strlen (temp); comment.entry = (unsigned char *) temp; FLAC__metadata_object_vorbiscomment_insert_comment (meta, meta->data.vorbis_comment.num_comments, comment, TRUE); g_free (temp); }
/* builtin-keyword: ${(empty)?}. returns TRUE if <arg> is empty. */ static gboolean tuple_formatter_expression_empty(Tuple *tuple, const gchar *expression) { gboolean ret = TRUE; const gchar *iter; TupleValueType type = tuple_get_value_type(tuple, -1, expression); if (type == TUPLE_UNKNOWN) return TRUE; if (type == TUPLE_INT) return (tuple_get_int(tuple, -1, expression) == 0); iter = tuple_get_string(tuple, -1, expression); if (!iter) return TRUE; while (ret && *iter != '\0') { if (*iter == ' ') iter++; else ret = FALSE; } return ret; }
static void ready (void *hook_data, void *user_data) { cleanup_current_track(); Tuple *current_track = aud_playlist_entry_get_tuple(aud_playlist_get_playing(), aud_playlist_get_position(aud_playlist_get_playing()), FALSE); int duration_seconds = tuple_get_int(current_track, FIELD_LENGTH) / 1000; if (duration_seconds <= 30) { tuple_unref(current_track); return; } pthread_mutex_lock(&communication_mutex); now_playing_track = tuple_ref(current_track); now_playing_requested = TRUE; pthread_cond_signal(&communication_signal); pthread_mutex_unlock(&communication_mutex); time_until_scrobble = (((gint64)duration_seconds)*G_USEC_PER_SEC) / 2; if (time_until_scrobble > 4*60*G_USEC_PER_SEC) { time_until_scrobble = 4*60*G_USEC_PER_SEC; } timestamp = g_get_real_time() / G_USEC_PER_SEC; play_started_at = g_get_monotonic_time(); playing_track = current_track; queue_function_ID = g_timeout_add_seconds(time_until_scrobble / G_USEC_PER_SEC, (GSourceFunc) queue_track_to_scrobble, NULL); }
static bool_t audpl_save (const char * path, VFSFile * file, const char * title, Index * filenames, Index * tuples) { if (! write_key (file, "title", title)) return FALSE; int count = index_count (filenames); for (int i = 0; i < count; i ++) { if (! write_key (file, "uri", index_get (filenames, i))) return FALSE; const Tuple * tuple = tuples ? index_get (tuples, i) : NULL; if (tuple) { int keys = 0; for (int f = 0; f < TUPLE_FIELDS; f ++) { if (f == FIELD_FILE_PATH || f == FIELD_FILE_NAME || f == FIELD_FILE_EXT) continue; TupleValueType type = tuple_get_value_type (tuple, f, NULL); if (type == TUPLE_STRING) { char * str = tuple_get_str (tuple, f, NULL); if (! write_key (file, tuple_field_get_name (f), str)) { str_unref (str); return FALSE; } str_unref (str); keys ++; } else if (type == TUPLE_INT) { char buf[32]; snprintf (buf, sizeof buf, "%d", tuple_get_int (tuple, f, NULL)); if (! write_key (file, tuple_field_get_name (f), buf)) return FALSE; keys ++; } } /* distinguish between an empty tuple and no tuple at all */ if (! keys && ! write_key (file, "empty", "1")) return FALSE; } } return TRUE; }
static void set_int_from_tuple (GValue * value, const Tuple * tuple, gint field) { gint i = tuple ? tuple_get_int (tuple, field, NULL) : 0; if (i > 0) g_value_take_string (value, g_strdup_printf ("%d", i)); else g_value_set_string (value, ""); }
static void insert_int_tuple_field_to_dictionary (const Tuple * tuple, int fieldn, GHashTable * dict, const char * key) { int val = tuple_get_int (tuple, fieldn); if (val > 0) g_hash_table_insert (dict, str_get (key), int_to_str (val)); else g_hash_table_remove (dict, key); }
LIBMTP_track_t *track_metadata(Tuple *from_tuple) { LIBMTP_track_t *tr; gchar *filename, *uri_path; VFSFile *f; uint64_t filesize; struct stat sb; uri_path = strdup_tuple_filename (from_tuple); gchar *tmp = g_strescape(uri_path,NULL); filename=g_filename_from_uri(tmp,NULL,NULL); g_free(tmp); /* dealing the stream upload (invalidating)*/ if(filename) { f = vfs_fopen(uri_path,"r"); g_free(uri_path); if(vfs_is_streaming(f)) { vfs_fclose(f); g_free(filename); return NULL; } } else { g_print("Warning! the filename is NULL, exiting"); return NULL; } if ( stat(filename, &sb) == -1 ) { #if DEBUG g_print("ERROR! encountered while stat()'ing \"%s\"\n",filename); #endif g_free(filename); return NULL; } filesize = (uint64_t) sb.st_size; /* track metadata*/ tr = LIBMTP_new_track_t(); tr->title = strdup_tuple_field (from_tuple, FIELD_TITLE); tr->artist = strdup_tuple_field (from_tuple, FIELD_ARTIST); tr->album = strdup_tuple_field (from_tuple, FIELD_ALBUM); tr->filesize = filesize; tr->filename = strdup_tuple_field (from_tuple, FIELD_FILE_NAME); tr->duration = (uint32_t)tuple_get_int(from_tuple, FIELD_LENGTH, NULL); tr->filetype = find_filetype (filename); tr->genre = strdup_tuple_field (from_tuple, FIELD_GENRE); tr->date = strdup_tuple_field (from_tuple, FIELD_YEAR); g_free(filename); return tr; }
/* clears gain info if tuple == NULL */ static void read_gain_from_tuple (const Tuple * tuple) { memset (& gain_from_playlist, 0, sizeof gain_from_playlist); if (tuple == NULL) return; int album_gain = tuple_get_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL); int album_peak = tuple_get_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL); int track_gain = tuple_get_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL); int track_peak = tuple_get_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL); int gain_unit = tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL); int peak_unit = tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL); if (gain_unit) { gain_from_playlist.album_gain = album_gain / (float) gain_unit; gain_from_playlist.track_gain = track_gain / (float) gain_unit; } if (peak_unit) { gain_from_playlist.album_peak = album_peak / (float) peak_unit; gain_from_playlist.track_peak = track_peak / (float) peak_unit; } }
static void set_gain_info(Tuple *tuple, int field, int unit_field, const char *text) { int value, unit; parse_gain_text(text, &value, &unit); if (tuple_get_value_type(tuple, unit_field, NULL) == TUPLE_INT) value = value * (int64_t) tuple_get_int(tuple, unit_field, NULL) / unit; else tuple_set_int(tuple, unit_field, NULL, unit); tuple_set_int(tuple, field, NULL, value); }
static void add_frameFromTupleInt (const Tuple * tuple, int field, int id3_field, GHashTable * dict) { if (tuple_get_value_type (tuple, field) != TUPLE_INT) { remove_frame (id3_field, dict); return; } char scratch[16]; str_itoa (tuple_get_int (tuple, field), scratch, sizeof scratch); add_text_frame (id3_field, scratch, dict); }
static void add_frameFromTupleInt (const Tuple * tuple, gint field, gint id3_field, mowgli_dictionary_t * dict) { if (tuple_get_value_type (tuple, field, NULL) != TUPLE_INT) { remove_frame (id3_field, dict); return; } gchar scratch[16]; snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, field, NULL)); add_text_frame (id3_field, scratch, dict); }
static void infowin_show (gint list, gint entry, const gchar * filename, const Tuple * tuple, PluginHandle * decoder, gboolean updating_enabled) { gchar * tmp; if (infowin == NULL) create_infowin (); else clear_infowin (); current_file = g_strdup (filename); current_decoder = decoder; can_write = updating_enabled; set_entry_str_from_field (entry_title, tuple, FIELD_TITLE, updating_enabled); set_entry_str_from_field (entry_artist, tuple, FIELD_ARTIST, updating_enabled); set_entry_str_from_field (entry_album, tuple, FIELD_ALBUM, updating_enabled); set_entry_str_from_field (entry_comment, tuple, FIELD_COMMENT, updating_enabled); set_entry_str_from_field (gtk_bin_get_child ((GtkBin *) entry_genre), tuple, FIELD_GENRE, updating_enabled); tmp = uri_to_display (filename); gtk_label_set_text ((GtkLabel *) location_text, tmp); g_free (tmp); set_entry_int_from_field (entry_year, tuple, FIELD_YEAR, updating_enabled); set_entry_int_from_field (entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled); infowin_label_set_text (label_format_name, tuple_get_string (tuple, FIELD_CODEC, NULL)); infowin_label_set_text (label_quality, tuple_get_string (tuple, FIELD_QUALITY, NULL)); if (tuple_get_value_type (tuple, FIELD_BITRATE, NULL) == TUPLE_INT) { tmp = g_strdup_printf (_("%d kb/s"), tuple_get_int (tuple, FIELD_BITRATE, NULL)); infowin_label_set_text (label_bitrate, tmp); g_free (tmp); } else infowin_label_set_text (label_bitrate, NULL); infowin_entry_set_image (image_artwork, list, entry); gtk_window_present ((GtkWindow *) infowin); }
static void set_entry_int_from_field (GtkWidget * widget, const Tuple * tuple, int fieldn, bool_t editable) { char scratch[32]; if (tuple_get_value_type (tuple, fieldn, NULL) == TUPLE_INT) snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, fieldn, NULL)); else scratch[0] = 0; gtk_entry_set_text ((GtkEntry *) widget, scratch); gtk_editable_set_editable ((GtkEditable *) widget, editable); }
static void insert_int_tuple_to_vc (FLAC__StreamMetadata * vc_block, const Tuple * tuple, int tuple_name, char * field_name) { FLAC__StreamMetadata_VorbisComment_Entry entry; int val = tuple_get_int(tuple, tuple_name, NULL); if (val <= 0) return; SPRINTF (str, "%s=%d", field_name, val); entry.entry = (FLAC__byte *) str; entry.length = strlen(str); FLAC__metadata_object_vorbiscomment_insert_comment(vc_block, vc_block->data.vorbis_comment.num_comments, entry, true); }
/* processes an expression and optional argument pair. */ gchar * tuple_formatter_process_expr(Tuple *tuple, const gchar *expression, const gchar *argument) { TupleFormatterExpression *expr = NULL; GList *iter; g_return_val_if_fail(tuple != NULL, NULL); g_return_val_if_fail(expression != NULL, NULL); for (iter = tuple_formatter_expr_list; iter != NULL; iter = iter->next) { TupleFormatterExpression *tmp = (TupleFormatterExpression *) iter->data; if (g_str_has_prefix(expression, tmp->name) == TRUE) { expr = tmp; expression += strlen(tmp->name); } } /* ${artist} */ if (expr == NULL && argument == NULL) { TupleValueType type = tuple_get_value_type(tuple, -1, expression); switch(type) { case TUPLE_STRING: return g_strdup(tuple_get_string(tuple, -1, expression)); break; case TUPLE_INT: return g_strdup_printf("%d", tuple_get_int(tuple, -1, expression)); break; case TUPLE_UNKNOWN: default: return NULL; } } else if (expr != NULL) { if (expr->func(tuple, expression) == TRUE && argument != NULL) return tuple_formatter_process_construct(tuple, argument); } return NULL; }
static GValue *tuple_value_to_gvalue(const Tuple * tuple, const gchar * key) { GValue *val; TupleValueType type = tuple_get_value_type((Tuple *) tuple, -1, key); if (type == TUPLE_STRING) { val = g_new0(GValue, 1); g_value_init(val, G_TYPE_STRING); g_value_take_string(val, g_strdup(tuple_get_string((Tuple *) tuple, -1, key))); return val; } else if (type == TUPLE_INT) { val = g_new0(GValue, 1); g_value_init(val, G_TYPE_INT); g_value_set_int(val, tuple_get_int((Tuple *) tuple, -1, key)); return val; } return NULL; }
static char * strdup_tuple_field (const Tuple * tuple, int field) { char * sval, * dup; int ival; switch (tuple_get_value_type (tuple, field, NULL)) { case TUPLE_INT: ival = tuple_get_int (tuple, field, NULL); dup = g_strdup_printf ("%d", ival); break; case TUPLE_STRING: sval = tuple_get_str (tuple, field, NULL); dup = g_strdup (sval); str_unref (sval); break; default: dup = NULL; break; } return dup; }
Tuple * xs_probe_for_tuple(const gchar *filename, xs_file_t *fd) { Tuple *tuple; xs_tuneinfo_t *info; gint tune = -1; if (xs_status.sidPlayer == NULL || filename == NULL) return NULL; XS_MUTEX_LOCK(xs_status); if (!xs_status.sidPlayer->plrProbe(fd)) { XS_MUTEX_UNLOCK(xs_status); return NULL; } XS_MUTEX_UNLOCK(xs_status); /* Get information from URL */ tuple = tuple_new_from_filename (filename); tune = tuple_get_int (tuple, FIELD_SUBSONG_NUM, NULL); /* Get tune information from emulation engine */ XS_MUTEX_LOCK(xs_status); info = xs_status.sidPlayer->plrGetSIDInfo (filename); XS_MUTEX_UNLOCK(xs_status); if (info == NULL) return tuple; xs_get_song_tuple_info(tuple, info, tune); if (xs_cfg.subAutoEnable && info->nsubTunes > 1 && ! tune) xs_fill_subtunes(tuple, info); xs_tuneinfo_free(info); return tuple; }
static gint vorbis_open(void) { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_init(NULL); vorbis_info_init(&vi); vorbis_comment_init(&vc); if (tuple) { gchar tmpstr[32]; gint scrint; add_string_from_tuple (& vc, "title", tuple, FIELD_TITLE); add_string_from_tuple (& vc, "artist", tuple, FIELD_ARTIST); add_string_from_tuple (& vc, "album", tuple, FIELD_ALBUM); add_string_from_tuple (& vc, "genre", tuple, FIELD_GENRE); add_string_from_tuple (& vc, "date", tuple, FIELD_DATE); add_string_from_tuple (& vc, "comment", tuple, FIELD_COMMENT); if ((scrint = tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL))) { g_snprintf(tmpstr, sizeof(tmpstr), "%d", scrint); vorbis_comment_add_tag(&vc, "tracknumber", tmpstr); } if ((scrint = tuple_get_int(tuple, FIELD_YEAR, NULL))) { g_snprintf(tmpstr, sizeof(tmpstr), "%d", scrint); vorbis_comment_add_tag(&vc, "year", tmpstr); } } if (vorbis_encode_init_vbr (& vi, input.channels, input.frequency, v_base_quality)) { vorbis_info_clear(&vi); return 0; } vorbis_analysis_init(&vd, &vi); vorbis_block_init(&vd, &vb); srand(time(NULL)); ogg_stream_init(&os, rand()); vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code); ogg_stream_packetin(&os, &header); ogg_stream_packetin(&os, &header_comm); ogg_stream_packetin(&os, &header_code); while (ogg_stream_flush (& os, & og)) { write_output(og.header, og.header_len); write_output(og.body, og.body_len); } return 1; }
Tuple *flac_probe_for_tuple(const char *filename, VFSFile *fd) { AUDDBG("Probe for tuple.\n"); Tuple *tuple = NULL; FLAC__Metadata_Iterator *iter; FLAC__Metadata_Chain *chain; FLAC__StreamMetadata *metadata = NULL; FLAC__Metadata_ChainStatus status; FLAC__StreamMetadata_VorbisComment_Entry *entry; char *key; char *value; tuple = tuple_new_from_filename(filename); tuple_set_str(tuple, FIELD_CODEC, NULL, "Free Lossless Audio Codec (FLAC)"); tuple_set_str(tuple, FIELD_QUALITY, NULL, _("lossless")); chain = FLAC__metadata_chain_new(); if (!FLAC__metadata_chain_read_with_callbacks(chain, fd, io_callbacks)) goto ERR; iter = FLAC__metadata_iterator_new(); FLAC__metadata_iterator_init(iter, chain); do { switch (FLAC__metadata_iterator_get_block_type(iter)) { case FLAC__METADATA_TYPE_VORBIS_COMMENT: if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT) { metadata = FLAC__metadata_iterator_get_block(iter); AUDDBG("Vorbis comment contains %d fields\n", metadata->data.vorbis_comment.num_comments); AUDDBG("Vendor string: %s\n", metadata->data.vorbis_comment.vendor_string.entry); entry = metadata->data.vorbis_comment.comments; for (int i = 0; i < metadata->data.vorbis_comment.num_comments; i++, entry++) { if (FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value) == false) AUDDBG("Could not parse comment\n"); else { parse_comment(tuple, key, value); free(key); free(value); } } } break; case FLAC__METADATA_TYPE_STREAMINFO: metadata = FLAC__metadata_iterator_get_block(iter); /* Calculate the stream length (milliseconds) */ if (metadata->data.stream_info.sample_rate == 0) { FLACNG_ERROR("Invalid sample rate for stream!\n"); tuple_set_int(tuple, FIELD_LENGTH, NULL, -1); } else { tuple_set_int(tuple, FIELD_LENGTH, NULL, (metadata->data.stream_info.total_samples / metadata->data.stream_info.sample_rate) * 1000); AUDDBG("Stream length: %d seconds\n", tuple_get_int(tuple, FIELD_LENGTH, NULL)); } int64_t size = vfs_fsize(fd); if (size == -1 || metadata->data.stream_info.total_samples == 0) tuple_set_int(tuple, FIELD_BITRATE, NULL, 0); else { int bitrate = 8 * size * (int64_t) metadata->data.stream_info.sample_rate / metadata->data.stream_info.total_samples; tuple_set_int(tuple, FIELD_BITRATE, NULL, (bitrate + 500) / 1000); } break; default: ; } } while (FLAC__metadata_iterator_next(iter)); FLAC__metadata_iterator_delete(iter); FLAC__metadata_chain_delete(chain); return tuple; ERR: status = FLAC__metadata_chain_status(chain); FLAC__metadata_chain_delete(chain); FLACNG_ERROR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]); return tuple; }
static gboolean xspf_playlist_save (const gchar * filename, VFSFile * file, const gchar * title, Index * filenames, Index * tuples) { gint entries = index_count (filenames); xmlDocPtr doc; xmlNodePtr rootnode, tracklist; gint count; doc = xmlNewDoc((xmlChar *)"1.0"); doc->charset = XML_CHAR_ENCODING_UTF8; doc->encoding = xmlStrdup((xmlChar *)"UTF-8"); rootnode = xmlNewNode(NULL, (xmlChar *)XSPF_ROOT_NODE_NAME); xmlSetProp(rootnode, (xmlChar *)"version", (xmlChar *)"1"); xmlSetProp(rootnode, (xmlChar *)"xmlns", (xmlChar *)XSPF_XMLNS); /* common */ xmlDocSetRootElement(doc, rootnode); if (title) xspf_add_node (rootnode, TUPLE_STRING, FALSE, "title", title, 0); tracklist = xmlNewNode(NULL, (xmlChar *)"trackList"); xmlAddChild(rootnode, tracklist); for (count = 0; count < entries; count ++) { const gchar * filename = index_get (filenames, count); const Tuple * tuple = index_get (tuples, count); xmlNodePtr track, location; gchar *scratch = NULL; gint scratchi = 0; track = xmlNewNode(NULL, (xmlChar *)"track"); location = xmlNewNode(NULL, (xmlChar *)"location"); xmlAddChild(location, xmlNewText((xmlChar *)filename)); xmlAddChild(track, location); xmlAddChild(tracklist, track); if (tuple != NULL) { gint i; for (i = 0; i < xspf_nentries; i++) { const xspf_entry_t *xs = &xspf_entries[i]; gboolean isOK = (tuple_get_value_type (tuple, xs->tupleField, NULL) == xs->type); switch (xs->type) { case TUPLE_STRING: scratch = tuple_get_str (tuple, xs->tupleField, NULL); if (! scratch) isOK = FALSE; str_unref(scratch); break; case TUPLE_INT: scratchi = tuple_get_int (tuple, xs->tupleField, NULL); break; default: break; } if (isOK) xspf_add_node(track, xs->type, xs->isMeta, xs->xspfName, scratch, scratchi); } } } xmlSaveCtxt * save = xmlSaveToIO (write_cb, close_cb, file, NULL, XML_SAVE_FORMAT); if (! save) goto ERR; if (xmlSaveDoc (save, doc) < 0 || xmlSaveClose (save) < 0) goto ERR; xmlFreeDoc(doc); return TRUE; ERR: xmlFreeDoc (doc); return FALSE; }
static gint file_open(gint fmt, gint rate, gint nch) { gchar *filename = NULL, *temp = NULL; gchar * directory; gint pos; gint rv; gint playlist; input.format = fmt; input.frequency = rate; input.channels = nch; playlist = aud_playlist_get_playing (); if (playlist < 0) return 0; pos = aud_playlist_get_position(playlist); tuple = aud_playlist_entry_get_tuple (playlist, pos, FALSE); if (tuple == NULL) return 0; if (filenamefromtags) { gchar * utf8 = aud_playlist_entry_get_title (playlist, pos, FALSE); string_replace_char (utf8, '/', ' '); gchar buf[3 * strlen (utf8) + 1]; str_encode_percent (utf8, -1, buf); str_unref (utf8); filename = g_strdup (buf); } else { temp = aud_playlist_entry_get_filename (playlist, pos); gchar * original = strrchr (temp, '/'); g_return_val_if_fail (original != NULL, 0); filename = g_strdup (original + 1); str_unref (temp); if (!use_suffix) if ((temp = strrchr(filename, '.')) != NULL) *temp = '\0'; } if (prependnumber) { gint number = tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL); if (!tuple || !number) number = pos + 1; temp = g_strdup_printf ("%d%%20%s", number, filename); g_free(filename); filename = temp; } if (save_original) { temp = aud_playlist_entry_get_filename (playlist, pos); directory = g_strdup (temp); str_unref (temp); temp = strrchr (directory, '/'); g_return_val_if_fail (temp != NULL, 0); temp[1] = 0; } else { g_return_val_if_fail (file_path[0], 0); if (file_path[strlen (file_path) - 1] == '/') directory = g_strdup (file_path); else directory = g_strdup_printf ("%s/", file_path); } temp = g_strdup_printf ("%s%s.%s", directory, filename, fileext_str[fileext]); g_free (directory); g_free (filename); filename = temp; output_file = safe_create (filename); g_free (filename); if (output_file == NULL) return 0; convert_init (fmt, plugin->format_required (fmt), nch); rv = (plugin->open)(); samples_written = 0; return rv; }
static bool_t playlist_load_cue (const char * cue_filename, VFSFile * file, char * * title, Index * filenames, Index * tuples) { void * buffer = NULL; vfs_file_read_all (file, & buffer, NULL); if (! buffer) return FALSE; * title = NULL; Cd * cd = cue_parse_string (buffer); g_free (buffer); if (cd == NULL) return FALSE; int tracks = cd_get_ntrack (cd); if (tracks == 0) return FALSE; Track * current = cd_get_track (cd, 1); if (current == NULL) return FALSE; char * track_filename = track_get_filename (current); if (track_filename == NULL) return FALSE; char * filename = uri_construct (track_filename, cue_filename); Tuple * base_tuple = NULL; bool_t base_tuple_scanned = FALSE; for (int track = 1; track <= tracks; track ++) { if (current == NULL || filename == NULL) return FALSE; if (base_tuple == NULL && ! base_tuple_scanned) { base_tuple_scanned = TRUE; PluginHandle * decoder = aud_file_find_decoder (filename, FALSE); if (decoder != NULL) base_tuple = aud_file_read_tuple (filename, decoder); } Track * next = (track + 1 <= tracks) ? cd_get_track (cd, track + 1) : NULL; char * next_filename = (next != NULL) ? uri_construct (track_get_filename (next), cue_filename) : NULL; bool_t last_track = (next_filename == NULL || strcmp (next_filename, filename)); Tuple * tuple = (base_tuple != NULL) ? tuple_copy (base_tuple) : tuple_new_from_filename (filename); tuple_set_int (tuple, FIELD_TRACK_NUMBER, track); int begin = (int64_t) track_get_start (current) * 1000 / 75; tuple_set_int (tuple, FIELD_SEGMENT_START, begin); if (last_track) { if (base_tuple != NULL && tuple_get_value_type (base_tuple, FIELD_LENGTH) == TUPLE_INT) tuple_set_int (tuple, FIELD_LENGTH, tuple_get_int (base_tuple, FIELD_LENGTH) - begin); } else { int length = (int64_t) track_get_length (current) * 1000 / 75; tuple_set_int (tuple, FIELD_LENGTH, length); tuple_set_int (tuple, FIELD_SEGMENT_END, begin + length); } for (int i = 0; i < ARRAY_LEN (pti_map); i ++) tuple_attach_cdtext (tuple, current, pti_map[i].tuple_type, pti_map[i].pti); index_insert (filenames, -1, str_get (filename)); index_insert (tuples, -1, tuple); current = next; str_unref (filename); filename = next_filename; if (last_track && base_tuple != NULL) { tuple_unref (base_tuple); base_tuple = NULL; base_tuple_scanned = FALSE; } } return TRUE; }
/* builtin-keyword: ${==arg1,arg2}, returns TRUE if <arg1> and <arg2> match. <arg1> and <arg2> can also be raw text, which should be enclosed in "double quotes". */ static gboolean tuple_formatter_expression_match(Tuple *tuple, const gchar *expression) { gchar **args = g_strsplit(expression, ",", 2); gchar *arg1 = NULL, *arg2 = NULL; gint ret; if (args[0][0] == '\"') /* check if arg1 is "raw text" */ { if ( strlen(args[0]) > 1 ) { args[0][strlen(args[0]) - 1] = '\0'; arg1 = g_strdup(&(args[0][1])); args[0][strlen(args[0]) - 1] = '\"'; } else /* bad formatted arg */ return FALSE; } else if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_UNKNOWN) { g_strfreev(args); return FALSE; } if (args[1][0] == '\"') /* check if arg2 is "raw text" */ { if ( strlen(args[1]) > 1 ) { args[1][strlen(args[1]) - 1] = '\0'; arg2 = g_strdup(&(args[1][1])); args[1][strlen(args[1]) - 1] = '\"'; } else /* bad formatted arg */ return FALSE; } else if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_UNKNOWN) { g_strfreev(args); return FALSE; } if (!arg1) /* if arg1 is not "raw text", get the tuple value */ { if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_STRING) arg1 = g_strdup(tuple_get_string(tuple, -1, args[0])); else arg1 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[0])); } if (!arg2) /* if arg2 is not "raw text", get the tuple value */ { if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_STRING) arg2 = g_strdup(tuple_get_string(tuple, -1, args[1])); else arg2 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[1])); } ret = g_ascii_strcasecmp(arg1, arg2); g_free(arg1); g_free(arg2); g_strfreev(args); return ret ? FALSE : TRUE; }
static void send_now_playing() { gchar *error_code = NULL; gchar *error_detail = NULL; /* * now_playing_track can be set to something else while we this method is * running. Creating a local variable avoids to get data for different tracks, * while now_playing_track was updated concurrently. */ Tuple *curr_track = now_playing_track; gchar *tab_remover; gchar *artist = tuple_get_str(curr_track, FIELD_ARTIST, NULL); gchar *album = tuple_get_str(curr_track, FIELD_ALBUM, NULL); gchar *title = tuple_get_str(curr_track, FIELD_TITLE, NULL); tab_remover = remove_tabs(artist); str_unref(artist); artist = tab_remover; tab_remover = remove_tabs(album); str_unref(album); album = tab_remover; tab_remover = remove_tabs(title); str_unref(title); title = tab_remover; tab_remover = NULL; gchar *number = g_strdup_printf("%i", tuple_get_int(curr_track, FIELD_TRACK_NUMBER, NULL)); gchar *length = g_strdup_printf("%i", tuple_get_int(curr_track, FIELD_LENGTH, NULL) / 1000); tuple_unref(curr_track); if (artist != NULL && strlen(artist) > 0 && title != NULL && strlen(title) > 0) { gchar *playingmsg = create_message_to_lastfm("track.updateNowPlaying", 7, "artist", artist, "album", (album == NULL ? "" : album), "track", title, "trackNumber", number, "duration", length, "api_key", SCROBBLER_API_KEY, "sk", session_key); g_free(artist); g_free(album); g_free(title); g_free(number); g_free(length); bool_t success = send_message_to_lastfm(playingmsg); g_free(playingmsg); if (success == FALSE) { AUDDBG("Network problems. Could not send \"now playing\" to last.fm\n"); scrobbling_enabled = FALSE; return; } if (read_scrobble_result(&error_code, &error_detail) == TRUE) { //see scrobble_cached_queue() AUDDBG("NOW PLAYING OK.\n"); } else { AUDDBG("NOW PLAYING NOT OK. Error code: %s. Error detail: %s.\n", error_code, error_detail); //From the API: Now Playing requests that fail should not be retried. if (g_strcmp0(error_code, "9") == 0) { //Bad Session. Reauth. //We don't really care about any other errors. scrobbling_enabled = FALSE; g_free(session_key); session_key = NULL; aud_set_string("scrobbler", "session_key", ""); } } g_free(error_code); g_free(error_detail); //We don't care if the now playing was not accepted, no need to read the result from the server. } }