Listing pages (rated/newest) and per-camera pages are fetched over HTTPS with the certificate bundle; the camera page's Live Feed mode yields the camera's own MJPEG URL (Current Still as fallback), resolved just before playing and cached in favourites. New Provider menu row: insecam / opentopia / mixed. cam_info_t gains provider + title fields and the settings blob a version byte; older favourites and settings still load.
54 lines
1.9 KiB
C
54 lines
1.9 KiB
C
#include "webpage.h"
|
|
#include "esp_crt_bundle.h"
|
|
#include "esp_heap_caps.h"
|
|
#include "esp_http_client.h"
|
|
#include "esp_log.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static const char *TAG = "webpage";
|
|
|
|
typedef struct { char *buf; size_t len, cap; bool overflow; } sink_t;
|
|
|
|
static esp_err_t on_event(esp_http_client_event_t *e)
|
|
{
|
|
sink_t *s = e->user_data;
|
|
if (e->event_id == HTTP_EVENT_ON_DATA && s) {
|
|
size_t room = s->cap - 1 - s->len;
|
|
size_t n = e->data_len < room ? e->data_len : room;
|
|
memcpy(s->buf + s->len, e->data, n);
|
|
s->len += n;
|
|
if (n < (size_t)e->data_len) s->overflow = true;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t webpage_get(const char *url, const char *user_agent, size_t cap, char **out, size_t *len)
|
|
{
|
|
sink_t sink = {.buf = heap_caps_malloc(cap, MALLOC_CAP_SPIRAM), .cap = cap};
|
|
if (!sink.buf) return ESP_ERR_NO_MEM;
|
|
esp_http_client_config_t cfg = {
|
|
.url = url, .user_agent = user_agent, .timeout_ms = 10000,
|
|
.event_handler = on_event, .user_data = &sink,
|
|
.crt_bundle_attach = esp_crt_bundle_attach,
|
|
.buffer_size = 4096, .buffer_size_tx = 1024,
|
|
.max_redirection_count = 3,
|
|
};
|
|
esp_http_client_handle_t client = esp_http_client_init(&cfg);
|
|
if (!client) { free(sink.buf); return ESP_FAIL; }
|
|
esp_err_t err = esp_http_client_perform(client);
|
|
int status = esp_http_client_get_status_code(client);
|
|
esp_http_client_cleanup(client);
|
|
if (err != ESP_OK || status != 200) {
|
|
ESP_LOGW(TAG, "%s -> %s / HTTP %d", url, esp_err_to_name(err), status);
|
|
free(sink.buf);
|
|
return err != ESP_OK ? err : ESP_FAIL;
|
|
}
|
|
if (sink.overflow) ESP_LOGW(TAG, "%s truncated at %u bytes", url, (unsigned)sink.len);
|
|
for (size_t i = 0; i < sink.len; i++) if (!sink.buf[i]) sink.buf[i] = ' ';
|
|
sink.buf[sink.len] = 0;
|
|
*out = sink.buf;
|
|
*len = sink.len;
|
|
return ESP_OK;
|
|
}
|