aboutsummaryrefslogtreecommitdiff
path: root/pl
diff options
context:
space:
mode:
Diffstat (limited to 'pl')
-rw-r--r--pl/atom_dcg.pl11
-rw-r--r--pl/episode_data.pl68
-rw-r--r--pl/local_episodes.pl31
-rw-r--r--pl/track_episodes.pl96
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).