diff options
Diffstat (limited to 'pl')
-rw-r--r-- | pl/atom_dcg.pl | 11 | ||||
-rw-r--r-- | pl/episode_data.pl | 68 | ||||
-rw-r--r-- | pl/local_episodes.pl | 31 | ||||
-rw-r--r-- | pl/track_episodes.pl | 96 |
4 files changed, 206 insertions, 0 deletions
diff --git a/pl/atom_dcg.pl b/pl/atom_dcg.pl new file mode 100644 index 0000000..74689d5 --- /dev/null +++ b/pl/atom_dcg.pl @@ -0,0 +1,11 @@ +:- module(atom_dcg, [atom_phrase/2]). + +:- meta_predicate atom_phrase(2, ?). + +atom_phrase(G, A) :- + ( var(A) + -> phrase(G, C), + atom_codes(A, C) + ; atom_codes(A, C), + phrase(G, C) + ). diff --git a/pl/episode_data.pl b/pl/episode_data.pl new file mode 100644 index 0000000..49dddd0 --- /dev/null +++ b/pl/episode_data.pl @@ -0,0 +1,68 @@ +:- module(episode_data, [retract_episode/1, + lookup_episode/3, + lookup_episode_local/3, + lookup_episode_remote/3]). + +:- use_module(library(dcg/basics)). +:- use_module(library(http/http_open)). +:- use_module(library(sgml)). +:- use_module(library(xpath)). +:- use_module(library(persistency)). +:- use_module(atom_dcg). + +:- persistent episode_name_data(episode:integer, name:atom, data:list). + +attach :- + absolute_file_name('episode_data.db', F, [access(write)]), + db_attach(F, []). + +detach :- + db_detach. + +retract_episode(Ep) :- + ( episode_name_data(Ep, _, _) + -> retractall_episode_name_data(Ep, _, _) + ; true + ). + +padding(Ep) --> { Ep < 10 }, "00". +padding(Ep) --> { Ep >= 10, Ep < 100 }, "0". +padding(Ep) --> { Ep >= 100 }. + +episode_number(Ep) --> padding(Ep), integer(Ep). + +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) :- + catch(http_load_html( + 'https://www.detectiveconanworld.com/wiki/Next_Conan%27s_Hint', + D), + _, + fail), + xpath(D, //tr, D1), + xpath(D1, td(index(1),text), T), + atom_phrase(episode_number(Ep), T), + xpath(D1, td(index(2),text), Name), + xpath(D1, td(index(3),text), Hint), + Data = [hint(Hint)], + assert_episode_name_data(Ep, Name, Data). + +http_load_html(URL, DOM) :- + setup_call_cleanup(http_open(URL, In, + [ timeout(60) + ]), + ( dtd(html, DTD), + load_structure(stream(In), + DOM, + [ dtd(DTD), + dialect(sgml), + shorttag(false), + max_errors(-1), + syntax_errors(quiet) + ]) + ), + close(In)). diff --git a/pl/local_episodes.pl b/pl/local_episodes.pl new file mode 100644 index 0000000..283ccb7 --- /dev/null +++ b/pl/local_episodes.pl @@ -0,0 +1,31 @@ +:- module(local_episodes, [local_episode//1, + episode_file/2, + open_episode/1]). + +:- use_module(library(dcg/basics)). +:- use_module(atom_dcg). + +local_episode --> + local_episode(_). +local_episode(N) --> + string(_), "Detective_Conan_-_", integer(N), string(_). +local_episode(N) --> + string(_), "Detective_Conan_-_", + integer(First), "-", integer(Last), string(_), + { Second is First + 1, between(Second, Last, N) }. + +% Find episode on disk. + +episode_file(N, F) :- + expand_file_name('C:/Users/John/Nedladdningar/Detective Conan season 1 to season 22 + season 23(incomplete)/*/*.*', + F1), + ( nonvar(N) + -> include(atom_phrase(local_episode(N)), F1, [F|_]) + ; include(atom_phrase(local_episode), F1, F2), + member(F, F2), + atom_phrase(local_episode(N), F) + ). + +open_episode(N) :- + episode_file(N, F), + win_shell(open, F). diff --git a/pl/track_episodes.pl b/pl/track_episodes.pl new file mode 100644 index 0000000..ec1785b --- /dev/null +++ b/pl/track_episodes.pl @@ -0,0 +1,96 @@ +:- module(track_episodes, [update_tracked_episodes/0, + toggle_episode/1, + forget_episode/1, + most_recently_watched/1, + watched/1]). + +:- use_module(library(dcg/basics)). +:- use_module(library(registry)). +:- use_module(library(persistency)). +:- use_module(local_episodes). + +attach :- + absolute_file_name('track_episodes.db', F, [access(write)]), + db_attach(F, []). + +detach :- + db_detach. + +:- persistent episode_watched(episode:integer, watched:atom). + +% Helpers. + +swapbc(P, A, B, C, D) :- call(P, A, C, B, D). +compound(F, A, B, T) :- T =.. [F, A, B]. + +% Get data from registry. + +file(N) --> "File Name ", integer(N). + +pos(N) --> "File Position ", integer(N). + +mpc_reg(Phrase, Value) :- + phrase(Phrase, Name), + atom_codes(Name1, Name), + registry_get_key(current_user/software/'mpc-hc'/'mpc-hc'/settings, + Name1, Value). + +% Create episode-position list. + +epipos(L) :- epipos_x(0, L). + +epipos_x(N, L) :- + ( catch((mpc_reg(file(N), File), + mpc_reg(pos(N), Pos)), + _, + fail) + -> M is N + 1, + ( atom_codes(File, File1), + findall(Ep, phrase(local_episode(Ep), File1), Eps) + -> atom_codes(Pos, Pos1), + phrase(integer(Pos2), Pos1), + maplist(swapbc(compound, '-', Pos2), Eps, Eps1), + append(Eps1, T, L), + epipos_x(M, T) + ; epipos_x(M, L)) + ; L = [] + ). + +considered_watched(_-Pos) :- + Pos > 11000000000. + +% Update database. + +update_tracked_episodes :- + epipos(All), + include(considered_watched, All, Watched), + maplist(add, Watched). + +add(Ep-_) :- episode_watched(Ep, _), !. +add(Ep-_) :- assert_episode_watched(Ep, true). + +forget_episode(Ep) :- + retractall_episode_watched(Ep, true), + retractall_episode_watched(Ep, false). + +toggle_episode(Ep) :- + episode_watched(Ep, true), !, + retractall_episode_watched(Ep, true), + assert_episode_watched(Ep, false). + +toggle_episode(Ep) :- + episode_watched(Ep, false), !, + retractall_episode_watched(Ep, false), + assert_episode_watched(Ep, true). + +toggle_episode(Ep) :- + assert_episode_watched(Ep, true). + +% Utility. + +most_recently_watched(Ep) :- + findall(N, episode_watched(N, true), All), + sort(0, @>, All, [Ep|_]). + +watched(Ep) :- + episode_watched(Ep, true). |