From a3a9bbb511595e2fd2b143b40535b842cae84a21 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Mon, 25 Sep 2023 16:45:49 -0500 Subject: [PATCH] initial working commit --- Controllers/kagiSummarizerController.php | 48 ++++++++++++++++ configure.phtml | 19 ++++++ extension.php | 36 ++++++++++++ i18n/en/ext.php | 16 ++++++ metadata.json | 8 +++ static/script.js | 73 ++++++++++++++++++++++++ 6 files changed, 200 insertions(+) create mode 100644 Controllers/kagiSummarizerController.php create mode 100644 configure.phtml create mode 100644 extension.php create mode 100644 i18n/en/ext.php create mode 100644 metadata.json create mode 100644 static/script.js diff --git a/Controllers/kagiSummarizerController.php b/Controllers/kagiSummarizerController.php new file mode 100644 index 0000000..eadc929 --- /dev/null +++ b/Controllers/kagiSummarizerController.php @@ -0,0 +1,48 @@ +view->_layout(false); + + $kagi_token = FreshRSS_Context::$user_conf->kagi_token; + + if ($kagi_token === null || trim($kagi_token) ==='') { + echo json_encode(array( + 'response' => array( + 'output_text' => _t('ext.kagiSummarizer.ui.no_token_configured'), + 'error' => 'configuration'), + 'status' => 200)); + return; + } + + $entry_id = Minz_Request::param('id'); + $entry_dao = FreshRSS_Factory::createEntryDao(); + $entry = $entry_dao->searchById($entry_id); + + if ($entry === null) { + echo json_encode(array('status' => 404)); + return; + } + + $entry_link = urlencode($entry->link()); + $url = 'https://kagi.com/mother/summary_labs?summary_type=summary&url=' . $entry_link; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=UTF-8', + 'Authorization: ' . $kagi_token + )); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, true); + + $response = curl_exec($curl); + $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + $response_body = substr($response, $header_size); + + echo json_encode(array( + 'response' => json_decode($response_body), + 'status' => curl_getinfo($curl, CURLINFO_HTTP_CODE) + )); + } +} diff --git a/configure.phtml b/configure.phtml new file mode 100644 index 0000000..ca3eee3 --- /dev/null +++ b/configure.phtml @@ -0,0 +1,19 @@ +kagi_token; +?> + +
+ +

+
+ +
+ +
+
+
+
+ +
+
+
diff --git a/extension.php b/extension.php new file mode 100644 index 0000000..adfd5da --- /dev/null +++ b/extension.php @@ -0,0 +1,36 @@ +registerTranslates(); + $this->registerHook('entry_before_display', [$this, 'addSummarizeButton']); + Minz_View::appendScript($this->getFileUrl('script.js', 'js'), false, false, false); + $this->registerController('kagiSummarizer'); + } + + public function handleConfigureAction() { + $this->registerTranslates(); + + if (Minz_Request::isPost()) { + $kagi_token = Minz_Request::param('kagi_token', ''); + $prefix = 'https://kagi.com/search?token='; + if (substr($kagi_token, 0, strlen($prefix)) == $prefix) { + $kagi_token = substr($kagi_token, strlen($prefix)); + } + FreshRSS_Context::$user_conf->kagi_token = $kagi_token; + FreshRSS_Context::$user_conf->save(); + } + } + + public function addSummarizeButton(FreshRSS_Entry $entry): FreshRSS_Entry { + $this->registerTranslates(); + $url = Minz_Url::display(array( + 'c' => 'kagiSummarizer', + 'a' => 'summarize', + 'params' => array( + 'id' => $entry->id() + ))); + $entry->_content('

' . _t('ext.kagiSummarizer.ui.summarize_button') . '

' . $entry->content()); + return $entry; + } +} diff --git a/i18n/en/ext.php b/i18n/en/ext.php new file mode 100644 index 0000000..b3577fc --- /dev/null +++ b/i18n/en/ext.php @@ -0,0 +1,16 @@ + array( + 'configure' => array( + 'kagi_token' => 'Kagi Token', + 'kagi_token_help' => 'Copy and paste the "Session Link" from your Kagi Account settings.' + ), + 'ui' => array( + 'summarize_button' => 'Summarize', + 'loading_summary' => 'Loading summary...', + 'error' => 'Error retrieving summary.', + 'no_token_configured' => 'No Kagi token configured.' + ) + ) +); diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..4fc8603 --- /dev/null +++ b/metadata.json @@ -0,0 +1,8 @@ +{ + "name": "Kagi Summarizer", + "author": "Rudis Muiznieks", + "description": "Add a button to summarize articles with the Kagi Universal Summarizer.", + "version": 0.1, + "entrypoint": "KagiSummarizer", + "type": "user" +} diff --git a/static/script.js b/static/script.js new file mode 100644 index 0000000..cf75f0e --- /dev/null +++ b/static/script.js @@ -0,0 +1,73 @@ +if (document.readyState && document.readyState !== 'loading') { + configureSummarizeButtons(); +} else { + document.addEventListener('DOMContentLoaded', configureSummarizeButtons, false); +} + +function configureSummarizeButtons() { + document.getElementById('global').addEventListener('click', function(e) { + for (var target = e.target; target && target != this; target = target.parentNode) { + if (target.matches('.kagi-summary a.btn')) { + e.preventDefault(); + e.stopPropagation(); + if (target.href) { + summarizeButtonClick(target); + } + break; + } + } + }, false); +} + +function summarizeButtonClick(button) { + var url = button.href; + var loadingMsg = button.dataset.loading; + var errorMsg = button.dataset.error; + var container = button.parentNode; + + container.classList.add('alert'); + container.classList.add('alert-warn'); + container.innerHTML = loadingMsg; + + var request = new XMLHttpRequest(); + request.open('POST', url, true); + request.responseType = 'json'; + + request.onload = function(e) { + if (this.status != 200) { + return request.onerror(e); + } + + var response = xmlHttpRequestJson(this); + if (!response) { + return request.onerror(e); + } + + if (response.status !== 200 || !response.response || !response.response.output_text) { + return request.onerror(e); + } + + if (response.response.error) { + container.classList.remove('alert-warn'); + container.classList.add('alert-error'); + } else { + container.classList.remove('alert-warn'); + container.classList.add('alert-success'); + } + + container.innerHTML = response.response.output_text; + } + + request.onerror = function(e) { + badAjax(this.status == 403); + container.classList.remove('alert-warn'); + container.classList.add('alert-error'); + container.innerHTML = errorMsg; + } + + request.setRequestHeader('Content-Type', 'application/json'); + request.send(JSON.stringify({ + ajax: true, + _csrf: context.csrf + })); +}