From 0c996d6836defcc190a4f071437d95cb1f5140cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Mon, 4 Apr 2022 01:22:58 +0200 Subject: Rewrite episode data code. TODO: Ignore duplicate hints. --- c/datalistview.c | 77 +++++++++++++++++++------------------------------ c/episodelistview.c | 18 +++++++----- pl/episode_data.pl | 83 ++++++++++++++++++++++------------------------------- 3 files changed, 76 insertions(+), 102 deletions(-) diff --git a/c/datalistview.c b/c/datalistview.c index fe16913..829f6d6 100644 --- a/c/datalistview.c +++ b/c/datalistview.c @@ -36,6 +36,7 @@ DlvShowEpisode(int iEpisode) { LVITEM lviKey, lviValue; term_t t; + qid_t q; ListView_DeleteAllItems(HDlv); @@ -44,54 +45,36 @@ DlvShowEpisode(int iEpisode) t = T(3); PI(t,iEpisode) return; - P("episode_data","lookup_episode_local",3,t) return; - - /* The episode data is a list of unary compounds, whose - * functor is the key and whose argument is the value. - * (Perhaps this should really be implemented in Prolog.) */ - - { - term_t tHead, tList; - - tHead = PL_new_term_ref(); - tList = PL_copy_term_ref(t+2); - - for (int i = 0; PL_get_list(tList, tHead, tList); i++) { - atom_t aKey; - const char *szKey; - char *szValue; - TCHAR *tszKey, *tszValue; - term_t tValue; - size_t iArity; - - if (!PL_get_name_arity(tHead,&aKey,&iArity)) continue; - szKey = PL_atom_chars(aKey); - if (!szKey) continue; - - tValue = PL_new_term_ref(); - if (!PL_get_arg(1, tHead, tValue)) continue; - GAC(tValue,&szValue) continue; - - tszKey = TszFromSz(szKey, CP_UTF8); - if (!tszKey) continue; - tszValue = TszFromSz(szValue, CP_UTF8); - if (!tszValue) goto c; - - lviKey.mask = LVIF_TEXT; - lviKey.iItem = i; - lviKey.iSubItem = 0; - lviKey.pszText = tszKey; - ListView_InsertItem(HDlv, &lviKey); - - lviValue.iItem = i; - lviValue.iSubItem = 1; - lviValue.pszText = tszValue; - ListView_SetItem(HDlv, &lviValue); - - free(tszValue); - c: free(tszKey); - } + q = Q("episode_data","episode_datum",3,t); + + for (int i = 0; Qn(q); i++) { + char *szKey; + char *szValue; + TCHAR *tszKey, *tszValue; + + GAC(t+1,&szKey) continue; + GAC(t+2,&szValue) continue; + + tszKey = TszFromSz(szKey, CP_UTF8); + if (!tszKey) continue; + tszValue = TszFromSz(szValue, CP_UTF8); + if (!tszValue) goto c; + + lviKey.mask = LVIF_TEXT; + lviKey.iItem = i; + lviKey.iSubItem = 0; + lviKey.pszText = tszKey; + ListView_InsertItem(HDlv, &lviKey); + + lviValue.iItem = i; + lviValue.iSubItem = 1; + lviValue.pszText = tszValue; + ListView_SetItem(HDlv, &lviValue); + + free(tszValue); + c: free(tszKey); } + Qc(q); UpdateLayout(); } diff --git a/c/episodelistview.c b/c/episodelistview.c index 0a85635..1389f53 100644 --- a/c/episodelistview.c +++ b/c/episodelistview.c @@ -175,6 +175,7 @@ ElvUpdate() lviName.mask = LVIF_TEXT; t = T(1); + P("episode_data","ensure_episode_data",0,t) return; P("episode_data","episode_count",1,t) return; GI(t,&iEpisodes) return; @@ -182,15 +183,15 @@ ElvUpdate() char *szName; int cb; TCHAR *tszEpisode, *tszName; - term_t t2; + term_t t; /* Format name string. */ - t2 = T(3); - PI(t2,i+1) return; + t = T(2); + PI(t,i+1) return; tszName = NULL; - P("episode_data","lookup_episode_local",3,t2) goto ep; - GAC(t2+1,&szName) goto ep; + P("episode_data","episode_title",2,t) goto ep; + GAC(t+1,&szName) goto ep; tszName = TszFromSz(szName, CP_UTF8); if (!tszName) return; @@ -239,9 +240,12 @@ ElvUpdateName(LPLVITEM lpLvi) TCHAR *tszName; term_t t; - t = T(3); + t = T(2); PI(t,lpLvi->lParam) return; - P("episode_data","lookup_episode",3,t) return; + P("episode_data","episode_title",2,t) { + P("episode_data","fetch_episode_data",0,t) return; + P("episode_data","episode_title",2,t) return; + } GAC(t+1,&szName) return; tszName = TszFromSz(szName, CP_UTF8); diff --git a/pl/episode_data.pl b/pl/episode_data.pl index 1d8fdef..08201f7 100644 --- a/pl/episode_data.pl +++ b/pl/episode_data.pl @@ -1,8 +1,6 @@ -:- module(episode_data, [retract_episode/1, - episode_count/1, - lookup_episode/3, - lookup_episode_local/3, - lookup_episode_remote/3]). +:- module(episode_data, [ensure_episode_data/0, + retract_episode/1, + episode_count/1]). :- use_module(library(clpfd)). :- use_module(library(dcg/basics)). @@ -12,7 +10,8 @@ :- use_module(library(persistency)). :- use_module(atom_dcg). -:- persistent episode_name_data(episode:integer, name:atom, data:list). +:- persistent episode_title(episode:integer, title:atom). +:- persistent episode_datum(episode:integer, key:atom, value:atom). attach :- absolute_file_name('episode_data.db', F, [access(write)]), @@ -21,29 +20,24 @@ attach :- detach :- db_detach. -% Interface. - -episode_count(N) :- - ensure, - setof(E, N^D^lookup_episode_local(E,N,D), Es), - last(Es, N). - -lookup_episode(Ep, Name, Data) :- lookup_episode_local(Ep, Name, Data), !. -lookup_episode(Ep, Name, Data) :- lookup_episode_remote(Ep, Name, Data). - -lookup_episode_local(Ep, Name, Data) :- - episode_name_data(Ep, Name, Data). -lookup_episode_remote(Ep, Name, Data) :- - update, !, - episode_name_data(Ep, Name, Data). +ensure_episode_data :- episode_title(Ep, _), !. +ensure_episode_data :- fetch_episode_data. retract_episode(Ep) :- - ( episode_name_data(Ep, _, _) - -> retractall_episode_name_data(Ep, _, _) + ( episode_title(Ep, _) + -> retractall_episode_title(Ep, _) + ; true + ), + ( episode_datum(Ep, 'Hint', _) + -> retractall_episode_datum(Ep, 'Hint', _) ; true ). -% Parsing. +episode_count(N) :- + setof(E, T^episode_title(E,T), Es), + last(Es, N). + +% Remote data retrieval. padding(Ep) --> { Ep #< 10 }, "00". padding(Ep) --> { Ep #>= 10, Ep #< 100 }, "0". @@ -52,22 +46,20 @@ padding(Ep) --> { Ep #>= 100 }. episode_number(Ep) --> padding(Ep), integer(Ep). episode_number(Ep) --> padding(Ep), integer(Ep), "WPS", integer(_). -% Database updating. - -ensure :- episode_name_data(_, _, _), !. -ensure :- update. - -update :- - findall(Ep-Name-Data, (remote_row(R), - row_episode(R, Ep), - row_episode_name_data(R, Ep, Name, Data)), - ENDs), !, - maplist(update, ENDs). - -update(Ep-Name-Data) :- episode_name_data(Ep, Name, Data), !. -update(Ep-Name-Data) :- assert_episode_name_data(Ep, Name, Data). - -% Remote retrieval. +fetch_episode_data :- + findall(Ep-Title-Hint, + (remote_row(R), + row_episode_title_hint(R, Ep, Title, Hint)), + Data), + maplist(set_episode_data, Data). + +set_episode_data(Ep-Title-Hint) :- + ( episode_title(Ep, Title), ! + ; assert_episode_title(Ep, Title) + ), + ( episode_datum(Ep, 'Hint', Hint), ! + ; assert_episode_datum(Ep, 'Hint', Hint) + ). remote_row(R) :- catch(http_load_html( @@ -77,16 +69,11 @@ remote_row(R) :- fail), !, xpath(R0, //tr, R). -row_episode(R, Ep) :- - xpath(R, td(index(1),text), T), - atom_phrase(episode_number(Ep), T). - -row_episode_name_data(R, Ep, Name, Data) :- +row_episode_title_hint(R, Ep, Title, Hint) :- xpath(R, td(index(1),text), T), atom_phrase(episode_number(Ep), T), - xpath(R, td(index(2),text), Name), - xpath(R, td(index(3),text), Hint), - Data = ['Hint'(Hint)]. + xpath(R, td(index(2),text), Title), + xpath(R, td(index(3),text), Hint). http_load_html(URL, DOM) :- setup_call_cleanup(http_open(URL, In, -- cgit v1.2.3