Compare commits
11 Commits
ecc7c46b8d
...
84530f76fd
Author | SHA1 | Date | |
---|---|---|---|
84530f76fd | |||
fa208858d9 | |||
6d452ecbc0 | |||
23fbddb055 | |||
fe2a209e44 | |||
82905a8cdd | |||
3751904cb4 | |||
bcf7625285 | |||
4a3e79f02e | |||
68e1073858 | |||
f73d45404f |
@ -170,3 +170,5 @@ PLS files, M3U files or podcast XML feeds are supported). |
|
|||||||
| `add_mapping=<ID>=<PATH>` | Adds a mapping between RFID card <ID> and path
|
| `add_mapping=<ID>=<PATH>` | Adds a mapping between RFID card <ID> and path
|
||||||
<PATH>. See `play` for valid path formats. |
|
<PATH>. See `play` for valid path formats. |
|
||||||
| `update` | Runs an update check. |
|
| `update` | Runs an update check. |
|
||||||
|
| `debug=<0|1>` | Enables / disables debug messages. This value is persisted across reboots. |
|
||||||
|
| `trace=<0|1>` | Enables / disables tracing messages. This value is also persisted across reboots. |
|
3
bin/update.manifest
Normal file
3
bin/update.manifest
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VERSION=1
|
||||||
|
IMAGE_PATH=https://files.schle.nz/esmp3/firmware.bin
|
||||||
|
IMAGE_MD5=00000000000000000000000000000000
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -x
|
#set -x
|
||||||
#set -e
|
set -e
|
||||||
|
|
||||||
if ! git diff-index --quiet HEAD ; then
|
if ! git diff-index --quiet HEAD ; then
|
||||||
echo "Git isn't clean. Cant deploy."
|
echo "Git isn't clean. Cant deploy."
|
||||||
@ -27,7 +27,7 @@ done <<< "$vers"
|
|||||||
read -p "Version to generate: " VERSION
|
read -p "Version to generate: " VERSION
|
||||||
|
|
||||||
OTA_VERSION=`grep "VERSION=" bin/update.manifest | cut -d"=" -f2`
|
OTA_VERSION=`grep "VERSION=" bin/update.manifest | cut -d"=" -f2`
|
||||||
OTA_VERSION=$(( "$OTA_VERSION" + 1 ))
|
OTA_VERSION=$(( $OTA_VERSION + 1 ))
|
||||||
|
|
||||||
sed -i.bak "s/#define OTA_VERSION .*/#define OTA_VERSION $OTA_VERSION/" include/config.h include/config.sample.h
|
sed -i.bak "s/#define OTA_VERSION .*/#define OTA_VERSION $OTA_VERSION/" include/config.h include/config.sample.h
|
||||||
rm include/config.h.bak include/config.sample.h.bak
|
rm include/config.h.bak include/config.sample.h.bak
|
||||||
|
@ -41,6 +41,8 @@ private:
|
|||||||
WiFiClient* _stream = NULL;
|
WiFiClient* _stream = NULL;
|
||||||
HTTPClientWrapper* _http = NULL;
|
HTTPClientWrapper* _http = NULL;
|
||||||
uint32_t _position;
|
uint32_t _position;
|
||||||
|
String _url;
|
||||||
|
void _init(String url, uint32_t offset);
|
||||||
public:
|
public:
|
||||||
HTTPSDataSource(String url, uint32_t offset=0);
|
HTTPSDataSource(String url, uint32_t offset=0);
|
||||||
~HTTPSDataSource();
|
~HTTPSDataSource();
|
||||||
@ -51,4 +53,6 @@ public:
|
|||||||
size_t size();
|
size_t size();
|
||||||
void close();
|
void close();
|
||||||
bool usable();
|
bool usable();
|
||||||
|
int peek(int offset=0);
|
||||||
|
void skip_id3_tag();
|
||||||
};
|
};
|
||||||
|
@ -34,4 +34,5 @@ public:
|
|||||||
uint32_t getSize();
|
uint32_t getSize();
|
||||||
String readUntil(String sep);
|
String readUntil(String sep);
|
||||||
String readLine();
|
String readLine();
|
||||||
|
int peek(int offset=0);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
void wifi_connect();
|
void wifi_connect();
|
||||||
|
|
||||||
extern const uint8_t file_index_html_start[] asm("_binary_src_index_html_start");
|
extern const uint8_t file_index_html_start[] asm("_binary_src_index_html_start");
|
||||||
|
extern bool debug_enabled;
|
||||||
|
extern bool trace_enabled;
|
||||||
|
extern Preferences prefs;
|
@ -301,6 +301,24 @@ bool Controller::process_message(String cmd) {
|
|||||||
} else if (cmd.equals("update")) {
|
} else if (cmd.equals("update")) {
|
||||||
Updater::run();
|
Updater::run();
|
||||||
#endif
|
#endif
|
||||||
|
} else if (cmd.startsWith("trace=")) {
|
||||||
|
int val = cmd.substring(6).toInt();
|
||||||
|
if (val==0) {
|
||||||
|
trace_enabled = false;
|
||||||
|
prefs.putBool("trace_enabled", false);
|
||||||
|
} else if (val==1) {
|
||||||
|
trace_enabled = true;
|
||||||
|
prefs.putBool("trace_enabled", true);
|
||||||
|
}
|
||||||
|
} else if (cmd.startsWith("debug=")) {
|
||||||
|
int val = cmd.substring(6).toInt();
|
||||||
|
if (val==0) {
|
||||||
|
debug_enabled = false;
|
||||||
|
prefs.putBool("debug_enabled", false);
|
||||||
|
} else if (val==1) {
|
||||||
|
debug_enabled = true;
|
||||||
|
prefs.putBool("debug_enabled", true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ERROR("Unknown command: %s\n", cmd.c_str());
|
ERROR("Unknown command: %s\n", cmd.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
@ -39,6 +39,12 @@ void SDDataSource::skip_id3_tag() {
|
|||||||
|
|
||||||
////////////// HTTPSDataSource //////////////
|
////////////// HTTPSDataSource //////////////
|
||||||
HTTPSDataSource::HTTPSDataSource(String url, uint32_t offset) {
|
HTTPSDataSource::HTTPSDataSource(String url, uint32_t offset) {
|
||||||
|
_url = url;
|
||||||
|
_init(url, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPSDataSource::_init(String url, uint32_t offset) {
|
||||||
|
_url = url;
|
||||||
_http = new HTTPClientWrapper();
|
_http = new HTTPClientWrapper();
|
||||||
if (!_http->get(url, offset)) return;
|
if (!_http->get(url, offset)) return;
|
||||||
_position = 0;
|
_position = 0;
|
||||||
@ -52,6 +58,31 @@ bool HTTPSDataSource::usable() { return _http; }
|
|||||||
size_t HTTPSDataSource::read(uint8_t* buf, size_t len) { size_t result = _http->read(buf, len); _position += result; return result; }
|
size_t HTTPSDataSource::read(uint8_t* buf, size_t len) { size_t result = _http->read(buf, len); _position += result; return result; }
|
||||||
int HTTPSDataSource::read() { int b = _http->read(); if (b>=0) _position++; return b; }
|
int HTTPSDataSource::read() { int b = _http->read(); if (b>=0) _position++; return b; }
|
||||||
size_t HTTPSDataSource::position() { return _position; }
|
size_t HTTPSDataSource::position() { return _position; }
|
||||||
void HTTPSDataSource::seek(size_t position) { return; /* TODO */ }
|
void HTTPSDataSource::seek(size_t position) { _http->close(); delete _http; _init(_url, position); }
|
||||||
size_t HTTPSDataSource::size() { return _http->getSize(); }
|
size_t HTTPSDataSource::size() { return _http->getSize(); }
|
||||||
void HTTPSDataSource::close() { _http->close(); }
|
void HTTPSDataSource::close() { _http->close(); }
|
||||||
|
int HTTPSDataSource::peek(int offset) { return _http->peek(offset); }
|
||||||
|
|
||||||
|
void HTTPSDataSource::skip_id3_tag() {
|
||||||
|
uint32_t offset = 0;
|
||||||
|
if (_http->peek(0)=='I' && _http->peek(1)=='D' && _http->peek(2)=='3') {
|
||||||
|
DEBUG("ID3 tag found\n");
|
||||||
|
// Skip ID3 tag marker
|
||||||
|
_http->read(); _http->read(); _http->read();
|
||||||
|
// Skip ID3 tag version
|
||||||
|
_http->read(); _http->read();
|
||||||
|
byte tags = _http->read();
|
||||||
|
bool footer_present = tags & 0x10;
|
||||||
|
DEBUG("ID3 footer found: %d\n", footer_present);
|
||||||
|
for (byte i=0; i<4; i++) {
|
||||||
|
offset <<= 7;
|
||||||
|
offset |= (0x7F & _http->read());
|
||||||
|
}
|
||||||
|
offset += 10;
|
||||||
|
if (footer_present) offset += 10;
|
||||||
|
DEBUG("ID3 tag length is %d bytes.\n", offset);
|
||||||
|
seek(offset);
|
||||||
|
} else {
|
||||||
|
DEBUG("No ID3 tag found\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -211,3 +211,12 @@ String HTTPClientWrapper::readUntil(String sep) {
|
|||||||
String HTTPClientWrapper::readLine() {
|
String HTTPClientWrapper::readLine() {
|
||||||
return readUntil("\n\r");
|
return readUntil("\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int HTTPClientWrapper::peek(int offset) {
|
||||||
|
if (_buffer_position >= _buffer_length) _fill_buffer();
|
||||||
|
|
||||||
|
if (_buffer_position + offset < 0 || _buffer_position + offset >= _buffer_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _buffer[_buffer_position + offset];
|
||||||
|
}
|
@ -9,9 +9,24 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||||
<script src="https://kit.fontawesome.com/272149490a.js" crossorigin="anonymous"></script>
|
<script src="https://kit.fontawesome.com/272149490a.js" crossorigin="anonymous"></script>
|
||||||
|
<style>
|
||||||
|
.overlay {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.85);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
margin: auto 0px;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: white;
|
||||||
|
font-size: 60px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div id="overlay" class="overlay">Not connected...</div>
|
||||||
<div class="container bg-dark text-light">
|
<div class="container bg-dark text-light">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
@ -104,7 +119,7 @@
|
|||||||
<input type="text" class="form-control" id="input_url" />
|
<input type="text" class="form-control" id="input_url" />
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button class="btn btn-primary" id="button_url_open">Go</button>
|
<button class="btn btn-primary" id="button_url_open">Go</button>
|
||||||
<button class="btn btn-danger" id="button_url_add_mapping" style="display: none;"><i class="fa fa-arrows-alt-h"></i></button>
|
<button class="btn btn-warning" id="button_url_add_mapping" style="display: none;"><i class="fa fa-arrows-alt-h"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -273,10 +288,30 @@ process_ws_message = function(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var play_on_click = true;
|
var play_on_click = true;
|
||||||
|
interval = null;
|
||||||
|
ws = null;
|
||||||
|
|
||||||
|
var start_reconnect_timer = function() {
|
||||||
|
console.log("start_reconnect_timer() running...");
|
||||||
|
$('#overlay').show();
|
||||||
|
interval = setInterval(connect_to_ws, 2500);
|
||||||
|
}
|
||||||
|
|
||||||
|
var connect_to_ws = function() {
|
||||||
|
if (!ws || ws.readyState >= ws.CLOSING) {
|
||||||
|
ws = new WebSocket("ws://" + location.host + "/ws");
|
||||||
|
ws.onopen = function() {
|
||||||
|
console.log("on_open() running...");
|
||||||
|
clearInterval(interval);
|
||||||
|
$('#overlay').hide();
|
||||||
|
};
|
||||||
|
ws.onmessage = process_ws_message;
|
||||||
|
ws.onclose = start_reconnect_timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
ws = new WebSocket("ws://" + location.host + "/ws");
|
start_reconnect_timer();
|
||||||
ws.onmessage = process_ws_message;
|
|
||||||
|
|
||||||
$('#volume_slider').change(function(e) { ws.send("volume=" + e.target.value); });
|
$('#volume_slider').change(function(e) { ws.send("volume=" + e.target.value); });
|
||||||
$('#button_play').click(function(e) { ws.send("play"); });
|
$('#button_play').click(function(e) { ws.send("play"); });
|
||||||
|
13
src/main.cpp
13
src/main.cpp
@ -4,6 +4,7 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiMulti.h>
|
#include <WiFiMulti.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
|
#include <Preferences.h>
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
@ -20,6 +21,10 @@ HTTPServer* http_server;
|
|||||||
|
|
||||||
uint8_t SPIMaster::state = 0;
|
uint8_t SPIMaster::state = 0;
|
||||||
|
|
||||||
|
bool debug_enabled = true;
|
||||||
|
bool trace_enabled = false;
|
||||||
|
Preferences prefs;
|
||||||
|
|
||||||
void wifi_connect() {
|
void wifi_connect() {
|
||||||
INFO("Connecting to WiFi...\n");
|
INFO("Connecting to WiFi...\n");
|
||||||
WiFiMulti wifi;
|
WiFiMulti wifi;
|
||||||
@ -69,6 +74,14 @@ void setup() {
|
|||||||
INFO("ESMP3, version unknown (OTA_VERSION %d)\n", OTA_VERSION);
|
INFO("ESMP3, version unknown (OTA_VERSION %d)\n", OTA_VERSION);
|
||||||
#endif
|
#endif
|
||||||
INFO("Initializing...\n");
|
INFO("Initializing...\n");
|
||||||
|
prefs.begin("esmp3");
|
||||||
|
debug_enabled = prefs.getBool("debug_enabled", true);
|
||||||
|
trace_enabled = prefs.getBool("trace_enabled", false);
|
||||||
|
|
||||||
|
PIN_SPEAKER_L_SETUP();
|
||||||
|
PIN_SPEAKER_R_SETUP();
|
||||||
|
PIN_SPEAKER_L(LOW);
|
||||||
|
PIN_SPEAKER_R(LOW);
|
||||||
|
|
||||||
DEBUG("Setting up SPI...\n");
|
DEBUG("Setting up SPI...\n");
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
|
@ -10,8 +10,6 @@ Player::Player(SPIMaster* s) {
|
|||||||
_spi = s;
|
_spi = s;
|
||||||
PIN_VS1053_XRESET_SETUP();
|
PIN_VS1053_XRESET_SETUP();
|
||||||
PIN_VS1053_XRESET(HIGH);
|
PIN_VS1053_XRESET(HIGH);
|
||||||
PIN_SPEAKER_L_SETUP();
|
|
||||||
PIN_SPEAKER_R_SETUP();
|
|
||||||
_speaker_off();
|
_speaker_off();
|
||||||
_spi->disable();
|
_spi->disable();
|
||||||
PIN_VS1053_DREQ_SETUP();
|
PIN_VS1053_DREQ_SETUP();
|
||||||
@ -534,6 +532,7 @@ bool Player::play() {
|
|||||||
if (_state != idle) return false;
|
if (_state != idle) return false;
|
||||||
if (_current_playlist == NULL) return false;
|
if (_current_playlist == NULL) return false;
|
||||||
if (_current_playlist->get_file_count()==0) return false;
|
if (_current_playlist->get_file_count()==0) return false;
|
||||||
|
_speaker_on();
|
||||||
_current_playlist->start();
|
_current_playlist->start();
|
||||||
String file;
|
String file;
|
||||||
if (!_current_playlist->get_current_file(&file)) {
|
if (!_current_playlist->get_current_file(&file)) {
|
||||||
|
@ -77,7 +77,6 @@ void Playlist::_examine_http_url(String url) {
|
|||||||
String ct = http->getContentType();
|
String ct = http->getContentType();
|
||||||
DEBUG("Content-Type is %s.\n", ct.c_str());
|
DEBUG("Content-Type is %s.\n", ct.c_str());
|
||||||
if (ct.startsWith("audio/x-mpegurl")) {
|
if (ct.startsWith("audio/x-mpegurl")) {
|
||||||
|
|
||||||
_parse_m3u(http);
|
_parse_m3u(http);
|
||||||
} else if (ct.startsWith("audio/")) {
|
} else if (ct.startsWith("audio/")) {
|
||||||
persistence = PERSIST_NONE;
|
persistence = PERSIST_NONE;
|
||||||
@ -108,37 +107,44 @@ void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t
|
|||||||
String tag(tagName);
|
String tag(tagName);
|
||||||
if (status & STATUS_START_TAG) xml_last_tag = tag;
|
if (status & STATUS_START_TAG) xml_last_tag = tag;
|
||||||
|
|
||||||
|
if (trace_enabled) {
|
||||||
|
if (status & STATUS_START_TAG) {
|
||||||
|
TRACE("Start of tag: %s\n", tagName);
|
||||||
|
} else if (status & STATUS_END_TAG) {
|
||||||
|
TRACE("End of tag: %s\n", tagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tag.equals("/rss/channel/title") && (status & STATUS_TAG_TEXT)) {
|
if (tag.equals("/rss/channel/title") && (status & STATUS_TAG_TEXT)) {
|
||||||
xml_album_title = data;
|
xml_album_title = data;
|
||||||
} else if (tag.endsWith("/item") && (status & STATUS_START_TAG)) {
|
} else if (tag.endsWith("/title") && (status & STATUS_TAG_TEXT)) {
|
||||||
xml_title = "";
|
|
||||||
xml_url = "";
|
|
||||||
xml_guid = "";
|
|
||||||
} else if (tag.endsWith("/item/title") && (status & STATUS_TAG_TEXT)) {
|
|
||||||
xml_title = String(data);
|
xml_title = String(data);
|
||||||
} else if (tag.endsWith("/item/guid") && (status & STATUS_TAG_TEXT)) {
|
} else if (tag.endsWith("/guid") && (status & STATUS_TAG_TEXT)) {
|
||||||
xml_guid = data;
|
xml_guid = data;
|
||||||
//} else if (xml_last_tag.endsWith("/item/enclosure") && (status & STATUS_ATTR_TEXT)) {
|
//} else if (xml_last_tag.endsWith("/item/enclosure") && (status & STATUS_ATTR_TEXT)) {
|
||||||
// DEBUG("tag: %s, data: %s\n", tag.c_str(), data);
|
// DEBUG("tag: %s, data: %s\n", tag.c_str(), data);
|
||||||
} else if (xml_last_tag.endsWith("/item/enclosure") && tag.equals("type") && (status & STATUS_ATTR_TEXT) && String(data).indexOf("audio/")>=0) {
|
} else if (xml_last_tag.endsWith("/enclosure") && tag.equals("type") && (status & STATUS_ATTR_TEXT) && String(data).indexOf("audio/")>=0) {
|
||||||
DEBUG("enclosure is audio\n");
|
DEBUG("enclosure is audio\n");
|
||||||
xml_enclosure_is_audio = true;
|
xml_enclosure_is_audio = true;
|
||||||
} else if (xml_last_tag.endsWith("/item/enclosure") && tag.equals("url") && (status & STATUS_ATTR_TEXT)) {
|
} else if (xml_last_tag.endsWith("/enclosure") && tag.equals("url") && (status & STATUS_ATTR_TEXT)) {
|
||||||
DEBUG("found url\n");
|
DEBUG("found url\n");
|
||||||
xml_enclosure_url = String(data);
|
xml_enclosure_url = String(data);
|
||||||
} else if (tag.endsWith("/item/enclosure") && (status & STATUS_END_TAG)) {
|
} else if (tag.endsWith("/enclosure") && (status & STATUS_END_TAG)) {
|
||||||
DEBUG("end of enclosure. xml_enclosure_is_audio: %d, xml_enclosure_url: %s\n", xml_enclosure_is_audio, xml_enclosure_url.c_str());
|
DEBUG("end of enclosure. xml_enclosure_is_audio: %d, xml_enclosure_url: %s\n", xml_enclosure_is_audio, xml_enclosure_url.c_str());
|
||||||
if (xml_enclosure_is_audio && xml_enclosure_url.length()>0) {
|
if (xml_enclosure_is_audio && xml_enclosure_url.length()>0) {
|
||||||
xml_url = xml_enclosure_url;
|
xml_url = xml_enclosure_url;
|
||||||
}
|
}
|
||||||
xml_enclosure_is_audio = false;
|
xml_enclosure_is_audio = false;
|
||||||
xml_enclosure_url = "";
|
xml_enclosure_url = "";
|
||||||
} else if (tag.endsWith("/item") && (status & STATUS_END_TAG)) {
|
} else if (tag.endsWith("/item") && (status & STATUS_END_TAG || status & STATUS_START_TAG)) {
|
||||||
if (xml_title.length()>0 && xml_url.length()>0) {
|
if (xml_title.length()>0 && xml_url.length()>0) {
|
||||||
if (xml_files_ptr->size() > 20) return;
|
if (xml_files_ptr->size() > 20) return;
|
||||||
DEBUG("Adding playlist entry: '%s' => '%s'\n", xml_title.c_str(), xml_url.c_str());
|
DEBUG("Adding playlist entry: '%s' => '%s'\n", xml_title.c_str(), xml_url.c_str());
|
||||||
xml_files_ptr->insert(xml_files_ptr->begin(), {.filename=xml_url, .title=xml_title, .id=xml_guid});
|
xml_files_ptr->insert(xml_files_ptr->begin(), {.filename=xml_url, .title=xml_title, .id=xml_guid});
|
||||||
}
|
}
|
||||||
|
xml_title = "";
|
||||||
|
xml_url = "";
|
||||||
|
xml_guid = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +184,7 @@ void Playlist::_parse_m3u(HTTPClientWrapper* http) {
|
|||||||
do {
|
do {
|
||||||
i = http->read();
|
i = http->read();
|
||||||
char c = i;
|
char c = i;
|
||||||
if (i>=-1 && c!='\r' && c!='\n') {
|
if (i>=0 && c!='\r' && c!='\n') {
|
||||||
line += c;
|
line += c;
|
||||||
} else {
|
} else {
|
||||||
if (line.equals("#EXTM3U")) {
|
if (line.equals("#EXTM3U")) {
|
||||||
|
Loading…
Reference in New Issue
Block a user