Compare commits
	
		
			6 Commits
		
	
	
		
			5aa07fd8af
			...
			v1.2.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						61a141203b
	
				 | 
					
					
						|||
| 
						
						
							
						
						48482ef2e5
	
				 | 
					
					
						|||
| 
						
						
							
						
						840c69767c
	
				 | 
					
					
						|||
| 
						
						
							
						
						a14a907b18
	
				 | 
					
					
						|||
| 
						
						
							
						
						333049de01
	
				 | 
					
					
						|||
| 
						
						
							
						
						4e3596db35
	
				 | 
					
					
						
@@ -1,5 +1,5 @@
 | 
				
			|||||||
cmake_minimum_required (VERSION 3.0)
 | 
					cmake_minimum_required (VERSION 3.0)
 | 
				
			||||||
project (nncmpp VERSION 1.1.1 LANGUAGES C)
 | 
					project (nncmpp VERSION 1.2.0 LANGUAGES C)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Moar warnings
 | 
					# Moar warnings
 | 
				
			||||||
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
 | 
					if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,14 @@
 | 
				
			|||||||
 | 
					1.2.0 (2021-12-21)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Added ability to control the volume of MPD's current PulseAudio sink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Now fetching Internet stream information asynchronously
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Added basic incremental search, normally bound to C-s, in all tabs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Fixed jumping to the beginning of the queue after deleting items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1.1.1 (2021-11-04)
 | 
					1.1.1 (2021-11-04)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * Terminal focus in/out events no longer ring the terminall bell
 | 
					 * Terminal focus in/out events no longer ring the terminall bell
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								liberty
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								liberty
									
									
									
									
									
								
							 Submodule liberty updated: 782a9a5977...7e8e085c97
									
								
							@@ -38,6 +38,7 @@ CHOOSE,             Choose item
 | 
				
			|||||||
DELETE,             Delete item
 | 
					DELETE,             Delete item
 | 
				
			||||||
UP,                 Go up a level
 | 
					UP,                 Go up a level
 | 
				
			||||||
MULTISELECT,        Toggle multiselect
 | 
					MULTISELECT,        Toggle multiselect
 | 
				
			||||||
 | 
					INCREMENTAL_SEARCH, Incremental search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SCROLL_UP,          Scroll up
 | 
					SCROLL_UP,          Scroll up
 | 
				
			||||||
SCROLL_DOWN,        Scroll down
 | 
					SCROLL_DOWN,        Scroll down
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										157
									
								
								nncmpp.c
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								nncmpp.c
									
									
									
									
									
								
							@@ -282,6 +282,10 @@ struct poller_curl
 | 
				
			|||||||
	struct poller_timer timer;          ///< cURL timer
 | 
						struct poller_timer timer;          ///< cURL timer
 | 
				
			||||||
	CURLM *multi;                       ///< cURL multi interface handle
 | 
						CURLM *multi;                       ///< cURL multi interface handle
 | 
				
			||||||
	struct poller_curl_fd *fds;         ///< List of all FDs
 | 
						struct poller_curl_fd *fds;         ///< List of all FDs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: also make sure to dispose of them at the end of the program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int registered;                     ///< Number of attached easy handles
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -390,6 +394,7 @@ poller_curl_init (struct poller_curl *self, struct poller *poller,
 | 
				
			|||||||
	 || (mres = curl_multi_setopt (self->multi, CURLMOPT_TIMERDATA, self)))
 | 
						 || (mres = curl_multi_setopt (self->multi, CURLMOPT_TIMERDATA, self)))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		curl_multi_cleanup (self->multi);
 | 
							curl_multi_cleanup (self->multi);
 | 
				
			||||||
 | 
							self->multi = NULL;
 | 
				
			||||||
		return error_set (e, "%s: %s",
 | 
							return error_set (e, "%s: %s",
 | 
				
			||||||
			"cURL setup failed", curl_multi_strerror (mres));
 | 
								"cURL setup failed", curl_multi_strerror (mres));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -450,6 +455,7 @@ poller_curl_add (struct poller_curl *self, CURL *easy, struct error **e)
 | 
				
			|||||||
	// "CURLMOPT_TIMERFUNCTION [...] will be called from within this function"
 | 
						// "CURLMOPT_TIMERFUNCTION [...] will be called from within this function"
 | 
				
			||||||
	if ((mres = curl_multi_add_handle (self->multi, easy)))
 | 
						if ((mres = curl_multi_add_handle (self->multi, easy)))
 | 
				
			||||||
		return error_set (e, "%s", curl_multi_strerror (mres));
 | 
							return error_set (e, "%s", curl_multi_strerror (mres));
 | 
				
			||||||
 | 
						self->registered++;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -459,6 +465,7 @@ poller_curl_remove (struct poller_curl *self, CURL *easy, struct error **e)
 | 
				
			|||||||
	CURLMcode mres;
 | 
						CURLMcode mres;
 | 
				
			||||||
	if ((mres = curl_multi_remove_handle (self->multi, easy)))
 | 
						if ((mres = curl_multi_remove_handle (self->multi, easy)))
 | 
				
			||||||
		return error_set (e, "%s", curl_multi_strerror (mres));
 | 
							return error_set (e, "%s", curl_multi_strerror (mres));
 | 
				
			||||||
 | 
						self->registered--;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1184,6 +1191,7 @@ static struct app_context
 | 
				
			|||||||
	// Event loop:
 | 
						// Event loop:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller poller;               ///< Poller
 | 
						struct poller poller;               ///< Poller
 | 
				
			||||||
 | 
						struct poller_curl poller_curl;     ///< cURL abstractor
 | 
				
			||||||
	bool quitting;                      ///< Quit signal for the event loop
 | 
						bool quitting;                      ///< Quit signal for the event loop
 | 
				
			||||||
	bool polling;                       ///< The event loop is running
 | 
						bool polling;                       ///< The event loop is running
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1500,6 +1508,7 @@ static void
 | 
				
			|||||||
app_init_context (void)
 | 
					app_init_context (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	poller_init (&g.poller);
 | 
						poller_init (&g.poller);
 | 
				
			||||||
 | 
						hard_assert (poller_curl_init (&g.poller_curl, &g.poller, NULL));
 | 
				
			||||||
	g.client = mpd_client_make (&g.poller);
 | 
						g.client = mpd_client_make (&g.poller);
 | 
				
			||||||
	g.config = config_make ();
 | 
						g.config = config_make ();
 | 
				
			||||||
	g.streams = strv_make ();
 | 
						g.streams = strv_make ();
 | 
				
			||||||
@@ -1588,6 +1597,7 @@ app_free_context (void)
 | 
				
			|||||||
	line_editor_free (&g.editor);
 | 
						line_editor_free (&g.editor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config_free (&g.config);
 | 
						config_free (&g.config);
 | 
				
			||||||
 | 
						poller_curl_free (&g.poller_curl);
 | 
				
			||||||
	poller_free (&g.poller);
 | 
						poller_free (&g.poller);
 | 
				
			||||||
	free (g.message);
 | 
						free (g.message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2079,6 +2089,8 @@ app_write_mpd_status (struct row_buffer *buf)
 | 
				
			|||||||
		row_buffer_append (buf, msg, APP_ATTR (HIGHLIGHT));
 | 
							row_buffer_append (buf, msg, APP_ATTR (HIGHLIGHT));
 | 
				
			||||||
		free (msg);
 | 
							free (msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else if (g.poller_curl.registered)
 | 
				
			||||||
 | 
							row_buffer_append (buf, "Downloading...", APP_ATTR (NORMAL));
 | 
				
			||||||
	else if (str_map_find (map, "updating_db"))
 | 
						else if (str_map_find (map, "updating_db"))
 | 
				
			||||||
		row_buffer_append (buf, "Updating database...", APP_ATTR (NORMAL));
 | 
							row_buffer_append (buf, "Updating database...", APP_ATTR (NORMAL));
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
@@ -2319,7 +2331,7 @@ app_setvol (int value)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
app_on_editor_end (bool confirmed)
 | 
					app_on_mpd_command_editor_end (bool confirmed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mpd_client *c = &g.client;
 | 
						struct mpd_client *c = &g.client;
 | 
				
			||||||
	if (!confirmed)
 | 
						if (!confirmed)
 | 
				
			||||||
@@ -2334,6 +2346,54 @@ app_on_editor_end (bool confirmed)
 | 
				
			|||||||
	mpd_client_idle (c, 0);
 | 
						mpd_client_idle (c, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t
 | 
				
			||||||
 | 
					incremental_search_match (const ucs4_t *needle, size_t len,
 | 
				
			||||||
 | 
						const struct row_buffer *row)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// XXX: this is slow and simplistic, but unistring is awkward to use
 | 
				
			||||||
 | 
						size_t best = 0;
 | 
				
			||||||
 | 
						for (size_t start = 0; start < row->chars_len; start++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							size_t i = 0;
 | 
				
			||||||
 | 
							for (; i < len && start + i < row->chars_len; i++)
 | 
				
			||||||
 | 
								if (uc_tolower(needle[i]) != uc_tolower(row->chars[start + i].c))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							best = MAX (best, i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return best;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					incremental_search_on_changed (void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tab *tab = g.active_tab;
 | 
				
			||||||
 | 
						if (!tab->item_count)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t best = 0, current = 0, index = MAX (tab->item_selected, 0), i = 0;
 | 
				
			||||||
 | 
						while (i++ < tab->item_count)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							struct row_buffer buf = row_buffer_make ();
 | 
				
			||||||
 | 
							tab->on_item_draw (index, &buf, COLS);
 | 
				
			||||||
 | 
							current = incremental_search_match (g.editor.line, g.editor.len, &buf);
 | 
				
			||||||
 | 
							row_buffer_free (&buf);
 | 
				
			||||||
 | 
							if (best < current)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								best = current;
 | 
				
			||||||
 | 
								tab->item_selected = index;
 | 
				
			||||||
 | 
								app_move_selection (0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							index = (index + 1) % tab->item_count;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					incremental_search_on_end (bool confirmed)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						(void) confirmed;
 | 
				
			||||||
 | 
						// Required callback, nothing to do here.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
@@ -2376,7 +2436,7 @@ app_process_action (enum action action)
 | 
				
			|||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	case ACTION_MPD_COMMAND:
 | 
						case ACTION_MPD_COMMAND:
 | 
				
			||||||
		line_editor_start (&g.editor, ':');
 | 
							line_editor_start (&g.editor, ':');
 | 
				
			||||||
		g.editor.on_end = app_on_editor_end;
 | 
							g.editor.on_end = app_on_mpd_command_editor_end;
 | 
				
			||||||
		app_invalidate ();
 | 
							app_invalidate ();
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -2393,6 +2453,12 @@ app_process_action (enum action action)
 | 
				
			|||||||
		else
 | 
							else
 | 
				
			||||||
			tab->item_mark = tab->item_selected;
 | 
								tab->item_mark = tab->item_selected;
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
						case ACTION_INCREMENTAL_SEARCH:
 | 
				
			||||||
 | 
							line_editor_start (&g.editor, '/');
 | 
				
			||||||
 | 
							g.editor.on_changed = incremental_search_on_changed;
 | 
				
			||||||
 | 
							g.editor.on_end = incremental_search_on_end;
 | 
				
			||||||
 | 
							app_invalidate ();
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case ACTION_TAB_LAST:
 | 
						case ACTION_TAB_LAST:
 | 
				
			||||||
		if (!g.last_tab)
 | 
							if (!g.last_tab)
 | 
				
			||||||
@@ -2683,6 +2749,7 @@ g_normal_defaults[] =
 | 
				
			|||||||
	{ "M-Up",       ACTION_UP                 },
 | 
						{ "M-Up",       ACTION_UP                 },
 | 
				
			||||||
	{ "Backspace",  ACTION_UP                 },
 | 
						{ "Backspace",  ACTION_UP                 },
 | 
				
			||||||
	{ "v",          ACTION_MULTISELECT        },
 | 
						{ "v",          ACTION_MULTISELECT        },
 | 
				
			||||||
 | 
						{ "C-s",        ACTION_INCREMENTAL_SEARCH },
 | 
				
			||||||
	{ "/",          ACTION_MPD_SEARCH         },
 | 
						{ "/",          ACTION_MPD_SEARCH         },
 | 
				
			||||||
	{ "a",          ACTION_MPD_ADD            },
 | 
						{ "a",          ACTION_MPD_ADD            },
 | 
				
			||||||
	{ "r",          ACTION_MPD_REPLACE        },
 | 
						{ "r",          ACTION_MPD_REPLACE        },
 | 
				
			||||||
@@ -3462,8 +3529,8 @@ struct stream_tab_task
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct poller_curl_task curl;       ///< Superclass
 | 
						struct poller_curl_task curl;       ///< Superclass
 | 
				
			||||||
	struct str data;                    ///< Downloaded data
 | 
						struct str data;                    ///< Downloaded data
 | 
				
			||||||
	bool polling;                       ///< Still downloading
 | 
					 | 
				
			||||||
	bool replace;                       ///< Should playlist be replaced?
 | 
						bool replace;                       ///< Should playlist be replaced?
 | 
				
			||||||
 | 
						struct curl_slist *alias_ok;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
@@ -3547,24 +3614,39 @@ streams_tab_extract_links (struct str *data, const char *content_type,
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					streams_tab_task_finalize (struct stream_tab_task *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						curl_easy_cleanup (self->curl.easy);
 | 
				
			||||||
 | 
						curl_slist_free_all (self->alias_ok);
 | 
				
			||||||
 | 
						str_free (&self->data);
 | 
				
			||||||
 | 
						free (self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					streams_tab_task_dispose (struct stream_tab_task *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						hard_assert (poller_curl_remove (&g.poller_curl, self->curl.easy, NULL));
 | 
				
			||||||
 | 
						streams_tab_task_finalize (self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
streams_tab_on_downloaded (CURLMsg *msg, struct poller_curl_task *task)
 | 
					streams_tab_on_downloaded (CURLMsg *msg, struct poller_curl_task *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct stream_tab_task *self =
 | 
						struct stream_tab_task *self =
 | 
				
			||||||
		CONTAINER_OF (task, struct stream_tab_task, curl);
 | 
							CONTAINER_OF (task, struct stream_tab_task, curl);
 | 
				
			||||||
	self->polling = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msg->data.result
 | 
						if (msg->data.result
 | 
				
			||||||
	 && msg->data.result != CURLE_WRITE_ERROR)
 | 
						 && msg->data.result != CURLE_WRITE_ERROR)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		cstr_uncapitalize (self->curl.curl_error);
 | 
							cstr_uncapitalize (self->curl.curl_error);
 | 
				
			||||||
		print_error ("%s", self->curl.curl_error);
 | 
							print_error ("%s", self->curl.curl_error);
 | 
				
			||||||
		return;
 | 
							goto dispose;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mpd_client *c = &g.client;
 | 
						struct mpd_client *c = &g.client;
 | 
				
			||||||
	if (c->state != MPD_CONNECTED)
 | 
						if (c->state != MPD_CONNECTED)
 | 
				
			||||||
		return;
 | 
							goto dispose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CURL *easy = msg->easy_handle;
 | 
						CURL *easy = msg->easy_handle;
 | 
				
			||||||
	CURLcode res;
 | 
						CURLcode res;
 | 
				
			||||||
@@ -3577,13 +3659,13 @@ streams_tab_on_downloaded (CURLMsg *msg, struct poller_curl_task *task)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		print_error ("%s: %s",
 | 
							print_error ("%s: %s",
 | 
				
			||||||
			"cURL info retrieval failed", curl_easy_strerror (res));
 | 
								"cURL info retrieval failed", curl_easy_strerror (res));
 | 
				
			||||||
		return;
 | 
							goto dispose;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// cURL is not willing to parse the ICY header, the code is zero then
 | 
						// cURL is not willing to parse the ICY header, the code is zero then
 | 
				
			||||||
	if (code && code != 200)
 | 
						if (code && code != 200)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		print_error ("%s: %ld", "unexpected HTTP response", code);
 | 
							print_error ("%s: %ld", "unexpected HTTP response", code);
 | 
				
			||||||
		return;
 | 
							goto dispose;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpd_client_list_begin (c);
 | 
						mpd_client_list_begin (c);
 | 
				
			||||||
@@ -3602,6 +3684,9 @@ streams_tab_on_downloaded (CURLMsg *msg, struct poller_curl_task *task)
 | 
				
			|||||||
	mpd_client_list_end (c);
 | 
						mpd_client_list_end (c);
 | 
				
			||||||
	mpd_client_add_task (c, mpd_on_simple_response, NULL);
 | 
						mpd_client_add_task (c, mpd_on_simple_response, NULL);
 | 
				
			||||||
	mpd_client_idle (c, 0);
 | 
						mpd_client_idle (c, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dispose:
 | 
				
			||||||
 | 
						streams_tab_task_dispose (self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t
 | 
					static size_t
 | 
				
			||||||
@@ -3620,60 +3705,44 @@ write_callback (char *ptr, size_t size, size_t nmemb, void *user_data)
 | 
				
			|||||||
static bool
 | 
					static bool
 | 
				
			||||||
streams_tab_process (const char *uri, bool replace, struct error **e)
 | 
					streams_tab_process (const char *uri, bool replace, struct error **e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct poller poller;
 | 
						// TODO: streams_tab_task_dispose() on that running task
 | 
				
			||||||
	poller_init (&poller);
 | 
						if (g.poller_curl.registered)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_error ("waiting for the last stream to time out");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller_curl pc;
 | 
						struct stream_tab_task *task = xcalloc (1, sizeof *task);
 | 
				
			||||||
	hard_assert (poller_curl_init (&pc, &poller, NULL));
 | 
						hard_assert (poller_curl_spawn (&task->curl, NULL));
 | 
				
			||||||
	struct stream_tab_task task;
 | 
					 | 
				
			||||||
	hard_assert (poller_curl_spawn (&task.curl, NULL));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CURL *easy = task.curl.easy;
 | 
						CURL *easy = task->curl.easy;
 | 
				
			||||||
	task.data = str_make ();
 | 
						task->data = str_make ();
 | 
				
			||||||
	task.replace = replace;
 | 
						task->replace = replace;
 | 
				
			||||||
	bool result = false;
 | 
						task->alias_ok = curl_slist_append (NULL, "ICY 200 OK");
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct curl_slist *ok_headers = curl_slist_append (NULL, "ICY 200 OK");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CURLcode res;
 | 
						CURLcode res;
 | 
				
			||||||
	if ((res = curl_easy_setopt (easy, CURLOPT_FOLLOWLOCATION, 1L))
 | 
						if ((res = curl_easy_setopt (easy, CURLOPT_FOLLOWLOCATION, 1L))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_NOPROGRESS,     1L))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_NOPROGRESS,     1L))
 | 
				
			||||||
	// TODO: make the timeout a bit larger once we're asynchronous
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_TIMEOUT,        10L))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_TIMEOUT,        5L))
 | 
					 | 
				
			||||||
	// Not checking anything, we just want some data, any data
 | 
						// Not checking anything, we just want some data, any data
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_SSL_VERIFYPEER, 0L))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_SSL_VERIFYPEER, 0L))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_SSL_VERIFYHOST, 0L))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_SSL_VERIFYHOST, 0L))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_URL,            uri))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_URL,            uri))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_HTTP200ALIASES, ok_headers))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_HTTP200ALIASES, task->alias_ok))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_VERBOSE, (long) g_debug_mode))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_VERBOSE, (long) g_debug_mode))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_DEBUGFUNCTION, print_curl_debug))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_DEBUGFUNCTION, print_curl_debug))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_WRITEDATA, &task.data))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_WRITEDATA, &task->data))
 | 
				
			||||||
	 || (res = curl_easy_setopt (easy, CURLOPT_WRITEFUNCTION, write_callback)))
 | 
						 || (res = curl_easy_setopt (easy, CURLOPT_WRITEFUNCTION, write_callback)))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		error_set (e, "%s: %s", "cURL setup failed", curl_easy_strerror (res));
 | 
							error_set (e, "%s: %s", "cURL setup failed", curl_easy_strerror (res));
 | 
				
			||||||
		goto error;
 | 
							streams_tab_task_finalize (task);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	task.curl.on_done = streams_tab_on_downloaded;
 | 
						task->curl.on_done = streams_tab_on_downloaded;
 | 
				
			||||||
	hard_assert (poller_curl_add (&pc, task.curl.easy, NULL));
 | 
						hard_assert (poller_curl_add (&g.poller_curl, task->curl.easy, NULL));
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
	// TODO: don't run a subloop, run the task fully asynchronously
 | 
					 | 
				
			||||||
	task.polling = true;
 | 
					 | 
				
			||||||
	while (task.polling)
 | 
					 | 
				
			||||||
		poller_run (&poller);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hard_assert (poller_curl_remove (&pc, task.curl.easy, NULL));
 | 
					 | 
				
			||||||
	result = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
	curl_easy_cleanup (task.curl.easy);
 | 
					 | 
				
			||||||
	curl_slist_free_all (ok_headers);
 | 
					 | 
				
			||||||
	str_free (&task.data);
 | 
					 | 
				
			||||||
	poller_curl_free (&pc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	poller_free (&poller);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user