Add reading time for entries

This commit is contained in:
Maxime Bailleul 2020-07-17 04:46:24 +02:00 committed by Frédéric Guillot
parent 499fb1f7df
commit ee5a8a05c9
25 changed files with 813 additions and 653 deletions

View File

@ -12,7 +12,7 @@ import (
"miniflux.app/logger"
)
const schemaVersion = 32
const schemaVersion = 33
// Migrate executes database migrations.
func Migrate(db *sql.DB) {

View File

@ -185,6 +185,7 @@ create index entries_user_feed_idx on entries (user_id, feed_id);
"schema_version_31": `alter table feeds add column ignore_http_cache bool default false;`,
"schema_version_32": `alter table users add column entries_per_page int default 100;
`,
"schema_version_33": `alter table users add column show_reading_time boolean default 't';`,
"schema_version_4": `create type entry_sorting_direction as enum('asc', 'desc');
alter table users add column entry_direction entry_sorting_direction default 'asc';
`,
@ -240,6 +241,7 @@ var SqlMapChecksums = map[string]string{
"schema_version_30": "3ec48a9b2e7a0fc32c85f31652f723565c34213f5f2d7e5e5076aad8f0b40d23",
"schema_version_31": "9290ef295731b03ddfe32dcaded0be70d41b63572420ad379cf2874a9b54581c",
"schema_version_32": "5b4de8dd2d7e3c6ae4150e0e3931df2ee989f2c667145bd67294e5a5f3fae456",
"schema_version_33": "bf38514efeb6c12511f41b1cc484f92722240b0a6ae874c32a958dfea3433d02",
"schema_version_4": "216ea3a7d3e1704e40c797b5dc47456517c27dbb6ca98bf88812f4f63d74b5d9",
"schema_version_5": "46397e2f5f2c82116786127e9f6a403e975b14d2ca7b652a48cd1ba843e6a27c",
"schema_version_6": "9d05b4fb223f0e60efc716add5048b0ca9c37511cf2041721e20505d6d798ce4",

View File

@ -0,0 +1 @@
alter table users add column show_reading_time boolean default 't';

View File

@ -82,6 +82,10 @@ var translations = map[string]string{
"entry.unshare.label": "Nicht teilen",
"entry.shared_entry.title": "Öffnen Sie den öffentlichen Link",
"entry.shared_entry.label": "Teilen",
"entry.estimated_reading_time": [
"%d Minute gelesen",
"%d Minuten gelesen"
],
"page.shared_entries.title": "Geteilte Artikel",
"page.unread.title": "Ungelesen",
"page.starred.title": "Lesezeichen",
@ -264,6 +268,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Älteste Artikel zuerst",
"form.prefs.select.recent_first": "Neueste Artikel zuerst",
"form.prefs.label.keyboard_shortcuts": "Tastaturkürzel aktivieren",
"form.prefs.label.show_reading_time": "Geschätzte Lesezeit für Artikel anzeigen",
"form.prefs.label.custom_css": "Benutzerdefiniertes CSS",
"form.import.label.file": "OPML Datei",
"form.import.label.url": "URL",
@ -422,6 +427,10 @@ var translations = map[string]string{
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Open the public link",
"entry.shared_entry.label": "Share",
"entry.estimated_reading_time": [
"%d minute read",
"%d minutes read"
],
"page.shared_entries.title": "Shared Entries",
"page.unread.title": "Unread",
"page.starred.title": "Starred",
@ -604,6 +613,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Older entries first",
"form.prefs.select.recent_first": "Recent entries first",
"form.prefs.label.keyboard_shortcuts": "Enable keyboard shortcuts",
"form.prefs.label.show_reading_time": "Show estimated reading time for articles",
"form.prefs.label.custom_css": "Custom CSS",
"form.import.label.file": "OPML file",
"form.import.label.url": "URL",
@ -742,6 +752,10 @@ var translations = map[string]string{
"entry.unshare.label": "No compartir",
"entry.shared_entry.title": "Abrir el enlace público",
"entry.shared_entry.label": "Compartir",
"entry.estimated_reading_time": [
"%d minuto de lectura",
"%d minutos de lectura"
],
"page.shared_entries.title": "Entradas compartidas",
"page.unread.title": "No leídos",
"page.starred.title": "Marcadores",
@ -924,6 +938,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Entradas más viejas primero",
"form.prefs.select.recent_first": "Entradas recientes primero",
"form.prefs.label.keyboard_shortcuts": "Habilitar atajos de teclado",
"form.prefs.label.show_reading_time": "Mostrar el tiempo estimado de lectura de los artículos",
"form.prefs.label.custom_css": "CSS personalizado",
"form.import.label.file": "Archivo OPML",
"form.import.label.url": "URL",
@ -1062,6 +1077,10 @@ var translations = map[string]string{
"entry.unshare.label": "Enlever le partage",
"entry.shared_entry.title": "Ouvrir le lien public",
"entry.shared_entry.label": "Partage",
"entry.estimated_reading_time": [
"%d minute de lecture",
"%d minutes de lecture"
],
"page.shared_entries.title": "Articles partagés",
"page.unread.title": "Non lus",
"page.starred.title": "Favoris",
@ -1244,6 +1263,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Ancien éléments en premier",
"form.prefs.select.recent_first": "Éléments récents en premier",
"form.prefs.label.keyboard_shortcuts": "Activer les raccourcis clavier",
"form.prefs.label.show_reading_time": "Afficher le temps de lecture estimé des articles",
"form.prefs.label.custom_css": "CSS personnalisé",
"form.import.label.file": "Fichier OPML",
"form.import.label.url": "URL",
@ -1402,6 +1422,10 @@ var translations = map[string]string{
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Apri il link pubblico",
"entry.shared_entry.label": "Condivisione",
"entry.estimated_reading_time": [
"%d minuto di lettura",
"%d minuti di lettura"
],
"page.shared_entries.title": "Voci condivise",
"page.unread.title": "Da leggere",
"page.starred.title": "Preferiti",
@ -1584,6 +1608,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Prima i più vecchi",
"form.prefs.select.recent_first": "Prima i più recenti",
"form.prefs.label.keyboard_shortcuts": "Abilita le scorciatoie da tastiera",
"form.prefs.label.show_reading_time": "Mostra il tempo di lettura stimato per gli articoli",
"form.prefs.label.custom_css": "CSS personalizzati",
"form.import.label.file": "File OPML",
"form.import.label.url": "URL",
@ -1722,6 +1747,10 @@ var translations = map[string]string{
"entry.unshare.label": "共有解除",
"entry.shared_entry.title": "公開リンクを開く",
"entry.shared_entry.label": "共有する",
"entry.estimated_reading_time": [
"%d分で読む",
"%d分で読む"
],
"page.shared_entries.title": "共有エントリ",
"page.unread.title": "未読",
"page.starred.title": "星付き",
@ -1904,6 +1933,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "古い記事を最初に",
"form.prefs.select.recent_first": "新しい記事を最初に",
"form.prefs.label.keyboard_shortcuts": "キーボード・ショートカットを有効にする",
"form.prefs.label.show_reading_time": "記事の推定読書時間を表示する",
"form.prefs.label.custom_css": "カスタムCSS",
"form.import.label.file": "OPML ファイル",
"form.import.label.url": "URL",
@ -2042,6 +2072,10 @@ var translations = map[string]string{
"entry.unshare.label": "Delen ongedaan maken",
"entry.shared_entry.title": "Open de openbare link",
"entry.shared_entry.label": "Delen",
"entry.estimated_reading_time": [
"%d minuut gelezen",
"%d minuten gelezen"
],
"page.shared_entries.title": "Gedeelde vermeldingen",
"page.unread.title": "Ongelezen",
"page.starred.title": "Favorieten",
@ -2224,6 +2258,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Oudere items eerst",
"form.prefs.select.recent_first": "Recente items eerst",
"form.prefs.label.keyboard_shortcuts": "Schakel sneltoetsen in",
"form.prefs.label.show_reading_time": "Toon geschatte leestijd voor artikelen",
"form.prefs.label.custom_css": "Aangepaste CSS",
"form.import.label.file": "OPML-bestand",
"form.import.label.url": "URL",
@ -2380,6 +2415,10 @@ var translations = map[string]string{
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Otwórz publiczny link",
"entry.shared_entry.label": "Udostępnianie",
"entry.estimated_reading_time": [
"%d minuta czytania",
"%d minut czytania"
],
"page.shared_entries.title": "Udostępnione wpisy",
"page.unread.title": "Nieprzeczytane",
"page.starred.title": "Oznaczone gwiazdką",
@ -2563,6 +2602,7 @@ var translations = map[string]string{
"form.prefs.label.entries_per_page": "Wpisy na stronie",
"form.prefs.select.older_first": "Najstarsze wpisy jako pierwsze",
"form.prefs.label.keyboard_shortcuts": "Włącz skróty klawiaturowe",
"form.prefs.label.show_reading_time": "Pokaż szacowany czas czytania artykułów",
"form.prefs.select.recent_first": "Najnowsze wpisy jako pierwsze",
"form.prefs.label.custom_css": "Niestandardowy CSS",
"form.import.label.file": "Plik OPML",
@ -2726,6 +2766,10 @@ var translations = map[string]string{
"entry.unshare.label": "Descompartilhar",
"entry.shared_entry.title": "Abrir link público",
"entry.shared_entry.label": "Compartilhar",
"entry.estimated_reading_time": [
"%d minuto lido",
"%d minutos lidos"
],
"page.shared_entries.title": "Itens compartilhados",
"page.unread.title": "Não lídos",
"page.starred.title": "Favoritos",
@ -2908,6 +2952,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Itens mais velhos primeiro",
"form.prefs.select.recent_first": "Itens mais recentes",
"form.prefs.label.keyboard_shortcuts": "Habilitar atalhos do teclado",
"form.prefs.label.show_reading_time": "Mostrar tempo estimado de leitura de artigos",
"form.prefs.label.custom_css": "CSS customizado",
"form.import.label.file": "Arquivo OPML",
"form.import.label.url": "URL",
@ -3046,6 +3091,10 @@ var translations = map[string]string{
"entry.unshare.label": "Удалить из общедоступных",
"entry.shared_entry.title": "Открыть публичную ссылку",
"entry.shared_entry.label": "Поделиться",
"entry.estimated_reading_time": [
"%d минута чтения",
"%d минут чтения"
],
"page.shared_entries.title": "Общедоступные записи",
"page.unread.title": "Непрочитанное",
"page.starred.title": "Избранное",
@ -3230,6 +3279,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "Сначала старые записи",
"form.prefs.select.recent_first": "Сначала последние записи",
"form.prefs.label.keyboard_shortcuts": "Включить сочетания клавиш",
"form.prefs.label.show_reading_time": "Показать примерное время чтения статей",
"form.prefs.label.custom_css": "Пользовательские CSS",
"form.import.label.file": "OPML файл",
"form.import.label.url": "URL",
@ -3374,6 +3424,10 @@ var translations = map[string]string{
"entry.unshare.label": "取消分享",
"entry.shared_entry.title": "打开公共链接",
"entry.shared_entry.label": "分享分享",
"entry.estimated_reading_time": [
"%d分钟阅读",
"%d分钟阅读"
],
"page.shared_entries.title": "共享条目",
"page.unread.title": "未读",
"page.starred.title": "星标",
@ -3554,6 +3608,7 @@ var translations = map[string]string{
"form.prefs.select.older_first": "旧->新",
"form.prefs.select.recent_first": "新->旧",
"form.prefs.label.keyboard_shortcuts": "启用键盘快捷键",
"form.prefs.label.show_reading_time": "显示文章的预计阅读时间",
"form.prefs.label.custom_css": "自定义CSS",
"form.import.label.file": "OPML 文件",
"form.import.label.url": "URL",
@ -3629,15 +3684,15 @@ var translations = map[string]string{
}
var translationsChecksums = map[string]string{
"de_DE": "e986a40b1748968725ddede18ae6451e4d1ae270b9c4c033daa81ee50b1d306e",
"en_US": "b27169fc7767e51e6f7610ff1844708e8111e527c7931e3f888864a66826e293",
"es_ES": "20a713468ca6ce00e899a80354912e927ded61cf8a79ad9d976c78f515e242dd",
"fr_FR": "251eb14fe8521bde772d293fa748307ecd4cae4b0597da03aad39e745a382f11",
"it_IT": "8ab664ec8d826aa3702a4f5294c3a3e87193437e64b0ef4990a3a9609b782786",
"ja_JP": "7dc146dc5815a8d6dbae2f7f467deea598a85099bbee63e92bf3862d445519af",
"nl_NL": "fd106f08b2f8902712a68716a0e33b063bdce32a8440f7a2b296b4f822088403",
"pl_PL": "85de665d29e873f6099ef5ea40efe569a05ec3cbf08e4ca7741778bf3d5c8593",
"pt_BR": "193847c5691590926e684894ef971141f69c0e2aaf270457e10331d75a29e34b",
"ru_RU": "6e765e44e250469fe1c5666f8ff24e5e07e6b04098c1325c2663a1f722e0bfe9",
"zh_CN": "0dc8c5b86a03f0ce58f6d2633ab3011d9bc8004af18f922944a65d151e54beda",
"de_DE": "f3dd20afc5cbd9ac689bec2939c1d2fbe71372360c4e8f335e3b8cbce4228958",
"en_US": "30cbcb2170782f1e66f69066947bf053f68065d7b270eea879f2c573819dd52b",
"es_ES": "50dc7c8c2db7368bae133f5b455721470d314321153d41e4f27436a0f3f176e6",
"fr_FR": "373fd2db868961758bd1483c34f117b03aadea17080f268bc8bbd0acdfbc5eed",
"it_IT": "8d8f0bd75b4e7dec9370647c888dd9438b691130d9c41f839cdfff8cbc606cb5",
"ja_JP": "ec3a21c547e4625ad359624e43ba31b556fb8d8b8ff7fc7a20df089317db99b3",
"nl_NL": "20e180be2375f07ec02eb05f372a9102c13037a79e5651ce9bd41507fd2180d2",
"pl_PL": "b1526955641823708b4c1ca753b61e1e0561d0a3d33da3f62170540903031b0d",
"pt_BR": "cf8e131d39daac82d3157c6538c0643392a06358b7bc98be8579412ebd63f60e",
"ru_RU": "4056e4e94861835d44064273371adbbded7190e2b719769886eb99e6c9feaf82",
"zh_CN": "044abb0a34eee3d8d5597811d40166762311b8e4cd08b891796113790cc775f0",
}

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Nicht teilen",
"entry.shared_entry.title": "Öffnen Sie den öffentlichen Link",
"entry.shared_entry.label": "Teilen",
"entry.estimated_reading_time": [
"%d Minute gelesen",
"%d Minuten gelesen"
],
"page.shared_entries.title": "Geteilte Artikel",
"page.unread.title": "Ungelesen",
"page.starred.title": "Lesezeichen",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Älteste Artikel zuerst",
"form.prefs.select.recent_first": "Neueste Artikel zuerst",
"form.prefs.label.keyboard_shortcuts": "Tastaturkürzel aktivieren",
"form.prefs.label.show_reading_time": "Geschätzte Lesezeit für Artikel anzeigen",
"form.prefs.label.custom_css": "Benutzerdefiniertes CSS",
"form.import.label.file": "OPML Datei",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Open the public link",
"entry.shared_entry.label": "Share",
"entry.estimated_reading_time": [
"%d minute read",
"%d minutes read"
],
"page.shared_entries.title": "Shared Entries",
"page.unread.title": "Unread",
"page.starred.title": "Starred",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Older entries first",
"form.prefs.select.recent_first": "Recent entries first",
"form.prefs.label.keyboard_shortcuts": "Enable keyboard shortcuts",
"form.prefs.label.show_reading_time": "Show estimated reading time for articles",
"form.prefs.label.custom_css": "Custom CSS",
"form.import.label.file": "OPML file",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "No compartir",
"entry.shared_entry.title": "Abrir el enlace público",
"entry.shared_entry.label": "Compartir",
"entry.estimated_reading_time": [
"%d minuto de lectura",
"%d minutos de lectura"
],
"page.shared_entries.title": "Entradas compartidas",
"page.unread.title": "No leídos",
"page.starred.title": "Marcadores",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Entradas más viejas primero",
"form.prefs.select.recent_first": "Entradas recientes primero",
"form.prefs.label.keyboard_shortcuts": "Habilitar atajos de teclado",
"form.prefs.label.show_reading_time": "Mostrar el tiempo estimado de lectura de los artículos",
"form.prefs.label.custom_css": "CSS personalizado",
"form.import.label.file": "Archivo OPML",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Enlever le partage",
"entry.shared_entry.title": "Ouvrir le lien public",
"entry.shared_entry.label": "Partage",
"entry.estimated_reading_time": [
"%d minute de lecture",
"%d minutes de lecture"
],
"page.shared_entries.title": "Articles partagés",
"page.unread.title": "Non lus",
"page.starred.title": "Favoris",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Ancien éléments en premier",
"form.prefs.select.recent_first": "Éléments récents en premier",
"form.prefs.label.keyboard_shortcuts": "Activer les raccourcis clavier",
"form.prefs.label.show_reading_time": "Afficher le temps de lecture estimé des articles",
"form.prefs.label.custom_css": "CSS personnalisé",
"form.import.label.file": "Fichier OPML",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Apri il link pubblico",
"entry.shared_entry.label": "Condivisione",
"entry.estimated_reading_time": [
"%d minuto di lettura",
"%d minuti di lettura"
],
"page.shared_entries.title": "Voci condivise",
"page.unread.title": "Da leggere",
"page.starred.title": "Preferiti",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Prima i più vecchi",
"form.prefs.select.recent_first": "Prima i più recenti",
"form.prefs.label.keyboard_shortcuts": "Abilita le scorciatoie da tastiera",
"form.prefs.label.show_reading_time": "Mostra il tempo di lettura stimato per gli articoli",
"form.prefs.label.custom_css": "CSS personalizzati",
"form.import.label.file": "File OPML",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "共有解除",
"entry.shared_entry.title": "公開リンクを開く",
"entry.shared_entry.label": "共有する",
"entry.estimated_reading_time": [
"%d分で読む",
"%d分で読む"
],
"page.shared_entries.title": "共有エントリ",
"page.unread.title": "未読",
"page.starred.title": "星付き",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "古い記事を最初に",
"form.prefs.select.recent_first": "新しい記事を最初に",
"form.prefs.label.keyboard_shortcuts": "キーボード・ショートカットを有効にする",
"form.prefs.label.show_reading_time": "記事の推定読書時間を表示する",
"form.prefs.label.custom_css": "カスタムCSS",
"form.import.label.file": "OPML ファイル",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Delen ongedaan maken",
"entry.shared_entry.title": "Open de openbare link",
"entry.shared_entry.label": "Delen",
"entry.estimated_reading_time": [
"%d minuut gelezen",
"%d minuten gelezen"
],
"page.shared_entries.title": "Gedeelde vermeldingen",
"page.unread.title": "Ongelezen",
"page.starred.title": "Favorieten",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Oudere items eerst",
"form.prefs.select.recent_first": "Recente items eerst",
"form.prefs.label.keyboard_shortcuts": "Schakel sneltoetsen in",
"form.prefs.label.show_reading_time": "Toon geschatte leestijd voor artikelen",
"form.prefs.label.custom_css": "Aangepaste CSS",
"form.import.label.file": "OPML-bestand",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Unshare",
"entry.shared_entry.title": "Otwórz publiczny link",
"entry.shared_entry.label": "Udostępnianie",
"entry.estimated_reading_time": [
"%d minuta czytania",
"%d minut czytania"
],
"page.shared_entries.title": "Udostępnione wpisy",
"page.unread.title": "Nieprzeczytane",
"page.starred.title": "Oznaczone gwiazdką",
@ -260,6 +264,7 @@
"form.prefs.label.entries_per_page": "Wpisy na stronie",
"form.prefs.select.older_first": "Najstarsze wpisy jako pierwsze",
"form.prefs.label.keyboard_shortcuts": "Włącz skróty klawiaturowe",
"form.prefs.label.show_reading_time": "Pokaż szacowany czas czytania artykułów",
"form.prefs.select.recent_first": "Najnowsze wpisy jako pierwsze",
"form.prefs.label.custom_css": "Niestandardowy CSS",
"form.import.label.file": "Plik OPML",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Descompartilhar",
"entry.shared_entry.title": "Abrir link público",
"entry.shared_entry.label": "Compartilhar",
"entry.estimated_reading_time": [
"%d minuto lido",
"%d minutos lidos"
],
"page.shared_entries.title": "Itens compartilhados",
"page.unread.title": "Não lídos",
"page.starred.title": "Favoritos",
@ -259,6 +263,7 @@
"form.prefs.select.older_first": "Itens mais velhos primeiro",
"form.prefs.select.recent_first": "Itens mais recentes",
"form.prefs.label.keyboard_shortcuts": "Habilitar atalhos do teclado",
"form.prefs.label.show_reading_time": "Mostrar tempo estimado de leitura de artigos",
"form.prefs.label.custom_css": "CSS customizado",
"form.import.label.file": "Arquivo OPML",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "Удалить из общедоступных",
"entry.shared_entry.title": "Открыть публичную ссылку",
"entry.shared_entry.label": "Поделиться",
"entry.estimated_reading_time": [
"%d минута чтения",
"%d минут чтения"
],
"page.shared_entries.title": "Общедоступные записи",
"page.unread.title": "Непрочитанное",
"page.starred.title": "Избранное",
@ -261,6 +265,7 @@
"form.prefs.select.older_first": "Сначала старые записи",
"form.prefs.select.recent_first": "Сначала последние записи",
"form.prefs.label.keyboard_shortcuts": "Включить сочетания клавиш",
"form.prefs.label.show_reading_time": "Показать примерное время чтения статей",
"form.prefs.label.custom_css": "Пользовательские CSS",
"form.import.label.file": "OPML файл",
"form.import.label.url": "URL",

View File

@ -77,6 +77,10 @@
"entry.unshare.label": "取消分享",
"entry.shared_entry.title": "打开公共链接",
"entry.shared_entry.label": "分享分享",
"entry.estimated_reading_time": [
"%d分钟阅读",
"%d分钟阅读"
],
"page.shared_entries.title": "共享条目",
"page.unread.title": "未读",
"page.starred.title": "星标",
@ -257,6 +261,7 @@
"form.prefs.select.older_first": "旧->新",
"form.prefs.select.recent_first": "新->旧",
"form.prefs.label.keyboard_shortcuts": "启用键盘快捷键",
"form.prefs.label.show_reading_time": "显示文章的预计阅读时间",
"form.prefs.label.custom_css": "自定义CSS",
"form.import.label.file": "OPML 文件",
"form.import.label.url": "URL",

View File

@ -23,6 +23,7 @@ type User struct {
EntryDirection string `json:"entry_sorting_direction"`
EntriesPerPage int `json:"entries_per_page"`
KeyboardShortcuts bool `json:"keyboard_shortcuts"`
ShowReadingTime bool `json:"show_reading_time"`
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
Extra map[string]string `json:"extra"`
}

View File

@ -64,7 +64,7 @@ func (s *Storage) CreateUser(user *model.User) (err error) {
VALUES
(LOWER($1), $2, $3, $4)
RETURNING
id, username, is_admin, language, theme, timezone, entry_direction, entries_per_page, keyboard_shortcuts
id, username, is_admin, language, theme, timezone, entry_direction, entries_per_page, keyboard_shortcuts, show_reading_time
`
err = s.db.QueryRow(query, user.Username, password, user.IsAdmin, extra).Scan(
@ -77,6 +77,7 @@ func (s *Storage) CreateUser(user *model.User) (err error) {
&user.EntryDirection,
&user.EntriesPerPage,
&user.KeyboardShortcuts,
&user.ShowReadingTime,
)
if err != nil {
return fmt.Errorf(`store: unable to create user: %v`, err)
@ -125,9 +126,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
timezone=$6,
entry_direction=$7,
entries_per_page=$8,
keyboard_shortcuts=$9
keyboard_shortcuts=$9,
show_reading_time=$10
WHERE
id=$10
id=$11
`
_, err = s.db.Exec(
@ -141,6 +143,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.EntryDirection,
user.EntriesPerPage,
user.KeyboardShortcuts,
user.ShowReadingTime,
user.ID,
)
if err != nil {
@ -156,9 +159,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
timezone=$5,
entry_direction=$6,
entries_per_page=$7,
keyboard_shortcuts=$8
keyboard_shortcuts=$8,
show_reading_time=$9
WHERE
id=$9
id=$10
`
_, err := s.db.Exec(
@ -171,6 +175,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.EntryDirection,
user.EntriesPerPage,
user.KeyboardShortcuts,
user.ShowReadingTime,
user.ID,
)
@ -209,6 +214,7 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
entry_direction,
entries_per_page,
keyboard_shortcuts,
show_reading_time,
last_login_at,
extra
FROM
@ -232,6 +238,7 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
entry_direction,
entries_per_page,
keyboard_shortcuts,
show_reading_time,
last_login_at,
extra
FROM
@ -255,6 +262,7 @@ func (s *Storage) UserByExtraField(field, value string) (*model.User, error) {
entry_direction,
entries_per_page,
keyboard_shortcuts,
show_reading_time,
last_login_at,
extra
FROM
@ -278,6 +286,7 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
u.entry_direction,
u.entries_per_page,
u.keyboard_shortcuts,
u.show_reading_time,
u.last_login_at,
u.extra
FROM
@ -304,6 +313,7 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
&user.EntryDirection,
&user.EntriesPerPage,
&user.KeyboardShortcuts,
&user.ShowReadingTime,
&user.LastLoginAt,
&extra,
)
@ -360,6 +370,7 @@ func (s *Storage) Users() (model.Users, error) {
entry_direction,
entries_per_page,
keyboard_shortcuts,
show_reading_time,
last_login_at,
extra
FROM
@ -386,6 +397,7 @@ func (s *Storage) Users() (model.Users, error) {
&user.EntryDirection,
&user.EntriesPerPage,
&user.KeyboardShortcuts,
&user.ShowReadingTime,
&user.LastLoginAt,
&extra,
)

View File

@ -237,6 +237,13 @@ SOFTWARE.
<li>
<time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed .user.Timezone .entry.Date }}</time>
</li>
{{ if .user.ShowReadingTime }}
<li>
<span>
{{ plural "entry.estimated_reading_time" (timeToRead .entry.Content) (timeToRead .entry.Content) }}
</span>
</li>
{{ end }}
</ul>
<ul class="item-meta-icons">
{{ if .entry.ShareCode }}
@ -510,7 +517,7 @@ var templateCommonMapChecksums = map[string]string{
"feed_list": "30acc9ecc413811e73a1dad120b5d44e29564de3ba794fb07ee886b30addfb19",
"feed_menu": "318d8662dda5ca9dfc75b909c8461e79c86fb5082df1428f67aaf856f19f4b50",
"icons": "3dbe754a98f524a227111191d76b8c6944711b13613cc548ee9e9808fe0bffb4",
"item_meta": "a5b07cc6597e5c8f3ca849ee486acb3f16f062d8a1eaa47d2fb402ae6825b7ef",
"item_meta": "a5b686c7af6348fdbd9a147e3fcfacc4a0b442c3b9637f3dce026ccf367fc312",
"layout": "91d2ab3f683a2ced5e9ce5cd04919e74b3e3f329a5eedcc60015b8d49ecb1b77",
"pagination": "7b61288e86283c4cf0dc83bcbf8bf1c00c7cb29e60201c8c0b633b2450d2911f",
"settings_menu": "e2b777630c0efdbc529800303c01d6744ed3af80ec505ac5a5b3f99c9b989156",

View File

@ -65,6 +65,9 @@ func (e *Engine) Render(name, language string, data interface{}) []byte {
"plural": func(key string, n int, args ...interface{}) string {
return printer.Plural(key, n, args...)
},
"timeToRead": func(content string) int {
return timeToRead(content)
},
})
var b bytes.Buffer

View File

@ -92,6 +92,9 @@ func (f *funcMap) Map() template.FuncMap {
"plural": func(key string, n int, args ...interface{}) string {
return ""
},
"timeToRead": func(content string) int {
return 0
},
}
}
@ -218,3 +221,9 @@ func formatFileSize(b int64) string {
return fmt.Sprintf("%.1f %ciB",
float64(b)/float64(div), "KMGTPE"[exp])
}
func timeToRead(content string) int {
nbOfWords := len(strings.Fields(content))
return int(math.Ceil(float64(nbOfWords) / 265))
}

View File

@ -7,6 +7,13 @@
<li>
<time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed .user.Timezone .entry.Date }}</time>
</li>
{{ if .user.ShowReadingTime }}
<li>
<span>
{{ plural "entry.estimated_reading_time" (timeToRead .entry.Content) (timeToRead .entry.Content) }}
</span>
</li>
{{ end }}
</ul>
<ul class="item-meta-icons">
{{ if .entry.ShareCode }}

View File

@ -54,6 +54,8 @@
<label><input type="checkbox" name="keyboard_shortcuts" value="1" {{ if .form.KeyboardShortcuts }}checked{{ end }}> {{ t "form.prefs.label.keyboard_shortcuts" }}</label>
<label><input type="checkbox" name="show_reading_time" value="1" {{ if .form.ShowReadingTime }}checked{{ end }}> {{ t "form.prefs.label.show_reading_time" }}</label>
<label>{{t "form.prefs.label.custom_css" }}</label><textarea name="custom_css" cols="40" rows="5">{{ .form.CustomCSS }}</textarea>
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>

View File

@ -1325,6 +1325,8 @@ var templateViewsMap = map[string]string{
<label><input type="checkbox" name="keyboard_shortcuts" value="1" {{ if .form.KeyboardShortcuts }}checked{{ end }}> {{ t "form.prefs.label.keyboard_shortcuts" }}</label>
<label><input type="checkbox" name="show_reading_time" value="1" {{ if .form.ShowReadingTime }}checked{{ end }}> {{ t "form.prefs.label.show_reading_time" }}</label>
<label>{{t "form.prefs.label.custom_css" }}</label><textarea name="custom_css" cols="40" rows="5">{{ .form.CustomCSS }}</textarea>
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
@ -1568,7 +1570,7 @@ var templateViewsMapChecksums = map[string]string{
"login": "79ff2ca488c0a19b37c8fa227a21f73e94472eb357a51a077197c852f7713f11",
"search_entries": "c0786ddc6b17e865007b975eefb97417935cbc601f5917cca1ee0d3f584594bc",
"sessions": "5d5c677bddbd027e0b0c9f7a0dd95b66d9d95b4e130959f31fb955b926c2201c",
"settings": "3d6dd0d7fa0ca48cfd9a5edb43c055af8b816eb4460f16b71ae22db40ed9b754",
"settings": "a4d3df17e6abc75881ec1ca5f92a9c2cfe24e3e08e5d844df848b4d6aaa1bbc0",
"shared_entries": "1494d81e46f6af534a73cf6a91f8dfda1932a477bb3a70143513896ac0f0220b",
"unread_entries": "e0080d0cf3583cda51d865422960137c8556c432853657086e43daf6bd5b73be",
"users": "d7ff52efc582bbad10504f4a04fa3adcc12d15890e45dff51cac281e0c446e45",

View File

@ -23,6 +23,7 @@ type SettingsForm struct {
EntryDirection string
EntriesPerPage int
KeyboardShortcuts bool
ShowReadingTime bool
CustomCSS string
}
@ -35,6 +36,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
user.EntryDirection = s.EntryDirection
user.EntriesPerPage = s.EntriesPerPage
user.KeyboardShortcuts = s.KeyboardShortcuts
user.ShowReadingTime = s.ShowReadingTime
user.Extra["custom_css"] = s.CustomCSS
if s.Password != "" {
@ -88,6 +90,7 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
EntryDirection: r.FormValue("entry_direction"),
EntriesPerPage: int(entriesPerPage),
KeyboardShortcuts: r.FormValue("keyboard_shortcuts") == "1",
ShowReadingTime: r.FormValue("show_reading_time") == "1",
CustomCSS: r.FormValue("custom_css"),
}
}

View File

@ -34,6 +34,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
EntryDirection: user.EntryDirection,
EntriesPerPage: user.EntriesPerPage,
KeyboardShortcuts: user.KeyboardShortcuts,
ShowReadingTime: user.ShowReadingTime,
CustomCSS: user.Extra["custom_css"],
}