Big update
This commit is contained in:
parent
b1fdc0767a
commit
f035f32967
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
src/data/
|
|
@ -1,4 +1,4 @@
|
|||||||
Miniflux - Minimalist Feed Reader
|
Miniflux - Minimalist News Reader
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
Miniflux is a minimalist web-based news reader.
|
Miniflux is a minimalist web-based news reader.
|
||||||
@ -16,22 +16,22 @@ Features
|
|||||||
- Protected by a login/password (only one possible user)
|
- Protected by a login/password (only one possible user)
|
||||||
- Use secure headers (only external images are allowed)
|
- Use secure headers (only external images are allowed)
|
||||||
- Open external links inside a new tab with a `rel="noreferrer"` attribute
|
- Open external links inside a new tab with a `rel="noreferrer"` attribute
|
||||||
|
- Mobile CSS (responsive design)
|
||||||
|
|
||||||
Todo
|
Todo
|
||||||
----
|
----
|
||||||
|
|
||||||
- Remove older items from the database
|
- Remove older items from the database
|
||||||
- Mobile CSS
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- PHP >= 5.3
|
- PHP >= 5.3
|
||||||
- XML extensions (SimpleXML, DOM...)
|
- PHP XML extensions (SimpleXML, DOM...)
|
||||||
- Sqlite
|
- PHP Sqlite extensions
|
||||||
|
|
||||||
Dependencies
|
Libraries used
|
||||||
------------
|
--------------
|
||||||
|
|
||||||
- [PicoFeed](https://github.com/fguillot/picoFeed)
|
- [PicoFeed](https://github.com/fguillot/picoFeed)
|
||||||
- [PicoFarad](https://github.com/fguillot/picoFarad)
|
- [PicoFarad](https://github.com/fguillot/picoFarad)
|
||||||
@ -42,4 +42,33 @@ Dependencies
|
|||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
In progress...
|
1. You must have a web server with PHP installed (version 5.3 minimum) with the Sqlite and XML extensions
|
||||||
|
2. Download the source code and copy the directory miniflux where you want
|
||||||
|
3. Check if the directory data is writeable (Miniflux store everything inside a Sqlite database)
|
||||||
|
4. With your browser go to <http://yourpersonalserver/miniflux>
|
||||||
|
5. The default login and password is admin/admin
|
||||||
|
6. Start to use the software
|
||||||
|
|
||||||
|
FAQ
|
||||||
|
----
|
||||||
|
|
||||||
|
### How to update your feeds with a cronjob?
|
||||||
|
|
||||||
|
You just need to be inside the directory `miniflux` and run the script `cronjob.php`.
|
||||||
|
|
||||||
|
By example:
|
||||||
|
|
||||||
|
crontab -e
|
||||||
|
|
||||||
|
0 */4 * * * cd /path/to/miniflux && php cronjob.php >/dev/null 2>&1
|
||||||
|
|
||||||
|
|
||||||
|
### How Miniflux update my feeds from the user interface?
|
||||||
|
|
||||||
|
Miniflux use an Ajax request to refresh each subscription.
|
||||||
|
By default, there is only 5 feeds updated in parallel.
|
||||||
|
|
||||||
|
|
||||||
|
### I have 600 subscriptions, how Miniflux handle that?
|
||||||
|
|
||||||
|
Your life is cluttered.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
figure,
|
||||||
li,
|
li,
|
||||||
ul,
|
ul,
|
||||||
table,
|
table,
|
||||||
@ -17,6 +18,8 @@ body {
|
|||||||
max-width: 750px;
|
max-width: 750px;
|
||||||
color: #333;
|
color: #333;
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@ -49,6 +52,71 @@ h3 {
|
|||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 4px solid #ddd;
|
||||||
|
padding-left: 25px;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #777;
|
||||||
|
line-height: 1.4em;
|
||||||
|
font-family: Georgia, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote + p {
|
||||||
|
color: #555;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table caption {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.0em;
|
||||||
|
text-align: left;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 0.8em;
|
||||||
|
overflow: auto;
|
||||||
|
color: brown;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: brown;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption code,
|
||||||
|
p code {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
/* forms */
|
/* forms */
|
||||||
form {
|
form {
|
||||||
@ -63,6 +131,10 @@ label {
|
|||||||
width: 10em;
|
width: 10em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="email"],
|
input[type="email"],
|
||||||
input[type="tel"],
|
input[type="tel"],
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
@ -160,7 +232,7 @@ textarea.form-error {
|
|||||||
|
|
||||||
/* buttons */
|
/* buttons */
|
||||||
.btn {
|
.btn {
|
||||||
display: block;
|
display: inline-block;
|
||||||
color: #333;
|
color: #333;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
background: #efefef;
|
background: #efefef;
|
||||||
@ -172,6 +244,24 @@ textarea.form-error {
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.btn {
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-red {
|
||||||
|
border-color: #b0281a;;
|
||||||
|
background: #d14836;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.btn-red:hover,
|
||||||
|
.btn-red:hover,
|
||||||
|
.btn-red:focus {
|
||||||
|
color: #fff;
|
||||||
|
background: #c53727;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-blue {
|
.btn-blue {
|
||||||
border-color: #3079ed;
|
border-color: #3079ed;
|
||||||
background: #4d90fe;
|
background: #4d90fe;
|
||||||
@ -237,6 +327,7 @@ nav .active a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.page-header li {
|
.page-header li {
|
||||||
|
font-size: 90%;
|
||||||
display: inline;
|
display: inline;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
@ -256,10 +347,10 @@ nav .active a {
|
|||||||
|
|
||||||
.items h2 {
|
.items h2 {
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.items a {
|
.items a {
|
||||||
@ -267,7 +358,7 @@ nav .active a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.items a:hover,
|
.items a:hover,
|
||||||
.items :focus {
|
.items a:focus {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,14 +371,29 @@ nav .active a {
|
|||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.items .preview {
|
||||||
|
color: #555;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-size: 100%;
|
||||||
|
font-family: Georgia, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* item */
|
/* item */
|
||||||
.item {
|
.item {
|
||||||
font-size: 110%;
|
color: #333;
|
||||||
color: #444;
|
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
text-rendering: optimizeLegibility;
|
}
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
|
.item p,
|
||||||
|
.item li {
|
||||||
|
font-family: Georgia, serif;
|
||||||
|
line-height: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item h2,
|
||||||
|
.item h3 {
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item pre,
|
.item pre,
|
||||||
@ -305,19 +411,6 @@ nav .active a {
|
|||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item li {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item pre {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 20px;
|
|
||||||
overflow: auto;
|
|
||||||
color: brown;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item img {
|
.item img {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
@ -325,29 +418,71 @@ nav .active a {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item code {
|
|
||||||
color: brown;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infos {
|
.infos {
|
||||||
padding-bottom: 30px;
|
padding-bottom: 20px;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item h1 {
|
|
||||||
}
|
|
||||||
|
|
||||||
.item h1 a {
|
.item h1 a {
|
||||||
font-size: 150%;
|
font-size: 2.1em;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
.item a:visited {
|
||||||
border-left: 4px solid #ddd;
|
color: purple;
|
||||||
padding-left: 25px;
|
}
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
/* mobile design */
|
||||||
color: #666;
|
@media only screen and (max-width: 480px) {
|
||||||
line-height: 22px;
|
|
||||||
|
body {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
max-width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav .active a {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ul {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
header li {
|
||||||
|
padding: 0;
|
||||||
|
width: 50%;
|
||||||
|
float: right;
|
||||||
|
display: block;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
clear: both;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item h1 {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item .infos {
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 847 B |
@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
if (! response.result) {
|
if (! response.result) {
|
||||||
|
|
||||||
window.alert('Unable to refresh this feed: ' + feed_id);
|
//window.alert('Unable to refresh this feed: ' + feed_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
1
miniflux/data/.gitignore
vendored
Normal file
1
miniflux/data/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
!.gitignore
|
@ -95,13 +95,28 @@ Router\get_action('history', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Router\get_action('confirm-remove', function() {
|
||||||
|
|
||||||
|
$id = Request\int_param('feed_id');
|
||||||
|
|
||||||
|
Response\html(Template\layout('confirm_remove', array(
|
||||||
|
'feed' => Model\get_feed($id),
|
||||||
|
'menu' => 'feeds'
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
Router\get_action('remove', function() {
|
Router\get_action('remove', function() {
|
||||||
|
|
||||||
$id = Request\int_param('feed_id');
|
$id = Request\int_param('feed_id');
|
||||||
|
|
||||||
if ($id) {
|
if ($id && Model\remove_feed($id)) {
|
||||||
|
|
||||||
Model\remove_feed($id);
|
Session\flash('This subscription has been removed successfully');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
Session\flash_error('Unable to remove this subscription');
|
||||||
}
|
}
|
||||||
|
|
||||||
Response\redirect('?action=feeds');
|
Response\redirect('?action=feeds');
|
||||||
@ -160,6 +175,7 @@ Router\get_action('feeds', function() {
|
|||||||
|
|
||||||
Response\html(Template\layout('feeds', array(
|
Response\html(Template\layout('feeds', array(
|
||||||
'feeds' => Model\get_feeds(),
|
'feeds' => Model\get_feeds(),
|
||||||
|
'nothing_to_read' => Request\int_param('nothing_to_read'),
|
||||||
'menu' => 'feeds'
|
'menu' => 'feeds'
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
@ -265,8 +281,15 @@ Router\post_action('config', function() {
|
|||||||
|
|
||||||
Router\notfound(function() {
|
Router\notfound(function() {
|
||||||
|
|
||||||
|
$items = Model\get_unread_items();
|
||||||
|
|
||||||
|
if (empty($items)) {
|
||||||
|
|
||||||
|
Response\redirect('?action=feeds¬hing_to_read=1');
|
||||||
|
}
|
||||||
|
|
||||||
Response\html(Template\layout('unread_items', array(
|
Response\html(Template\layout('unread_items', array(
|
||||||
'items' => Model\get_unread_items(),
|
'items' => $items,
|
||||||
'menu' => 'unread'
|
'menu' => 'unread'
|
||||||
)));
|
)));
|
||||||
});
|
});
|
@ -129,7 +129,7 @@ function get_unread_items()
|
|||||||
{
|
{
|
||||||
return \PicoTools\singleton('db')
|
return \PicoTools\singleton('db')
|
||||||
->table('items')
|
->table('items')
|
||||||
->columns('items.id', 'items.title', 'items.updated', 'items.url', 'feeds.site_url')
|
->columns('items.id', 'items.title', 'items.updated', 'items.url', 'feeds.site_url', 'items.content')
|
||||||
->join('feeds', 'id', 'feed_id')
|
->join('feeds', 'id', 'feed_id')
|
||||||
->eq('status', 'unread')
|
->eq('status', 'unread')
|
||||||
->desc('updated')
|
->desc('updated')
|
||||||
@ -197,11 +197,6 @@ function update_feeds()
|
|||||||
|
|
||||||
update_items($feed['id'], $parser->execute()->items);
|
update_items($feed['id'], $parser->execute()->items);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
|
||||||
print_r($feed);
|
|
||||||
die;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
miniflux/templates/confirm_remove.php
Normal file
10
miniflux/templates/confirm_remove.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<div class="page-header">
|
||||||
|
<h2>Confirmation</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="alert alert-info">Do you really want to remove this subscription: "<?= Helper\escape($feed['title']) ?>"?</p>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<a href="?action=remove&feed_id=<?= $feed['id'] ?>" class="btn btn-red">Yes</a>
|
||||||
|
or <a href="?action=feeds">cancel</a>
|
||||||
|
</div>
|
@ -14,6 +14,10 @@
|
|||||||
|
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php if ($nothing_to_read): ?>
|
||||||
|
<p class="alert">Nothing to read, do you want to <a href="?action=refresh-all" data-action="refresh-all">update your subscriptions?</a></p>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<section class="items">
|
<section class="items">
|
||||||
<?php foreach ($feeds as $feed): ?>
|
<?php foreach ($feeds as $feed): ?>
|
||||||
<article>
|
<article>
|
||||||
@ -23,7 +27,8 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
<?= Helper\get_host_from_url($feed['site_url']) ?> |
|
<?= Helper\get_host_from_url($feed['site_url']) ?> |
|
||||||
<a href="?action=remove&feed_id=<?= $feed['id'] ?>">remove</a> |
|
<a href="<?= Helper\escape($feed['feed_url']) ?>">feed link</a> |
|
||||||
|
<a href="?action=confirm-remove&feed_id=<?= $feed['id'] ?>">remove</a> |
|
||||||
<a href="?action=refresh-feed&feed_id=<?= $feed['id'] ?>" data-feed-id="<?= $feed['id'] ?>" data-action="refresh-feed">refresh</a>
|
<a href="?action=refresh-feed&feed_id=<?= $feed['id'] ?>" data-feed-id="<?= $feed['id'] ?>" data-action="refresh-feed">refresh</a>
|
||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
@ -1,6 +1,6 @@
|
|||||||
<?php if (empty($items)): ?>
|
<?php if (empty($items)): ?>
|
||||||
|
|
||||||
<p class="alert alert-info">No unread items.</p>
|
<p class="alert alert-info">Nothing to read.</p>
|
||||||
|
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
|
||||||
@ -15,6 +15,9 @@
|
|||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<article>
|
<article>
|
||||||
<h2><a href="?action=read&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
<h2><a href="?action=read&id=<?= urlencode($item['id']) ?>"><?= Helper\escape($item['title']) ?></a></h2>
|
||||||
|
<p class="preview">
|
||||||
|
<?= Helper\escape(Helper\summary(strip_tags($item['content']), 50, 300)) ?>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<?= Helper\get_host_from_url($item['url']) ?> |
|
<?= Helper\get_host_from_url($item['url']) ?> |
|
||||||
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank">direct link</a>
|
<a href="<?= $item['url'] ?>" rel="noreferrer" target="_blank">direct link</a>
|
@ -40,7 +40,12 @@ class Filter
|
|||||||
'br' => array(),
|
'br' => array(),
|
||||||
'del' => array(),
|
'del' => array(),
|
||||||
'a' => array('href'),
|
'a' => array('href'),
|
||||||
'img' => array('src', 'width', 'height')
|
'img' => array('src'),
|
||||||
|
'figure' => array(),
|
||||||
|
'figcaption' => array(),
|
||||||
|
'cite' => array(),
|
||||||
|
'time' => array('datetime'),
|
||||||
|
'abbr' => array('title')
|
||||||
);
|
);
|
||||||
|
|
||||||
public $strip_tags_content = array(
|
public $strip_tags_content = array(
|
@ -55,6 +55,23 @@ function get_host_from_url($url)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function summary($value, $min_length = 5, $max_length = 120, $end = '[...]')
|
||||||
|
{
|
||||||
|
$length = strlen($value);
|
||||||
|
|
||||||
|
if ($length > $max_length) {
|
||||||
|
|
||||||
|
return substr($value, 0, strpos($value, ' ', $max_length)).' '.$end;
|
||||||
|
}
|
||||||
|
else if ($length < $min_length) {
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function in_list($id, array $listing)
|
function in_list($id, array $listing)
|
||||||
{
|
{
|
||||||
if (isset($listing[$id])) {
|
if (isset($listing[$id])) {
|
Binary file not shown.
Before Width: | Height: | Size: 75 KiB |
Binary file not shown.
Before Width: | Height: | Size: 154 KiB |
Binary file not shown.
Before Width: | Height: | Size: 55 KiB |
Loading…
Reference in New Issue
Block a user