static int vlclua_input_item_set_meta( lua_State *L ) { input_item_t *p_item = vlclua_input_item_get_internal( L ); lua_settop( L, 1 + 2 ); // two arguments const char *psz_name = luaL_checkstring( L, 2 ), *psz_value = luaL_checkstring( L, 3 ); #define META_TYPE( n, s ) { s, vlc_meta_ ## n }, static const struct { const char psz_name[15]; unsigned char type; } pp_meta_types[] = { META_TYPE( Title, "title" ) META_TYPE( Artist, "artist" ) META_TYPE( Genre, "genre" ) META_TYPE( Copyright, "copyright" ) META_TYPE( Album, "album" ) META_TYPE( TrackNumber, "track_number" ) META_TYPE( Description, "description" ) META_TYPE( Rating, "rating" ) META_TYPE( Date, "date" ) META_TYPE( Setting, "setting" ) META_TYPE( URL, "url" ) META_TYPE( Language, "language" ) META_TYPE( NowPlaying, "now_playing" ) META_TYPE( ESNowPlaying, "now_playing" ) META_TYPE( Publisher, "publisher" ) META_TYPE( EncodedBy, "encoded_by" ) META_TYPE( ArtworkURL, "artwork_url" ) META_TYPE( TrackID, "track_id" ) META_TYPE( TrackTotal, "track_total" ) META_TYPE( Director, "director" ) META_TYPE( Season, "season" ) META_TYPE( Episode, "episode" ) META_TYPE( ShowName, "show_name" ) META_TYPE( Actors, "actors" ) }; #undef META_TYPE static_assert( sizeof(pp_meta_types) == VLC_META_TYPE_COUNT * sizeof(pp_meta_types[0]), "Inconsistent meta data types" ); vlc_meta_type_t type = vlc_meta_Title; for( unsigned i = 0; i < VLC_META_TYPE_COUNT; i++ ) { if( !strcasecmp( pp_meta_types[i].psz_name, psz_name ) ) { type = pp_meta_types[i].type; input_item_SetMeta( p_item, type, psz_value ); return 1; } } vlc_meta_AddExtra( p_item->p_meta, psz_name, psz_value ); return 1; }
void libvlc_media_set_meta( libvlc_media_t *p_md, libvlc_meta_t e_meta, const char *psz_value ) { assert( p_md ); input_item_SetMeta( p_md->p_input_item, libvlc_to_vlc_meta[e_meta], psz_value ); }
/***************************************************************************** * Connect: *****************************************************************************/ static int Connect( stream_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; vlc_url_t srv = p_sys->b_proxy ? p_sys->proxy : p_sys->url; ssize_t val; /* Clean info */ free( p_sys->psz_location ); free( p_sys->psz_mime ); free( p_sys->psz_icy_genre ); free( p_sys->psz_icy_name ); free( p_sys->psz_icy_title ); vlc_http_auth_Init( &p_sys->auth ); vlc_http_auth_Init( &p_sys->proxy_auth ); p_sys->psz_location = NULL; p_sys->psz_mime = NULL; p_sys->i_icy_meta = 0; p_sys->i_icy_offset = 0; p_sys->psz_icy_name = NULL; p_sys->psz_icy_genre = NULL; p_sys->psz_icy_title = NULL; p_sys->b_has_size = false; p_sys->offset = 0; p_sys->size = 0; struct vlc_memstream stream; vlc_memstream_open(&stream); vlc_memstream_puts(&stream, "GET "); if( p_sys->b_proxy ) vlc_memstream_printf( &stream, "http://%s:%d", p_sys->url.psz_host, p_sys->url.i_port ); if( p_sys->url.psz_path == NULL || p_sys->url.psz_path[0] == '\0' ) vlc_memstream_putc( &stream, '/' ); else vlc_memstream_puts( &stream, p_sys->url.psz_path ); if( p_sys->url.psz_option != NULL ) vlc_memstream_printf( &stream, "?%s", p_sys->url.psz_option ); vlc_memstream_puts( &stream, " HTTP/1.0\r\n" ); vlc_memstream_printf( &stream, "Host: %s", p_sys->url.psz_host ); if( p_sys->url.i_port != 80 ) vlc_memstream_printf( &stream, ":%d", p_sys->url.i_port ); vlc_memstream_puts( &stream, "\r\n" ); /* User Agent */ vlc_memstream_printf( &stream, "User-Agent: %s\r\n", p_sys->psz_user_agent ); /* Referrer */ if (p_sys->psz_referrer) vlc_memstream_printf( &stream, "Referer: %s\r\n", p_sys->psz_referrer ); /* Authentication */ if( p_sys->url.psz_username != NULL && p_sys->url.psz_password != NULL ) { char *auth; auth = vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access), &p_sys->auth, "GET", p_sys->url.psz_path, p_sys->url.psz_username, p_sys->url.psz_password ); if( auth != NULL ) vlc_memstream_printf( &stream, "Authorization: %s\r\n", auth ); free( auth ); } /* Proxy Authentication */ if( p_sys->b_proxy && p_sys->proxy.psz_username != NULL && p_sys->proxy.psz_password != NULL ) { char *auth; auth = vlc_http_auth_FormatAuthorizationHeader( VLC_OBJECT(p_access), &p_sys->proxy_auth, "GET", p_sys->url.psz_path, p_sys->proxy.psz_username, p_sys->proxy.psz_password ); if( auth != NULL ) vlc_memstream_printf( &stream, "Proxy-Authorization: %s\r\n", auth ); free( auth ); } /* ICY meta data request */ vlc_memstream_puts( &stream, "Icy-MetaData: 1\r\n" ); vlc_memstream_puts( &stream, "\r\n" ); if( vlc_memstream_close( &stream ) ) return -1; /* Open connection */ assert(p_sys->stream == NULL); /* No open sockets (leaking fds is BAD) */ p_sys->stream = vlc_tls_SocketOpenTCP(VLC_OBJECT(p_access), srv.psz_host, srv.i_port); if (p_sys->stream == NULL) { msg_Err( p_access, "cannot connect to %s:%d", srv.psz_host, srv.i_port ); free( stream.ptr ); return -1; } msg_Dbg( p_access, "sending request:\n%s", stream.ptr ); val = vlc_tls_Write(p_sys->stream, stream.ptr, stream.length); free( stream.ptr ); if( val < (ssize_t)stream.length ) { msg_Err( p_access, "failed to send request" ); Disconnect( p_access ); return -2; } /* Read Answer */ char *psz = vlc_tls_GetLine(p_sys->stream); if( psz == NULL ) { msg_Err( p_access, "failed to read answer" ); goto error; } if( !strncmp( psz, "HTTP/1.", 7 ) ) { p_sys->i_code = atoi( &psz[9] ); msg_Dbg( p_access, "HTTP answer code %d", p_sys->i_code ); } else if( !strncmp( psz, "ICY", 3 ) ) { p_sys->i_code = atoi( &psz[4] ); msg_Dbg( p_access, "ICY answer code %d", p_sys->i_code ); p_sys->b_icecast = true; p_sys->b_reconnect = true; } else { msg_Err( p_access, "invalid HTTP reply '%s'", psz ); free( psz ); goto error; } /* Authentication error - We'll have to display the dialog */ if( p_sys->i_code == 401 ) { } /* Other fatal error */ else if( p_sys->i_code >= 400 ) { msg_Err( p_access, "error: %s", psz ); free( psz ); goto error; } free( psz ); for( ;; ) { char *p, *p_trailing; psz = vlc_tls_GetLine(p_sys->stream); if( psz == NULL ) { msg_Err( p_access, "failed to read answer" ); goto error; } /* msg_Dbg( p_input, "Line=%s", psz ); */ if( *psz == '\0' ) { free( psz ); break; } if( ( p = strchr( psz, ':' ) ) == NULL ) { msg_Err( p_access, "malformed header line: %s", psz ); free( psz ); goto error; } *p++ = '\0'; p += strspn( p, " \t" ); /* trim trailing white space */ p_trailing = p + strlen( p ); if( p_trailing > p ) { p_trailing--; while( ( *p_trailing == ' ' || *p_trailing == '\t' ) && p_trailing > p ) { *p_trailing = '\0'; p_trailing--; } } if( !strcasecmp( psz, "Content-Length" ) ) { uint64_t i_size = (uint64_t)atoll( p ); if(i_size > p_sys->size) { p_sys->b_has_size = true; p_sys->size = i_size; } } else if( !strcasecmp( psz, "Location" ) ) { char * psz_new_loc; /* This does not follow RFC 2068, but yet if the url is not absolute, * handle it as everyone does. */ if( p[0] == '/' ) { if( p_sys->url.i_port == 80 ) { if( asprintf(&psz_new_loc, "http://%s%s", p_sys->url.psz_host, p) < 0 ) goto error; } else { if( asprintf(&psz_new_loc, "http://%s:%d%s", p_sys->url.psz_host, p_sys->url.i_port, p) < 0 ) goto error; } } else { psz_new_loc = strdup( p ); } free( p_sys->psz_location ); p_sys->psz_location = psz_new_loc; } else if( !strcasecmp( psz, "Content-Type" ) ) { free( p_sys->psz_mime ); p_sys->psz_mime = strdup( p ); msg_Dbg( p_access, "Content-Type: %s", p_sys->psz_mime ); } else if( !strcasecmp( psz, "Content-Encoding" ) ) { msg_Dbg( p_access, "Content-Encoding: %s", p ); } else if( !strcasecmp( psz, "Server" ) ) { msg_Dbg( p_access, "Server: %s", p ); if( !strncasecmp( p, "Icecast", 7 ) || !strncasecmp( p, "Nanocaster", 10 ) ) { /* Remember if this is Icecast * we need to force demux in this case without breaking * autodetection */ /* Let live 365 streams (nanocaster) piggyback on the icecast * routine. They look very similar */ p_sys->b_reconnect = true; p_sys->b_icecast = true; } } else if( !strcasecmp( psz, "Icy-MetaInt" ) ) { msg_Dbg( p_access, "Icy-MetaInt: %s", p ); p_sys->i_icy_meta = atoi( p ); if( p_sys->i_icy_meta < 0 ) p_sys->i_icy_meta = 0; if( p_sys->i_icy_meta > 1 ) { p_sys->i_icy_offset = p_sys->i_icy_meta; p_sys->b_icecast = true; } msg_Warn( p_access, "ICY metaint=%d", p_sys->i_icy_meta ); } else if( !strcasecmp( psz, "Icy-Name" ) ) { free( p_sys->psz_icy_name ); char *psz_tmp = strdup( p ); p_sys->psz_icy_name = EnsureUTF8( psz_tmp ); if( !p_sys->psz_icy_name ) free( psz_tmp ); else vlc_xml_decode( p_sys->psz_icy_name ); msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name ); if ( p_access->p_input_item ) input_item_SetMeta( p_access->p_input_item, vlc_meta_Title, p_sys->psz_icy_name ); p_sys->b_icecast = true; /* be on the safeside. set it here as well. */ p_sys->b_reconnect = true; } else if( !strcasecmp( psz, "Icy-Genre" ) ) { free( p_sys->psz_icy_genre ); char *psz_tmp = strdup( p ); p_sys->psz_icy_genre = EnsureUTF8( psz_tmp ); if( !p_sys->psz_icy_genre ) free( psz_tmp ); else vlc_xml_decode( p_sys->psz_icy_genre ); msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre ); if( p_access->p_input_item ) input_item_SetMeta( p_access->p_input_item, vlc_meta_Genre, p_sys->psz_icy_genre ); } else if( !strncasecmp( psz, "Icy-Notice", 10 ) ) { msg_Dbg( p_access, "Icy-Notice: %s", p ); } else if( !strncasecmp( psz, "icy-", 4 ) || !strncasecmp( psz, "ice-", 4 ) || !strncasecmp( psz, "x-audiocast", 11 ) ) { msg_Dbg( p_access, "Meta-Info: %s: %s", psz, p ); } else if( !strcasecmp( psz, "www-authenticate" ) ) { msg_Dbg( p_access, "Authentication header: %s", p ); vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access), &p_sys->auth, p ); } else if( !strcasecmp( psz, "proxy-authenticate" ) ) { msg_Dbg( p_access, "Proxy authentication header: %s", p ); vlc_http_auth_ParseWwwAuthenticateHeader( VLC_OBJECT(p_access), &p_sys->proxy_auth, p ); } else if( !strcasecmp( psz, "authentication-info" ) ) { msg_Dbg( p_access, "Authentication Info header: %s", p ); if( AuthCheckReply( p_access, p, &p_sys->url, &p_sys->auth ) ) goto error; } else if( !strcasecmp( psz, "proxy-authentication-info" ) ) { msg_Dbg( p_access, "Proxy Authentication Info header: %s", p ); if( AuthCheckReply( p_access, p, &p_sys->proxy, &p_sys->proxy_auth ) ) goto error; } free( psz ); } return 0; error: Disconnect( p_access ); return -2; }
static int ReadICYMeta( stream_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; uint8_t buffer; char *p, *psz_meta; int i_read; /* Read meta data length */ if( ReadData( p_access, &i_read, &buffer, 1 ) ) return VLC_EGENERIC; if( i_read != 1 ) return VLC_EGENERIC; const int i_size = buffer << 4; /* msg_Dbg( p_access, "ICY meta size=%u", i_size); */ psz_meta = malloc( i_size + 1 ); for( i_read = 0; i_read < i_size; ) { int i_tmp; if( ReadData( p_access, &i_tmp, (uint8_t *)&psz_meta[i_read], i_size - i_read ) || i_tmp <= 0 ) { free( psz_meta ); return VLC_EGENERIC; } i_read += i_tmp; } psz_meta[i_read] = '\0'; /* Just in case */ /* msg_Dbg( p_access, "icy-meta=%s", psz_meta ); */ /* Now parse the meta */ /* Look for StreamTitle= */ p = strcasestr( (char *)psz_meta, "StreamTitle=" ); if( p ) { p += strlen( "StreamTitle=" ); if( *p == '\'' || *p == '"' ) { char closing[] = { p[0], ';', '\0' }; char *psz = strstr( &p[1], closing ); if( !psz ) psz = strchr( &p[1], ';' ); if( psz ) *psz = '\0'; p++; } else { char *psz = strchr( p, ';' ); if( psz ) *psz = '\0'; } if( !p_sys->psz_icy_title || strcmp( p_sys->psz_icy_title, p ) ) { free( p_sys->psz_icy_title ); char *psz_tmp = strdup( p ); p_sys->psz_icy_title = EnsureUTF8( psz_tmp ); if( !p_sys->psz_icy_title ) free( psz_tmp ); msg_Dbg( p_access, "New Icy-Title=%s", p_sys->psz_icy_title ); if( p_access->p_input_item ) input_item_SetMeta( p_access->p_input_item, vlc_meta_NowPlaying, p_sys->psz_icy_title ); } } free( psz_meta ); return VLC_SUCCESS; }