files for newsbluer plugin

This commit is contained in:
Martin Rotter 2022-02-18 11:57:35 +01:00
parent 4c79df2bb9
commit 5ce90e5943
23 changed files with 1066 additions and 102 deletions

View File

@ -22,7 +22,7 @@
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="66"/>
<source>Cannot enable AdBlock</source>
<translation type="unfinished"/>
<translation>AdBlock nelze povolit</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="67"/>
@ -32,25 +32,27 @@
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="102"/>
<source>OK!</source>
<translation type="unfinished"/>
<translation>OK!</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="114"/>
<source>There is error, check application log for more details and head to online documentation.</source>
<translation type="unfinished"/>
<translation>Došlo k chybě, zkontrolujte log programu a případně prověřte dokumentaci.</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="89"/>
<source>There is error, check application log for more details and head to online documentation. Also make sure that Node.js is installed.
Error: %1</source>
<translation type="unfinished"/>
<translation>Došlo k chybě, zkontrolujte log programu a případně prověřte dokumentaci. Ujistětě se, že máte nakonfigurovaný Node.js.
Chyba: %1</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="92"/>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="116"/>
<source>ERROR!</source>
<translation type="unfinished"/>
<translation>CHYBA!</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="39"/>
@ -58,12 +60,12 @@ Error: %1</source>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="106"/>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="107"/>
<source>No additional info.</source>
<translation type="unfinished"/>
<translation>Žádné další info.</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.cpp" line="101"/>
<source>It seems your AdBlock runs fine, but wait few seconds to be sure.</source>
<translation type="unfinished"/>
<translation>Vypadá to, že AdBlock běží dobře, ale počkejme pár vteřin.</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.ui" line="20"/>
@ -78,7 +80,7 @@ Error: %1</source>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.ui" line="58"/>
<source>Filter lists</source>
<translation type="unfinished"/>
<translation>Filtrovací seznamy</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockdialog.ui" line="64"/>
@ -114,7 +116,7 @@ Error: %1</source>
<message>
<location filename="../src/librssguard/network-web/adblock/adblockmanager.cpp" line="382"/>
<source>failed to download filter list &apos;%1&apos;</source>
<translation type="unfinished"/>
<translation>nepodařilo se stáhnout filter &apos;%1&apos;</translation>
</message>
</context>
<context>
@ -167,22 +169,22 @@ Error: %1</source>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="862"/>
<source>Packages %1 were updated.</source>
<translation type="unfinished"/>
<translation>Balíčky %1 byly aktualizovány.</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="687"/>
<source>Unread articles fetched</source>
<translation type="unfinished"/>
<translation>Staženy nepřečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="236"/>
<source>Go to changelog</source>
<translation type="unfinished"/>
<translation>Zobrazit seznam změn</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="673"/>
<source>AdBlock needs to be configured</source>
<translation type="unfinished"/>
<translation>Je třeba nastavit AdBlock</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="217"/>
@ -202,7 +204,7 @@ Error: %1</source>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="231"/>
<source>Welcome</source>
<translation type="unfinished"/>
<translation>Vítejte</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="232"/>
@ -218,7 +220,7 @@ na tuto bublinu.</translation>
<message>
<location filename="../src/librssguard/miscellaneous/application.cpp" line="757"/>
<source>Already running</source>
<translation type="unfinished"/>
<translation>Již běží</translation>
</message>
</context>
<context>
@ -286,7 +288,7 @@ na tuto bublinu.</translation>
<message>
<location filename="../src/librssguard/gui/reusable/baselineedit.cpp" line="13"/>
<source>Show/hide the password</source>
<translation type="unfinished"/>
<translation>Zobrazit/skrýt heslo</translation>
</message>
</context>
<context>
@ -327,32 +329,32 @@ na tuto bublinu.</translation>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="25"/>
<source>Removing read articles...</source>
<translation type="unfinished"/>
<translation>Mažu přečtené zprávy...</translation>
</message>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="30"/>
<source>Read articles purged...</source>
<translation type="unfinished"/>
<translation>Přečtené zprávy smazány...</translation>
</message>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="45"/>
<source>Removing old articles...</source>
<translation type="unfinished"/>
<translation>Mažu staré zprávy...</translation>
</message>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="50"/>
<source>Old articles purged...</source>
<translation type="unfinished"/>
<translation>Staré zprávy smazány...</translation>
</message>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="55"/>
<source>Removing starred articles...</source>
<translation type="unfinished"/>
<translation>Mažu důležité zprávy...</translation>
</message>
<message>
<location filename="../src/librssguard/database/databasecleaner.cpp" line="60"/>
<source>Starred articles purged...</source>
<translation type="unfinished"/>
<translation>Důležité zprávy smazány...</translation>
</message>
</context>
<context>
@ -393,7 +395,7 @@ na tuto bublinu.</translation>
<message>
<location filename="../src/librssguard/gui/reusable/discoverfeedsbutton.cpp" line="55"/>
<source>Not supported by account</source>
<translation type="unfinished"/>
<translation>Není podporováno</translation>
</message>
</context>
<context>
@ -483,7 +485,7 @@ Klikněte sem pro otevření nadřazeného adresáře.</translation>
<message>
<location filename="../src/librssguard/network-web/downloadmanager.cpp" line="423"/>
<source>Open folder</source>
<translation type="unfinished"/>
<translation>Otevřít složku</translation>
</message>
<message>
<location filename="../src/librssguard/network-web/downloaditem.ui" line="54"/>
@ -612,39 +614,39 @@ Stav: %3</translation>
<location filename="../src/librssguard/services/abstract/feed.cpp" line="224"/>
<source>does not use auto-fetching of articles</source>
<extracomment>Describes feed auto-update status.</extracomment>
<translation type="unfinished"/>
<translation>nestahuje zprávy automaticky</translation>
</message>
<message numerus="yes">
<location filename="../src/librssguard/services/abstract/feed.cpp" line="231"/>
<source>uses global settings (%n minute(s) to next auto-fetch of articles)</source>
<extracomment>Describes feed auto-update status.</extracomment>
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
<translation><numerusform>používá globální nastavení (%n minuta do dalšího stahování zpráv)</numerusform><numerusform>používá globální nastavení (%n minuty do dalšího stahování zpráv)</numerusform><numerusform>používá globální nastavení (%n minut do dalšího stahování zpráv)</numerusform><numerusform>používá globální nastavení (%n minut do dalšího stahování zpráv)</numerusform></translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/feed.cpp" line="234"/>
<source>uses global settings (global auto-fetching of articles is disabled)</source>
<translation type="unfinished"/>
<translation>používá globální nastavení (globální stahování zpráv je zakázáno)</translation>
</message>
<message numerus="yes">
<location filename="../src/librssguard/services/abstract/feed.cpp" line="241"/>
<source>uses specific settings (%n minute(s) to next auto-fetching of new articles)</source>
<extracomment>Describes feed auto-update status.</extracomment>
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
<translation><numerusform>používá specifické nastavení (%n minuta do dalšího automatického stažení zpráv)</numerusform><numerusform>používá specifické nastavení (%n minuty do dalšího automatického stažení zpráv)</numerusform><numerusform>používá specifické nastavení (%n minut do dalšího automatického stažení zpráv)</numerusform><numerusform>používá specifické nastavení (%n minut do dalšího automatického stažení zpráv)</numerusform></translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/feed.cpp" line="254"/>
<source>has new articles</source>
<translation type="unfinished"/>
<translation> nové zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/feed.cpp" line="263"/>
<source>parsing error</source>
<translation type="unfinished"/>
<translation>špatný formát kanálu</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/feed.cpp" line="266"/>
<source>error</source>
<translation type="unfinished"/>
<translation>chyba</translation>
</message>
</context>
<context>
@ -657,7 +659,7 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/gui/feedmessageviewer.cpp" line="50"/>
<source>Toolbar for articles</source>
<translation type="unfinished"/>
<translation>Nástrojová lišta pro zprávy</translation>
</message>
</context>
<context>
@ -665,22 +667,22 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/miscellaneous/feedreader.cpp" line="332"/>
<source>Starting auto-download of some feeds&apos; articles</source>
<translation type="unfinished"/>
<translation>Zahajuji automatické stažení zpráv pro některé kanály</translation>
</message>
<message numerus="yes">
<location filename="../src/librssguard/miscellaneous/feedreader.cpp" line="333"/>
<source>I will auto-download new articles for %n feed(s).</source>
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
<translation><numerusform>Budou se stahovat zprávy pro %n kanál</numerusform><numerusform>Budou se stahovat zprávy pro %n kanály</numerusform><numerusform>Budou se stahovat zprávy pro %n kanálů</numerusform><numerusform>Budou se stahovat zprávy pro %n kanálů</numerusform></translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/feedreader.cpp" line="87"/>
<source>Cannot fetch articles at this point</source>
<translation type="unfinished"/>
<translation>V tuto chvíli nelze stáhnout zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/miscellaneous/feedreader.cpp" line="88"/>
<source>You cannot fetch new articles now because another critical operation is ongoing.</source>
<translation type="unfinished"/>
<translation>V tuto chvíli nelze zahájit stahování zpráv, protože běží jiná důležitá operace.</translation>
</message>
</context>
<context>
@ -704,7 +706,7 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.ui" line="53"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.ui" line="90"/>
@ -714,7 +716,7 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.ui" line="106"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="28"/>
@ -770,17 +772,17 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="139"/>
<source>Login was successful.</source>
<translation type="unfinished"/>
<translation>Přihlášení bylo úspěšné.</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="35"/>
<source>Your %1 build has official Feedly support. You do not have to use &quot;developer access token&quot;. You can therefore leave corresponding field empty.</source>
<translation type="unfinished"/>
<translation>Vaše verze programu %1 oficiální podporu Feedly. Nemusíte tedy používat DAC, a tak můžete nechat odpovídající políčko prázdné.</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="145"/>
<source>Some problems.</source>
<translation type="unfinished"/>
<translation>Nějaké problémy.</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="153"/>
@ -795,22 +797,22 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="170"/>
<source>Access token is empty.</source>
<translation type="unfinished"/>
<translation>Přístupový token je prázdný.</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="173"/>
<source>Access token is okay.</source>
<translation type="unfinished"/>
<translation>Přístupový token je v pořádku.</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="144"/>
<source>Error: &apos;%1&apos;</source>
<translation type="unfinished"/>
<translation>Chyba: &apos;%1&apos;</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/gui/feedlyaccountdetails.cpp" line="46"/>
<source>Beware of downloading too many articles, because Feedly permanently caches ALL articles of the feed, so you might end up with thousands of articles which you will never read anyway.</source>
<translation type="unfinished"/>
<translation>Zvažte, zda je dobrá věc stahovat příliš mnoho zpráv. Feedly permantně cachuje všechny dřívější zprávy z kanálu, takže můžete skončit s tisícovkami zpráv, které stejně nebudete číst.</translation>
</message>
</context>
<context>
@ -818,7 +820,7 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/feedlynetwork.cpp" line="513"/>
<source>Feedly: authentication error</source>
<translation type="unfinished"/>
<translation>Feedly: chyba autentizace</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/feedlynetwork.cpp" line="514"/>
@ -828,7 +830,7 @@ Stav: %3</translation>
<message>
<location filename="../src/librssguard/services/feedly/feedlynetwork.cpp" line="529"/>
<source>Feedly: authorization denied</source>
<translation type="unfinished"/>
<translation>Feedly: přihlašovací údaje zamítnuty</translation>
</message>
<message>
<location filename="../src/librssguard/services/feedly/feedlynetwork.cpp" line="530"/>
@ -1006,13 +1008,13 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/feedsview.cpp" line="711"/>
<source>Context menu for important articles</source>
<translation type="unfinished"/>
<translation>Kontextové menu pro důležité zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/gui/feedsview.cpp" line="131"/>
<location filename="../src/librssguard/gui/feedsview.cpp" line="149"/>
<source>Not supported by account</source>
<translation type="unfinished"/>
<translation>Není podporováno</translation>
</message>
</context>
<context>
@ -1082,7 +1084,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formabout.ui" line="242"/>
<source>GNU LGPL License (applies to Breeze source code)</source>
<translation type="unfinished"/>
<translation>GNU LGPL Licence (pro kód komponenty Breeze)</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formabout.ui" line="310"/>
@ -1122,7 +1124,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formabout.ui" line="468"/>
<source>Database location</source>
<translation type="unfinished"/>
<translation>Umístění databáze</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formabout.ui" line="482"/>
@ -1135,7 +1137,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/abstract/gui/formaccountdetails.cpp" line="14"/>
<source>Network proxy</source>
<translation type="unfinished"/>
<translation>Síťová proxy</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formaccountdetails.cpp" line="39"/>
@ -1145,7 +1147,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/abstract/gui/formaccountdetails.cpp" line="42"/>
<source>Edit account &quot;%1&quot;</source>
<translation type="unfinished"/>
<translation>Upravit účet &quot;%1&quot;</translation>
</message>
</context>
<context>
@ -1431,12 +1433,12 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/abstract/gui/formcategorydetails.cpp" line="83"/>
<source>Edit &quot;%1&quot;</source>
<translation type="unfinished"/>
<translation>Upravit &quot;%1&quot;</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formcategorydetails.ui" line="31"/>
<source>Parent folder</source>
<translation type="unfinished"/>
<translation>Nadřazený uzel</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formcategorydetails.ui" line="41"/>
@ -1506,32 +1508,32 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="20"/>
<source>Cleanup settings</source>
<translation type="unfinished"/>
<translation>Nastavení čištění</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="26"/>
<source>Optimize database file</source>
<translation type="unfinished"/>
<translation>Optimalizovat databázi</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="36"/>
<source>Remove all read articles</source>
<translation type="unfinished"/>
<translation>Smazat přečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="53"/>
<source>Remove all articles from recycle bin</source>
<translation type="unfinished"/>
<translation>Smazat zprávy z košů</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="63"/>
<source>Remove all articles older than</source>
<translation type="unfinished"/>
<translation>Smazat zprávy starší než</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="86"/>
<source>Remove all starred articles</source>
<translation type="unfinished"/>
<translation>Smazat důležité zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="96"/>
@ -1541,7 +1543,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="102"/>
<source>Total data size</source>
<translation type="unfinished"/>
<translation>Velikost dat</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formdatabasecleanup.ui" line="119"/>
@ -1572,7 +1574,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/feedly/gui/formeditfeedlyaccount.cpp" line="19"/>
<source>Service setup</source>
<translation type="unfinished"/>
<translation>Nastavení služby</translation>
</message>
</context>
<context>
@ -1580,7 +1582,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/gmail/gui/formeditgmailaccount.cpp" line="16"/>
<source>Server setup</source>
<translation type="unfinished"/>
<translation>Nastavení serveru</translation>
</message>
</context>
<context>
@ -1588,7 +1590,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/greader/gui/formeditgreaderaccount.cpp" line="16"/>
<source>Server setup</source>
<translation type="unfinished"/>
<translation>Nastavení serveru</translation>
</message>
</context>
<context>
@ -1596,7 +1598,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/owncloud/gui/formeditowncloudaccount.cpp" line="15"/>
<source>Server setup</source>
<translation type="unfinished"/>
<translation>Nastavení serveru</translation>
</message>
</context>
<context>
@ -1604,7 +1606,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/reddit/gui/formeditredditaccount.cpp" line="16"/>
<source>Server setup</source>
<translation type="unfinished"/>
<translation>Nastavení serveru</translation>
</message>
</context>
<context>
@ -1612,7 +1614,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/formeditttrssaccount.cpp" line="13"/>
<source>Server setup</source>
<translation type="unfinished"/>
<translation>Nastavení serveru</translation>
</message>
</context>
<context>
@ -1625,62 +1627,62 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="107"/>
<source>Cannot save changes: %1</source>
<translation type="unfinished"/>
<translation>Změny nelze uložit: %1</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="90"/>
<source>Edit &quot;%1&quot;</source>
<translation type="unfinished"/>
<translation>Upravit &quot;%1&quot;</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="120"/>
<source>Fetch articles using global interval</source>
<translation type="unfinished"/>
<translation>Stahovat zprávy dle hlavního nastavení</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="122"/>
<source>Fetch articles every</source>
<translation type="unfinished"/>
<translation>Stahovat zprávy každých</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="124"/>
<source>Disable auto-fetching of articles</source>
<translation type="unfinished"/>
<translation>Zakázat automatické stahování zpráv</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.cpp" line="106"/>
<source>Cannot save feed properties</source>
<translation type="unfinished"/>
<translation>Nelze uložit vlastnosti kanálu</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="24"/>
<source>Articles</source>
<translation type="unfinished"/>
<translation>Zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="30"/>
<source>Auto-downloading of articles</source>
<translation type="unfinished"/>
<translation>Automatické stahování zpráv</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="42"/>
<source>Select the auto-download strategy for messages of this feed. Default auto-download strategy means that new messges of this feed will be downloaded in time intervals set in application settings.</source>
<translation type="unfinished"/>
<translation>Zvolte strategii auto-aktualizací zpráv tohoto kanálu. Výchozí strategorie auto-aktualizace znamená, že kanál bude aktualizován v intervalech udaných v nastavení aplikace.</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="58"/>
<source>Open articles via their URL automatically</source>
<translation type="unfinished"/>
<translation>Otevírat zdrojové URL zpráv automaticky</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="66"/>
<source>Miscellaneous</source>
<translation type="unfinished"/>
<translation>Různé</translation>
</message>
<message>
<location filename="../src/librssguard/services/abstract/gui/formfeeddetails.ui" line="72"/>
<source>Disable this feed</source>
<translation type="unfinished"/>
<translation>Vypnout kanál</translation>
</message>
</context>
<context>
@ -1703,7 +1705,7 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formmain.cpp" line="80"/>
<source>Open main menu</source>
<translation type="unfinished"/>
<translation>Otevřít hlavní menu</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formmain.cpp" line="88"/>
@ -1738,12 +1740,12 @@ or this functionality is not implemented yet.</source>
<message>
<location filename="../src/librssguard/gui/dialogs/formmain.ui" line="103"/>
<source>F&amp;eeds</source>
<translation type="unfinished"/>
<translation>&amp;Kanály</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formmain.ui" line="107"/>
<source>&amp;Add item</source>
<translation type="unfinished"/>
<translation>&amp;Přidat položku</translation>
</message>
<message>
<location filename="../src/librssguard/gui/dialogs/formmain.ui" line="139"/>
@ -3149,7 +3151,7 @@ Nyní ho můžete nainstalovat.</translation>
<message>
<location filename="../src/librssguard/services/gmail/gui/gmailaccountdetails.ui" line="110"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/gmail/gui/gmailaccountdetails.ui" line="134"/>
@ -3159,7 +3161,7 @@ Nyní ho můžete nainstalovat.</translation>
<message>
<location filename="../src/librssguard/services/gmail/gui/gmailaccountdetails.ui" line="163"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
</context>
<context>
@ -3413,7 +3415,7 @@ Tokeny vyprší: %2</translation>
<message>
<location filename="../src/librssguard/services/greader/gui/greaderaccountdetails.ui" line="40"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/greader/gui/greaderaccountdetails.ui" line="47"/>
@ -3428,7 +3430,7 @@ Tokeny vyprší: %2</translation>
<message>
<location filename="../src/librssguard/services/greader/gui/greaderaccountdetails.ui" line="74"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/greader/gui/greaderaccountdetails.ui" line="95"/>
@ -4434,12 +4436,12 @@ Tokeny vyprší: %2</translation>
<message>
<location filename="../src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui" line="34"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui" line="43"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/owncloud/gui/owncloudaccountdetails.ui" line="81"/>
@ -4835,7 +4837,7 @@ List of supported readers:</source>
<message>
<location filename="../src/librssguard/services/reddit/gui/redditaccountdetails.ui" line="110"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/reddit/gui/redditaccountdetails.ui" line="134"/>
@ -4845,7 +4847,7 @@ List of supported readers:</source>
<message>
<location filename="../src/librssguard/services/reddit/gui/redditaccountdetails.ui" line="163"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
</context>
<context>
@ -5160,7 +5162,7 @@ File filter for external e-mail selection dialog.</extracomment>
<message>
<location filename="../src/librssguard/gui/settings/settingsbrowsermail.cpp" line="22"/>
<source>Network proxy</source>
<translation type="unfinished"/>
<translation>Síťová proxy</translation>
</message>
<message>
<location filename="../src/librssguard/gui/settings/settingsbrowsermail.cpp" line="244"/>
@ -5469,7 +5471,7 @@ Authors of this application are NOT responsible for lost data.</source>
<message>
<location filename="../src/librssguard/gui/settings/settingsfeedsmessages.ui" line="283"/>
<source>Articles</source>
<translation type="unfinished"/>
<translation>Zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/gui/settings/settingsfeedsmessages.ui" line="289"/>
@ -6309,7 +6311,7 @@ Also, you can post-process generated feed data with yet another script if you wi
<message>
<location filename="../src/librssguard/services/standard/gui/standardfeeddetails.ui" line="20"/>
<source>Parent folder</source>
<translation type="unfinished"/>
<translation>Nadřazený uzel</translation>
</message>
<message>
<location filename="../src/librssguard/services/standard/gui/standardfeeddetails.ui" line="30"/>
@ -6798,12 +6800,12 @@ Nepřečtené zprávy: %2</translation>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui" line="47"/>
<source>Download unread articles only</source>
<translation type="unfinished"/>
<translation>Stahovat pouze nepřečtené zprávy</translation>
</message>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui" line="56"/>
<source>Only download newest X articles per feed</source>
<translation type="unfinished"/>
<translation>Stáhnout pouze X nejnovějších zpráv pro každý kanál</translation>
</message>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/ttrssaccountdetails.ui" line="91"/>
@ -6887,7 +6889,7 @@ Nepřečtené zprávy: %2</translation>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/ttrssfeeddetails.ui" line="20"/>
<source>Parent folder</source>
<translation type="unfinished"/>
<translation>Nadřazený uzel</translation>
</message>
<message>
<location filename="../src/librssguard/services/tt-rss/gui/ttrssfeeddetails.ui" line="30"/>

View File

@ -26,7 +26,7 @@
<url type="donation">https://github.com/sponsors/martinrotter</url>
<content_rating type="oars-1.1" />
<releases>
<release version="4.1.2" date="2022-02-17"/>
<release version="4.1.2" date="2022-02-18"/>
</releases>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">none</content_attribute>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -34,6 +34,7 @@
<file>graphics/misc/google.png</file>
<file>graphics/misc/image-placeholder.png</file>
<file>graphics/misc/inoreader.png</file>
<file>graphics/misc/newsblur.png</file>
<file>graphics/misc/nextcloud.png</file>
<file>graphics/misc/reddit.png</file>
<file>graphics/misc/reedah.png</file>

View File

@ -305,6 +305,17 @@ set(SOURCES
services/greader/gui/formeditgreaderaccount.h
services/greader/gui/greaderaccountdetails.cpp
services/greader/gui/greaderaccountdetails.h
services/newsblur/definitions.h
services/newsblur/newsblurentrypoint.cpp
services/newsblur/newsblurentrypoint.h
services/newsblur/newsblurnetwork.cpp
services/newsblur/newsblurnetwork.h
services/newsblur/newsblurserviceroot.cpp
services/newsblur/newsblurserviceroot.h
services/newsblur/gui/formeditnewsbluraccount.cpp
services/newsblur/gui/formeditnewsbluraccount.h
services/newsblur/gui/newsbluraccountdetails.cpp
services/newsblur/gui/newsbluraccountdetails.h
services/owncloud/definitions.h
services/owncloud/gui/formeditowncloudaccount.cpp
services/owncloud/gui/formeditowncloudaccount.h
@ -447,6 +458,7 @@ set(UI_FILES
services/gmail/gui/formdownloadattachment.ui
services/gmail/gui/gmailaccountdetails.ui
services/greader/gui/greaderaccountdetails.ui
services/newsblur/gui/newsbluraccountdetails.ui
services/owncloud/gui/owncloudaccountdetails.ui
services/reddit/gui/redditaccountdetails.ui
services/standard/gui/formstandardimportexport.ui

View File

@ -14,6 +14,7 @@
#define SERVICE_CODE_INOREADER "inoreader"
#define SERVICE_CODE_GMAIL "gmail"
#define SERVICE_CODE_REDDIT "reddit"
#define SERVICE_CODE_NEWSBLUR "newsblur"
#define ADBLOCK_SERVER_PORT 48484
#define ADBLOCK_HOWTO "https://github.com/martinrotter/rssguard/blob/master/resources/docs/Documentation.md#adbl"
@ -139,6 +140,7 @@
#define LOGSEC_GMAIL "gmail: "
#define LOGSEC_OAUTH "oauth: "
#define LOGSEC_REDDIT "reddit: "
#define LOGSEC_NEWSBLUR "newsblur: "
#define MAX_ZOOM_FACTOR 5.0f
#define MIN_ZOOM_FACTOR 0.25f

View File

@ -850,7 +850,7 @@ void Application::parseCmdArgumentsFromMyInstance() {
void Application::onNodeJsPackageUpdateError(const QList<NodeJs::PackageMetadata>& pkgs, const QString& error) {
qApp->showGuiMessage(Notification::Event::NodePackageFailedToUpdate,
{ {},
tr("Packages %1 were NOT updated because of error: %3.").arg(NodeJs::packagesToString(pkgs),
tr("Packages %1 were NOT updated because of error: %2.").arg(NodeJs::packagesToString(pkgs),
error),
QSystemTrayIcon::MessageIcon::Critical });
}

View File

@ -17,6 +17,7 @@
#include "services/feedly/feedlyentrypoint.h"
#include "services/gmail/gmailentrypoint.h"
#include "services/greader/greaderentrypoint.h"
#include "services/newsblur/newsblurentrypoint.h"
#include "services/owncloud/owncloudserviceentrypoint.h"
#include "services/reddit/redditentrypoint.h"
#include "services/standard/standardserviceentrypoint.h"
@ -60,6 +61,7 @@ QList<ServiceEntryPoint*> FeedReader::feedServices() {
m_feedServices.append(new FeedlyEntryPoint());
m_feedServices.append(new GmailEntryPoint());
m_feedServices.append(new GreaderEntryPoint());
m_feedServices.append(new NewsBlurEntryPoint());
m_feedServices.append(new OwnCloudServiceEntryPoint());
#if defined(DEBUG)

View File

@ -171,6 +171,17 @@ void Downloader::finished() {
m_lastOutputMultipartData = decodeMultipartAnswer(reply);
}
QVariant set_cookies_header = reply->header(QNetworkRequest::SetCookieHeader);
if (set_cookies_header.isValid()) {
QList<QNetworkCookie> cookies = set_cookies_header.value<QList<QNetworkCookie>>();
m_lastCookies = cookies;
}
else {
m_lastCookies = {};
}
m_lastContentType = reply->header(QNetworkRequest::ContentTypeHeader);
m_lastOutputError = reply->error();
m_activeReply->deleteLater();
@ -292,6 +303,10 @@ void Downloader::runGetRequest(const QNetworkRequest& request) {
connect(m_activeReply, &QNetworkReply::finished, this, &Downloader::finished);
}
QList<QNetworkCookie> Downloader::lastCookies() const {
return m_lastCookies;
}
QVariant Downloader::lastContentType() const {
return m_lastContentType;
}

View File

@ -28,6 +28,7 @@ class Downloader : public QObject {
QNetworkReply::NetworkError lastOutputError() const;
QList<HttpResponse> lastOutputMultipartData() const;
QVariant lastContentType() const;
QList<QNetworkCookie> lastCookies() const;
void setProxy(const QNetworkProxy& proxy);
@ -98,6 +99,7 @@ class Downloader : public QObject {
QNetworkReply::NetworkError m_lastOutputError;
QVariant m_lastContentType;
QList<QNetworkCookie> m_lastCookies;
};
#endif // DOWNLOADER_H

View File

@ -229,11 +229,15 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList<QPair<QStri
return network_result;
}
NetworkResult NetworkFactory::performNetworkOperation(const QString& url, int timeout, const QByteArray& input_data,
QByteArray& output, QNetworkAccessManager::Operation operation,
NetworkResult NetworkFactory::performNetworkOperation(const QString& url,
int timeout,
const QByteArray& input_data,
QByteArray& output,
QNetworkAccessManager::Operation operation,
const QList<QPair<QByteArray, QByteArray>>& additional_headers,
bool protected_contents,
const QString& username, const QString& password,
const QString& username,
const QString& password,
const QNetworkProxy& custom_proxy) {
Downloader downloader;
QEventLoop loop;

View File

@ -0,0 +1,15 @@
#ifndef NEWSBLUR_DEFINITIONS_H
#define NEWSBLUR_DEFINITIONS_H
// Misc.
#define NEWSBLUR_DEFAULT_BATCH_SIZE 500
// URLs.
#define NEWSBLUR_URL "https://newsblur.com"
// API.
#define NEWSBLUR_API_LOGIN "api/login"
#define NEWSBLUR_API_LOGOUT "api/logout"
#define NEWSBLUR_API_SIGNUP "api/signup"
#endif // NEWSBLUR_DEFINITIONS_H

View File

@ -0,0 +1,63 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "gui/guiutilities.h"
#include "miscellaneous/iconfactory.h"
#include "network-web/networkfactory.h"
#include "services/newsblur/definitions.h"
#include "services/newsblur/gui/newsbluraccountdetails.h"
#include "services/newsblur/newsblurnetwork.h"
#include "services/newsblur/newsblurserviceroot.h"
FormEditNewsBlurAccount::FormEditNewsBlurAccount(QWidget* parent)
: FormAccountDetails(qApp->icons()->miscIcon(QSL("newsblur")), parent), m_details(new NewsBlurAccountDetails(this)) {
insertCustomTab(m_details, tr("Server setup"), 0);
activateTab(0);
connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditNewsBlurAccount::performTest);
m_details->m_ui.m_txtUrl->setFocus();
}
void FormEditNewsBlurAccount::apply() {
FormAccountDetails::apply();
NewsBlurServiceRoot* existing_root = account<NewsBlurServiceRoot>();
bool using_another_acc =
m_details->m_ui.m_txtUsername->lineEdit()->text() != existing_root->network()->username() ||
m_details->m_ui.m_txtUrl->lineEdit()->text() != existing_root->network()->baseUrl();
existing_root->network()->setBaseUrl(m_details->m_ui.m_txtUrl->lineEdit()->text());
existing_root->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text());
existing_root->network()->setPassword(m_details->m_ui.m_txtPassword->lineEdit()->text());
existing_root->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value());
existing_root->network()->setDownloadOnlyUnreadMessages(m_details->m_ui.m_cbDownloadOnlyUnreadMessages->isChecked());
existing_root->saveAccountDataToDatabase();
accept();
if (!m_creatingNew) {
if (using_another_acc) {
existing_root->completelyRemoveAllData();
}
existing_root->start(true);
}
}
void FormEditNewsBlurAccount::loadAccountData() {
FormAccountDetails::loadAccountData();
NewsBlurServiceRoot* existing_root = account<NewsBlurServiceRoot>();
m_details->m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->username());
m_details->m_ui.m_txtPassword->lineEdit()->setText(existing_root->network()->password());
m_details->m_ui.m_txtUrl->lineEdit()->setText(existing_root->network()->baseUrl());
m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize());
m_details->m_ui.m_cbDownloadOnlyUnreadMessages->setChecked(existing_root->network()->downloadOnlyUnreadMessages());
}
void FormEditNewsBlurAccount::performTest() {
m_details->performTest(m_proxyDetails->proxy());
}

View File

@ -0,0 +1,30 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef FORMEDITNEWSBLURACCOUNT_H
#define FORMEDITNEWSBLURACCOUNT_H
#include "services/abstract/gui/formaccountdetails.h"
class NewsBlurAccountDetails;
class NewsBlurServiceRoot;
class FormEditNewsBlurAccount : public FormAccountDetails {
Q_OBJECT
public:
explicit FormEditNewsBlurAccount(QWidget* parent = nullptr);
protected slots:
virtual void apply();
protected:
virtual void loadAccountData();
private slots:
void performTest();
private:
NewsBlurAccountDetails* m_details;
};
#endif // FORMEDITNEWSBLURACCOUNT_H

View File

@ -0,0 +1,114 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/gui/newsbluraccountdetails.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/systemfactory.h"
#include "network-web/webfactory.h"
#include "services/newsblur/definitions.h"
#include "services/newsblur/newsblurnetwork.h"
#include <QVariantHash>
NewsBlurAccountDetails::NewsBlurAccountDetails(QWidget* parent) : QWidget(parent), m_lastProxy({}) {
m_ui.setupUi(this);
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtPassword->lineEdit()->setPasswordMode(true);
m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your account"));
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your account"));
m_ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your server, without any service-specific path"));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("No test done yet."),
tr("Here, results of connection test are shown."));
m_ui.m_lblLimitMessages->setHelpText(tr("Some feeds might contain tens of thousands of articles "
"and downloading all of them could take great amount of time, "
"so sometimes it is good to download "
"only certain amount of newest messages."),
true);
connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onPasswordChanged);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onUsernameChanged);
connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onUrlChanged);
setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_cbDownloadOnlyUnreadMessages);
setTabOrder(m_ui.m_cbDownloadOnlyUnreadMessages, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_txtUsername->lineEdit());
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtPassword->lineEdit());
setTabOrder(m_ui.m_txtPassword->lineEdit(), m_ui.m_btnTestSetup);
onPasswordChanged();
onUsernameChanged();
onUrlChanged();
}
void NewsBlurAccountDetails::performTest(const QNetworkProxy& custom_proxy) {
m_lastProxy = custom_proxy;
NewsBlurNetwork factory;
factory.setUsername(m_ui.m_txtUsername->lineEdit()->text());
factory.setPassword(m_ui.m_txtPassword->lineEdit()->text());
factory.setBaseUrl(m_ui.m_txtUrl->lineEdit()->text());
try {
LoginResult result = factory.login(custom_proxy);
if (result.m_authenticated && !result.m_sessiodId.isEmpty()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("You are good to go!"),
tr("Yeah."));
}
else {
throw ApplicationException(result.m_errors.join(QSL(", ")));
}
}
catch (const NetworkException& netEx) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(netEx.networkError())),
tr("Network error, have you entered correct username and password?"));
}
catch (const ApplicationException& ex) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Error: '%1'.").arg(ex.message()),
tr("Error, have you entered correct Nextcloud endpoint and password?"));
}
}
void NewsBlurAccountDetails::onUsernameChanged() {
const QString username = m_ui.m_txtUsername->lineEdit()->text();
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("Username cannot be empty."));
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Username is okay."));
}
}
void NewsBlurAccountDetails::onPasswordChanged() {
const QString password = m_ui.m_txtPassword->lineEdit()->text();
if (password.isEmpty()) {
m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Error, tr("Password cannot be empty."));
}
else {
m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Ok, tr("Password is okay."));
}
}
void NewsBlurAccountDetails::onUrlChanged() {
const QString url = m_ui.m_txtUrl->lineEdit()->text();
if (url.isEmpty()) {
m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Error, tr("URL cannot be empty."));
}
else {
m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Ok, tr("URL is okay."));
}
}

View File

@ -0,0 +1,33 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURACCOUNTDETAILS_H
#define NEWSBLURACCOUNTDETAILS_H
#include <QWidget>
#include "ui_newsbluraccountdetails.h"
#include "services/newsblur/newsblurserviceroot.h"
#include <QNetworkProxy>
class NewsBlurAccountDetails : public QWidget {
Q_OBJECT
friend class FormEditNewsBlurAccount;
public:
explicit NewsBlurAccountDetails(QWidget* parent = nullptr);
private slots:
void performTest(const QNetworkProxy& custom_proxy);
void onUsernameChanged();
void onPasswordChanged();
void onUrlChanged();
private:
Ui::NewsBlurAccountDetails m_ui;
QNetworkProxy m_lastProxy;
};
#endif // NEWSBLURACCOUNTDETAILS_H

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewsBlurAccountDetails</class>
<widget class="QWidget" name="NewsBlurAccountDetails">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>430</width>
<height>281</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblTitle">
<property name="text">
<string>URL</string>
</property>
<property name="buddy">
<cstring>m_txtUrl</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtUrl" native="true"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_cbDownloadOnlyUnreadMessages">
<property name="text">
<string>Download unread articles only</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="m_lblLimitMessagesShort">
<property name="text">
<string>Only download newest X articles per feed</string>
</property>
<property name="buddy">
<cstring>m_spinLimitMessages</cstring>
</property>
</widget>
</item>
<item>
<widget class="MessageCountSpinBox" name="m_spinLimitMessages"/>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="HelpSpoiler" name="m_lblLimitMessages" native="true"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="m_gbAuth">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Authentication</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Username</string>
</property>
<property name="buddy">
<cstring>m_txtUsername</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtUsername" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Password</string>
</property>
<property name="buddy">
<cstring>m_txtPassword</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LineEditWithStatus" name="m_txtPassword" native="true"/>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="m_btnTestSetup">
<property name="text">
<string>&amp;Test setup</string>
</property>
</widget>
</item>
<item>
<widget class="LabelWithStatus" name="m_lblTestResult" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>409</width>
<height>60</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LabelWithStatus</class>
<extends>QWidget</extends>
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LineEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MessageCountSpinBox</class>
<extends>QSpinBox</extends>
<header>messagecountspinbox.h</header>
</customwidget>
<customwidget>
<class>HelpSpoiler</class>
<extends>QWidget</extends>
<header>helpspoiler.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_cbDownloadOnlyUnreadMessages</tabstop>
<tabstop>m_spinLimitMessages</tabstop>
<tabstop>m_btnTestSetup</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,42 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurentrypoint.h"
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "services/newsblur/newsblurserviceroot.h"
ServiceRoot* NewsBlurEntryPoint::createNewRoot() const {
FormEditNewsBlurAccount form_acc(qApp->mainFormWidget());
return form_acc.addEditAccount<NewsBlurServiceRoot>();
}
QList<ServiceRoot*> NewsBlurEntryPoint::initializeSubtree() const {
QSqlDatabase database = qApp->database()->driver()->connection(QSL("NewsBlurEntryPoint"));
return DatabaseQueries::getAccounts<NewsBlurServiceRoot>(database, code());
}
QString NewsBlurEntryPoint::name() const {
return QSL("NewsBlur");
}
QString NewsBlurEntryPoint::code() const {
return QSL(SERVICE_CODE_NEWSBLUR);
}
QString NewsBlurEntryPoint::description() const {
return QObject::tr("Personal news reader bringing people together to talk about the world.");
}
QString NewsBlurEntryPoint::author() const {
return QSL(APP_AUTHOR);
}
QIcon NewsBlurEntryPoint::icon() const {
return qApp->icons()->miscIcon(QSL("newsblur"));
}

View File

@ -0,0 +1,19 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURENTRYPOINT_H
#define NEWSBLURENTRYPOINT_H
#include "services/abstract/serviceentrypoint.h"
class NewsBlurEntryPoint : public ServiceEntryPoint {
public:
virtual ServiceRoot* createNewRoot() const;
virtual QList<ServiceRoot*> initializeSubtree() const;
virtual QString name() const;
virtual QString code() const;
virtual QString description() const;
virtual QString author() const;
virtual QIcon icon() const;
};
#endif // NEWSBLURENTRYPOINT_H

View File

@ -0,0 +1,177 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurnetwork.h"
#include "3rd-party/boolinq/boolinq.h"
#include "database/databasequeries.h"
#include "exceptions/applicationexception.h"
#include "exceptions/feedfetchexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "network-web/networkfactory.h"
#include "network-web/webfactory.h"
#include "services/abstract/category.h"
#include "services/abstract/label.h"
#include "services/abstract/labelsnode.h"
#include "services/newsblur/definitions.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
NewsBlurNetwork::NewsBlurNetwork(QObject* parent)
: QObject(parent), m_root(nullptr), m_username(QString()), m_password(QString()), m_baseUrl(QSL(NEWSBLUR_URL)),
m_batchSize(NEWSBLUR_DEFAULT_BATCH_SIZE),
m_downloadOnlyUnreadMessages(false) {
clearCredentials();
}
LoginResult NewsBlurNetwork::login(const QNetworkProxy& proxy) {
const QString full_url = generateFullUrl(Operations::Login);
const auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
const QString data = QSL("username=%1&password=%2").arg(m_username, m_password);
QByteArray output;
auto network_result = NetworkFactory::performNetworkOperation(full_url,
timeout,
data.toUtf8(),
output,
QNetworkAccessManager::Operation::PostOperation,
{ {
QSL(HTTP_HEADERS_CONTENT_TYPE).toLocal8Bit(),
QSL("application/x-www-form-urlencoded").toLocal8Bit()
} },
false,
{},
{},
proxy);
if (network_result.first == QNetworkReply::NetworkError::NoError) {
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(output, &err);
if (err.error != QJsonParseError::ParseError::NoError) {
throw ApplicationException(err.errorString());
}
LoginResult res;
res.decodeBaseResponse(doc);
res.m_userId = doc.object()["user_id"].toInt();
return res;
}
else {
throw NetworkException(network_result.first, output);
}
}
QString NewsBlurNetwork::username() const {
return m_username;
}
void NewsBlurNetwork::setUsername(const QString& username) {
m_username = username;
}
QString NewsBlurNetwork::password() const {
return m_password;
}
void NewsBlurNetwork::setPassword(const QString& password) {
m_password = password;
}
QString NewsBlurNetwork::baseUrl() const {
return m_baseUrl;
}
void NewsBlurNetwork::setBaseUrl(const QString& base_url) {
m_baseUrl = base_url;
}
QPair<QByteArray, QByteArray> NewsBlurNetwork::authHeader() const {
return { QSL("Cookie").toLocal8Bit(),
QSL("newsblur_sessionid=%1").arg(m_authSid).toLocal8Bit() };
}
void NewsBlurNetwork::ensureLogin(const QNetworkProxy& proxy) {
if (m_authSid.isEmpty()) {
try {
auto log = login(proxy);
if (log.m_authenticated && !log.m_sessiodId.isEmpty()) {
m_authSid = log.m_sessiodId;
}
else {
throw ApplicationException(log.m_errors.join(QSL(", ")));
}
}
catch (const NetworkException& ex) {
throw ex;
}
catch (const ApplicationException& ex) {
throw ex;
}
}
}
int NewsBlurNetwork::batchSize() const {
return m_batchSize;
}
void NewsBlurNetwork::setBatchSize(int batch_size) {
m_batchSize = batch_size;
}
void NewsBlurNetwork::clearCredentials() {
m_authSid = {};
m_userId = {};
}
QString NewsBlurNetwork::sanitizedBaseUrl() const {
QString base_url = m_baseUrl;
if (!base_url.endsWith('/')) {
base_url = base_url + QL1C('/');
}
return base_url;
}
QString NewsBlurNetwork::generateFullUrl(NewsBlurNetwork::Operations operation) const {
switch (operation) {
case Operations::Login:
return sanitizedBaseUrl() + QSL(NEWSBLUR_API_LOGIN);
default:
return sanitizedBaseUrl();
}
}
void NewsBlurNetwork::setRoot(NewsBlurServiceRoot* root) {
m_root = root;
}
bool NewsBlurNetwork::downloadOnlyUnreadMessages() const {
return m_downloadOnlyUnreadMessages;
}
void NewsBlurNetwork::setDownloadOnlyUnreadMessages(bool download_only_unread) {
m_downloadOnlyUnreadMessages = download_only_unread;
}
void ApiResult::decodeBaseResponse(const QJsonDocument& doc) {
m_authenticated = doc.object()["authenticated"].toBool();
m_code = doc.object()["code"].toInt();
QStringList errs;
QJsonObject obj_errs = doc.object()["errors"].toObject();
for (const QString& key : obj_errs.keys()) {
for (const QJsonValue& val: obj_errs.value(key).toArray()) {
errs << val.toString();
}
}
m_errors = errs;
}

View File

@ -0,0 +1,77 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURNETWORK_H
#define NEWSBLURNETWORK_H
#include <QObject>
#include "network-web/networkfactory.h"
#include "services/abstract/feed.h"
#include "services/newsblur/newsblurserviceroot.h"
struct ApiResult {
bool m_authenticated;
int m_code;
QStringList m_errors;
void decodeBaseResponse(const QJsonDocument& doc);
};
struct LoginResult : ApiResult {
QString m_sessiodId;
int m_userId;
};
class NewsBlurNetwork : public QObject {
Q_OBJECT
public:
enum class Operations {
Login
};
explicit NewsBlurNetwork(QObject* parent = nullptr);
void clearCredentials();
QString username() const;
void setUsername(const QString& username);
QString password() const;
void setPassword(const QString& password);
QString baseUrl() const;
void setBaseUrl(const QString& base_url);
int batchSize() const;
void setBatchSize(int batch_size);
bool downloadOnlyUnreadMessages() const;
void setDownloadOnlyUnreadMessages(bool download_only_unread);
void setRoot(NewsBlurServiceRoot* root);
// API methods.
LoginResult login(const QNetworkProxy& proxy);
private:
QPair<QByteArray, QByteArray> authHeader() const;
// Make sure we are logged in and if we are not, throw exception.
void ensureLogin(const QNetworkProxy& proxy);
QString sanitizedBaseUrl() const;
QString generateFullUrl(Operations operation) const;
private:
NewsBlurServiceRoot* m_root;
QString m_username;
QString m_password;
QString m_baseUrl;
int m_batchSize;
bool m_downloadOnlyUnreadMessages;
QString m_authSid;
int m_userId;
};
#endif // NEWSBLURNETWORK_H

View File

@ -0,0 +1,145 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurserviceroot.h"
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "exceptions/feedfetchexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/textfactory.h"
#include "network-web/oauth2service.h"
#include "services/abstract/importantnode.h"
#include "services/abstract/recyclebin.h"
#include "services/newsblur/definitions.h"
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "services/newsblur/newsblurentrypoint.h"
#include "services/newsblur/newsblurnetwork.h"
NewsBlurServiceRoot::NewsBlurServiceRoot(RootItem* parent)
: ServiceRoot(parent), m_network(new NewsBlurNetwork(this)) {
m_network->setRoot(this);
setIcon(NewsBlurEntryPoint().icon());
}
bool NewsBlurServiceRoot::isSyncable() const {
return true;
}
bool NewsBlurServiceRoot::canBeEdited() const {
return true;
}
bool NewsBlurServiceRoot::editViaGui() {
FormEditNewsBlurAccount form_pointer(qApp->mainFormWidget());
form_pointer.addEditAccount(this);
return true;
}
QVariantHash NewsBlurServiceRoot::customDatabaseData() const {
QVariantHash data;
data[QSL("username")] = m_network->username();
data[QSL("password")] = TextFactory::encrypt(m_network->password());
data[QSL("url")] = m_network->baseUrl();
return data;
}
void NewsBlurServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setUsername(data[QSL("username")].toString());
m_network->setPassword(TextFactory::decrypt(data[QSL("password")].toString()));
m_network->setBaseUrl(data[QSL("url")].toString());
}
QList<Message> NewsBlurServiceRoot::obtainNewMessages(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Feed::Status error = Feed::Status::Normal;
QList<Message> msgs;
// TODO::
if (error != Feed::Status::NewMessages && error != Feed::Status::Normal) {
throw FeedFetchException(error);
}
else {
return msgs;
}
}
void NewsBlurServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}
updateTitleIcon();
if (getSubTreeFeeds().isEmpty()) {
syncIn();
}
}
QString NewsBlurServiceRoot::code() const {
return NewsBlurEntryPoint().code();
}
void NewsBlurServiceRoot::saveAllCachedData(bool ignore_errors) {
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
/*
// Save the actual data read/unread.
while (i.hasNext()) {
i.next();
auto key = i.key();
QStringList ids = i.value();
if (!ids.isEmpty()) {
if (network()->markMessagesRead(key, ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(ids, key);
}
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {
j.next();
auto key = j.key();
QList<Message> messages = j.value();
if (!messages.isEmpty()) {
QStringList custom_ids; custom_ids.reserve(messages.size());
for (const Message& msg : messages) {
custom_ids.append(msg.m_customId);
}
if (network()->markMessagesStarred(key, custom_ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(messages, key);
}
}
}
*/
}
ServiceRoot::LabelOperation NewsBlurServiceRoot::supportedLabelOperations() const {
return ServiceRoot::LabelOperation::Synchronised;
}
void NewsBlurServiceRoot::updateTitleIcon() {
setTitle(QSL("%1 (%2)").arg(m_network->username(), NewsBlurEntryPoint().name()));
}
RootItem* NewsBlurServiceRoot::obtainNewTreeForSyncIn() const {
return nullptr;
//return m_network->categoriesFeedsLabelsTree(true, networkProxy());
}

View File

@ -0,0 +1,46 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURSERVICEROOT_H
#define NEWSBLURSERVICEROOT_H
#include "services/abstract/cacheforserviceroot.h"
#include "services/abstract/serviceroot.h"
class NewsBlurNetwork;
class NewsBlurServiceRoot : public ServiceRoot, public CacheForServiceRoot {
Q_OBJECT
public:
explicit NewsBlurServiceRoot(RootItem* parent = nullptr);
virtual bool isSyncable() const;
virtual bool canBeEdited() const;
virtual bool editViaGui();
virtual void start(bool freshly_activated);
virtual QString code() const;
virtual void saveAllCachedData(bool ignore_errors);
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
NewsBlurNetwork* network() const;
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;
private:
void updateTitleIcon();
private:
NewsBlurNetwork* m_network;
};
inline NewsBlurNetwork* NewsBlurServiceRoot::network() const {
return m_network;
}
#endif // NEWSBLURSERVICEROOT_H