opt: pronounce audio rewrite (#922)

* opt: pronounce audio rewrite

* 🎨 apply clang-format changes

* fix:use javscript Map to hold the dictionary audio url

* Update mainwindow.cc

---------

Co-authored-by: xiaoyifang <xiaoyifang@users.noreply.github.com>
This commit is contained in:
xiaoyifang 2023-07-13 14:49:41 +08:00 committed by GitHub
parent 2b1d91638e
commit 2ed7990531
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 22 deletions

View file

@ -369,6 +369,7 @@ HEADERS += \
src/metadata.hh \ src/metadata.hh \
src/multimediaaudioplayer.hh \ src/multimediaaudioplayer.hh \
src/parsecmdline.hh \ src/parsecmdline.hh \
src/pronounceengine.hh \
src/resourceschemehandler.hh \ src/resourceschemehandler.hh \
src/splitfile.hh \ src/splitfile.hh \
src/termination.hh \ src/termination.hh \
@ -492,6 +493,7 @@ SOURCES += \
src/metadata.cc \ src/metadata.cc \
src/multimediaaudioplayer.cc \ src/multimediaaudioplayer.cc \
src/parsecmdline.cc \ src/parsecmdline.cc \
src/pronounceengine.cc \
src/resourceschemehandler.cc \ src/resourceschemehandler.cc \
src/splitfile.cc \ src/splitfile.cc \
src/termination.cc \ src/termination.cc \

View file

@ -2,13 +2,17 @@
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "audiolink.hh" #include "audiolink.hh"
#include "globalbroadcaster.hh"
std::string addAudioLink( std::string const & url, std::string addAudioLink( std::string const & url,
std::string const & dictionaryId ) std::string const & dictionaryId )
{ {
return std::string( "<script type=\"text/javascript\">" + if ( url.empty() || url.length() < 2 )
makeAudioLinkScript( url, dictionaryId ) + return {};
"</script>" ); GlobalBroadcaster::instance()->pronounce_engine.sendAudio(
QString::fromStdString( url.substr( 1, url.length() - 2 ) ) );
return std::string( "<script type=\"text/javascript\">" + makeAudioLinkScript( url, dictionaryId ) + "</script>" );
} }
std::string makeAudioLinkScript( std::string const & url, std::string makeAudioLinkScript( std::string const & url,
@ -18,9 +22,7 @@ std::string makeAudioLinkScript( std::string const & url,
std::string ref; std::string ref;
bool escaped = false; bool escaped = false;
for( unsigned x = 0; x < url.size(); x++ ) for ( const char ch : url ) {
{
char ch = url[ x ];
if( escaped ) if( escaped )
{ {
ref += ch; ref += ch;
@ -33,7 +35,13 @@ std::string makeAudioLinkScript( std::string const & url,
escaped = ( ch == '\\' ); escaped = ( ch == '\\' );
} }
std::string audioLinkForDict = "gdAudioLinks['" + dictionaryId + "']"; const std::string audioLinkForDict = QString::fromStdString( R"(
return "gdAudioLinks.first = gdAudioLinks.first || " + ref + ";" + if(!gdAudioMap.has('%1')){
audioLinkForDict + " = " + audioLinkForDict + " || " + ref + ";"; gdAudioMap.set('%1',%2);
}
)" ).arg(
QString::fromStdString( dictionaryId ),
QString::fromStdString( url ) ).toStdString();
return "gdAudioLinks.first = gdAudioLinks.first || " + ref + ";" +
audioLinkForDict ;
} }

View file

@ -4,6 +4,7 @@
#include <QObject> #include <QObject>
#include <vector> #include <vector>
#include "config.hh" #include "config.hh"
#include "pronounceengine.hh"
struct ActiveDictIds struct ActiveDictIds
{ {
@ -17,10 +18,11 @@ struct ActiveDictIds
} }
}; };
class GlobalBroadcaster : public QObject class GlobalBroadcaster : public QObject
{ {
Q_OBJECT Q_OBJECT
private:
Config::Preferences * preference; Config::Preferences * preference;
QSet<QString> whitelist; QSet<QString> whitelist;
@ -37,7 +39,7 @@ public:
QSet< QString > collapsedDicts; QSet< QString > collapsedDicts;
QMap< QString, QSet< QString > > folderFavoritesMap; QMap< QString, QSet< QString > > folderFavoritesMap;
QMap< unsigned, QString > groupFolderMap; QMap< unsigned, QString > groupFolderMap;
PronounceEngine pronounce_engine;
signals: signals:
void dictionaryChanges( ActiveDictIds ad ); void dictionaryChanges( ActiveDictIds ad );

22
src/pronounceengine.cc Normal file
View file

@ -0,0 +1,22 @@
#include "pronounceengine.hh"
PronounceEngine::PronounceEngine( QObject * parent ):
QObject{ parent }
{
}
void PronounceEngine::reset()
{
QMutexLocker _( &mutex );
state = PronounceState::AVAILABLE;
}
void PronounceEngine::sendAudio( QString audioLink )
{
QMutexLocker _( &mutex );
if ( state == PronounceState::OCCUPIED )
return;
state = PronounceState::OCCUPIED;
emit emitAudio( audioLink );
}

29
src/pronounceengine.hh Normal file
View file

@ -0,0 +1,29 @@
#ifndef PRONOUNCEENGINE_HH
#define PRONOUNCEENGINE_HH
#include <QObject>
#include <QMutexLocker>
#include <QMutex>
enum class PronounceState {
AVAILABLE,
OCCUPIED
};
class PronounceEngine: public QObject
{
Q_OBJECT
PronounceState state = PronounceState::AVAILABLE;
QMutex mutex;
public:
explicit PronounceEngine( QObject * parent = nullptr );
void reset();
void sendAudio( QString audioLink );
signals:
void emitAudio( QString audioLink );
};
#endif // PRONOUNCEENGINE_HH

View file

@ -4,6 +4,9 @@ var gdAudioLinks = {
"current": null "current": null
}; };
//store dictionary audio link.
var gdAudioMap= new Map();
function gdMakeArticleActive(newId,noEvent) { function gdMakeArticleActive(newId,noEvent) {
var gdCurrentArticle = $_$(".gdactivearticle").attr("id") var gdCurrentArticle = $_$(".gdactivearticle").attr("id")
if (gdCurrentArticle !== 'gdfrom-' + newId) { if (gdCurrentArticle !== 'gdfrom-' + newId) {

View file

@ -294,6 +294,7 @@ void ArticleView::showDefinition( QString const & word, unsigned group,
QString const & scrollTo, QString const & scrollTo,
Contexts const & contexts_ ) Contexts const & contexts_ )
{ {
GlobalBroadcaster::instance()->pronounce_engine.reset();
currentWord = word.trimmed(); currentWord = word.trimmed();
if( currentWord.isEmpty() ) if( currentWord.isEmpty() )
return; return;
@ -1479,7 +1480,7 @@ void ArticleView::reload() { webview->reload(); }
void ArticleView::hasSound( const std::function< void( bool ) > & callback ) void ArticleView::hasSound( const std::function< void( bool ) > & callback )
{ {
webview->page()->runJavaScript( "if(typeof(gdAudioLinks)!=\"undefined\") gdAudioLinks.first", webview->page()->runJavaScript( R"(if(typeof(gdAudioLinks)!="undefined") gdAudioLinks.first)",
[ callback ]( const QVariant & v ) { [ callback ]( const QVariant & v ) {
bool has = false; bool has = false;
if( v.type() == QVariant::String ) if( v.type() == QVariant::String )
@ -1491,11 +1492,11 @@ void ArticleView::hasSound( const std::function< void( bool ) > & callback )
//use webengine javascript to playsound //use webengine javascript to playsound
void ArticleView::playSound() void ArticleView::playSound()
{ {
QString variable = " (function(){ var link=gdAudioLinks[gdAudioLinks.current]; " QString variable = R"( (function(){ var link=gdAudioMap.get(gdAudioLinks.current);
" if(link==undefined){ " if(link==undefined){
" link=gdAudioLinks.first; " link=gdAudioLinks.first;
" } " }
" return link;})(); "; return link;})(); )";
webview->page()->runJavaScript( variable, [ this ]( const QVariant & result ) { webview->page()->runJavaScript( variable, [ this ]( const QVariant & result ) {
if( result.type() == QVariant::String ) { if( result.type() == QVariant::String ) {

View file

@ -685,6 +685,15 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
this, this,
&MainWindow::showFTSIndexingName ); &MainWindow::showFTSIndexingName );
connect( &GlobalBroadcaster::instance()->pronounce_engine,
&PronounceEngine::emitAudio,
this,
[ this ]( auto audioUrl ) {
auto view = getCurrentArticleView();
if ( cfg.preferences.pronounceOnLoadMain && view != nullptr ) {
view->openLink( QUrl::fromEncoded( audioUrl.toUtf8() ), {} );
}
} );
applyProxySettings(); applyProxySettings();
//set webengineview font //set webengineview font
@ -1915,12 +1924,7 @@ void MainWindow::pageLoaded( ArticleView * view )
return; // It was background action return; // It was background action
updateBackForwardButtons(); updateBackForwardButtons();
updatePronounceAvailability(); updatePronounceAvailability();
if ( cfg.preferences.pronounceOnLoadMain && view != nullptr ) {
view->playSound();
}
} }
void MainWindow::showStatusBarMessage( QString const & message, int timeout, QPixmap const & icon ) void MainWindow::showStatusBarMessage( QString const & message, int timeout, QPixmap const & icon )