mirror of
https://github.com/tenox7/wrp.git
synced 2026-02-08 05:44:41 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5c495811 | ||
|
|
2457473706 | ||
|
|
79f56a920c | ||
|
|
2042d1bb9d | ||
|
|
ff293f2b7a | ||
|
|
e808b494ab | ||
|
|
88fbe63fb7 | ||
|
|
25b10409db | ||
|
|
5bea0ae9ff | ||
|
|
0d805d82de | ||
|
|
9ccd770e85 | ||
|
|
48ecf6fbe9 | ||
|
|
d4f00119cb | ||
|
|
a87a37f673 | ||
|
|
0fd6967393 | ||
|
|
3ad8f78c45 | ||
|
|
e3dbe85c51 | ||
|
|
30c42bd9b8 |
60
README.md
60
README.md
@@ -3,7 +3,7 @@
|
||||
A browser-in-browser "proxy" server that allows to use historical / vintage web browsers on the modern web. It has two modes:
|
||||
|
||||
- ISMAP "graphical" mode, renders web page in to a GIF, PNG or JPG image with clickable imagemap.
|
||||
- Simple HTML mode converts web page in to Markdown, then renders it into simplified HTML for old browsers.
|
||||
- Simple HTML "text" mode converts web page in to Markdown, then renders it into simplified HTML for old browsers.
|
||||
|
||||

|
||||
|
||||
@@ -19,11 +19,12 @@ A browser-in-browser "proxy" server that allows to use historical / vintage web
|
||||
|
||||
* Adjust your screen **W**idth/**H**eight/**S**cale/**C**olors to fit in your old browser.
|
||||
* Scroll web page by clicking on the in-image scroll bar on the right.
|
||||
* WRP also allows **a single tall image without the vertical scrollbar** and use client scrolling. To enable this, simply height **H** to `0` . However this should not be used with old and low spec clients. Such tall images will be very large, take a lot of memory and long time to process, especially for GIFs.
|
||||
* WRP also allows **a single tall image without the vertical scrollbar** and use client scrolling. To enable this, simply height **H** to `0` (or flag `-g 1152x0x216`. However this should not be used with old and low spec clients. Such tall images will be very large, take a lot of memory and long time to process, especially for GIFs.
|
||||
* Do not use client browser history-back, instead use **Bk** button in the app.
|
||||
* You can re-capture page screenshot without reloading by using **St** (Stop). This is useful if page didn't render fully before screenshot is taken.
|
||||
* You can also reload and re-capture current page with **Re** (Reload).
|
||||
* You can re-capture screenshot without reloading page by using **St** (Stop). This is useful if page didn't render fully before screenshot is taken.
|
||||
* You can also reload page and re-capture screenshot with **Re** (Reload).
|
||||
* To send keystrokes, fill **K** input box and press **Go**. There also are buttons for backspace, enter and arrow keys.
|
||||
* The default image type GIP is a ultra fast, optimized, parallel encoded GIF type.
|
||||
* If your browser supports it, prefer PNG over GIF/JPG. PNG is much faster, whereas GIF/JPG requires a lot of additional processing on both client and server to encode/decode.
|
||||
* GIF images are by default encoded with 216 colors, "web safe" palette. This uses an ultra fast but not very accurate color mapping algorithm. If you want better color representation switch to 256 color mode.
|
||||
|
||||
@@ -36,33 +37,39 @@ A browser-in-browser "proxy" server that allows to use historical / vintage web
|
||||
|
||||
The first unnamed input box is either search (google) or URL starting with http/https
|
||||
|
||||
**Go** instructs browser to navigate to the url or perform search
|
||||
`Go` Navigate to the url or perform search
|
||||
|
||||
**Bk** is History Back
|
||||
`Bk` History Back
|
||||
|
||||
**St** is Stop, also re-capture screenshot without refreshing page, for example if page
|
||||
render takes a long time or it changes periodically
|
||||
`St` Stop, also re-capture screenshot without refreshing page, for example if page
|
||||
render takes a long time or it updates / changes periodically
|
||||
|
||||
**Re** is Reload
|
||||
`Re` Remote Reload / Refresh
|
||||
|
||||
**W** is width in pixels, adjust it to get rid of horizontal scroll bar
|
||||
`Up` Page Up
|
||||
|
||||
**H** is height in pixels, adjust it to get rid of vertical scroll bar.
|
||||
`Dn` Page Down
|
||||
|
||||
`W` is width in pixels, adjust it to get rid of horizontal scroll bar
|
||||
|
||||
`H` is height in pixels, adjust it to get rid of vertical scroll bar.
|
||||
It can also be set to 0 to produce one very tall image and use
|
||||
client scroll. This 0 size is experimental, buggy and should be
|
||||
used with PNG and lots of memory on a client side.
|
||||
|
||||
**Z** is zoom or scale
|
||||
`Z` Zoom or scale
|
||||
|
||||
**C** is colors, for GIF images only (unused in PNG, JPG)
|
||||
`M` Mode - ISMAP (clickable imagemap) or simple HTML mode
|
||||
|
||||
**K** is keystroke input, you can type some letters in it and when you click Go it will be typed in the remote browser.
|
||||
`T` Image type PNG / GIF / JPEG
|
||||
|
||||
**Bs** is backspace
|
||||
`C` Colors, for GIF images only
|
||||
|
||||
**Rt** is return / enter
|
||||
`K` Keystroke input, you can type some letters in it and when you click Go it will be typed in the remote browser.
|
||||
|
||||
**< ^ v >** are arrow keys, typically for navigating a map, buggy.
|
||||
`Bs` Backspace
|
||||
|
||||
`Rt` Return / enter
|
||||
|
||||
### UI Customization
|
||||
|
||||
@@ -130,11 +137,11 @@ Unfortunately Google Cloud Run forces you to use HTTPS, which likely won't work
|
||||
C (number of colors) is only used for GIF
|
||||
-q Jpeg image quality, default 75%
|
||||
-h headless mode, hide browser window on the server (default true)
|
||||
-d chromedp debug logging (default false)
|
||||
-n do not free maps and images after use (default false)
|
||||
-ui html template file (default "wrp.html")
|
||||
-ua user agent, override the default "headless" agent (only for ismap mode)
|
||||
-s delay/sleep after page is rendered before screenshot is taken (default 2s)
|
||||
-b browser executable path (e.g., for Brave Browser)
|
||||
```
|
||||
|
||||
## Minimal Requirements
|
||||
@@ -154,9 +161,14 @@ $ chmod +x wrp-amd64-macos
|
||||
$ ./wrp-amd64-macos
|
||||
```
|
||||
|
||||
### Pages are chopped off
|
||||
|
||||
Click `st` to re-capture screenshot. You may want to increase the page delay using `-s` flag.
|
||||
|
||||
### Websites are blocking headless browsers
|
||||
|
||||
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. The first and foremost recommendation is to change the `User Agent`, so that it doesn't say "headless". Add `-ua="my agent"` to override the default one. Obtain your regular desktop browser user agent and specify it as the flag. For example:
|
||||
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. By default WRP tries to obtain some current valid User Agent
|
||||
from https://github.com/jnrbsn/user-agents rather than using the internal "HeadlessChrome". You can override this to your own, for example:
|
||||
|
||||
```shell
|
||||
$ wrp -ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
|
||||
@@ -166,14 +178,16 @@ $ wrp -ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (K
|
||||
|
||||
WRP originally started as true http proxy. However this stopped working because the whole internet is now encrypted thanks to [Let's Encrypt](https://en.wikipedia.org/wiki/Let%27s_Encrypt). Legacy browsers do not support modern SSL/TLS certs as well as [HTTP CONNECT](https://en.wikipedia.org/wiki/HTTP_tunnel#HTTP_CONNECT_method) so this mode had to be disabled.
|
||||
|
||||
### Will you support http proxy mode in future?
|
||||
|
||||
Some efforts (ssl strip) are under way but it's very [difficult](https://en.wikipedia.org/wiki/HTTP_tunnel#HTTP_CONNECT_method) to do it correctly and the priority is rather low.
|
||||
|
||||
### Why isn't there a Docker image for armv6
|
||||
|
||||
Because https://hub.docker.com/r/chromedp/headless-shell/ doesn't have one. WRP uses that image. If you have a fork that builds for armv6 let me know.
|
||||
|
||||
### WTF is GIP image format
|
||||
|
||||
It's just GIF but optimized. Avoids dithering, uses fast color palette and parallel encoding. https://github.com/tenox7/gip
|
||||
|
||||
## History
|
||||
|
||||
* Version 1.0 (2014) started as a *cgi-bin* script, adaptation of `webkit2png.py` and `pcidade.py`, [blog post](https://virtuallyfun.com/2014/03/03/surfing-modern-web-with-ancient-browsers/).
|
||||
@@ -187,6 +201,7 @@ Because https://hub.docker.com/r/chromedp/headless-shell/ doesn't have one. WRP
|
||||
* Version 4.6.3 adds arm64 / aarch64 Docker container support - you can run it on Raspberry PI!
|
||||
* Version 4.7 add simple html aka reader aka text mode.
|
||||
* Version 4.8 add image support to simple html mode.
|
||||
* Version 4.9 adds support for ultra fast, parallel encoded gif image (GIP)
|
||||
|
||||
## Credits
|
||||
|
||||
@@ -209,6 +224,5 @@ You may also be interested in:
|
||||
|
||||
```text
|
||||
License: Apache 2.0
|
||||
Copyright (c) 2013-2024 Antoni Sawicki
|
||||
Copyright (c) 2019-2024 Google LLC
|
||||
Copyright (c) 2013-2025 Antoni Sawicki
|
||||
```
|
||||
|
||||
23
go.mod
23
go.mod
@@ -1,33 +1,34 @@
|
||||
module github.com/tenox7/wrp
|
||||
|
||||
go 1.23
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.6.0
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb
|
||||
github.com/breml/rootcerts v0.2.20
|
||||
github.com/chromedp/cdproto v0.0.0-20250210231439-aea867ea8506
|
||||
github.com/chromedp/chromedp v0.12.1
|
||||
github.com/breml/rootcerts v0.3.1
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
|
||||
github.com/chromedp/chromedp v0.14.1
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4
|
||||
github.com/lithammer/shortuuid/v4 v4.2.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/soniakeys/quant v1.0.0
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
golang.org/x/image v0.24.0
|
||||
github.com/tenox7/gip v1.0.1
|
||||
github.com/yuin/goldmark v1.7.13
|
||||
golang.org/x/image v0.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.2 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.4.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
75
go.sum
75
go.sum
@@ -2,33 +2,28 @@ github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.6.0/go.mod h1:NUI78lGg/a7vpEJTz/0uOcYMaibytE4BUOQS8k78yPQ=
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb h1:YQ+d0g0P0F/06oDoeEgDHeZCIrnKgLxXcqYOpe8sTuU=
|
||||
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb/go.mod h1:J86XzS1wgzJPjpQmpriJ+SetP17JSQUd9l+HWQK86jA=
|
||||
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
|
||||
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
|
||||
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
|
||||
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/breml/rootcerts v0.2.17 h1:0/M2BE2Apw0qEJCXDOkaiu7d5Sx5ObNfe1BkImJ4u1I=
|
||||
github.com/breml/rootcerts v0.2.17/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/breml/rootcerts v0.2.20 h1:koth1lShwiiDp3VOX6/4qKEZ87S7HgDKsnDr47XEIq0=
|
||||
github.com/breml/rootcerts v0.2.20/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU=
|
||||
github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/cdproto v0.0.0-20250210231439-aea867ea8506 h1:OfjMcN8R6eUWZfKyJaTnlyiZh1BGgmEKmRkCZuDtGRw=
|
||||
github.com/chromedp/cdproto v0.0.0-20250210231439-aea867ea8506/go.mod h1:RTGuBeCeabAJGi3OZf71a6cGa7oYBfBP75VJZFLv6SU=
|
||||
github.com/chromedp/chromedp v0.10.0 h1:bRclRYVpMm/UVD76+1HcRW9eV3l58rFfy7AdBvKab1E=
|
||||
github.com/chromedp/chromedp v0.10.0/go.mod h1:ei/1ncZIqXX1YnAYDkxhD4gzBgavMEUu7JCKvztdomE=
|
||||
github.com/chromedp/chromedp v0.12.1 h1:kBMblXk7xH5/6j3K9uk8d7/c+fzXWiUsCsPte0VMwOA=
|
||||
github.com/chromedp/chromedp v0.12.1/go.mod h1:F6+wdq9LKFDMoyxhq46ZLz4VLXrsrCAR3sFqJz4Nqc0=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/breml/rootcerts v0.3.1 h1:PTO35OcW58K2ZYtdBykCsZh9k/eRd57bY65EHrKK/xA=
|
||||
github.com/breml/rootcerts v0.3.1/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
|
||||
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/chromedp v0.14.1 h1:0uAbnxewy/Q+Bg7oafVePE/6EXEho9hnaC38f+TTENg=
|
||||
github.com/chromedp/chromedp v0.14.1/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
|
||||
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 h1:iizUGZ9pEquQS5jTGkh4AqeeHCMbfbjeb0zMt0aEFzs=
|
||||
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
@@ -36,11 +31,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
|
||||
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -48,14 +40,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y=
|
||||
github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkIcHO0h8c=
|
||||
github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
@@ -73,12 +59,12 @@ github.com/soniakeys/quant v1.0.0/go.mod h1:HI1k023QuVbD4H8i9YdfZP2munIHU4QpjsIm
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tenox7/gip v1.0.1 h1:yRcHROzwBjV2BhCjnh1y19wIg5Ei5CTMaZ+lx9nMl3Q=
|
||||
github.com/tenox7/gip v1.0.1/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
|
||||
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
|
||||
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
@@ -86,10 +72,10 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||
golang.org/x/image v0.29.0 h1:HcdsyR4Gsuys/Axh0rDEmlBmB68rW1U9BUdB3UVHsas=
|
||||
golang.org/x/image v0.29.0/go.mod h1:RVJROnf3SLK8d26OW91j4FrIHGbsJ8QnbEocVTOWQDA=
|
||||
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
|
||||
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -105,11 +91,11 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -130,12 +116,11 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
||||
58
ismap.go
58
ismap.go
@@ -17,12 +17,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/css"
|
||||
"github.com/chromedp/cdproto/emulation"
|
||||
"github.com/chromedp/cdproto/input"
|
||||
"github.com/chromedp/cdproto/page"
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
"github.com/tenox7/gip"
|
||||
)
|
||||
|
||||
func chromedpStart() (context.CancelFunc, context.CancelFunc) {
|
||||
@@ -32,9 +32,16 @@ func chromedpStart() (context.CancelFunc, context.CancelFunc) {
|
||||
chromedp.Flag("enable-automation", false),
|
||||
chromedp.Flag("disable-blink-features", "AutomationControlled"),
|
||||
)
|
||||
if *userAgent != "" {
|
||||
if *userAgent == "jnrbsn" {
|
||||
if ua := fetchJnrbsnUserAgent(); ua != "" {
|
||||
opts = append(opts, chromedp.UserAgent(ua))
|
||||
}
|
||||
} else if *userAgent != "" {
|
||||
opts = append(opts, chromedp.UserAgent(*userAgent))
|
||||
}
|
||||
if *browserPath != "" {
|
||||
opts = append(opts, chromedp.ExecPath(*browserPath))
|
||||
}
|
||||
actx, acncl = chromedp.NewExecAllocator(context.Background(), opts...)
|
||||
ctx, cncl = chromedp.NewContext(actx)
|
||||
return cncl, acncl
|
||||
@@ -127,15 +134,11 @@ func chromedpCaptureScreenshot(res *[]byte, h int64) chromedp.Action {
|
||||
|
||||
// Capture Screenshot using CDP
|
||||
func (rq *wrpReq) captureScreenshot() {
|
||||
var styles []*css.ComputedStyleProperty
|
||||
var r, g, b int
|
||||
var bgColorSet bool
|
||||
var h int64
|
||||
var pngCap []byte
|
||||
chromedp.Run(ctx,
|
||||
emulation.SetDeviceMetricsOverride(int64(float64(rq.width)/rq.zoom), 10, rq.zoom, false),
|
||||
chromedp.Location(&rq.url),
|
||||
chromedp.ComputedStyle("body", &styles, chromedp.ByQuery),
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
_, _, _, _, _, s, err := page.GetLayoutMetrics().Do(ctx)
|
||||
if err == nil {
|
||||
@@ -145,19 +148,6 @@ func (rq *wrpReq) captureScreenshot() {
|
||||
}),
|
||||
)
|
||||
log.Printf("%s Landed on: %s, Height: %v\n", rq.r.RemoteAddr, rq.url, h)
|
||||
for _, style := range styles {
|
||||
if style.Name != "background-color" {
|
||||
continue
|
||||
}
|
||||
fmt.Sscanf(style.Value, "rgb(%d,%d,%d)", &r, &g, &b)
|
||||
bgColorSet = true
|
||||
break
|
||||
}
|
||||
if !bgColorSet {
|
||||
r = 255
|
||||
g = 255
|
||||
b = 255
|
||||
}
|
||||
height := int64(float64(rq.height) / rq.zoom)
|
||||
if rq.height == 0 && h > 0 {
|
||||
height = h + 30
|
||||
@@ -169,12 +159,38 @@ func (rq *wrpReq) captureScreenshot() {
|
||||
// Capture screenshot...
|
||||
ctxErr(chromedp.Run(ctx, chromedpCaptureScreenshot(&pngCap, rq.height)), rq.w)
|
||||
seq := shortuuid.New()
|
||||
imgPath := fmt.Sprintf("/img/%s.%s", seq, rq.imgType)
|
||||
var imgExt string
|
||||
if rq.imgType == "gip" {
|
||||
imgExt = "gif"
|
||||
} else {
|
||||
imgExt = rq.imgType
|
||||
}
|
||||
imgPath := fmt.Sprintf("/img/%s.%s", seq, imgExt)
|
||||
mapPath := fmt.Sprintf("/map/%s.map", seq)
|
||||
ismap[mapPath] = *rq
|
||||
var sSize string
|
||||
var iW, iH int
|
||||
switch rq.imgType {
|
||||
case "gip":
|
||||
i, err := png.Decode(bytes.NewReader(pngCap))
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to decode PNG screenshot: %s\n", rq.r.RemoteAddr, err)
|
||||
fmt.Fprintf(rq.w, "<BR>Unable to decode page PNG screenshot:<BR>%s<BR>\n", err)
|
||||
return
|
||||
}
|
||||
st := time.Now()
|
||||
var gipBuf bytes.Buffer
|
||||
err = gip.Encode(&gipBuf, i, nil)
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to encode GIP: %s\n", rq.r.RemoteAddr, err)
|
||||
fmt.Fprintf(rq.w, "<BR>Unable to encode GIP:<BR>%s<BR>\n", err)
|
||||
return
|
||||
}
|
||||
img[imgPath] = gipBuf
|
||||
sSize = fmt.Sprintf("%.0f KB", float32(len(gipBuf.Bytes()))/1024.0)
|
||||
iW = i.Bounds().Max.X
|
||||
iH = i.Bounds().Max.Y
|
||||
log.Printf("%s Encoded GIP image: %s, Size: %s, Res: %dx%d, Time: %vms\n", rq.r.RemoteAddr, imgPath, sSize, iW, iH, time.Since(st).Milliseconds())
|
||||
case "png":
|
||||
pngBuf := bytes.NewBuffer(pngCap)
|
||||
img[imgPath] = *pngBuf
|
||||
@@ -225,7 +241,7 @@ func (rq *wrpReq) captureScreenshot() {
|
||||
log.Printf("%s Encoded JPG image: %s, Size: %s, Quality: %d, Res: %dx%d, Time: %vms\n", rq.r.RemoteAddr, imgPath, sSize, *defJpgQual, iW, iH, time.Since(st).Milliseconds())
|
||||
}
|
||||
rq.printUI(uiParams{
|
||||
bgColor: fmt.Sprintf("#%02X%02X%02X", r, g, b),
|
||||
bgColor: "#FFFFFF",
|
||||
pageHeight: fmt.Sprintf("%d PX", h),
|
||||
imgSize: sSize,
|
||||
imgURL: imgPath,
|
||||
|
||||
13
shtml.go
13
shtml.go
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/JohannesKaufmann/html-to-markdown/plugin"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/tenox7/gip"
|
||||
"github.com/yuin/goldmark"
|
||||
"github.com/yuin/goldmark/ast"
|
||||
"github.com/yuin/goldmark/extension"
|
||||
@@ -147,6 +148,8 @@ func smallImg(src []byte, imgType string, maxSize, imgOpt int) ([]byte, error) {
|
||||
img = resize.Thumbnail(uint(maxSize), uint(maxSize), img, resize.NearestNeighbor)
|
||||
var outBuf bytes.Buffer
|
||||
switch imgType {
|
||||
case "gip":
|
||||
err = gip.Encode(&outBuf, img, nil)
|
||||
case "png":
|
||||
err = png.Encode(&outBuf, img)
|
||||
case "gif":
|
||||
@@ -173,7 +176,13 @@ func (t *astTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
||||
link.Destination = append([]byte("/?m=html&t="+t.imgType+"&s="+strconv.Itoa(t.maxSize)+"&url="), link.Destination...)
|
||||
}
|
||||
if img, ok := n.(*ast.Image); ok && entering {
|
||||
seq := shortuuid.New() + "." + t.imgType
|
||||
var imgExt string
|
||||
if t.imgType == "gip" {
|
||||
imgExt = "gif"
|
||||
} else {
|
||||
imgExt = t.imgType
|
||||
}
|
||||
seq := shortuuid.New() + "." + imgExt
|
||||
size, err := fetchImage(seq, string(img.Destination), t.imgType, t.maxSize, t.imgOpt) // TODO: use goroutines with waitgroup
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@@ -205,6 +214,8 @@ func (rq *wrpReq) captureMarkdown() {
|
||||
imgOpt = int(rq.jQual)
|
||||
case "gif":
|
||||
imgOpt = int(rq.nColors)
|
||||
case "gip":
|
||||
imgOpt = 0
|
||||
}
|
||||
t := &astTransformer{imgType: rq.imgType, maxSize: int(rq.maxSize), imgOpt: imgOpt}
|
||||
gm := goldmark.New(
|
||||
|
||||
74
util.go
74
util.go
@@ -2,14 +2,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"image"
|
||||
"image/color/palette"
|
||||
"image/color"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/MaxHalford/halfgone"
|
||||
"github.com/soniakeys/quant/median"
|
||||
"github.com/ericpauley/go-quantize/quantize"
|
||||
)
|
||||
|
||||
func printMyIPs(b string) {
|
||||
@@ -41,37 +44,17 @@ func gifPalette(i image.Image, n int64) image.Image {
|
||||
switch n {
|
||||
case 2:
|
||||
i = halfgone.FloydSteinbergDitherer{}.Apply(halfgone.ImageToGray(i))
|
||||
case 216:
|
||||
var FastGifLut = [256]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
|
||||
r := i.Bounds()
|
||||
// NOTE: the color index computation below works only for palette.WebSafe!
|
||||
p := image.NewPaletted(r, palette.WebSafe)
|
||||
if i64, ok := i.(image.RGBA64Image); ok {
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
c := i64.RGBA64At(x, y)
|
||||
r6 := FastGifLut[c.R>>8]
|
||||
g6 := FastGifLut[c.G>>8]
|
||||
b6 := FastGifLut[c.B>>8]
|
||||
p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
c := i.At(x, y)
|
||||
r, g, b, _ := c.RGBA()
|
||||
r6 := FastGifLut[r&0xff]
|
||||
g6 := FastGifLut[g&0xff]
|
||||
b6 := FastGifLut[b&0xff]
|
||||
p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6))
|
||||
}
|
||||
default:
|
||||
q := quantize.MedianCutQuantizer{}
|
||||
p := q.Quantize(make([]color.Color, 0, int(n)), i)
|
||||
bounds := i.Bounds()
|
||||
quantized := image.NewPaletted(bounds, p)
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
quantized.Set(x, y, i.At(x, y))
|
||||
}
|
||||
}
|
||||
i = p
|
||||
default:
|
||||
q := median.Quantizer(n)
|
||||
i = q.Paletted(i)
|
||||
i = quantized
|
||||
}
|
||||
return i
|
||||
}
|
||||
@@ -87,3 +70,32 @@ func asciify(s []byte) []byte {
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func fetchJnrbsnUserAgent() string {
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Get("https://jnrbsn.github.io/user-agents/user-agents.json")
|
||||
if err != nil {
|
||||
log.Printf("Failed to fetch user agents from jnrbsn: %v", err)
|
||||
return ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.Printf("jnrbsn API returned status: %d", resp.StatusCode)
|
||||
return ""
|
||||
}
|
||||
|
||||
var userAgents []string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&userAgents); err != nil {
|
||||
log.Printf("Failed to decode jnrbsn user agents JSON: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(userAgents) == 0 {
|
||||
log.Printf("jnrbsn API returned no user agents")
|
||||
return ""
|
||||
}
|
||||
|
||||
log.Printf("Fetched user agent from jnrbsn: %s", userAgents[0])
|
||||
return userAgents[0]
|
||||
}
|
||||
|
||||
33
wrp.go
33
wrp.go
@@ -1,8 +1,7 @@
|
||||
//
|
||||
// WRP - Web Rendering Proxy
|
||||
//
|
||||
// Copyright (c) 2013-2024 Antoni Sawicki
|
||||
// Copyright (c) 2019-2024 Google LLC
|
||||
// Copyright (c) 2013-2025 Antoni Sawicki
|
||||
//
|
||||
|
||||
package main
|
||||
@@ -29,20 +28,22 @@ import (
|
||||
_ "github.com/breml/rootcerts"
|
||||
)
|
||||
|
||||
const version = "4.8.0"
|
||||
const version = "4.9.3"
|
||||
|
||||
var (
|
||||
addr = flag.String("l", ":8080", "Listen address:port, default :8080")
|
||||
headless = flag.Bool("h", true, "Headless mode / hide browser window (default true)")
|
||||
noDel = flag.Bool("n", false, "Do not free maps and images after use")
|
||||
defType = flag.String("t", "gif", "Image type: png|gif|jpg")
|
||||
wrpMode = flag.String("m", "ismap", "WRP Mode: ismap|html")
|
||||
defImgSize = flag.Int64("is", 200, "html mode default image size")
|
||||
defJpgQual = flag.Int64("q", 75, "Jpeg image quality, default 75%") // TODO: this should be form dropdown when jpeg is selected as image type
|
||||
fgeom = flag.String("g", "1152x600x216", "Geometry: width x height x colors, height can be 0 for unlimited")
|
||||
htmFnam = flag.String("ui", "wrp.html", "HTML template file for the UI")
|
||||
delay = flag.Duration("s", 2*time.Second, "Delay/sleep after page is rendered and before screenshot is taken")
|
||||
userAgent = flag.String("ua", "", "override chrome user agent")
|
||||
addr = flag.String("l", ":8080", "Listen address:port, default :8080")
|
||||
headless = flag.Bool("h", true, "Headless mode / hide browser window (default true)")
|
||||
noDel = flag.Bool("n", false, "Do not free maps and images after use")
|
||||
defType = flag.String("t", "gip", "Image type: gip|png|gif|jpg")
|
||||
wrpMode = flag.String("m", "ismap", "WRP Mode: ismap|html")
|
||||
defImgSize = flag.Int64("is", 200, "html mode default image size")
|
||||
defJpgQual = flag.Int64("q", 75, "Jpeg image quality, default 75%") // TODO: this should be form dropdown when jpeg is selected as image type
|
||||
fgeom = flag.String("g", "1152x600x216", "Geometry: width x height x colors, height can be 0 for unlimited")
|
||||
htmFnam = flag.String("ui", "wrp.html", "HTML template file for the UI")
|
||||
delay = flag.Duration("s", 2*time.Second, "Delay/sleep after page is rendered and before screenshot is taken")
|
||||
userAgent = flag.String("ua", "jnrbsn", "override chrome user agent (jnrbsn=fetch from API, empty=default)")
|
||||
browserPath = flag.String("b", "", "browser executable path (e.g., /Applications/Brave Browser.app/Contents/MacOS/Brave Browser)")
|
||||
searchEng = flag.String("se", "https://duckduckgo.com/search?q=", "Search engine string")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -128,7 +129,7 @@ func (rq *wrpReq) parseForm() {
|
||||
}
|
||||
rq.url = rq.r.FormValue("url")
|
||||
if len(rq.url) > 1 && !strings.HasPrefix(rq.url, "http") {
|
||||
rq.url = fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(rq.url))
|
||||
rq.url = *searchEng + url.QueryEscape(rq.url)
|
||||
}
|
||||
// TODO: implement atoiOrZero
|
||||
rq.width, _ = strconv.ParseInt(rq.r.FormValue("w"), 10, 64)
|
||||
@@ -143,7 +144,7 @@ func (rq *wrpReq) parseForm() {
|
||||
}
|
||||
rq.imgType = rq.r.FormValue("t")
|
||||
switch rq.imgType {
|
||||
case "png", "gif", "jpg":
|
||||
case "gip", "png", "gif", "jpg":
|
||||
default:
|
||||
rq.imgType = *defType
|
||||
}
|
||||
|
||||
5
wrp.html
5
wrp.html
@@ -37,6 +37,7 @@
|
||||
</SELECT>
|
||||
T <SELECT NAME="t">
|
||||
<OPTION DISABLED>Type</OPTION>
|
||||
<OPTION VALUE="gip" {{ if eq .ImgType "gip"}}SELECTED{{end}}>GIP</OPTION>
|
||||
<OPTION VALUE="png" {{ if eq .ImgType "png"}}SELECTED{{end}}>PNG</OPTION>
|
||||
<OPTION VALUE="gif" {{ if eq .ImgType "gif"}}SELECTED{{end}}>GIF</OPTION>
|
||||
<OPTION VALUE="jpg" {{ if eq .ImgType "jpg"}}SELECTED{{end}}>JPG</OPTION>
|
||||
@@ -58,8 +59,8 @@
|
||||
{{ if eq .WrpMode "ismap" }}
|
||||
K <INPUT TYPE="TEXT" NAME="k" VALUE="" SIZE="4">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="Bs">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="Rt">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="All"><!--
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="Rt"><!--
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="All">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="<">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="^">
|
||||
<INPUT TYPE="SUBMIT" NAME="Fn" VALUE="v">
|
||||
|
||||
Reference in New Issue
Block a user