aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-08-22 22:22:29 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-08-22 22:22:29 +0200
commit5d0979480ff50390b3883795ec2093e0d3d6193b (patch)
tree34a5fc5d18cb2d9cc87c01e6eb2eb40e0f3d5050
parent8566655b85f0a4e515d57f6686636db516116f95 (diff)
downloadEpisodeBrowser-5d0979480ff50390b3883795ec2093e0d3d6193b.tar.gz
Open episodes without Prolog.
-rw-r--r--c/episodelistview.cpp12
-rw-r--r--c/ext.cpp132
-rw-r--r--c/ext.h8
-rw-r--r--c/resource.rc2
-rw-r--r--c/test.cpp3
-rw-r--r--c/util.h22
-rw-r--r--c/win.h9
7 files changed, 165 insertions, 23 deletions
diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp
index 6caff99..14aa192 100644
--- a/c/episodelistview.cpp
+++ b/c/episodelistview.cpp
@@ -7,6 +7,7 @@
#include "data.h"
#include "datalistview.h"
#include "episodelistview.h"
+#include "ext.h"
#include "listview.h"
#include "pl.h"
#include "util.h"
@@ -68,25 +69,20 @@ void EpisodeListView::HandleContextMenu(const WORD command)
/* Process other commands. */
switch (command) {
case IDM_WATCH_LOCALLY:
- if (!Pl("local_episode","open_episode_locally",lvi.lParam))
+ if(!OpenLocally(lvi.lParam))
cNotFound++;
break;
case IDM_WATCH_ONLINE:
- Pl("local_episode","open_episode_online",lvi.lParam);
+ OpenOnline(lvi.lParam);
break;
case IDM_TOGGLE:
e.bWatched = !e.bWatched;
break;
- case IDM_FORGET:
- Pl("track_episodes","forget_episode",lvi.lParam);
- Pl("track_episodes","update_tracked_episodes");
- break;
-
case IDM_WIKI:
- Pl("episode_data","open_episode_wiki",lvi.lParam);
+ OpenWiki(lvi.lParam);
break;
}
}
diff --git a/c/ext.cpp b/c/ext.cpp
new file mode 100644
index 0000000..f485dce
--- /dev/null
+++ b/c/ext.cpp
@@ -0,0 +1,132 @@
+#include <ctype.h>
+#include <string>
+#include <string_view>
+
+#include "data.h"
+
+extern CfgA& g_cfg;
+extern FileView<ElvDataA> g_fvElv;
+extern FileView<DlvDataA> g_fvDlv;
+
+void OpenOnline(int iEp)
+{
+ wchar_t url[sizeof(g_cfg.url)+4];
+ Swprintf(url, L"%s%d", g_cfg.url, iEp);
+ INT_PTR r = reinterpret_cast<INT_PTR>(
+ ShellExecute(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL));
+ if (r <= 32)
+ throw Win32Error();
+}
+
+void OpenWiki(int iEp)
+{
+ const DlvDataA& d = g_fvDlv.At(iEp-1);
+ wchar_t url[sizeof(d.wiki)+35];
+ Swprintf(url, L"https://www.detectiveconanworld.com%s", d.wiki);
+ INT_PTR r = reinterpret_cast<INT_PTR>(
+ ShellExecute(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL));
+ if (r <= 32)
+ throw Win32Error();
+}
+
+static inline bool MatchFileName(wchar_t (&file)[MAX_PATH], const wchar_t* const siEp) noexcept
+{
+ /* This is a hand-written parser that matches file names of
+ * the type "Detective Conan - 010.mkv". */
+
+ wchar_t* f = file;
+
+ /* Match Detective Conan prefix. */
+ if (*f != L'D' && *f != L'd')
+ return false;
+ f++;
+
+ if (wcsncmp(f, L"etective", 8) != 0)
+ return false;
+ f += 8;
+
+ if (*f != L' ' && *f != L'_' && *f != L'-')
+ return false;
+ f++;
+
+ if (*f != L'C' && *f != L'c')
+ return false;
+ f++;
+
+ if (wcsncmp(f, L"onan", 4) != 0)
+ return false;
+ f += 4;
+
+ /* Match garbage before episode number. */
+ while (*f == L' ' || *f == L'_' || *f == L'-' || *f == L'0')
+ f++;
+
+ /* Match episode number. */
+ size_t lenEp = wcslen(siEp);
+ if (wcsncmp(f, siEp, lenEp) != 0)
+ return false;
+ f += lenEp;
+
+ if (isdigit(*f))
+ return false;
+
+ return true;
+}
+
+static bool FindMatchingFile(wchar_t (&file)[MAX_PATH], const wchar_t* const root,
+ const wchar_t* const siEp, const int level = 0)
+{
+ /* Don't recurse too much. */
+ if (level > 3)
+ return false;
+
+ wchar_t pat[MAX_PATH];
+ Swprintf(pat, L"%s\\*", root);
+
+ WIN32_FIND_DATA fdata;
+ HANDLE hf = FindFirstFile(pat, &fdata);
+ if (hf == INVALID_HANDLE_VALUE)
+ throw Win32Error().what();
+
+ do {
+ if (fdata.cFileName[0] == L'.')
+ continue;
+ if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* Recurse into directory. */
+ wchar_t root2[MAX_PATH];
+ Swprintf(root2, L"%s\\%s", root, fdata.cFileName);
+ try {
+ if (FindMatchingFile(file, root2, siEp, level+1))
+ return true;
+ } catch (...) {
+ FindClose(hf);
+ throw;
+ }
+ }
+ else /* Try to match file name. */
+ if (MatchFileName(fdata.cFileName, siEp)) {
+ Swprintf(file, L"%s\\%s", root, fdata.cFileName);
+ return true;
+ }
+ } while (FindNextFile(hf, &fdata));
+
+ DWORD e = GetLastError();
+ FindClose(hf);
+ if (e != ERROR_NO_MORE_FILES)
+ throw Win32Error(e);
+
+ return false;
+}
+
+bool OpenLocally(int iEp)
+{
+ wchar_t file[MAX_PATH];
+ if (FindMatchingFile(file, g_cfg.root, g_fvElv.At(iEp-1).siEp)) {
+ INT_PTR r = reinterpret_cast<INT_PTR>(
+ ShellExecute(nullptr, L"open", file, nullptr, nullptr, SW_SHOWNORMAL));
+ if (r <= 32)
+ throw Win32Error();
+ return true;
+ } else
+ return false;
+}
diff --git a/c/ext.h b/c/ext.h
new file mode 100644
index 0000000..3f9ddbd
--- /dev/null
+++ b/c/ext.h
@@ -0,0 +1,8 @@
+#ifndef EXT_H
+#define EXT_H
+
+bool OpenOnline(int iEp);
+bool OpenWiki(int iEp);
+bool OpenLocally(int iEp);
+
+#endif
diff --git a/c/resource.rc b/c/resource.rc
index 102f627..2b7a9a7 100644
--- a/c/resource.rc
+++ b/c/resource.rc
@@ -34,8 +34,6 @@ BEGIN
MENUITEM "&Watch Locally", IDM_WATCH_LOCALLY
MENUITEM "Watch &Online", IDM_WATCH_ONLINE
MENUITEM "&Toggle", IDM_TOGGLE
- MENUITEM "&Forget", IDM_FORGET
- MENUITEM "&Lookup", IDM_LOOKUP
MENUITEM "Wi&ki", IDM_WIKI
POPUP "&Rate"
BEGIN
diff --git a/c/test.cpp b/c/test.cpp
index 2e96bbc..e56d7aa 100644
--- a/c/test.cpp
+++ b/c/test.cpp
@@ -3,6 +3,7 @@
#include "data.h"
#include "episodelistview.h"
+#include "ext.h"
#include "pl.h"
#include "util.h"
#include "win.h"
@@ -16,7 +17,7 @@ struct Test
Test(const char* name) : name(name) {}
};
-#define TESTS struct UNUSED
+#define TESTS struct _
#define TEST(id) }; struct id : public Test { id() : Test(#id)
#define FAIL(...) do { Sprintf(error, __VA_ARGS__); return; } while (0)
diff --git a/c/util.h b/c/util.h
index 8281fc9..7ca8bfe 100644
--- a/c/util.h
+++ b/c/util.h
@@ -7,11 +7,22 @@
#include <SWI-Prolog.h>
#include <windows.h>
+#define CONCAT_IMPL(a, b) a##b
+#define CONCAT(a, b) CONCAT_IMPL(a, b)
+#define _ CONCAT(unused_, __LINE__)
+
inline size_t Min(size_t a, size_t b)
{
return a < b? a: b;
}
+inline int Cmp(const int a, const int b)
+{
+ if (a == b) return 0;
+ if (a > b) return 1;
+ return -1;
+}
+
/* Buf is a span-like structure of a buffer and its size. */
template <typename T>
struct Buf
@@ -58,15 +69,4 @@ inline char* Strcpy(Buf<char> dst, const char* const src)
return dst;
}
-inline int Cmp(const int a, const int b)
-{
- if (a == b) return 0;
- if (a > b) return 1;
- return -1;
-}
-
-#define CAT(a, b) a##b
-#define APPLY(a, ...) a(__VA_ARGS__)
-#define UNUSED APPLY(CAT, unused_, __COUNTER__)
-
#endif
diff --git a/c/win.h b/c/win.h
index 26a21b2..62cb2ac 100644
--- a/c/win.h
+++ b/c/win.h
@@ -7,12 +7,19 @@
/* Run given procedure at creation of next window. */
void WithNextWindow(void (*proc)(HWND));
+
/* Display message box centered in main window. */
int EBMessageBox(std::wstring_view text, std::wstring_view data, UINT uType);
+
/* Show message box for current exception. */
-void ShowException(const wchar_t* fmt, const wchar_t* title, UINT uType = MB_ICONWARNING) noexcept;
+void ShowException(
+ const wchar_t* fmt = L"An error occurred: %s",
+ const wchar_t* title = L"Error",
+ UINT uType = MB_ICONWARNING) noexcept;
+
/* Retrieve mouse position relative to given window's client area. */
int GetRelativeCursorPos(HWND hWnd, POINT* pt) noexcept;
+
/* Cached values from GetSystemMetrics. */
template <int I> auto Metric = GetSystemMetrics(I);