Skip to content

Commit

Permalink
Merge pull request #71 from xiaoyifang/feature/anki
Browse files Browse the repository at this point in the history
add Feature/anki connect
  • Loading branch information
xiaoyifang authored May 21, 2022
2 parents 0ddf32f + 0a2661f commit 2b9b278
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 29 deletions.
85 changes: 85 additions & 0 deletions ankiconnector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "ankiconnector.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include "utils.hh"
AnkiConnector::AnkiConnector( QObject * parent, Config::Class const & _cfg ) : QObject{ parent }, cfg( _cfg )
{
mgr = new QNetworkAccessManager( this );
connect( mgr, &QNetworkAccessManager::finished, this, &AnkiConnector::finishedSlot );
}

void AnkiConnector::sendToAnki( QString const & word, QString const & text )
{
//for simplicity. maybe use QJsonDocument in future?
QString postTemplate = QString( "{"
"\"action\": \"addNote\","
"\"version\": 6,"
"\"params\": {"
" \"note\": {"
" \"deckName\": \"%1\","
" \"modelName\": \"%2\","
" \"fields\":%3,"
" \"options\": {"
" \"allowDuplicate\": true"
" },"
" \"tags\": []"
"}"
"}"
"}"
"" );

QJsonObject fields;
fields.insert( "Front", word );
fields.insert( "Back", text );

QString postData = postTemplate.arg( cfg.preferences.ankiConnectServer.deck,
cfg.preferences.ankiConnectServer.model,
Utils::json2String( fields ) );

// qDebug().noquote() << postData;
QUrl url;
url.setScheme( "http" );
url.setHost( cfg.preferences.ankiConnectServer.host );
url.setPort( cfg.preferences.ankiConnectServer.port );
QNetworkRequest request( url );
request.setTransferTimeout( 3000 );
// request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy );
request.setHeader( QNetworkRequest::ContentTypeHeader, "applicaion/json" );
auto reply = mgr->post( request, postData.toUtf8() );
connect( reply,
&QNetworkReply::errorOccurred,
this,
[ this ]( QNetworkReply::NetworkError e )
{
qWarning() << e;
emit this->errorText( tr( "anki: post to anki failed" ) );
} );
}

void AnkiConnector::finishedSlot( QNetworkReply * reply )
{
if( reply->error() == QNetworkReply::NoError )
{
QByteArray bytes = reply->readAll();
QJsonDocument json = QJsonDocument::fromJson( bytes );
auto obj = json.object();
if( obj.size() != 2 || !obj.contains( "error" ) || !obj.contains( "result" ) ||
obj[ "result" ].toString().isEmpty() )
{
emit errorText( QObject::tr( "anki: post to anki failed" ) );
}
QString result = obj[ "result" ].toString();

qDebug() << "anki result:" << result;

emit errorText( tr( "anki: post to anki success" ) );
}
else
{
qDebug() << "anki connect error" << reply->errorString();
emit errorText( "anki:" + reply->errorString() );
}

reply->deleteLater();
}
28 changes: 28 additions & 0 deletions ankiconnector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef ANKICONNECTOR_H
#define ANKICONNECTOR_H

#include "config.hh"

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QObject>

class AnkiConnector : public QObject
{
Q_OBJECT
public:
explicit AnkiConnector( QObject * parent, Config::Class const & cfg );

void sendToAnki( QString const & word, QString const & text );

private:
QNetworkAccessManager * mgr;
Config::Class const & cfg;
public :
signals:
void errorText( QString const & );
private slots:
void finishedSlot(QNetworkReply * reply);
};

#endif // ANKICONNECTOR_H
22 changes: 22 additions & 0 deletions articleview.cc
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, Au
channel = new QWebChannel(ui.definition->page());
agent = new ArticleViewAgent(this);
attachWebChannelToHtml();
ankiConnector = new AnkiConnector( this, cfg );
connect( ankiConnector,
&AnkiConnector::errorText,
this,
[ this ]( QString const & errorText ) { emit statusBarMessage( errorText ); } );
}

// explicitly report the minimum size, to avoid
Expand Down Expand Up @@ -489,6 +494,10 @@ void ArticleView::showDefinition( QString const & word, QStringList const & dict
ui.definition->setCursor( Qt::WaitCursor );
}

void ArticleView::sendToAnki(QString const & word, QString const & text ){
ankiConnector->sendToAnki(word,text);
}

void ArticleView::showAnticipation()
{
ui.definition->setHtml( "" );
Expand Down Expand Up @@ -1721,6 +1730,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
QAction * followLinkExternal = 0;
QAction * followLinkNewTab = 0;
QAction * lookupSelection = 0;
QAction * sendToAnkiAction = 0 ;
QAction * lookupSelectionGr = 0;
QAction * lookupSelectionNewTab = 0;
QAction * lookupSelectionNewTabGr = 0;
Expand Down Expand Up @@ -1850,6 +1860,14 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
}
}

// add anki menu
if( !text.isEmpty() && cfg.preferences.ankiConnectServer.enabled )
{
QString txt = ui.definition->title();
sendToAnkiAction = new QAction( tr( "&Send \"%1\" to anki with selected text." ).arg( txt ), &menu );
menu.addAction( sendToAnkiAction );
}

if( text.isEmpty() && !cfg.preferences.storeHistory)
{
QString txt = ui.definition->title();
Expand Down Expand Up @@ -1942,6 +1960,10 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
else
if ( result == lookupSelection )
showDefinition( selectedText, getGroup( ui.definition->url() ), getCurrentArticle() );
else if( result = sendToAnkiAction )
{
sendToAnki( ui.definition->title(), ui.definition->selectedText() );
}
else
if ( result == lookupSelectionGr && groupComboBox )
showDefinition( selectedText, groupComboBox->getCurrentGroup(), QString() );
Expand Down
4 changes: 4 additions & 0 deletions articleview.hh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtCore5Compat/QRegExp>
#endif
#include "ankiconnector.h"

class ResourceToSaveHandler;
class ArticleViewAgent ;
Expand All @@ -39,6 +40,8 @@ class ArticleView: public QFrame
ArticleViewAgent * agent;
Ui::ArticleView ui;

AnkiConnector * ankiConnector;

QAction pasteAction, articleUpAction, articleDownAction,
goBackAction, goForwardAction, selectCurrentArticleAction,
copyAsTextAction, inspectAction;
Expand Down Expand Up @@ -129,6 +132,7 @@ public:
QRegExp const & searchRegExp, unsigned group,
bool ignoreDiacritics );

void sendToAnki(QString const & word, QString const & text );
/// Clears the view and sets the application-global waiting cursor,
/// which will be restored when some article loads eventually.
void showAnticipation();
Expand Down
41 changes: 41 additions & 0 deletions config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ ProxyServer::ProxyServer(): enabled( false ), useSystemProxy( false ), type( Soc
{
}

AnkiConnectServer::AnkiConnectServer(): enabled( false ), host("127.0.0.1"), port( 8765 )
{
}

HotKey::HotKey(): modifiers( 0 ), key1( 0 ), key2( 0 )
{
}
Expand Down Expand Up @@ -937,6 +941,17 @@ Class load()
c.preferences.proxyServer.systemProxyPassword = proxy.namedItem( "systemProxyPassword" ).toElement().text();
}

QDomNode ankiConnectServer = preferences.namedItem( "ankiConnectServer" );

if ( !ankiConnectServer.isNull() )
{
c.preferences.ankiConnectServer.enabled = ( ankiConnectServer.toElement().attribute( "enabled" ) == "1" );
c.preferences.ankiConnectServer.host = ankiConnectServer.namedItem( "host" ).toElement().text();
c.preferences.ankiConnectServer.port = ankiConnectServer.namedItem( "port" ).toElement().text().toULong();
c.preferences.ankiConnectServer.deck = ankiConnectServer.namedItem( "deck" ).toElement().text();
c.preferences.ankiConnectServer.model = ankiConnectServer.namedItem( "model" ).toElement().text();
}

if ( !preferences.namedItem( "checkForNewReleases" ).isNull() )
c.preferences.checkForNewReleases = ( preferences.namedItem( "checkForNewReleases" ).toElement().text() == "1" );

Expand Down Expand Up @@ -1872,6 +1887,32 @@ void save( Class const & c )
proxy.appendChild( opt );
}

//anki connect
{
QDomElement proxy = dd.createElement( "ankiConnectServer" );
preferences.appendChild( proxy );

QDomAttr enabled = dd.createAttribute( "enabled" );
enabled.setValue( c.preferences.ankiConnectServer.enabled ? "1" : "0" );
proxy.setAttributeNode( enabled );

opt = dd.createElement( "host" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.host ) );
proxy.appendChild( opt );

opt = dd.createElement( "port" );
opt.appendChild( dd.createTextNode( QString::number( c.preferences.ankiConnectServer.port ) ) );
proxy.appendChild( opt );

opt = dd.createElement( "deck" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.deck ) );
proxy.appendChild( opt );

opt = dd.createElement( "model" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.model ) );
proxy.appendChild( opt );
}

opt = dd.createElement( "checkForNewReleases" );
opt.appendChild( dd.createTextNode( c.preferences.checkForNewReleases ? "1" : "0" ) );
preferences.appendChild( opt );
Expand Down
13 changes: 13 additions & 0 deletions config.hh
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ struct ProxyServer
ProxyServer();
};

struct AnkiConnectServer
{
bool enabled;

QString host;
unsigned port;
QString deck;
QString model;

AnkiConnectServer();
};

// A hotkey -- currently qt modifiers plus one or two keys
struct HotKey
{
Expand Down Expand Up @@ -329,6 +341,7 @@ struct Preferences
QString audioPlaybackProgram;

ProxyServer proxyServer;
AnkiConnectServer ankiConnectServer;

bool checkForNewReleases;
bool disallowContentFromOtherSites;
Expand Down
2 changes: 2 additions & 0 deletions goldendict.pro
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ DEFINES += PROGRAM_VERSION=\\\"$$VERSION\\\"

# Input
HEADERS += folding.hh \
ankiconnector.h \
article_inspect.h \
articlewebpage.h \
globalbroadcaster.h \
Expand Down Expand Up @@ -364,6 +365,7 @@ FORMS += groups.ui \
fulltextsearch.ui

SOURCES += folding.cc \
ankiconnector.cpp \
article_inspect.cpp \
articlewebpage.cpp \
globalbroadcaster.cpp \
Expand Down
49 changes: 47 additions & 2 deletions locale/zh_CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@
<translation>(c) 2008-2013 Konstantin Isakov (ikm@goldendict.org)</translation>
</message>
</context>
<context>
<name>AnkiConnector</name>
<message>
<location filename="../ankiconnector.cpp" line="56"/>
<source>anki: post to anki failed</source>
<translatorcomment>anki:发布成功</translatorcomment>
<translation>anki:发布失败</translation>
</message>
<message>
<location filename="../ankiconnector.cpp" line="76"/>
<source>anki: post to anki success</source>
<translation>anki: 发布成功</translation>
</message>
</context>
<context>
<name>ArticleInspector</name>
<message>
Expand Down Expand Up @@ -315,7 +329,12 @@
<translation>引用的音频播放程序不存在。</translation>
</message>
<message>
<location filename="../articleview.cc" line="1971"/>
<location filename="../articleview.cc" line="1867"/>
<source>&amp;Send &quot;%1&quot; to anki with selected text.</source>
<translation>将“%1”发送到anki并附带选择的文本。</translation>
</message>
<message>
<location filename="../articleview.cc" line="2016"/>
<source>Sound files (*.wav *.ogg *.oga *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)</source>
<translation>声音文件(*.wav *.ogg *.oga *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;所有文件(*.*)</translation>
</message>
Expand Down Expand Up @@ -3903,7 +3922,27 @@ however, the article from the topmost dictionary is shown.</source>
<translation>自定义设置</translation>
</message>
<message>
<location filename="../preferences.ui" line="1147"/>
<location filename="../preferences.ui" line="1087"/>
<source>Anki Connect</source>
<translation>Anki连接</translation>
</message>
<message>
<location filename="../preferences.ui" line="1108"/>
<source>http://</source>
<translation>http://</translation>
</message>
<message>
<location filename="../preferences.ui" line="1152"/>
<source>Deck:</source>
<translation>牌组:</translation>
</message>
<message>
<location filename="../preferences.ui" line="1162"/>
<source>Model:</source>
<translation>模板:</translation>
</message>
<message>
<location filename="../preferences.ui" line="1214"/>
<source>Some sites detect GoldenDict via HTTP headers and block the requests.
Enable this option to workaround the problem.</source>
<translation>部分网站屏蔽了使用 GoldenDict 浏览器标识(UA)的请求,启用此选项以绕过该问题。</translation>
Expand Down Expand Up @@ -4420,6 +4459,12 @@ from Stardict, Babylon and GLS dictionaries</source>
<source>Date: %1%2</source>
<translation>日期:%1%2</translation>
</message>
<message>
<location filename="../ankiconnector.cpp" line="55"/>
<location filename="../ankiconnector.cpp" line="69"/>
<source>anki: post to anki failed</source>
<translation>anki:发布失败</translation>
</message>
</context>
<context>
<name>QuickFilterLine</name>
Expand Down
Loading

0 comments on commit 2b9b278

Please sign in to comment.