New stats overview of dates with most unread articles (#8089)

New view with direct links to dates with most unread articles:

<img width="734" height="581" alt="image" src="https://github.com/user-attachments/assets/159a39b3-3a06-4ae9-9cc0-62ae36d9db9c" />
This commit is contained in:
Alexandre Alapetite
2025-10-14 11:05:17 +02:00
committed by GitHub
parent 20ecbeb09c
commit 5eba322cbd
63 changed files with 299 additions and 25 deletions

View File

@@ -227,31 +227,31 @@ Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensio
| Langage | Progression | |
| - | - | - |
| Čeština (cs) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%24%2F) |
| Deutsch (de) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
| Deutsch (de) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
| Ελληνικά (el) | ■■・・・・・・・・ 22% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%24%2F) |
| English (en) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%24%2F) |
| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
| Español (es) | ■■■■■■■■■・ 91% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
| فارسی (fa) | ■■■■■■■■■・ 97% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
| Suomi (fi) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
| Suomi (fi) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
| Français (fr) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
| עברית (he) | ■■■■・・・・・・ 45% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
| Magyar (hu) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
| Magyar (hu) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
| Bahasa Indonesia (id) | ■■■■■■■■■・ 96% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
| Italiano (it) | ■■■■■■■■■・ 96% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |
| 日本語 (ja) | ■■■■■■■■■・ 95% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
| 日本語 (ja) | ■■■■■■■■■・ 94% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
| 한국어 (ko) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%24%2F) |
| Latviešu (lv) | ■■■■■■■■・・ 82% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%24%2F) |
| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Occitan (oc) | ■■■■■■■■・・ 81% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
| Polski (pl) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Brasil) (pt-BR) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
| Occitan (oc) | ■■■■■■■■・・ 80% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
| Polski (pl) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Brasil) (pt-BR) | ■■■■■■■■・・ 87% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Portugal) (pt-PT) | ■■■■■■■■・・ 87% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%24%2F) |
| Русский (ru) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%24%2F) |
| Slovenčina (sk) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%24%2F) |
| Türkçe (tr) | ■■■■■■■■■・ 96% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%24%2F) |
| Українська (uk) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
| 简体中文 (zh-CN) | ■■■■■■■■・ 90% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
| Українська (uk) | ■■■■■■■■■・ 98% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
| 简体中文 (zh-CN) | ■■■■■■■■89% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
| 正體中文 (zh-TW) | ■■■■■■■■・・ 88% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%24%2F) |
</translations>

View File

@@ -123,31 +123,31 @@ See the [repository dedicated to those extensions](https://github.com/FreshRSS/E
| Language | Progress | |
| - | - | - |
| Čeština (cs) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fcs+%2F%28TODO%7CDIRTY%29%24%2F) |
| Deutsch (de) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
| Deutsch (de) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fde+%2F%28TODO%7CDIRTY%29%24%2F) |
| Ελληνικά (el) | ■■・・・・・・・・ 22% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fel+%2F%28TODO%7CDIRTY%29%24%2F) |
| English (en) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen+%2F%28TODO%7CDIRTY%29%24%2F) |
| English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
| Español (es) | ■■■■■■■■■・ 91% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
| فارسی (fa) | ■■■■■■■■■・ 97% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
| Suomi (fi) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
| Suomi (fi) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
| Français (fr) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
| עברית (he) | ■■■■・・・・・・ 45% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
| Magyar (hu) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
| Magyar (hu) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
| Bahasa Indonesia (id) | ■■■■■■■■■・ 96% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
| Italiano (it) | ■■■■■■■■■・ 96% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |
| 日本語 (ja) | ■■■■■■■■■・ 95% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
| 日本語 (ja) | ■■■■■■■■■・ 94% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fja+%2F%28TODO%7CDIRTY%29%24%2F) |
| 한국어 (ko) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fko+%2F%28TODO%7CDIRTY%29%24%2F) |
| Latviešu (lv) | ■■■■■■■■・・ 82% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Flv+%2F%28TODO%7CDIRTY%29%24%2F) |
| Nederlands (nl) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fnl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Occitan (oc) | ■■■■■■■■・・ 81% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
| Polski (pl) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Brasil) (pt-BR) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
| Occitan (oc) | ■■■■■■■■・・ 80% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Foc+%2F%28TODO%7CDIRTY%29%24%2F) |
| Polski (pl) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpl+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Brasil) (pt-BR) | ■■■■■■■■・・ 87% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-BR+%2F%28TODO%7CDIRTY%29%24%2F) |
| Português (Portugal) (pt-PT) | ■■■■■■■■・・ 87% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fpt-PT+%2F%28TODO%7CDIRTY%29%24%2F) |
| Русский (ru) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fru+%2F%28TODO%7CDIRTY%29%24%2F) |
| Slovenčina (sk) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fsk+%2F%28TODO%7CDIRTY%29%24%2F) |
| Türkçe (tr) | ■■■■■■■■■・ 96% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ftr+%2F%28TODO%7CDIRTY%29%24%2F) |
| Українська (uk) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
| 简体中文 (zh-CN) | ■■■■■■■■・ 90% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
| Українська (uk) | ■■■■■■■■■・ 98% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fuk+%2F%28TODO%7CDIRTY%29%24%2F) |
| 简体中文 (zh-CN) | ■■■■■■■■89% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-CN+%2F%28TODO%7CDIRTY%29%24%2F) |
| 正體中文 (zh-TW) | ■■■■■■■■・・ 88% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fzh-TW+%2F%28TODO%7CDIRTY%29%24%2F) |
</translations>

View File

@@ -246,4 +246,18 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
$this->view->hours24Labels = $hours24Labels;
}
public function unreadDatesAction(): void {
$statsDAO = FreshRSS_Factory::createStatsDAO();
$field = Minz_Request::paramString('field', plaintext: true);
if (!in_array($field, ['id', 'date'], true)) {
$field = 'id';
}
$granularity = Minz_Request::paramString('granularity', plaintext: true);
if (!in_array($granularity, ['day', 'month', 'year'], true)) {
$granularity = 'day';
}
$dates = $statsDAO->getMaxUnreadDates($field, $granularity, Minz_Request::paramInt('max') ?: 100);
$this->view->unreadDates = $dates;
}
}

View File

@@ -5,6 +5,30 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo {
public const ENTRY_COUNT_PERIOD = 30;
/** Get the number of seconds to add to UTC to get the user's local time */
protected function getTimezoneOffset(): int {
$timezone = new DateTimeZone(date_default_timezone_get());
return $timezone->getOffset(new DateTime('now', new DateTimeZone('UTC')));
}
/**
* @param string $field to use for the date
* @param int $precision to apply to the timestamp (1 for seconds, 1000 for milliseconds, 1000000 for microseconds)
* @param 'day'|'month'|'year' $granularity of the date intervals
*/
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
if (!preg_match('/^[a-zA-Z0-9_]+$/', $field)) {
throw new InvalidArgumentException('Invalid date field!');
}
$offset = $this->getTimezoneOffset();
return match ($granularity) {
'day' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y-%m-%d')",
'month' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y-%m')",
'year' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y')",
default => throw new InvalidArgumentException('Invalid date granularity!'),
};
}
protected function sqlFloor(string $s): string {
return "FLOOR($s)";
}
@@ -132,8 +156,9 @@ SQL;
if ($feed) {
$restrict = "WHERE e.id_feed = {$feed}";
}
$offset = $this->getTimezoneOffset();
$sql = <<<SQL
SELECT DATE_FORMAT(FROM_UNIXTIME(e.date), '{$period}') AS period
SELECT DATE_FORMAT(FROM_UNIXTIME(e.date + {$offset}), '{$period}') AS period
, COUNT(1) AS count
FROM `_entry` AS e
{$restrict}
@@ -356,4 +381,26 @@ SQL;
return $translated;
}
/**
* Gets the date intervals with the largest number of unread articles.
* @param 'id'|'date' $field to use for the date
* @param 'day'|'month'|'year' $granularity of the date intervals
* @return list<array{'granularity':string,'unread_count':int}>
*/
public function getMaxUnreadDates(string $field, string $granularity, int $max = 100): array {
$sql = <<<SQL
SELECT
{$this->sqlDateToIsoGranularity($field, precision: $field === 'id' ? 1000000 : 1, granularity: $granularity)} AS granularity,
COUNT(*) AS unread_count
FROM `_entry`
WHERE is_read = 0
GROUP BY granularity
ORDER BY unread_count DESC, granularity DESC
LIMIT $max;
SQL;
$res = $this->fetchAssoc($sql);
/** @var list<array{granularity:string,unread_count:int}>|null $res */
return is_array($res) ? $res : [];
}
}

View File

@@ -3,6 +3,17 @@ declare(strict_types=1);
class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
#[\Override]
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
$offset = $this->getTimezoneOffset();
return match ($granularity) {
'day' => "to_char(to_timestamp(($field / $precision) + $offset), 'YYYY-MM-DD')",
'month' => "to_char(to_timestamp(($field / $precision) + $offset), 'YYYY-MM')",
'year' => "to_char(to_timestamp(($field / $precision) + $offset), 'YYYY')",
default => throw new InvalidArgumentException('Invalid date granularity'),
};
}
/**
* Calculates the number of article per hour of the day per feed
*
@@ -43,8 +54,9 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
if ($feed) {
$restrict = "WHERE e.id_feed = {$feed}";
}
$offset = $this->getTimezoneOffset();
$sql = <<<SQL
SELECT extract( {$period} from to_timestamp(e.date)) AS period
SELECT extract( {$period} from to_timestamp(e.date + {$offset})) AS period
, COUNT(1) AS count
FROM `_entry` AS e
{$restrict}

View File

@@ -3,6 +3,17 @@ declare(strict_types=1);
class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
#[\Override]
protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string {
$offset = $this->getTimezoneOffset();
return match ($granularity) {
'day' => "strftime('%Y-%m-%d', ($field / $precision) + $offset, 'unixepoch')",
'month' => "strftime('%Y-%m', ($field / $precision) + $offset, 'unixepoch')",
'year' => "strftime('%Y', ($field / $precision) + $offset, 'unixepoch')",
default => throw new InvalidArgumentException('Invalid date granularity'),
};
}
#[\Override]
protected function sqlFloor(string $s): string {
return "CAST(($s) AS INT)";
@@ -18,8 +29,9 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
} else {
$restrict = '';
}
$offset = $this->getTimezoneOffset();
$sql = <<<SQL
SELECT strftime('{$period}', e.date, 'unixepoch') AS period
SELECT strftime('{$period}', e.date + {$offset}, 'unixepoch') AS period
, COUNT(1) AS count
FROM `_entry` AS e
{$restrict}

View File

@@ -44,4 +44,7 @@ final class FreshRSS_ViewStats extends FreshRSS_View {
public array $repartitionMonth;
/** @var list<array{id:int,name:string,category:string,count:int}> */
public array $topFeed;
/** @var list<array{granularity:string,unread_count:int}> */
public array $unreadDates;
}

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistika',
'all_feeds' => 'Všechny kanály',
'category' => 'Kategorie',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Počet položek',
'entry_per_category' => 'Položek na kategorii',
'entry_per_day' => 'Položek za den (posledních 30 dní)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Nečinné kanály',
'main' => 'Hlavní statistika',
'main_stream' => 'Všechny kanály',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Nejsou žádné nečinné kanály!',
'number_entries' => '%d článků',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Nepřečtené',
'title' => 'Statistika',
'top_feed' => 'Top 10 kanálů',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Nastavení systému',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Nečinné kanály',
'main' => 'Hlavní statistika',
'repartition' => 'Přerozdělení článků',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Správa odběrů',
'subscription_tools' => 'Nástroje odběrů',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistiken',
'all_feeds' => 'Alle Feeds',
'category' => 'Kategorie',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Anzahl der Einträge',
'entry_per_category' => 'Einträge pro Kategorie',
'entry_per_day' => 'Einträge pro Tag (letzten 30 Tage)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Inaktive Feeds',
'main' => 'Haupt-Statistiken',
'main_stream' => 'Haupt-Feeds',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Es gibt keinen inaktiven Feed!',
'number_entries' => '%d Artikel',
'overview' => 'Übersicht',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Ungelesen',
'title' => 'Statistiken',
'top_feed' => 'Top 10-Feeds',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Systemeinstellungen',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Inaktive Feeds',
'main' => 'Haupt-Statistiken',
'repartition' => 'Artikel-Verteilung',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Abonnementverwaltung',
'subscription_tools' => 'Abonnement-Tools',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Στατιστικά',
'all_feeds' => 'Όλες οι τροφοδοσίες',
'category' => 'Κατηγορία',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Αριθμός καταχωρίσεων',
'entry_per_category' => 'Καταχωρίσεις ανά κατηγορία',
'entry_per_day' => 'Καταχωρίσεις ανά ημέρα (τελευταίες 30 ημέρες)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Αδρανείς τροφοδοσίες',
'main' => 'Κύρια στατισικά',
'main_stream' => 'Κύρια ροή',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Δεν υπάρχουν αδρανείς τροφοδοσίες!',
'number_entries' => '%d άρθρα',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Μη αναγνωσμένα',
'title' => 'Στατιστικά',
'top_feed' => 'Κορυφαίες δέκα τροφοδοσίες',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Ρυθμίσεις συστήματος',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Idle feeds', // TODO
'main' => 'Main statistics', // TODO
'repartition' => 'Articles repartition', // TODO
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Subscription management', // TODO
'subscription_tools' => 'Subscription tools', // TODO

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistics', // IGNORE
'all_feeds' => 'All feeds', // IGNORE
'category' => 'Category', // IGNORE
'date_published' => 'Publication date', // IGNORE
'date_received' => 'Received date', // IGNORE
'entry_count' => 'Entry count', // IGNORE
'entry_per_category' => 'Entries per category', // IGNORE
'entry_per_day' => 'Entries per day (last 30 days)', // IGNORE
@@ -146,6 +148,7 @@ return array(
'idle' => 'Idle feeds', // IGNORE
'main' => 'Main statistics', // IGNORE
'main_stream' => 'Main stream', // IGNORE
'nb_unreads' => 'Number of unread articles', // IGNORE
'no_idle' => 'There are no idle feeds!', // IGNORE
'number_entries' => '%d articles', // IGNORE
'overview' => 'Overview', // IGNORE
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Unread', // IGNORE
'title' => 'Statistics', // IGNORE
'top_feed' => 'Top ten feeds', // IGNORE
'unread_dates' => 'Dates with most unread articles', // IGNORE
),
'system' => array(
'_' => 'System configuration', // IGNORE

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Idle feeds', // IGNORE
'main' => 'Main statistics', // IGNORE
'repartition' => 'Articles repartition', // IGNORE
'unread_dates' => 'Unread dates', // IGNORE
),
'subscription_management' => 'Subscription management', // IGNORE
'subscription_tools' => 'Subscription tools', // IGNORE

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistics',
'all_feeds' => 'All feeds',
'category' => 'Category',
'date_published' => 'Publication date',
'date_received' => 'Received date',
'entry_count' => 'Entry count',
'entry_per_category' => 'Entries per category',
'entry_per_day' => 'Entries per day (last 30 days)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Idle feeds',
'main' => 'Main statistics',
'main_stream' => 'Main stream',
'nb_unreads' => 'Number of unread articles',
'no_idle' => 'There are no idle feeds!',
'number_entries' => '%d articles',
'overview' => 'Overview',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Unread',
'title' => 'Statistics',
'top_feed' => 'Top ten feeds',
'unread_dates' => 'Dates with most unread articles',
),
'system' => array(
'_' => 'System configuration',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Idle feeds',
'main' => 'Main statistics',
'repartition' => 'Articles repartition',
'unread_dates' => 'Unread dates',
),
'subscription_management' => 'Subscription management',
'subscription_tools' => 'Subscription tools',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Estadísticas',
'all_feeds' => 'Todas las fuentes',
'category' => 'Categoría',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Cómputo total',
'entry_per_category' => 'Entradas por categoría',
'entry_per_day' => 'Entradas por día (últimos 30 días)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Fuentes inactivas',
'main' => 'Estadísticas principales',
'main_stream' => 'Salida principal',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'No hay fuentes inactivas',
'number_entries' => '%d artículos',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Pendientes',
'title' => 'Estadísticas',
'top_feed' => 'Las 10 fuentes más activas',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Configuración del sistema',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Fuentes inactivas',
'main' => 'Estadísticas principales',
'repartition' => 'Reparto de artículos',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Administración de suscripciones',
'subscription_tools' => 'Herramientas de suscripción',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'آمار',
'all_feeds' => ' همه فیدها',
'category' => ' دسته',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => ' تعداد ورودی',
'entry_per_category' => ' ورودی در هر دسته',
'entry_per_day' => ' ورودی در روز (30 روز گذشته)',
@@ -146,6 +148,7 @@ return array(
'idle' => ' تغذیه بیکار',
'main' => ' آمار اصلی',
'main_stream' => ' جریان اصلی',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => ' هیچ فید بیکار وجود ندارد!',
'number_entries' => ' %d مقاله',
'overview' => 'بررسی اجمالی',
@@ -157,6 +160,7 @@ return array(
'status_unread' => ' خوانده نشده',
'title' => 'آمار',
'top_feed' => ' ده فید برتر',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => ' پیکربندی سیستم',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => ' تغذیه بیکار',
'main' => ' آمار اصلی',
'repartition' => ' تقسیم مجدد مقالات',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => ' مدیریت اشتراک',
'subscription_tools' => 'ابزارهای اشتراک',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Tilastot',
'all_feeds' => 'Kaikki syötteet',
'category' => 'Luokka',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Artikkelien määrä',
'entry_per_category' => 'Artikkelit luokan mukaan',
'entry_per_day' => 'Artikkelit päivän mukaan (edelliset 30 päivää)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Hiljentyneet syötteet',
'main' => 'Päätilastot',
'main_stream' => 'Pääsyötevirta',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Hiljentyneitä syötteitä ei ole.',
'number_entries' => '%d artikkelia',
'overview' => 'Katsaus',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Lukemattomat',
'title' => 'Tilastot',
'top_feed' => '10 parasta syötettä',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Järjestelmän määritys',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Hiljentyneet syötteet',
'main' => 'Tilastot',
'repartition' => 'Artikkelien uudelleenjaottelu',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Tilausten hallinta',
'subscription_tools' => 'Tilaustyökalut',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistiques',
'all_feeds' => 'Tous les flux',
'category' => 'Catégorie',
'date_published' => 'Date de publication',
'date_received' => 'Date de réception',
'entry_count' => 'Nombre darticles',
'entry_per_category' => 'Articles par catégorie',
'entry_per_day' => 'Nombre darticles par jour (30 derniers jours)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Flux inactifs',
'main' => 'Statistiques principales',
'main_stream' => 'Flux principal',
'nb_unreads' => 'Nombre darticles non lus',
'no_idle' => 'Il ny a aucun flux inactif !',
'number_entries' => '%d articles', // IGNORE
'overview' => 'Vue densemble',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'non lus',
'title' => 'Statistiques',
'top_feed' => 'Les dix plus gros flux',
'unread_dates' => 'Dates avec le plus darticles non lus',
),
'system' => array(
'_' => 'Configuration du système',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Flux inactifs',
'main' => 'Statistiques principales',
'repartition' => 'Répartition des articles',
'unread_dates' => 'Dates non lues',
),
'subscription_management' => 'Gestion des abonnements',
'subscription_tools' => 'Outils dabonnement',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'סטטיסטיקות',
'all_feeds' => 'כל ההזנות',
'category' => 'קטגוריה',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'סכום המאמרים',
'entry_per_category' => 'מאמרים על פי קטגוריה',
'entry_per_day' => 'מספר מאמרים ליום (30 ימים אחרונים)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'הזנות שלא עודכנו',
'main' => 'סטטיסטיקות ראשיות',
'main_stream' => 'הזנה ראשית',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'אין הזנות מובטלות!',
'number_entries' => '%d מאמרים',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'לא נקרא',
'title' => 'סטטיסטיקות',
'top_feed' => 'עשרת ההזנות המובילות',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'System configuration', // TODO

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'הזנות שלא עודכנו',
'main' => 'סטטיסטיקות ראשיות',
'repartition' => 'חלוקת המאמרים',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'ניהול הרשמות',
'subscription_tools' => 'Subscription tools', // TODO

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statisztika',
'all_feeds' => 'Minden hírforrás',
'category' => 'Kategória',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Bejegyzések száma',
'entry_per_category' => 'Bejegyzések kategóriánként',
'entry_per_day' => 'Bejegyzések naponta (utolsó 30 nap)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Tétlen hírforrások',
'main' => 'Fő statisztika',
'main_stream' => 'Minden cikk',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Nincsenek tétlen hírforrások!',
'number_entries' => '%d cikk',
'overview' => 'Áttekintés',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Olvasatlan',
'title' => 'Statisztika',
'top_feed' => 'Top 10 hírforrás',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Rendszer konfiguráció',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Tétlen hírforrások',
'main' => 'Fő statisztika',
'repartition' => 'Cikkek eloszlása',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Hírforrások kezelése',
'subscription_tools' => 'Hírforrás eszközök',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistik',
'all_feeds' => 'Semua umpan',
'category' => 'Kategori',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Jumlah entri',
'entry_per_category' => 'Entri per kategori',
'entry_per_day' => 'Entri per hari (30 hari terakhir)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Umpan Tak Terbarukan',
'main' => 'Statistik utama',
'main_stream' => 'Bagian utama',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Tidak ada umpan tak terbarukan!',
'number_entries' => '%d artikel',
'overview' => 'Ringkasan',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Belum Terbaca',
'title' => 'Statistik',
'top_feed' => 'Sepuluh umpan teratas',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Konfigurasi Sistem',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Umpan tak terbarukan',
'main' => 'Statistik utama',
'repartition' => 'Pengkategorian artikel',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Pengelolaan langganan',
'subscription_tools' => 'Alat langganan',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistiche',
'all_feeds' => 'Tutti i feeds',
'category' => 'Categoria',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Articoli',
'entry_per_category' => 'Articoli per categoria',
'entry_per_day' => 'Articoli per giorno (ultimi 30 giorni)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Feeds non aggiornati',
'main' => 'Statistiche principali',
'main_stream' => 'Flusso principale',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Non ci sono feed non aggiornati',
'number_entries' => '%d articoli',
'overview' => 'Panoramica',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Non letti',
'title' => 'Statistiche',
'top_feed' => 'I migliori 10 feeds',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Configurazione di sistema',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Feed non aggiornati',
'main' => 'Statistiche principali',
'repartition' => 'Ripartizione articoli',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Gestione sottoscrizioni',
'subscription_tools' => 'Strumenti di sottoscrizione',

View File

@@ -134,6 +134,8 @@ return array(
'_' => '統計',
'all_feeds' => 'すべてのフィード',
'category' => 'カテゴリ',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'エントリの統計',
'entry_per_category' => 'カテゴリのエントリ',
'entry_per_day' => '日にちごとのエントリ (直近30日間)',
@@ -146,6 +148,7 @@ return array(
'idle' => '休止中のフィード',
'main' => '主な統計',
'main_stream' => '主なストリーム',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => '休止中のフィードはありません!',
'number_entries' => '%d 記事',
'overview' => '概要',
@@ -157,6 +160,7 @@ return array(
'status_unread' => '未読',
'title' => '統計',
'top_feed' => '上位10位のフィード',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'システム設定',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => '休止中のフィード',
'main' => '主な統計',
'repartition' => '記事の割合',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => '購読フィードの管理',
'subscription_tools' => '購読ツール',

View File

@@ -134,6 +134,8 @@ return array(
'_' => '통계',
'all_feeds' => '모든 피드',
'category' => '카테고리',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => '글 개수',
'entry_per_category' => '카테고리별 글 개수',
'entry_per_day' => '일일 글 개수 (최근 30 일)',
@@ -146,6 +148,7 @@ return array(
'idle' => '유휴 피드',
'main' => '주요 통계',
'main_stream' => '메인 스트림',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => '유휴 피드가 없습니다!',
'number_entries' => '%d 개의 글',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => '읽지 않음',
'title' => '통계',
'top_feed' => '상위 10 개 피드',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => '시스템 설정',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => '유휴 피드',
'main' => '주요 통계',
'repartition' => '글 분류',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => '구독 관리',
'subscription_tools' => '구독 도구',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistika',
'all_feeds' => 'Visas barotnes',
'category' => 'Kategorija',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Ierakstu skaits',
'entry_per_category' => 'Ieraksti katrā kategorijā',
'entry_per_day' => 'Ieraksti dienā (pēdējās 30 dienas)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Neaktīvās barotnes',
'main' => 'Galvenās statistikas',
'main_stream' => 'Galvenā plūsma',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Nav neaktīvu barotņu!',
'number_entries' => '%d raksti',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Neizlasīti',
'title' => 'Statistika',
'top_feed' => 'Top 10 barotnes',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Sistēmas konfigurācija',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Neaktīvās barotnes',
'main' => 'Galvenās statistikas',
'repartition' => 'Rakstu pārdalīšana',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Abonementu pārvalde',
'subscription_tools' => 'Abonamentu rīki',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statistieken',
'all_feeds' => 'Alle feeds',
'category' => 'Categorie',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Invoer aantallen',
'entry_per_category' => 'Aantallen per categorie',
'entry_per_day' => 'Aantallen per dag (laatste 30 dagen)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Gepauzeerde feeds',
'main' => 'Hoofd statistieken',
'main_stream' => 'Overzicht',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Er is geen gepauzeerde feed!',
'number_entries' => '%d artikelen',
'overview' => 'Overzicht',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Ongelezen',
'title' => 'Statistieken',
'top_feed' => 'Top tien feeds',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Systeem configuratie',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Gepauzeerde feeds',
'main' => 'Hoofd statistieken',
'repartition' => 'Artikelen verdeling',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Abonnementenbeheer',
'subscription_tools' => 'Hulpmiddelen voor abonnementen',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Estatisticas',
'all_feeds' => 'Totes los fluxes',
'category' => 'Categoria',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Nombre darticles',
'entry_per_category' => 'Articles per categoria',
'entry_per_day' => 'Nombre darticles per jorn (darrièrs 30 jorns)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Fluxes inactius',
'main' => 'Estatisticas principalas',
'main_stream' => 'Flux màger',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'I a pas cap darticle inactiu!',
'number_entries' => '%d articles', // IGNORE
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Pas legits',
'title' => 'Estatisticas',
'top_feed' => 'Los dètz fluxes mai gròsses',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Configuracion sistèma',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Fluxes inactius',
'main' => 'Estatisticas principalas',
'repartition' => 'Reparticion dels articles',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Gestion dels abonaments',
'subscription_tools' => 'Aisinas dabonament',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Statystyki',
'all_feeds' => 'Wszystkie kanały',
'category' => 'Kategoria',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Liczba wiadomości',
'entry_per_category' => 'Wiadomości w podziale na kategorie',
'entry_per_day' => 'Wiadomości na dzień (przez ostatnie 30 dni)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Bezczynne kanały',
'main' => 'Główne statystyki',
'main_stream' => 'Kanał główny',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Brak bezczynnych kanałów!',
'number_entries' => '%d wiadomości',
'overview' => 'Podsumowanie',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Nieprzeczytane',
'title' => 'Statystyki',
'top_feed' => '10 największych kanałów',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Konfiguracja serwera',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Bezczynne kanały',
'main' => 'Główne statystyki',
'repartition' => 'Podział wiadomości',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Zarządzanie subskrypcjami',
'subscription_tools' => 'Narzędzia subskrypcji',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Estatísticas',
'all_feeds' => 'Todos os feeds',
'category' => 'Categoria',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Contagem de entrada',
'entry_per_category' => 'Entradas por categoria',
'entry_per_day' => 'Entradas por dia (últimos 30 dias)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Feeds inativos',
'main' => 'Estatísticas principais',
'main_stream' => 'Stream principal',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Não há nenhum feed inativo!',
'number_entries' => '%d artigos',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Não lidos',
'title' => 'Estatísticas',
'top_feed' => 'Top10 Feeds',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Configuração do sistema',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Feeds inativos',
'main' => 'Estatísticas principais',
'repartition' => 'Repartição de artigos',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Gerenciamento de inscrições',
'subscription_tools' => 'Ferramentas de inscrição',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Estatísticas',
'all_feeds' => 'Todos os feeds',
'category' => 'Categoria',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Contagem de entrada',
'entry_per_category' => 'Entradas por categoria',
'entry_per_day' => 'Entradas por dia (últimos 30 dias)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Feeds inativos',
'main' => 'Estatísticas principais',
'main_stream' => 'Stream principal',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Não há nenhum feed inativo!',
'number_entries' => '%d artigos',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Não lidos',
'title' => 'Estatísticas',
'top_feed' => 'Top10 Feeds',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Configuração do sistema',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Feeds inativos',
'main' => 'Estatísticas principais',
'repartition' => 'Repartição de artigos',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Gerir de inscrições',
'subscription_tools' => 'Ferramentas de inscrição',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Статистика',
'all_feeds' => 'Все подписки',
'category' => 'Категория',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Количество статей',
'entry_per_category' => 'Статей в категории',
'entry_per_day' => 'Статей за день (за последние 30 дней)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Неактивные ленты',
'main' => 'Основная статистика',
'main_stream' => 'Основной поток',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Нет неактивных лент!',
'number_entries' => 'статей: %d',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Не прочитано',
'title' => 'Статистика',
'top_feed' => '10 лучших лент',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Системные настройки',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Неактивные ленты',
'main' => 'Основная статистика',
'repartition' => 'Расределение статей',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Управление подписками',
'subscription_tools' => 'Инструменты подписки',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Štatistiky',
'all_feeds' => 'Všetky kanály',
'category' => 'Kategória',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Počet položiek',
'entry_per_category' => 'Položiek v kategórii',
'entry_per_day' => 'Položiek za deň (posledných 30 dní)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Neaktívne kanály',
'main' => 'Hlavné štatistiky',
'main_stream' => 'Všetky kanály',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Žiadne neaktívne kanály!',
'number_entries' => 'Počet článkov: %d',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Neprečítané',
'title' => 'Štatistiky',
'top_feed' => 'Top 10 kanálov',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Nastavenia systému',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Neaktívne kanály',
'main' => 'Hlavné štatistiky',
'repartition' => 'Rozdelenie článkov',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Správa odoberaných kanálov',
'subscription_tools' => 'Nástroje na odoberanie kanálov',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'İstatistikler',
'all_feeds' => 'Tüm beslemeler',
'category' => 'Kategori',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Giriş sayısı',
'entry_per_category' => 'Kategorilere göre girişler',
'entry_per_day' => 'Günlük girişler (son 30 gün)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Boşta beslemeler',
'main' => 'Ana istatistikler',
'main_stream' => 'Ana akış',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Boşta besleme yok!',
'number_entries' => '%d makale',
'overview' => 'Genel Bakış',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Okunmadı',
'title' => 'İstatistikler',
'top_feed' => 'En iyi on besleme',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Sistem yapılandırması',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Boşta olan beslemeler',
'main' => 'Ana istatistikler',
'repartition' => 'Makale dağılımı',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Abonelik yönetimi',
'subscription_tools' => 'Abonelik araçları',

View File

@@ -134,6 +134,8 @@ return array(
'_' => 'Статистика',
'all_feeds' => 'Всі стрічки',
'category' => 'Категорія',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => 'Кількість статей',
'entry_per_category' => 'Статей у категорії',
'entry_per_day' => 'Статей за день (минулі 30 днів)',
@@ -146,6 +148,7 @@ return array(
'idle' => 'Неактивні стрічки',
'main' => 'Основна статистика',
'main_stream' => 'Головний потік',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => 'Неактивних стрічок нема!',
'number_entries' => 'Статей: %d',
'overview' => 'Огляд',
@@ -157,6 +160,7 @@ return array(
'status_unread' => 'Непрочитано',
'title' => 'Статистика',
'top_feed' => 'Десять найактивніших стрічок',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => 'Налаштування системи',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => 'Неактивні стрічки',
'main' => 'Основна статистика',
'repartition' => 'Перерозподіл статей',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => 'Керування підписками',
'subscription_tools' => 'Засоби підписки',

View File

@@ -134,6 +134,8 @@ return array(
'_' => '统计数据',
'all_feeds' => '所有订阅源',
'category' => '分类',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => '文章数',
'entry_per_category' => '各分类文章数',
'entry_per_day' => '每日文章数(近三十日)',
@@ -146,6 +148,7 @@ return array(
'idle' => '长期无更新订阅源',
'main' => '主要统计数据',
'main_stream' => '首页',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => '订阅源近期皆有更新!',
'number_entries' => '%d 篇文章',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => '未读',
'title' => '统计',
'top_feed' => '前十订阅源',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => '系统配置',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => '长期无更新订阅源',
'main' => '主要统计',
'repartition' => '文章分布',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => '订阅管理',
'subscription_tools' => '订阅工具',

View File

@@ -134,6 +134,8 @@ return array(
'_' => '統計',
'all_feeds' => '所有訂閱源',
'category' => '分類',
'date_published' => 'Publication date', // TODO
'date_received' => 'Received date', // TODO
'entry_count' => '文章數',
'entry_per_category' => '各分類文章數',
'entry_per_day' => '近三十日每日文章數',
@@ -146,6 +148,7 @@ return array(
'idle' => '長期無更新訂閱源',
'main' => '主要統計',
'main_stream' => '首頁',
'nb_unreads' => 'Number of unread articles', // TODO
'no_idle' => '訂閱源近期皆有更新!',
'number_entries' => '%d 篇文章',
'overview' => 'Overview', // TODO
@@ -157,6 +160,7 @@ return array(
'status_unread' => '未讀',
'title' => '統計',
'top_feed' => '前十訂閱源',
'unread_dates' => 'Dates with most unread articles', // TODO
),
'system' => array(
'_' => '系統配置',

View File

@@ -282,6 +282,7 @@ return array(
'idle' => '長期無更新訂閱源',
'main' => '主要統計',
'repartition' => '文章分布',
'unread_dates' => 'Unread dates', // TODO
),
'subscription_management' => '訂閱管理',
'subscription_tools' => '訂閱工具',

View File

@@ -39,20 +39,23 @@
<li class="item nav-section">
<div class="nav-header"><?= _t('admin.stats') ?></div>
<ul>
<li class="item<?= Minz_Request::controllerName() == 'stats' && Minz_Request::actionName() == 'index' ? ' active' : '' ?>">
<li class="item<?= Minz_Request::controllerName() === 'stats' && Minz_Request::actionName() === 'index' ? ' active' : '' ?>">
<a href="<?= _url('stats', 'index') ?>"><?= _t('sub.menu.stats.main') ?></a>
</li>
<li class="item<?= Minz_Request::actionName() == 'idle' ? ' active' : '' ?>">
<li class="item<?= Minz_Request::actionName() === 'idle' ? ' active' : '' ?>">
<a href="<?= _url('stats', 'idle') ?>"><?= _t('sub.menu.stats.idle') ?></a>
</li>
<li class="item<?= Minz_Request::actionName() == 'repartition' ? ' active' : '' ?>">
<li class="item<?= Minz_Request::actionName() === 'repartition' ? ' active' : '' ?>">
<a href="<?= _url('stats', 'repartition') ?>"><?= _t('sub.menu.stats.repartition') ?></a>
</li>
<li class="item<?= Minz_Request::actionName() === 'unreadDates' ? ' active' : '' ?>">
<a href="<?= _url('stats', 'unreadDates') ?>"><?= _t('sub.menu.stats.unread_dates') ?></a>
</li>
</ul>
</li>
</ul>
</nav>
<?php if (Minz_Request::actionName() != 'repartition') { ?>
<?php if (Minz_Request::actionName() !== 'repartition') { ?>
<a class="close-aside" href="#close"></a>
<nav class="nav_menu nav_mobile">
<a class="btn toggle_aside" href="#aside_feed"><?= _i('category') ?></a>

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_ViewStats $this */
$this->partial('aside_subscription');
?>
<main class="post">
<h1><?= _t('admin.stats.unread_dates') ?></h1>
<form>
<input type="hidden" name="c" value="stats" />
<input type="hidden" name="a" value="unreadDates" />
<select name="field" id="field">
<option value="id" <?= Minz_Request::paramString('field') === 'id' ? 'selected="selected"' : '' ?>><?= _t('admin.stats.date_received') ?></option>
<option value="date" <?= Minz_Request::paramString('field') === 'date' ? 'selected="selected"' : '' ?>><?= _t('admin.stats.date_published') ?></option>
</select>
<input type="number" name="max" id="max" value="<?= Minz_Request::paramInt('max') ?: 100 ?>" min="1" />
<select name="granularity" id="granularity">
<option value="day" <?= Minz_Request::paramString('granularity') === 'day' ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
<option value="month" <?= Minz_Request::paramString('granularity') === 'month' ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
<option value="year" <?= Minz_Request::paramString('granularity') === 'year' ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
</select>
<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
</form>
<table>
<thead>
<tr>
<th>
<?php if (Minz_Request::paramString('field') === 'date'): ?>
<?= _t('admin.stats.date_published') ?>
<?php else: ?>
<?= _t('admin.stats.date_received') ?>
<?php endif; ?>
</th>
<th><?= _t('admin.stats.nb_unreads') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($this->unreadDates as $row): ?>
<tr><?php /* TODO: Make that URL show all articles, including those with PRIORITY_ARCHIVED */ ?>
<td><a href="<?= _url('index', 'index', 'search',
(Minz_Request::paramString('field') === 'date' ? 'pubdate:' : 'date:') . $row['granularity']) ?>">
<?= htmlspecialchars($row['granularity'], ENT_NOQUOTES, 'UTF-8') ?>
</a></td>
<td><?= format_number($row['unread_count']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</main>