ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
playlist.h File Reference

Go to the source code of this file.

Data Structures

struct  media_playlist_t

Macros

#define MEDIA_PLAYLIST_MAX_ITEMS   64
#define MEDIA_PLAYLIST_PATH_MAX   256

Functions

asciichat_error_t media_playlist_append (media_playlist_t *list, const char *path, bool url)
asciichat_error_t media_playlist_parse (const char *text, media_playlist_t *list)
asciichat_error_t media_playlist_format (const media_playlist_t *list, char *text, size_t capacity)
bool media_playlist_adjacent (const media_playlist_t *list, int direction, size_t *index)

Macro Definition Documentation

◆ MEDIA_PLAYLIST_MAX_ITEMS

#define MEDIA_PLAYLIST_MAX_ITEMS   64

Definition at line 6 of file playlist.h.

Referenced by media_playlist_append().

◆ MEDIA_PLAYLIST_PATH_MAX

#define MEDIA_PLAYLIST_PATH_MAX   256

Definition at line 7 of file playlist.h.

Referenced by media_playlist_append(), and media_playlist_parse().

Function Documentation

◆ media_playlist_adjacent()

bool media_playlist_adjacent ( const media_playlist_t * list,
int direction,
size_t * index )

Find an adjacent item without wrapping at playlist boundaries.

Definition at line 113 of file playlist.c.

113 {
114 if (!list || !index || !list->count || list->index >= list->count || (direction != -1 && direction != 1))
115 return false;
116 if (direction < 0 && list->index) {
117 *index = list->index - 1;
118 return true;
119 }
120 if (direction > 0 && list->index + 1 < list->count) {
121 *index = list->index + 1;
122 return true;
123 }
124 return false;
125}
static bool size_t index
Definition queries.h:8

References media_playlist_t::count, index, and media_playlist_t::index.

Referenced by session_capture_at_end().

◆ media_playlist_append()

asciichat_error_t media_playlist_append ( media_playlist_t * list,
const char * path,
bool url )

Append one already separated argument; preserves insertion order.

Definition at line 7 of file playlist.c.

7 {
8 if (!list || !path || list->count >= MEDIA_PLAYLIST_MAX_ITEMS)
9 return SET_ERRNO(ERROR_INVALID_PARAM, "A playlist supports at most %d artifacts", MEDIA_PLAYLIST_MAX_ITEMS);
10 char normalized[MEDIA_PLAYLIST_PATH_MAX];
11 asciichat_error_t result = media_input_normalize(path, normalized, sizeof(normalized));
12 if (result != ASCIICHAT_OK)
13 return result;
14 if (url && !strstr(normalized, "://")) {
15 char absolute[MEDIA_PLAYLIST_PATH_MAX];
16 if (strlen(normalized) + 7 >= sizeof(absolute))
17 return SET_ERRNO(ERROR_INVALID_PARAM, "Media URL is too long");
18 snprintf(absolute, sizeof(absolute), "http://%s", normalized);
19 const size_t absolute_bytes = strlen(absolute) + 1;
20 memcpy(normalized, absolute, absolute_bytes);
21 }
22 if (strcmp(normalized, "-") == 0 && list->count)
23 return SET_ERRNO(ERROR_INVALID_PARAM, "Stdin must be the only playlist artifact");
24 if (list->count && strcmp(list->paths[0], "-") == 0)
25 return SET_ERRNO(ERROR_INVALID_PARAM, "Stdin must be the only playlist artifact");
26 const size_t normalized_bytes = strlen(normalized) + 1;
27 memcpy(list->paths[list->count], normalized, normalized_bytes);
28 list->urls[list->count++] = url;
29 return ASCIICHAT_OK;
30}
#define SET_ERRNO(code,...)
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
asciichat_error_t media_input_normalize(const char *text, char *output, size_t capacity)
Definition media/input.c:14
#define MEDIA_PLAYLIST_PATH_MAX
Definition playlist.h:7
#define MEDIA_PLAYLIST_MAX_ITEMS
Definition playlist.h:6
bool urls[64]
Definition playlist.h:11
char paths[64][256]
Definition playlist.h:10

References ASCIICHAT_OK, media_playlist_t::count, ERROR_INVALID_PARAM, media_input_normalize(), MEDIA_PLAYLIST_MAX_ITEMS, MEDIA_PLAYLIST_PATH_MAX, media_playlist_t::paths, SET_ERRNO, and media_playlist_t::urls.

Referenced by media_playlist_parse(), session_capture_create(), session_capture_open_media(), and ui_input_read_key().

◆ media_playlist_format()

asciichat_error_t media_playlist_format ( const media_playlist_t * list,
char * text,
size_t capacity )

Render one quoted artifact per line, with no trailing whitespace.

Definition at line 89 of file playlist.c.

89 {
90 if (!list || !text || !capacity)
91 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid playlist display buffer");
92 size_t used = 0;
93 text[0] = '\0';
94 for (size_t i = 0; i < list->count; ++i) {
95 const char *path = list->paths[i];
96 char quote = strchr(path, '"') ? '\'' : '"';
97 if (strchr(path, quote))
98 return SET_ERRNO(ERROR_INVALID_PARAM, "Cannot quote media artifact");
99 size_t bytes = strlen(path);
100 if (used + bytes + 3 + (i != 0) > capacity)
101 return SET_ERRNO(ERROR_INVALID_PARAM, "Playlist display is too long");
102 if (i)
103 text[used++] = '\n';
104 text[used++] = quote;
105 memcpy(text + used, path, bytes);
106 used += bytes;
107 text[used++] = quote;
108 text[used] = '\0';
109 }
110 return ASCIICHAT_OK;
111}

References ASCIICHAT_OK, media_playlist_t::count, ERROR_INVALID_PARAM, media_playlist_t::paths, and SET_ERRNO.

Referenced by session_handle_keyboard_input(), and ui_input_read_key().

◆ media_playlist_parse()

asciichat_error_t media_playlist_parse ( const char * text,
media_playlist_t * list )

Parse shell-quoted paths, file URIs or URLs. A lone unquoted path may contain spaces.

Definition at line 32 of file playlist.c.

32 {
33 if (!text || !list)
34 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid playlist input");
35 media_playlist_t parsed = {0};
36 while (isspace((unsigned char)*text))
37 ++text;
38 if (text[0] == '&' && text[1] == ' ')
39 text += 2;
40 while (*text) {
41 while (isspace((unsigned char)*text))
42 ++text;
43 if (!*text)
44 break;
45 const char *start = text;
46 if (*text == '\'' || *text == '"') {
47 char quote = *text++;
48 while (*text && *text != quote)
49 ++text;
50 if (!*text || (text[1] && !isspace((unsigned char)text[1])))
51 return SET_ERRNO(ERROR_INVALID_PARAM, "Separate media artifacts with whitespace and match their quotes");
52 ++text;
53 } else {
54 // Preserve a manually typed path containing spaces. Newline-delimited
55 // clipboard URI lists remain separate artifacts.
56 while (*text && *text != '\n' && *text != '\r') {
57 if (isspace((unsigned char)*text)) {
58 const char *next = text;
59 while (*next == ' ' || *next == '\t')
60 ++next;
61 bool path_start = *next == '\'' || *next == '"' || *next == '/' || *next == '\\' ||
62 (isalpha((unsigned char)next[0]) && next[1] == ':');
63 const char *scheme = strstr(next, "://");
64 const char *space = strpbrk(next, " \t\r\n");
65 if (path_start || (scheme && (!space || scheme < space)))
66 break;
67 }
68 ++text;
69 }
70 }
71 size_t bytes = (size_t)(text - start);
72 char argument[MEDIA_PLAYLIST_PATH_MAX + 2];
73 if (bytes >= sizeof(argument))
74 return SET_ERRNO(ERROR_INVALID_PARAM, "Media artifact is too long");
75 memcpy(argument, start, bytes);
76 argument[bytes] = '\0';
77 bool url = strstr(argument, "://") &&
78 strncmp(argument + (argument[0] == '\'' || argument[0] == '"'), "file://", sizeof("file://") - 1) != 0;
79 asciichat_error_t result = media_playlist_append(&parsed, argument, url);
80 if (result != ASCIICHAT_OK)
81 return result;
82 }
83 if (!parsed.count)
84 return SET_ERRNO(ERROR_INVALID_PARAM, "Enter at least one media path or URL");
85 *list = parsed;
86 return ASCIICHAT_OK;
87}
asciichat_error_t media_playlist_append(media_playlist_t *list, const char *path, bool url)
Definition playlist.c:7

References ASCIICHAT_OK, media_playlist_t::count, ERROR_INVALID_PARAM, media_playlist_append(), MEDIA_PLAYLIST_PATH_MAX, and SET_ERRNO.

Referenced by session_capture_open_playlist(), session_handle_keyboard_input(), ui_input_media_take(), and ui_input_read_key().