Play position in stuff like podcasts can now be permanently persisted.

This commit is contained in:
2019-11-29 17:41:16 +01:00
parent 076f0e9dfd
commit 65118fbc42
5 changed files with 121 additions and 9 deletions

View File

@ -613,7 +613,8 @@ void Player::stop(bool turn_speaker_off) {
if (_state != playing) return;
INFO("Stopping...\n");
_current_playlist->set_position(_current_play_position);
_controller->pm->persist(_current_playlist);
_state = stopping;
_stop_delay = 0;
_write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL);

View File

@ -7,7 +7,9 @@
#include <TinyXML.h>
Playlist::Playlist(String path) {
_path = path;
if (path.startsWith("/")) {
persistence = PERSIST_TEMPORARY;
_add_path(path);
} else if (path.startsWith("http")) {
_examine_http_url(path);
@ -44,7 +46,7 @@ void Playlist::_add_path(String path) {
ext.equals(".mpa"))) {
TRACE(" Adding entry %s\n", entry.name());
String title = filename.substring(0, filename.length() - 4);
_files.push_back({.filename=entry.name(), .title=title});
_files.push_back({.filename=entry.name(), .title=title, .id=String(_files.size())});
bool non_ascii_chars = false;
for(int i=0; i<filename.length(); i++) {
char c = filename.charAt(i);
@ -75,12 +77,16 @@ void Playlist::_examine_http_url(String url) {
String ct = http->getContentType();
DEBUG("Content-Type is %s.\n", ct.c_str());
if (ct.startsWith("audio/x-mpegurl")) {
_parse_m3u(http);
} else if (ct.startsWith("audio/")) {
_files.push_back({.filename=url, .title=url});
persistence = PERSIST_NONE;
_files.push_back({.filename=url, .title=url, .id="none"});
} else if (ct.startsWith("application/rss+xml")) {
persistence = PERSIST_PERMANENTLY;
_parse_rss(http);
} else if (ct.startsWith("application/pls+xml")) {
persistence = PERSIST_PERMANENTLY;
_parse_pls(http);
} else {
ERROR("Unknown content type %s.\n", ct.c_str());
@ -95,6 +101,7 @@ String xml_title = "";
String xml_album_title = "";
String xml_url = "";
String xml_enclosure_url = "";
String xml_guid = "";
bool xml_enclosure_is_audio = false;
void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t dataLen) {
@ -106,8 +113,11 @@ void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t
} else if (tag.endsWith("/item") && (status & STATUS_START_TAG)) {
xml_title = "";
xml_url = "";
xml_guid = "";
} else if (tag.endsWith("/item/title") && (status & STATUS_TAG_TEXT)) {
xml_title = String(data);
} else if (tag.endsWith("/item/guid") && (status & STATUS_TAG_TEXT)) {
xml_guid = data;
//} else if (xml_last_tag.endsWith("/item/enclosure") && (status & STATUS_ATTR_TEXT)) {
// 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) {
@ -126,7 +136,7 @@ void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t
} else if (tag.endsWith("/item") && (status & STATUS_END_TAG)) {
if (xml_title.length()>0 && xml_url.length()>0) {
DEBUG("Adding playlist entry: '%s' => '%s'\n", xml_title.c_str(), xml_url.c_str());
xml_files_ptr->push_back({xml_url, xml_title});
xml_files_ptr->insert(xml_files_ptr->begin(), {.filename=xml_url, .title=xml_title, .id=xml_guid});
}
}
}
@ -180,7 +190,7 @@ void Playlist::_parse_m3u(HTTPClientWrapper* http) {
}
} else if (line.startsWith("http")) {
if (title.length()==0) title = line;
_files.push_back({.filename=line, .title=title});
_files.push_back({.filename=line, .title=title, .id="none"});
title = "";
}
line = "";
@ -222,7 +232,7 @@ void Playlist::_parse_pls(HTTPClientWrapper* http) {
}
if (title.length()>0 && url.length()>0) {
_files.push_back({.filename=url, .title=title});
_files.push_back({.filename=url, .title=title, .id="none"});
last_index = -1;
title = "";
url = "";
@ -231,6 +241,10 @@ void Playlist::_parse_pls(HTTPClientWrapper* http) {
// don't close http at the end
}
String Playlist::path() {
return _path;
}
uint16_t Playlist::get_file_count() {
return _files.size();
}
@ -274,6 +288,15 @@ bool Playlist::set_track(uint8_t track) {
return false;
}
void Playlist::set_track_by_id(String id) {
for (int i=0; i<_files.size(); i++) {
if (id.equals(_files[i].id)) {
set_track(i);
return;
}
}
}
void Playlist::track_restart() {
_position = 0;
}
@ -310,8 +333,15 @@ void Playlist::reset() {
_started = false;
}
String Playlist::get_current_track_id() {
if (_current_track > _files.size()) {
return "";
}
return _files[_current_track].id;
}
bool Playlist::get_current_file(String* dst) {
if (_current_track < _files.size()) {
if (_current_track > _files.size()) {
return false;
} else {
dst->concat(_files[_current_track].filename);

View File

@ -104,10 +104,41 @@ Playlist* PlaylistManager::get_playlist_for_id(String id) {
}
Playlist* PlaylistManager::get_playlist_for_folder(String folder) {
Playlist* p;
if (!_playlists.count(folder)) {
_playlists[folder] = new Playlist(folder);
p = new Playlist(folder);
_playlists[folder] = p;
if (p->persistence == PERSIST_PERMANENTLY) {
// TODO Load persistence from file
String search = folder;
search += "=";
SPIMaster::select_sd();
if (SD.exists("/_positions.txt")) {
File f = SD.open("/_positions.txt", "r");
while (true) {
String s = f.readStringUntil('\n');
if (s.length()==0) break;
if (s.startsWith(search)) {
s = s.substring(search.length());
int idx = s.indexOf(',');
String title_index = s.substring(0, idx);
uint32_t position = s.substring(idx+1).toInt();
p->set_track_by_id(title_index);
p->set_position(position);
break;
}
}
f.close();
}
SPIMaster::select_sd(false);
}
} else {
p = _playlists[folder];
if (p->persistence == PERSIST_NONE) {
p->reset();
}
}
return _playlists[folder];
return p;
}
void PlaylistManager::dump_ids() {
@ -164,3 +195,40 @@ String PlaylistManager::create_mapping_txt() {
}
return s;
}
void PlaylistManager::persist(Playlist* p) {
if (p->persistence != PERSIST_PERMANENTLY) return;
String search = p->path();
search += '=';
bool old_file_existed = false;
SPIMaster::select_sd();
if (SD.exists("_positions.txt")) {
SD.rename("/_positions.txt", "/_positions.temp.txt");
old_file_existed = true;
}
File dst = SD.open("/_positions.txt", "w");
if (old_file_existed) {
File src = SD.open("/_positions.temp.txt", "r");
while (true) {
String line = src.readStringUntil('\n');
line.trim();
if (line.startsWith(search)) continue;
dst.println(line);
}
src.close();
SD.remove("/_positions.temp.txt");
}
dst.print(search);
dst.print(p->get_current_track_id());
dst.print(',');
dst.println(p->get_position());
dst.close();
SPIMaster::select_sd(false);
}