Compare commits

...

4 commits

Author SHA1 Message Date
954d24bbb2 Update doc 2024-09-18 10:46:46 +02:00
844eee663d Update theme 2024-09-18 10:46:46 +02:00
ed90b31019 Update Docker file 2024-09-18 10:46:46 +02:00
70f4ea616e Update Docker version 2024-09-18 10:46:46 +02:00
11 changed files with 272 additions and 131 deletions

View file

@ -1,4 +1,4 @@
docker run -v soshot_datas:/var/www/datas -v soshot_cache_img:/var/www/cache/img -e TZ=UTC -p 8080:80 --name soshot soshot:0.2.0 docker run -v soshot_datas:/var/www/datas -v soshot_cache_img:/var/www/cache/img -e TZ=UTC -p 8080:80 --name soshot soshot:0.3.0
or or

View file

@ -2,7 +2,7 @@ FROM ubuntu/apache2
MAINTAINER Knah Tsaeb <knah-tsaeb_soshot@knah-tsaeb.org> MAINTAINER Knah Tsaeb <knah-tsaeb_soshot@knah-tsaeb.org>
LABEL version="0.2.0" LABEL version="0.3.0"
LABEL description="Apache 2 / PHP / SoShot" LABEL description="Apache 2 / PHP / SoShot"
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
@ -17,14 +17,13 @@ WORKDIR /var/www/
RUN git clone https://forge.leslibres.org/Knah-Tsaeb/Soshot.git --branch dev --single-branch --depth 1 . RUN git clone https://forge.leslibres.org/Knah-Tsaeb/Soshot.git --branch dev --single-branch --depth 1 .
RUN composer install --no-dev && chown -R www-data:www-data /var/www/ RUN composer install --no-dev && chown -R www-data:www-data /var/www/
COPY .docker/start.sh /usr/bin/start.sh RUN cp .docker/start.sh /usr/bin/start.sh
RUN chmod +x /usr/bin/start.sh RUN chmod +x /usr/bin/start.sh
WORKDIR / RUN cp .docker/apache2/soshot.conf /etc/apache2/sites-available/soshot.conf
COPY .docker/apache2/soshot.conf /etc/apache2/sites-available/soshot.conf
RUN a2dissite 000-default.conf && a2ensite soshot.conf && a2enmod rewrite RUN a2dissite 000-default.conf && a2ensite soshot.conf && a2enmod rewrite
WORKDIR /
RUN echo '*/4 * * * * www-data php /var/www/bin/thumbShoter.php' > /etc/cron.d/soshot && chmod 0644 /etc/cron.d/soshot && crontab /etc/cron.d/soshot RUN echo '*/4 * * * * www-data php /var/www/bin/thumbShoter.php' > /etc/cron.d/soshot && chmod 0644 /etc/cron.d/soshot && crontab /etc/cron.d/soshot
EXPOSE 80 EXPOSE 80
@ -35,6 +34,6 @@ WORKDIR /var/www/
ENTRYPOINT "start.sh" ENTRYPOINT "start.sh"
# Build image # Build image
# docker build -t soshot:0.2.0 . # docker build -t soshot:0.3.0 .
# Run container # Run container
# docker run -v soshot_datas:/var/www/datas -v soshot_cache_img:/var/www/cache/img -e TZ=UTC -p 8080:80 --name soshot soshot:0.2.0 # docker run -v soshot_datas:/var/www/datas -v soshot_cache_img:/var/www/cache/img -e TZ=UTC -p 8080:80 --name soshot soshot:0.3.0

152
README.md
View file

@ -2,7 +2,7 @@
## Use at your own risk ## Use at your own risk
Soshot make webshot of internet page with headless machine. Soshot make webshot of internet page with headless machine (Google Chrome).
## Ideas ## Ideas
@ -16,15 +16,40 @@ SoShot always make complete webshot (1920x page lenght) + first demande size.
Size use 16/9 ratio : Size use 16/9 ratio :
- fav = define by config (default 48px) - fav = define by config (default 48px)
- og = define by the website himself (no resize or crop) - og = define by the website himself (no resize or crop)
- thumb = 160x90 - thumb = 160x90
- nhd = 640x360
- hd = 1280x720 - hd = 1280x720
- full = 1920x1080 - full = 1920x1080
- complete = 1920xpage height - complete = 1920xpage height
## Requirements ## Installation
### Docker (recommended)
For the moment I don't provide any image in any hub.
#### Build image
```shell
wget https://forge.leslibres.org/Knah-Tsaeb/Soshot/raw/branch/main/Dockerfile
docker buildx build --no-cache -t soshot:0.3.0 .
```
#### Start container
You can use native docker volume.
docker run -v soshot_datas:/var/www/datas -v soshot_cache:/var/www/cache -e TZ=UTC -p 8187:80 --name soshot soshot:0.3.0
Or use absolute path
docker run -v /opt/soshot/datas:/var/www/datas -v /opt/soshot/cache:/var/www/public/cache -e TZ=UTC -p 8187:80 --name soshot soshot:0.3.0
### Classic way
#### Requirements
- PHP 8.* - PHP 8.*
- Sqlite3 - Sqlite3
@ -35,39 +60,35 @@ Size use 16/9 ratio :
- CRON - CRON
- Chrome / Chromium - Chrome / Chromium
## Installation
Make directory on your web server and go in Make directory on your web server and go in
` ```shell
mkdir /var/www/soshot && cd /var/www/soshot mkdir /var/www/soshot && cd /var/www/soshot
` ```
Clone git repo Clone git repo
` ```shell
git clone https://forge.leslibres.org/Knah-Tsaeb/Soshot.git . git clone https://forge.leslibres.org/Knah-Tsaeb/Soshot.git .
` ```
Install dependencies Install dependencies
` ```shell
composer install --no-dev composer install --no-dev
` ```
Add cron task Add cron task
```shell
`
sudo crontab -u www-data -e sudo crontab -u www-data -e
` ```
```shell
`
php /var/www/soshot/bin/thumbShoter.php php /var/www/soshot/bin/thumbShoter.php
` ```
Configure your web server to serve in "public" directory Configure your web server to serve in "public" directory.
Go to web page Go to web page
https://shoshot.your-domain.tld https://shoshot.your-domain.tld
@ -78,73 +99,36 @@ You can use a web interface (if option "use web gui" is set to true), https://sh
Or you can modify config file /datas/config.json. Or you can modify config file /datas/config.json.
#### Accept only request from 127.0.0.1 ```json
{
"onlyLocalServer": true,
"webPage": false,
"log": true,
"alwaysMakePdf": false,
"icoSize": 48,
"expireCache": 12,
"maxGenPerBatch": 5,
"permitType": [],
"password": null,
"key": null,
"chromePath": null,
"fileFormat": "jpeg"
}
```
Default : true | Option | Type | Default | Description |
| --- | --- | --- | --- |
ShoShot only work for local machine, return 404 if use with remote machine. | onlyLocalServer | bool | true | ShoShot only work for local machine, return 404 if use with remote machine |
| webPage | bool | false | Soshot only work with endpoint /api. Return 404 if not |
#### Use web gui | log | bool | true | Not implemented yet |
| alwaysMakePdf | bool | false | If true, SoShot make a complete webshot and PDF of page |
Default : false | icoSize | int | 48 | Define size of favicon |
| expireCache | int | 12 | Not implemented yet |
Soshot only work with endpoint /api. Return 404 if endpoint is not /api | permitType | array | null | Select authorized size or type of webshot |
| maxGenPerBatch | int | 5 | Foreach cron task as launch, SoShot make 5 webshot |
#### Use log | key | string | 12 | !!! DANGER !!! If you change key, all previous generation will be invalid. Soshot re make all previous generationt |
| password | string | null | Password for admin interface. No min or max character |
Default : true | chromePath | string | null | If path of Chrome/Chromium is not in PATH, you can define here |
Not implemented yet.
#### Always make PDF
Default : false
If true, SoShot make a complete webshot and PDF of page.
#### Favicon size
Default : 48
Define size of favicon.
#### Permit type of webshot
Default : none
Select authorized size or type of webshot.
#### Cache expiration (for web GUI) in hour
Default : 12
Not implemented yet.
#### Maximum work per batch
Default : 5
Foreach cron task as launch, SoShot make 5 webshot.
#### Api key
Default : random string, lenght 12
!!! DANGER !!!
If you change key, all previous generation will be invalid. Soshot re make all previous generation.
#### Password
Default : null
Password for admin interface. No min or max character.
#### Chrome path
Default : empty
If path of Chrome/Chromium is not in PATH, you can define here.
## Usage ## Usage

View file

@ -5,13 +5,13 @@ namespace App\Utils;
class ConvertStatus { class ConvertStatus {
static function convertToIcon($status) { static function convertToIcon($status) {
if ($status === 1) { if ($status === 1) {
echo '<i class="fa fa-check w3-text-green" aria-hidden="true"></i>'; echo '<i class="fa fa-check gen" aria-hidden="true"></i>';
} elseif ($status === 2) { } elseif ($status === 2) {
echo '<i class="fa fa-check w3-text-red" aria-hidden="true"></i>'; echo '<i class="fa fa-check notGen" aria-hidden="true"></i>';
} elseif ($status === 3) { } elseif ($status === 3) {
echo '<i class="fa fa-clock-o w3-text-orange" aria-hidden="true"></i>'; echo '<i class="fa fa-clock-o pending" aria-hidden="true"></i>';
} else { } else {
echo '<i class="fa fa-ban w3-text-red" aria-hidden="true"></i>'; echo '<i class="fa fa-ban notGen" aria-hidden="true"></i>';
} }
} }
} }

View file

@ -1,8 +1,89 @@
:root {
color-scheme: dark light;
--primary: #cc2027;
--primary-darken: #8E161B;
--primary-lighten: #D64C52;
--primary-text-contrast: #FFF;
--secondary: #20ccc5;
--secondary-darken: #168E89;
--secondary-lighten: #4CD6D0;
--secondary-text-contrast: #FFF;
--error: #c43933;
--error-darken: #892723;
--error-lighten: #CF605B;
--error-text-contrast: #FFF;
--info: #206ccc;
--info-darken: #164B8E;
--info-lighten: #4C89D6;
--info-text-contrast: #FFF;
--success: #7dcc20;
--success-darken: #578E16;
--success-lighten: #97D64C;
--success-text-contrast: #000;
--warning: #cc5e20;
--warning-darken: #8E4116;
--warning-lighten: #D67E4C;
--warning-text-contrast: #FFF;
--background-color: light-dark(#fffbfb, #171414);
--background-color-darken: light-dark(#B2AFAF, #100E0E);
--background-color-lighten: light-dark(#FFFBFB, #454343);
--header-background-color: light-dark(#171414, #fffbfb);
--header-background-color-darken: light-dark(#100E0E, #B2AFAF);
--header-background-color-lighten: light-dark(#454343, #FFFBFB);
--header-text-color: light-dark(#fffbfb, #171414);
--header-text-color-secondary: #ffffffb3;
--header-text-color-disable: light-dark(#ffffff80, #454343);
--text-color: light-dark(#171414, #fffbfb);
--text-color-secondary: #ffffffb3;
--text-color-disable: light-dark(#454343, #ffffff80);
--text-color-inverse: light-dark(#fffbfb, #171414);
--text-color-secondary-inverse: #ffffffb3;
--text-color-disable-inverse: light-dark(#ffffff80, #454343);
--h1-color: var(--primary);
--h2-color: #c33d35;
--h3-color: #b94f44;
--h4-color: #ae5e52;
--h5-color: #a16a61;
--h6-color: #927671;
}
[data-theme="light"] {
--background-color: #fffbfb;
--text-color: #171414;
--text-color-inverse: #fffbfb;
.title:hover {
color: var(--text-color);
}
}
[data-theme="dark"] {
table {
color: var(--text-color);
}
.title:hover {
color: var(--text-color-inverse);
}
}
html { html {
font-family: arial, sans-serif; font-family: arial, sans-serif;
font-weight: bold; font-weight: bold;
line-height: 2em; line-height: 2em;
background-color: #ffffffcb; background-color: var(--background-color);
overflow: auto;
color: var(--text-color);
} }
html, html,
@ -16,25 +97,32 @@ h6 {
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
} }
h1 {
color: var(--primary);
}
.fa {
/*color: var(--primary);*/
}
.w3-sidebar { .w3-sidebar {
z-index: 3; z-index: 3;
width: 250px; width: 250px;
top: 43px;
height: inherit; height: inherit;
} }
a { a {
text-decoration: none; text-decoration: none;
color: #8AC007; color: var(--primary);
} }
a:hover, a:hover {
.title:hover {
text-decoration: none; text-decoration: none;
color: var(--primary-darken)
} }
a:visited { a:visited {
color: #8AC007; color: var(--primary);
} }
.centerBlock { .centerBlock {
@ -46,16 +134,17 @@ a:visited {
} }
.w3-bar { .w3-bar {
background-color: #333333 !important; background-color: var(--background-color) !important;
} }
#mySidebar { #mySidebar {
top: inherit; top: 84px;
background-color: initial !important; background-color: var(--header-background-color);
} }
#mySidebar a:hover { #mySidebar>:hover {
text-decoration: none; text-decoration: none;
color: var(--primary-darken);
} }
.w3-bar-block .w3-bar-item { .w3-bar-block .w3-bar-item {
@ -63,7 +152,12 @@ a:visited {
} }
.w3-bar { .w3-bar {
background-color: #fff !important; background-color: var(--header-background-color) !important;
}
.w3-bar-item-selected {
background-color: var(--secondary);
color: var(--secondary-text-contrast);
} }
#myFooter { #myFooter {
@ -82,10 +176,6 @@ a:visited {
padding-bottom: 16px; padding-bottom: 16px;
} }
.fa {
color: #009688;
}
form label { form label {
width: 48% !important; width: 48% !important;
display: inline-block; display: inline-block;
@ -99,14 +189,58 @@ form label {
width: 48%; width: 48%;
} }
.w3-input {
background-color: var(--primary-lighten);
color: var(--text-color);
}
button,
.w3-button {
background-color: var(--primary) !important;
color: var(--text-color) !important;
}
button:hover,
.w3-button:hover {
background-color: var(--primary-darken) !important;
color: var(--text-color-inverse) !important;
}
.zoom { .zoom {
cursor: zoom-in; cursor: zoom-in;
} }
.delete,
.notGen {
color: var(--error);
}
.gen {
color: var(--success);
}
.pending {
color: var(--warning);
}
#myFooter {
background-color: var(--header-background-color);
color: var(--header-text-color);
}
#myFooter a:hover {
color: var(--primary-darken);
}
.title {
color: var(--text-color-inverse);
padding: .5em;
}
@media (max-width:768px) { @media (max-width:768px) {
#mySidebar { #mySidebar {
background-color: #ffffffcb !important; background-color: var(--header-background-color) !important;
width: 100%; width: 100%;
height: 50%; height: 50%;
} }

View file

@ -1,6 +1,24 @@
</div> </div>
<script>
function switchTheme(e) {
let actualTheme = document.documentElement.getAttribute('data-theme');
if (actualTheme === null || actualTheme === 'light') {
document.documentElement.setAttribute('data-theme', 'dark');
localStorage.setItem('theme', 'dark');
} else {
document.documentElement.setAttribute('data-theme', 'light');
localStorage.setItem('theme', 'light');
}
return false;
}
const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);
}
</script>
<footer id="myFooter" class="w3-bottom"> <footer id="myFooter" class="w3-bottom">
<div class="w3-container w3-theme-l1"> <div class="w3-container">
<p>Powered by <a href="https://www.w3schools.com/w3css/default.asp" target="_blank">w3.css</a></p> <p>Powered by <a href="https://forge.leslibres.org/Knah-Tsaeb/Soshot" target="_blank"> Soshot </a>| Theme by <a href="https://www.w3schools.com/w3css/default.asp" target="_blank">w3.css</a></p>
</div> </div>
</footer> </footer>

View file

@ -1,7 +1,9 @@
<div class="w3-row-padding centerBlock homeForm"> <div class="w3-row-padding centerBlock homeForm">
<h1 class="w3-center">SoShot</h1> <h1 class="w3-center">SoShot</h1>
<p>Per<b>so</b>nal web<b>shot</b>er</p> <p>
<div> <h3>Per<b>so</b>nal web<b>shot</b>er</h3>
</p>
<div class="w3-center">
<img src="assets/img/wikipedia_logiciel_libre.png" alt="Thumbshot of french wikipedia home page" width="720px"> <img src="assets/img/wikipedia_logiciel_libre.png" alt="Thumbshot of french wikipedia home page" width="720px">
</div> </div>
<p class="w3-center"> <p class="w3-center">

View file

@ -6,7 +6,7 @@ use App\Utils\Domains;
?> ?>
<div class="w3-row soshot-main w3-margin-bottom"> <div class="w3-row soshot-main w3-margin-bottom">
<div class="w3-container"> <div class="w3-container">
<h1 class="w3-text-teal">Infos</h1> <h1 class="w3-text">Infos</h1>
<ul> <ul>
<li>Total : <?= $total; ?></li> <li>Total : <?= $total; ?></li>
@ -15,11 +15,11 @@ use App\Utils\Domains;
</ul> </ul>
<form> <form>
<input type="text" name="search" value="<?= $search; ?>"> <input class="w3-input" type="text" name="search" value="<?= $search; ?>" placeholder="Search">
<input type="submit" value="Rechercher"> <input class="w3-button" type="submit" value="Rechercher">
</form> </form>
<table class="w3-table-all w3-hoverable"> <table class="w3-table-all w3-hoverable" data-theme="light">
<thead> <thead>
<tr> <tr>
<td>Domain</td> <td>Domain</td>
@ -42,7 +42,7 @@ use App\Utils\Domains;
<a href="#" class="linkDetail" data-hmac="<?= $value->id; ?>" data-href="<?= $value->url; ?>"><?= Domains::getDomain($value->url); ?></a> <a href="#" class="linkDetail" data-hmac="<?= $value->id; ?>" data-href="<?= $value->url; ?>"><?= Domains::getDomain($value->url); ?></a>
</span> </span>
<span class="w3-right" style="width:40px"> <span class="w3-right" style="width:40px">
<a href="?page=infos&deleteGen=<?= $value->id; ?>"><i class="fa fa-trash-o w3-text-red" aria-hidden="true"></i></a> <a href="?page=infos&deleteGen=<?= $value->id; ?>"><i class="fa fa-trash-o delete" aria-hidden="true"></i></a>
</span> </span>
</td> </td>
<td><?= $value->created; ?></td> <td><?= $value->created; ?></td>
@ -62,10 +62,10 @@ use App\Utils\Domains;
<div class="w3-center w3-margin-top"> <div class="w3-center w3-margin-top">
<div class="w3-bar"> <div class="w3-bar">
<?php if ($start > 0) : ?> <?php if ($start > 0) : ?>
<a href="?page=infos&start=<?= $previous; ?>" class="w3-teal w3-button">&laquo; Previous</a> <a href="?page=infos&start=<?= $previous; ?>" class="w3 w3-button">&laquo; Previous</a>
<?php endif; ?> <?php endif; ?>
<?php if ($next != $start) :; ?> <?php if ($next != $start) :; ?>
<a href="?page=infos&start=<?= $next; ?>" class="w3-teal w3-button">Next &raquo; </a> <a href="?page=infos&start=<?= $next; ?>" class="w3 w3-button">Next &raquo; </a>
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@
<div class="w3-section"> <div class="w3-section">
<input class="w3-input w3-border" type="password" placeholder="Password" name="loginPassword" required> <input class="w3-input w3-border" type="password" placeholder="Password" name="loginPassword" required>
<input type="hidden" name="token" value="<?= $token; ?>" /> <input type="hidden" name="token" value="<?= $token; ?>" />
<button class="w3-button w3-block w3-teal w3-section w3-padding" style="width:30%; margin:0 auto" type="submit">Login</button> <button class="w3-button w3-block w3-section w3-padding" style="width:30%; margin:0 auto" type="submit">Login</button>
</div> </div>
</form> </form>
</div> </div>

View file

@ -5,7 +5,7 @@ use App\Utils\Page;
<div class="w3-top w3-round"> <div class="w3-top w3-round">
<div class="w3-bar w3-theme w3-top w3-left-align w3-large"> <div class="w3-bar w3-theme w3-top w3-left-align w3-large">
<a class="w3-bar-item w3-button w3-right w3-hide-large w3-hover-white w3-large w3-theme-l1" href="javascript:void(0)" onclick="w3_open()"><i class="fa fa-bars"></i></a> <a class="w3-bar-item w3-button w3-right w3-hide-large w3-hover-white w3-large w3-theme-l1" href="javascript:void(0)" onclick="w3_open()"><i class="fa fa-bars"></i></a>
<a href="#" class="w3-bar-item w3-button w3-theme-l1 title"><i class="fa fa-camera" aria-hidden="true"></i> SoShot</a> <h1><a href="#" class="title"><i class="fa fa-camera" aria-hidden="true"></i> SoShot</a></h1>
<?php if ($this->runningJob) : ?><i class="fa fa-refresh fa-spin w3-text-red"></i><?php endif; ?> <?php if ($this->runningJob) : ?><i class="fa fa-refresh fa-spin w3-text-red"></i><?php endif; ?>
</div> </div>
</div> </div>
@ -15,9 +15,13 @@ use App\Utils\Page;
<a href="javascript:void(0)" onclick="w3_close()" class="w3-right w3-xlarge w3-padding-large w3-hover-black w3-hide-large" title="Close Menu"> <a href="javascript:void(0)" onclick="w3_close()" class="w3-right w3-xlarge w3-padding-large w3-hover-black w3-hide-large" title="Close Menu">
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</a> </a>
<a class="w3-bar-item w3-button <?= Page::active($params->page, 'infos', 'w3-gray') ?>" href="?page=infos">&nbsp;<i class="fa fa-info"></i> Infos</a> <a class="w3-bar-item <?= Page::active($params->page, 'infos', 'w3-bar-item-selected') ?>" href="?page=infos">&nbsp;<i class="fa fa-info"></i> Infos</a>
<a class="w3-bar-item w3-button <?= Page::active($params->page, 'settings', 'w3-gray') ?>" href="?page=settings"><i class="fa fa-cog"></i> Settings</a> <a class="w3-bar-item <?= Page::active($params->page, 'settings', 'w3-bar-item-selected') ?>" href="?page=settings"><i class="fa fa-cog"></i> Settings</a>
<a class="w3-bar-item w3-button w3-margin-top <?= Page::active($params->page, 'logout', 'w3-gray') ?>" href="/logout"><i class="fa fa-sign-out"></i> Logout</a>
<a class="w3-bar-item w3-margin-top" onclick="switchTheme();" href="#" ><i class="fa fa-moon" aria-hidden="true"></i> Dark/Light</a>
<a class="w3-bar-item w3-margin-top <?= Page::active($params->page, 'logout', 'w3-bar-item-selected') ?>" href="/logout"><i class="fa fa-sign-out"></i> Logout</a>
</nav> </nav>
<!-- Overlay effect when opening sidebar on small screens --> <!-- Overlay effect when opening sidebar on small screens -->

View file

@ -5,8 +5,8 @@ use App\Utils\Page;
<div class="w3-row soshot-main w3-margin-bottom"> <div class="w3-row soshot-main w3-margin-bottom">
<div class="w3-container"> <div class="w3-container">
<h1 class="w3-text-teal"><?= $this->title; ?></h1> <h1 class="w3-text"><?= $this->title; ?></h1>
<form class="w3-container" method="post"> <form class="w3-container" method="post" data-theme="dark">
<p> <p>
<label>Accept only request from 127.0.0.1</label> <label>Accept only request from 127.0.0.1</label>
@ -75,7 +75,7 @@ use App\Utils\Page;
<p> <p>
<input type="hidden" name="page" value="settings"> <input type="hidden" name="page" value="settings">
<input type="hidden" name="token" value="<?= $token; ?>"> <input type="hidden" name="token" value="<?= $token; ?>">
<button type="submit" class="w3-btn w3-padding w3-teal" style="width:120px">Save</button> <button type="submit" class="w3-btn w3-padding w3" style="width:120px">Save</button>
</p> </p>
</form> </form>
</div> </div>