+/**
+ * Download the art using the URL or an art downloaded
+ * This function should be called only if data is not already in cache
+ */
+static int DownloadArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item )
+{
+ char *psz_arturl = input_item_GetArtURL( p_item );
+ assert( *psz_arturl );
+
+ if( !strncmp( psz_arturl , "file://", 7 ) )
+ {
+ msg_Dbg( p_fetcher->p_playlist,
+ "Album art is local file, no need to cache" );
+ free( psz_arturl );
+ return VLC_SUCCESS;
+ }
+
+ if( !strncmp( psz_arturl , "APIC", 4 ) )
+ {
+ msg_Warn( p_fetcher->p_playlist, "APIC fetch not supported yet" );
+ goto error;
+ }
+
+ stream_t *p_stream = stream_UrlNew( p_fetcher->p_playlist, psz_arturl );
+ if( !p_stream )
+ goto error;
+
+ uint8_t *p_data = NULL;
+ int i_data = 0;
+ for( ;; )
+ {
+ int i_read = 65536;
+
+ if( i_data >= INT_MAX - i_read )
+ break;
+
+ p_data = realloc_or_free( p_data, i_data + i_read );
+ if( !p_data )
+ break;
+
+ i_read = stream_Read( p_stream, &p_data[i_data], i_read );
+ if( i_read <= 0 )
+ break;
+
+ i_data += i_read;
+ }
+ stream_Delete( p_stream );
+
+ if( p_data && i_data > 0 )
+ {
+ char *psz_type = strrchr( psz_arturl, '.' );
+ if( psz_type && strlen( psz_type ) > 5 )
+ psz_type = NULL; /* remove extension if it's > to 4 characters */
+
+ playlist_SaveArt( p_fetcher->p_playlist, p_item, p_data, i_data, psz_type );
+ }
+
+ free( p_data );
+
+ free( psz_arturl );
+ return VLC_SUCCESS;
+
+error:
+ free( psz_arturl );
+ return VLC_EGENERIC;
+}
+
+/**
+ * FetchMeta, run the "meta fetcher". They are going to do network
+ * connections, and gather information upon the playing media.
+ * (even artwork).
+ */
+static void FetchMeta( playlist_fetcher_t *p_fetcher, input_item_t *p_item )
+{
+ demux_meta_t *p_demux_meta = vlc_custom_create(p_fetcher->p_playlist,
+ sizeof(*p_demux_meta),
+ VLC_OBJECT_GENERIC, "demux meta" );
+ if( !p_demux_meta )
+ return;
+
+ vlc_object_attach( p_demux_meta, p_fetcher->p_playlist );
+ p_demux_meta->p_demux = NULL;
+ p_demux_meta->p_item = p_item;
+
+ module_t *p_meta_fetcher = module_need( p_demux_meta, "meta fetcher", NULL, false );
+ if( p_meta_fetcher )
+ module_unneed( p_demux_meta, p_meta_fetcher );
+ vlc_object_release( p_demux_meta );
+}
+
+static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+ vlc_cond_t *p_cond = p_data;
+
+ if( newval.i_int == INPUT_EVENT_ITEM_META ||
+ newval.i_int == INPUT_EVENT_DEAD )
+ vlc_cond_signal( p_cond );
+
+ return VLC_SUCCESS;
+}
+
+
+/* Check if it is not yet preparsed and if so wait for it
+ * (at most 0.5s)
+ * (This can happen if we fetch art on play)
+ * FIXME this doesn't work if we need to fetch meta before art...
+ */
+static void WaitPreparsed( playlist_fetcher_t *p_fetcher, input_item_t *p_item )
+{
+ if( input_item_IsPreparsed( p_item ) )
+ return;
+
+ input_thread_t *p_input = playlist_CurrentInput( p_fetcher->p_playlist );
+ if( !p_input )
+ return;
+
+ if( input_GetItem( p_input ) != p_item )
+ goto exit;
+
+ vlc_cond_t cond;
+ vlc_cond_init( &cond );
+ var_AddCallback( p_input, "intf-event", InputEvent, &cond );
+
+ const mtime_t i_deadline = mdate() + 500*1000;
+ bool b_timeout = false;
+
+ while( !p_input->b_eof && !p_input->b_error
+ && !input_item_IsPreparsed( p_item ) && !b_timeout )
+ {
+ /* A bit weird, but input_item_IsPreparsed holds the protected value */
+ /* FIXME: locking looks wrong here */
+ vlc_mutex_lock( &p_fetcher->lock );
+ if( vlc_cond_timedwait( &cond, &p_fetcher->lock, i_deadline ) )
+ b_timeout = true;
+ vlc_mutex_unlock( &p_fetcher->lock );
+ }
+
+ var_DelCallback( p_input, "intf-event", InputEvent, &cond );
+ vlc_cond_destroy( &cond );
+
+exit:
+ vlc_object_release( p_input );
+}