be9229b80d
- Extracted app_context (global AppCtx G definition) - storage: path helpers, LRU, sort, fmt_time, per-episode resume map, state persistence - network: resolve_host, normalize URL, http_get_raw with growing PSRAM buffer, fetch_data - download: dl_ep_raw with progress tracking, cancel, overlay UI (show/hide/update) - player: audio device, stream, play_task with resume seek, start/select/next/prev with position save/restore - ui: build_ui, timers, season picker, button callbacks, periodic save - main: minimal glue, fetch_task, onShow/onHide, app registration - Preserves all previous fixes: download progress overlay, per-episode resume, robust download handling - Build verified: 111 undef, all exported
122 lines
3.5 KiB
C
122 lines
3.5 KiB
C
#include <tt_app.h>
|
||
#include <tt_lvgl.h>
|
||
#include "app_context.h"
|
||
#include "storage.h"
|
||
#include "network.h"
|
||
#include "download.h"
|
||
#include "player.h"
|
||
#include "ui.h"
|
||
|
||
#include <string.h>
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include "esp_log.h"
|
||
|
||
static void fetch_task_fn(void* arg){
|
||
(void)arg;
|
||
G.fetching=true;
|
||
ESP_LOGI(TAG,"fetch task start");
|
||
fetch_data();
|
||
ESP_LOGI(TAG,"fetch done seasons=%d eps=%d",G.season_cnt,G.ep_cnt);
|
||
if(strlen(G.last_slug)>0){
|
||
for(int i=0;i<G.ep_cnt;i++) if(strcmp(G.eps[i].slug,G.last_slug)==0){ G.cur_ep_idx=i; G.cur_season=G.eps[i].season; break; }
|
||
}
|
||
if(G.cur_ep_idx<0){
|
||
int s1=-1;
|
||
for(int i=0;i<G.ep_cnt;i++) if(G.eps[i].season==G.cur_season){ s1=i; break; }
|
||
if(s1==-1) s1=0;
|
||
G.cur_ep_idx=s1;
|
||
}
|
||
tt_lvgl_lock(portMAX_DELAY);
|
||
if(G.ep_cnt>0 && G.cur_ep_idx>=0){
|
||
EpInfo* ep=&G.eps[G.cur_ep_idx];
|
||
int saved = get_saved_pos_for_slug(ep->slug);
|
||
if(saved==0) saved = G.pos_sec;
|
||
if(G.lbl_title) lv_label_set_text(G.lbl_title,ep->title);
|
||
if(G.lbl_meta){
|
||
char b[64];
|
||
if(saved>5){
|
||
char tbuf[16];
|
||
fmt_time(tbuf,saved);
|
||
snprintf(b,sizeof(b),"S%02d E%02d %s • %s",ep->season,ep->ep_num,ep->seen?"*":"",tbuf);
|
||
} else {
|
||
snprintf(b,sizeof(b),"S%02d E%02d %s",ep->season,ep->ep_num,ep->seen?"*":"");
|
||
}
|
||
lv_label_set_text(G.lbl_meta,b);
|
||
}
|
||
if(G.lbl_status){
|
||
if(saved>5) lv_label_set_text(G.lbl_status,"Resume – tap Play");
|
||
else lv_label_set_text(G.lbl_status,ep->seen?"On SD – tap Play":"Tap Play to DL");
|
||
}
|
||
if(G.bar) lv_bar_set_value(G.bar,0,LV_ANIM_OFF);
|
||
if(G.lbl_time){
|
||
if(saved>5){
|
||
char a[16];
|
||
fmt_time(a,saved);
|
||
char buf[40];
|
||
snprintf(buf,sizeof(buf),"%s / --:--",a);
|
||
lv_label_set_text(G.lbl_time,buf);
|
||
} else {
|
||
lv_label_set_text(G.lbl_time,"0:00 / --:--");
|
||
}
|
||
}
|
||
if(saved>0) G.pos_sec=saved;
|
||
} else {
|
||
if(G.lbl_status) lv_label_set_text(G.lbl_status,"No data");
|
||
}
|
||
tt_lvgl_unlock();
|
||
G.fetching=false;
|
||
G.fetch_handle=NULL;
|
||
save_state();
|
||
vTaskDelete(NULL);
|
||
}
|
||
|
||
static void onShow(AppHandle app, void* data, lv_obj_t* parent){
|
||
(void)app; (void)data; (void)parent;
|
||
memset(&G,0,sizeof(G));
|
||
G.pos_sec=0;
|
||
G.total_sec=0;
|
||
G.cur_season=1;
|
||
G.cur_ep_idx=-1;
|
||
G.volume=80;
|
||
G.last_pct=-1;
|
||
G.dl_last_pct=-1;
|
||
G.dl_expected=-1;
|
||
ensure_dir();
|
||
load_state();
|
||
build_ui();
|
||
xTaskCreate(fetch_task_fn,"dm_fetch",16384,NULL,5,&G.fetch_handle);
|
||
}
|
||
|
||
static void onHide(AppHandle app, void* data){
|
||
(void)app; (void)data;
|
||
save_current_ep_pos();
|
||
tt_lvgl_lock(portMAX_DELAY);
|
||
if(G.fetch_handle){
|
||
vTaskDelete(G.fetch_handle);
|
||
G.fetch_handle=NULL;
|
||
G.fetching=false;
|
||
}
|
||
if(G.dl_handle){
|
||
G.dl_cancel_req=true;
|
||
vTaskDelay(pdMS_TO_TICKS(100));
|
||
if(G.dl_handle){
|
||
vTaskDelete(G.dl_handle);
|
||
G.dl_handle=NULL;
|
||
G.downloading=false;
|
||
if(G.dl_overlay) hide_dl_overlay();
|
||
}
|
||
}
|
||
wait_play_exit();
|
||
close_overlay();
|
||
if(G.dl_overlay) hide_dl_overlay();
|
||
tt_lvgl_unlock();
|
||
save_state();
|
||
}
|
||
|
||
int main(int argc, char* argv[]){
|
||
(void)argc; (void)argv;
|
||
tt_app_register((AppRegistration){ .onShow=onShow, .onHide=onHide });
|
||
return 0;
|
||
}
|