637 lines
17 KiB
PHP
Executable file
637 lines
17 KiB
PHP
Executable file
#!/usr/bin/php
|
||
<?php
|
||
|
||
/*
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
// todo: add a "last updated on" header
|
||
|
||
$SCRIPTNAME='pfaltgall';
|
||
$SCRIPTVERSION='0.3.1';
|
||
$SCRIPTURL='https://git.lattuga.net/Jones/pfaltgall';
|
||
|
||
require 'lib/ckratelimit.php';
|
||
require 'lib/httpjson.php';
|
||
|
||
$configfp=null;
|
||
$outfp=null;
|
||
|
||
$conf=[
|
||
'host'=>null,
|
||
'token'=>null,
|
||
'lang'=>null
|
||
];
|
||
|
||
$help=
|
||
"[[[ SYNOPSIS ]]]
|
||
|
||
{$SCRIPTNAME} [options] <configuration file path> <output file path>
|
||
|
||
[[[ DESCRIPTION ]]]
|
||
|
||
This is {$SCRIPTNAME} v{$SCRIPTVERSION}, a CLI PHP script that can generate an html file
|
||
with a gallery from your Pixelfed profile. The html gallery file will load
|
||
images dynamically from your Pixelfed instance or its CDN, display each one
|
||
using almost all the available screen space and let you jump right from the
|
||
start to any point in the timeline.
|
||
It will also show each post’s text content, its date, and provide each image
|
||
with its description (alt-text), if it’s present on Pixelfed.
|
||
Here is example gallery: https://rame.altervista.org/foto-pixelfed
|
||
In order to create the html gallery file, you just need to login to your
|
||
Pixelfed account from the official web frontend and get an app token
|
||
(Settings -> Applications -> Create new token), then create a configuration
|
||
file for {$SCRIPTNAME} like this (don’t write the «---» lines):
|
||
|
||
---
|
||
host=your_instance_host
|
||
token=your_token
|
||
lang=your_html_page_language_code
|
||
---
|
||
|
||
For example:
|
||
|
||
---
|
||
host=pixelfed.social
|
||
token=as7f8a7s0d89f7as97df09a8s7d90f81jkl2h34lkj12h3jkl4
|
||
lang=it
|
||
---
|
||
|
||
Then run {$SCRIPTNAME} with the path of the configuration file you have created
|
||
and the path of an output file as arguments (if the output file exists, it
|
||
will be overwritten), e.g.: «{$SCRIPTNAME} pixelfed.social.conf index.html».
|
||
This will create an «index.html» file that will be ready to be put where you
|
||
want (you’ll also be able to see it locally, obviously). There is a sample
|
||
bash script that you can adapt to run {$SCRIPTNAME} and automatically upload
|
||
it where you want.
|
||
|
||
[[[ OPTIONS ]]]
|
||
|
||
-h, --help
|
||
Show this help text and exit.
|
||
|
||
[[[ DISCLAIMER AND LICENSE ]]]
|
||
|
||
This program comes with ABSOLUTELY NO WARRANTY; for details see the source.
|
||
This is free software, and you are welcome to redistribute it under certain
|
||
conditions; see <http://www.gnu.org/licenses/> for details.\n";
|
||
|
||
for ($i=1; $i<$argc; $i++) {
|
||
if ($argv[$i]=='-h' || $argv[$i]=='--help') {
|
||
echo $help;
|
||
exit(0);
|
||
} elseif ($argv[$i]=='--make-readme') {
|
||
file_put_contents(__DIR__.'/README.md',"```text\n{$help}\n```\n");
|
||
exit(0);
|
||
} elseif (is_null($configfp)) {
|
||
$configfp=$argv[$i];
|
||
} elseif (is_null($outfp)) {
|
||
$outfp=$argv[$i];
|
||
} else {
|
||
eecho("Error: «{$argv[$i]}» is not a valid option and configuration file and output file have already been set to «{$configfp}» and «{$outfp}» (use «-h» or «--help» to read help).\n");
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
$errors=[];
|
||
if (is_null($configfp))
|
||
$errors[]="you have not specified a config file";
|
||
if (is_null($outfp))
|
||
$errors[]="you have not specified an output file";
|
||
if (count($errors)>0) {
|
||
eecho("Errors:\n");
|
||
foreach ($errors as $val)
|
||
eecho(" - {$val}\n");
|
||
eecho("Use «-h» or «--help» to read help.\n");
|
||
exit(1);
|
||
}
|
||
|
||
$fconf=@parse_ini_file($configfp);
|
||
if ($fconf===false) {
|
||
eecho("Error: {$SCRIPTNAME} could not open configuration file «{$configfp}».\n");
|
||
exit(1);
|
||
}
|
||
|
||
$errors=[];
|
||
if (!array_key_exists('host',$fconf))
|
||
$errors[]="no «host» defined";
|
||
if (!array_key_exists('token',$fconf))
|
||
$errors[]="no «token» defined";
|
||
if (!array_key_exists('lang',$fconf))
|
||
$errors[]="no «lang» defined";
|
||
if (count($errors)>0) {
|
||
eecho("Error: {$SCRIPTNAME} has found errors in «{$configfp}» configuration file:\n");
|
||
foreach ($errors as $val)
|
||
eecho(" - {$val}\n");
|
||
eecho("Use «-h» or «--help» to read help.\n");
|
||
exit(1);
|
||
}
|
||
foreach ($conf as $key=>$val)
|
||
if (array_key_exists($key,$fconf))
|
||
$conf[$key]=$fconf[$key];
|
||
//print_r($conf);
|
||
|
||
$acc=httpjson("https://{$conf['host']}/api/v1/accounts/verify_credentials",null,null,null,null,$conf['token']);
|
||
//print_r($res);
|
||
if (!$acc['ok']) {
|
||
eecho("Error: {$SCRIPTNAME} could not retrieve the account associated with the given token ({$acc['errors']}).\n");
|
||
exit(2);
|
||
}
|
||
ckrl($acc['headers']);
|
||
$acc=$acc['content'];
|
||
|
||
$imgsurls=[];
|
||
$imgs='';
|
||
$thumbsurls=[];
|
||
$thumbs='';
|
||
$i=0;
|
||
$ic=0;
|
||
do {
|
||
$i++;
|
||
echo "\rRetrieving chunk {$i}";
|
||
$endpoint="https://{$conf['host']}/api/v1/accounts/{$acc['id']}/statuses?limit=40&only_media=1&exclude_replies=1&exclude_reblogs=1";
|
||
if (isset($max_id)) $endpoint.="&max_id={$max_id}";
|
||
$res=httpjson($endpoint,null,null,null,null,$conf['token']);
|
||
//print_r($res);
|
||
if (!$res['ok']) {
|
||
eecho("\rError: {$SCRIPTNAME} could not retrieve chunk {$i} of statuses ({$res['errors']}).\n");
|
||
exit(2);
|
||
}
|
||
$count=count($res['content']);
|
||
if ($count>0) {
|
||
foreach ($res['content'] as $status) {
|
||
//print_r($status);die();
|
||
if (isset($status['created_at']) && preg_match('#^\s+$#',$status['created_at'])!==1) {
|
||
$date=strtotime($status['created_at']);
|
||
$date=' <span class="grey">['.date('Y/m/d',$date).']</span>';
|
||
} else {
|
||
$date='';
|
||
}
|
||
if (isset($status['content']) && preg_match('#^\s+$#',$status['content'])!==1) {
|
||
$desc=strip_tags($status['content']);
|
||
$desc=preg_replace('/#\w+/','',$desc);
|
||
$desc=trim($desc);
|
||
} else {
|
||
$desc='';
|
||
}
|
||
if (isset($status['media_attachments']) && is_array($status['media_attachments'])) {
|
||
$ca=count($status['media_attachments']);
|
||
$ia=0;
|
||
foreach ($status['media_attachments'] as $attachment) {
|
||
if (isset($attachment['url'])) {
|
||
$thumburl=$attachment['preview_url'];
|
||
$thumbsurls[]=$thumburl;
|
||
$imgurl=$attachment['url'];
|
||
$imgsurls[]=$imgurl;
|
||
$ia++;
|
||
if (isset($attachment['description']) && preg_match('#^\s+$#',$attachment['description'])!==1)
|
||
$altdesc=' alt="'.htmlspecialchars(trim($attachment['description']),ENT_QUOTES|ENT_HTML5).'"';
|
||
else
|
||
$altdesc='';
|
||
if ($ca>1)
|
||
$icnt=" ({$ia}/{$ca})";
|
||
else
|
||
$icnt='';
|
||
/* $imgs.="<div class=\"page\"><table class=\"imgtab\"><tr><td class=\"imgcel\"><a href=\"{$imgurl}\" name=\"img{$ic}\"><img class=\"img\" decoding=\"async\" loading=\"lazy\" id=\"img{$ic}\" src=\"{$imgurl}\"{$altdesc}></a></td></tr><caption class=\"imgcaptcel\">{$desc}{$icnt}{$date}</caption></table></div>\n";
|
||
$thumbs.="<div class=\"thumbd\" id=\"thumbdiv{$ic}\" onclick=\"goto({$ic});\"><img class=\"thumb\" id=\"thumb{$ic}\" decoding=\"async\" loading=\"lazy\" src=\"{$thumburl}\"{$altdesc}></div>";*/
|
||
$imgs.="<div class=\"page\"><table class=\"imgtab\"><tr><td class=\"imgcel\"><a href=\"{$imgurl}\" name=\"img{$ic}\"><img class=\"img\" decoding=\"async\" loading=\"eager\" isset=\"0\" id=\"img{$ic}\" src=\"{$acc['avatar_static']}\"{$altdesc}></a></td></tr><caption class=\"imgcaptcel\">{$desc}{$icnt}{$date}</caption></table></div>\n";
|
||
$thumbs.="<div class=\"thumbd\" id=\"thumbdiv{$ic}\" onclick=\"goto({$ic});\"><img class=\"thumb\" id=\"thumb{$ic}\" decoding=\"async\" loading=\"eager\" isset=\"0\" src=\"{$acc['avatar_static']}\"{$altdesc}></div>";
|
||
$ic++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
$max_id=$res['content'][$count-1]['id'];
|
||
//echo "count: {$count}; max_id: {$max_id}\n";
|
||
if ($count<40)
|
||
break;
|
||
}
|
||
ckrl($res['headers']);
|
||
} while ($count>0);
|
||
echo "\n";
|
||
|
||
$accadd="{$acc['username']}@{$conf['host']}";
|
||
$title=$accadd;
|
||
$profhead="<a href=\"{$acc['url']}\">{$accadd}</a>";
|
||
if ($acc['display_name']!='') {
|
||
$accdispname=htmlspecialchars($acc['display_name'],ENT_QUOTES|ENT_HTML5);
|
||
$title="{$accdispname} ({$title})";
|
||
$profhead="<strong>{$accdispname}</strong><br>({$profhead})";
|
||
}
|
||
|
||
$html='<!DOCTYPE HTML>
|
||
<html lang="'.$conf['lang'].'">
|
||
<head>
|
||
<title>'.$title.'</title>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
<meta name="description" content="Album">
|
||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0, user-scalable=yes">
|
||
<meta property="og:image" content="'.$acc['avatar_static'].'">
|
||
<link rel="icon" type="image/png" href="'.$acc['avatar_static'].'">
|
||
<!--
|
||
<meta property="og:image" content="imgs/ogimage.jpg">
|
||
<link rel="icon" type="image/png" href="imgs/icon-16.png" sizes="16x16">
|
||
<link rel="icon" type="image/png" href="imgs/icon-24.png" sizes="24x24">
|
||
<link rel="icon" type="image/png" href="imgs/icon-32.png" sizes="32x32">
|
||
<link rel="icon" type="image/png" href="imgs/icon-64.png" sizes="64x64">
|
||
<link rel="icon" type="image/png" href="imgs/icon-128.png" sizes="128x128">
|
||
<link rel="apple-touch-icon-precomposed" href="imgs/icon-180.png">
|
||
<link rel="icon" type="image/png" href="imgs/icon-192.png" sizes="192x192">
|
||
<link rel="icon" type="image/png" href="imgs/icon-256.png" sizes="256x256">
|
||
<link rel="icon" type="image/png" href="imgs/icon-512.png" sizes="512x512">
|
||
-->
|
||
<!-- <link rel="stylesheet" type="text/css" href="gallery.css"> -->
|
||
<style>
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
height: 100vh;
|
||
}
|
||
|
||
body {
|
||
font-family: "sans";
|
||
font-size: 12pt;
|
||
background-color: black;
|
||
color: white;
|
||
margin: 0;
|
||
height: 100vh;
|
||
}
|
||
|
||
a {
|
||
color: #87decd;
|
||
}
|
||
|
||
a:focus {
|
||
outline: none;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
padding: 0;
|
||
text-indent: 3mm;
|
||
line-height: 1.5em;
|
||
}
|
||
|
||
p.firstp, p.center {
|
||
text-indent: 0;
|
||
}
|
||
|
||
p.center {
|
||
text-align: center;
|
||
text-wrap: balance;
|
||
padding: 0 0 1.5em 0;
|
||
}
|
||
|
||
.profile {
|
||
width: 640px;
|
||
}
|
||
|
||
.avatar {
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.grey {
|
||
color: #888;
|
||
}
|
||
|
||
hr {
|
||
display: block;
|
||
border: none;
|
||
height: 1px;
|
||
background-color: #666666;
|
||
margin: 3mm 0 3mm 0;
|
||
}
|
||
|
||
#maindiv {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: auto;
|
||
scroll-snap-type: y mandatory;
|
||
scroll-padding: 0;
|
||
}
|
||
|
||
.page {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
scroll-snap-stop: always;
|
||
scroll-snap-align: start;
|
||
scroll-margin: 0;
|
||
/*border: 1px solid yellow;*/
|
||
}
|
||
|
||
.imgtab, .imgtab tr, .imgtab td {
|
||
margin: 0;
|
||
padding: 0;
|
||
border: none;
|
||
border-collapse: collapse;
|
||
table-layout: fixed;
|
||
scroll-snap-align: none;
|
||
}
|
||
|
||
.img {
|
||
display: block;
|
||
position: relative;
|
||
max-width: 92vw;
|
||
max-height: 92vh;
|
||
border: 8px solid white;
|
||
border-bottom: none;
|
||
scroll-snap-align: none;
|
||
}
|
||
|
||
.imgcaptcel {
|
||
background-color: white;
|
||
color: black;
|
||
padding: 4px 8px 4px 8px;
|
||
font-size: 10pt;
|
||
caption-side: bottom;
|
||
text-align: left;
|
||
line-height: 1.2;
|
||
scroll-snap-align: none;
|
||
}
|
||
|
||
.textdiv {
|
||
width: 20cm;
|
||
max-width: 92%;
|
||
background-color: #333333;
|
||
border-radius: 8px;
|
||
padding: 3mm;
|
||
scroll-snap-align: none;
|
||
}
|
||
|
||
#notif {
|
||
display: none;
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
background-color: rgb(51 51 51 / .85);
|
||
padding: 4px 6px 4px 6px;
|
||
color: white;
|
||
border-radius: 6px;
|
||
font-size: 10pt;
|
||
z-index: 1;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.link {
|
||
margin-top: 2px;
|
||
float: right;
|
||
color: #333333;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#toolbar {
|
||
display: block;
|
||
width: 100%;
|
||
height: 48px;
|
||
position: fixed;
|
||
right: 0;
|
||
bottom: 0;
|
||
/*background-color: rgb(0 0 0 / .85);*/
|
||
background-color: #444444;
|
||
z-index: 1;
|
||
overflow: auto;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
-webkit-user-select: none; /* Safari */
|
||
-moz-user-select: none; /* Firefox */
|
||
-ms-user-select: none; /* IE10+/Edge */
|
||
user-select: none; /* Standard */
|
||
}
|
||
|
||
#browser {
|
||
display: none;/*default: block*/
|
||
text-align: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
background-color: rgb(0 0 0 / .85);
|
||
padding: 3px;
|
||
z-index: 2;
|
||
overflow: auto;
|
||
/*border: 1px solid yellow;*/
|
||
}
|
||
|
||
.thumbd {
|
||
display: inline-flex;
|
||
justify-content: center;
|
||
width: 320px;
|
||
height: 320px;
|
||
background-color: white;
|
||
margin: 3px;
|
||
border: 3px solid white;
|
||
border-radius: 12px;
|
||
overflow: clip;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.thumb {
|
||
display: block;
|
||
object-fit: contain;
|
||
max-width: 100%;
|
||
max-height: 100%;
|
||
/*width: auto;
|
||
height: auto;*/
|
||
}
|
||
|
||
@media only screen and (max-width:15cm) {
|
||
.img {
|
||
max-width: 100vw;
|
||
max-height: 98vh;
|
||
border: 2px solid white;
|
||
}
|
||
.imgcaptcel {
|
||
padding: 1px 2px 1px 2px;
|
||
font-size: 8pt;
|
||
}
|
||
.textdiv {
|
||
font-size: 9pt;
|
||
}
|
||
.link {
|
||
margin-top: 0;
|
||
}
|
||
}
|
||
</style>
|
||
<script type="text/javascript">
|
||
let totimgs='.$ic.';
|
||
let thumbsurls=["'.implode('", "',$thumbsurls).'"];
|
||
let imgsurls=["'.implode('", "',$imgsurls).'"];
|
||
window.onresize=setToolBar;
|
||
function prel() {
|
||
let ph=window.innerHeight;
|
||
if (window.innerWidth < window.innerHeight)
|
||
ph-=48;
|
||
let md=document.getElementById("maindiv"),
|
||
th=md.scrollHeight,
|
||
pages=th/ph,
|
||
sy=md.scrollTop,
|
||
page=Math.floor(pages-(th-sy)/ph)+1,
|
||
img;
|
||
// console.log("ph: "+ph+"; th: "+th+"; sy: "+sy+"; pages: "+pages+"; page: "+page);
|
||
if (page>1) {//current
|
||
img=document.getElementById("img"+(page-2));
|
||
if (img.getAttribute("isset")=="0") {
|
||
img.src=imgsurls[page-2];
|
||
img.loading="eager";
|
||
img.setAttribute=("isset","1");
|
||
}
|
||
}
|
||
if (page+1<pages) {//next
|
||
img=document.getElementById("img"+(page-1));
|
||
if (img.getAttribute("isset")=="0") {
|
||
img.src=imgsurls[page-1];
|
||
img.loading="eager";
|
||
img.setAttribute=("isset","1");
|
||
}
|
||
}
|
||
if (page>2) {//previous
|
||
img=document.getElementById("img"+(page-3));
|
||
if (img.getAttribute("isset")=="0") {
|
||
img.src=imgsurls[page-3];
|
||
img.loading="eager";
|
||
img.setAttribute=("isset","1");
|
||
}
|
||
}
|
||
if (page+2<pages) {//next-next
|
||
img=document.getElementById("img"+page);
|
||
if (img.getAttribute("isset")=="0") {
|
||
img.src=imgsurls[page];
|
||
img.loading="eager";
|
||
img.setAttribute=("isset","1");
|
||
}
|
||
}
|
||
if (page>3) {//previous-previous
|
||
img=document.getElementById("img"+(page-4));
|
||
if (img.getAttribute("isset")=="0") {
|
||
img.src=imgsurls[page-4];
|
||
img.loading="eager";
|
||
img.setAttribute=("isset","1");
|
||
}
|
||
}
|
||
}
|
||
|
||
function isInViewport(el) {
|
||
let rect=el.getBoundingClientRect(),
|
||
wh=(window.innerHeight || document.documentElement.clientHeight),
|
||
ww=(window.innerWidth || document.documentElement.clientWidth);
|
||
return (
|
||
(rect.top>=0 && rect.top<=wh && rect.left>=0 && rect.left<=ww) ||
|
||
(rect.bottom>=0 && rect.bottom<=wh && rect.right>=0 && rect.right<=ww)
|
||
);
|
||
}
|
||
|
||
function prelb() {
|
||
let i, timg;
|
||
for (i=0; i<totimgs; i++) {
|
||
timg=document.getElementById("thumb"+i);
|
||
if (timg.getAttribute("isset")=="0" && isInViewport(timg)) {
|
||
console.log(i);
|
||
timg.src=thumbsurls[i];
|
||
timg.setAttribute("isset","1");
|
||
}
|
||
}
|
||
}
|
||
|
||
function setToolBar() {
|
||
var md=document.getElementById("maindiv"),
|
||
td=document.getElementById("toolbar"),
|
||
bd=document.getElementById("browser"),
|
||
dw=window.innerWidth,
|
||
dh=window.innerHeight;
|
||
//console.log("dw: "+dw+"; dh: "+dh);
|
||
if (dw >= dh) {
|
||
dw-=48;
|
||
md.style.width=dw+"px";
|
||
md.style.height="100%";
|
||
bd.style.width=dw+"px";
|
||
bd.style.height="100%";
|
||
td.setAttribute("style","width:48px;height:100%;padding-left:15px;padding-top:0;writing-mode:vertical-lr;text-orientation:upright;");
|
||
} else {
|
||
dh-=48;
|
||
md.style.width="100%";
|
||
md.style.height=dh+"px";
|
||
bd.style.width="100%";
|
||
bd.style.height=dh+"px";
|
||
td.setAttribute("style","width:100%;height:48px;padding-left:0;padding-top:13px;writing-mode:horizontal-tb;text-orientation:mixed;");
|
||
}
|
||
}
|
||
let bshows=false;
|
||
function shbrowser() {
|
||
bd=document.getElementById("browser");
|
||
if (bshows) {
|
||
bd.style.display="none";
|
||
bshows=false;
|
||
} else {
|
||
bd.style.display="block";
|
||
bshows=true;
|
||
prelb();
|
||
}
|
||
}
|
||
function goto(i) {
|
||
document.location.href="#img"+i;
|
||
document.getElementById("browser").style.display="none";
|
||
bshows=false;
|
||
}
|
||
</script>
|
||
</head>
|
||
<body onload="setToolBar();prel();">
|
||
<div id="browser" onscroll="prelb();">
|
||
'.$thumbs."\n".'
|
||
</div>
|
||
<div id="toolbar" onclick="shbrowser();">Miniature</div>
|
||
<div id="maindiv" onscroll="prel();">
|
||
<div class="page">
|
||
<div class="profile">
|
||
<p class="center"><img src="'.$acc['avatar_static'].'" class="avatar"></p>
|
||
<p class="center">'.$profhead.'</p>
|
||
<p class="center">'.nl2br($acc['note']).'</p>
|
||
<p class="center"><span class="grey">Made with <a href="'.$SCRIPTURL.'">'.$SCRIPTNAME.'</a> v'.$SCRIPTVERSION.'</span></p>
|
||
</div>
|
||
</div>
|
||
'.$imgs.'
|
||
</div>
|
||
</body>
|
||
</html>
|
||
';
|
||
|
||
if (@file_put_contents($outfp,$html)===false) {
|
||
eecho("Error: {$SCRIPTNAME} could not save html into «{$outfp}».\n");
|
||
exit(2);
|
||
}
|
||
|
||
exit(0);
|
||
|
||
|
||
function eecho($text) {
|
||
fwrite(STDERR,$text);
|
||
}
|
||
|
||
function ckrl($headers) {
|
||
$rl=ckratelimit($headers);
|
||
if ($rl['ok'] && $rl['remaining']==0) {
|
||
echo "\rInfo: reached rate limit, sleeping for {$rl['sleep']} second(s)... ";
|
||
sleep($rl['sleep']);
|
||
echo "\n";
|
||
}
|
||
}
|
||
|
||
?>
|