mirror of https://github.com/jlelse/GoBlog
Add AI-generated-summary plugin (aitldr), many new plugin hooks and update dependencies
This commit is contained in:
parent
d5db07fb73
commit
609780db79
|
@ -70,7 +70,7 @@ func (a *goBlog) openDatabase(file string, logging bool) (*database, error) {
|
||||||
ConnectHook: func(c *sqlite.SQLiteConn) error {
|
ConnectHook: func(c *sqlite.SQLiteConn) error {
|
||||||
// Register functions
|
// Register functions
|
||||||
for n, f := range map[string]any{
|
for n, f := range map[string]any{
|
||||||
"mdtext": a.renderText,
|
"mdtext": a.renderTextSafe,
|
||||||
"tolocal": toLocalSafe,
|
"tolocal": toLocalSafe,
|
||||||
"toutc": toUTCSafe,
|
"toutc": toUTCSafe,
|
||||||
"wordcount": wordCount,
|
"wordcount": wordCount,
|
||||||
|
|
|
@ -27,17 +27,9 @@ You need to specify the path to the plugin (remember to mount the path to your G
|
||||||
|
|
||||||
## Types of plugins
|
## Types of plugins
|
||||||
|
|
||||||
- `SetApp` (Access more GoBlog functionalities like the database) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#SetApp]
|
There are different plugin types for different functionalities a plugin wants to support. A plugin can implement multiple plugin types. You can find more information about the plugin types [in the Go documentation](https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes).
|
||||||
- `SetConfig` (Access the configuration provided for the plugin) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#SetConfig]
|
|
||||||
|
|
||||||
- `Exec` (Command that is executed in a Go routine when starting GoBlog) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#Exec]
|
You can take a look at the demo plugin, which implements many of the plugin types.
|
||||||
- `Middleware` (HTTP middleware to intercept or modify HTTP requests) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/]plugintypes#Middleware
|
|
||||||
- `UI` (Modify rendered HTML) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UI]
|
|
||||||
- `UI2` (Modify rendered HTML using a goquery document which improves performance and avoids multiple HTML parsing and rendering when using multiple plugins) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UI2]
|
|
||||||
- `UISummary` (like UI2 for only the post summary on indexes) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UISummary]
|
|
||||||
- `UIFooter` (like UI2 for only the post summary on indexes) - see [https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UIFooter]
|
|
||||||
|
|
||||||
More types will be added later. Any plugin can implement multiple types, see the demo plugin as example.
|
|
||||||
|
|
||||||
## Plugin implementation
|
## Plugin implementation
|
||||||
|
|
||||||
|
@ -131,3 +123,22 @@ config:
|
||||||
prev: https://example.com/ # Link to previous webring site
|
prev: https://example.com/ # Link to previous webring site
|
||||||
next: https://example.net/ # Link to next webring site
|
next: https://example.net/ # Link to next webring site
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### AI generated summary (Path `embedded:aitldr`, Import `aitldr`)
|
||||||
|
|
||||||
|
A plugin that uses the ChatGPT API to generated a short one-sentence summary for the blog post (after creating or updating it). To prevent it from generating a summary for a post, add the following post parameter:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
noaitldr: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Config
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
config:
|
||||||
|
# Required
|
||||||
|
apikey: YOUR_OPEN_AI_API_KEY
|
||||||
|
# Optional:
|
||||||
|
default: # Name of the blog
|
||||||
|
title: "Custom title for the summary box:"
|
||||||
|
```
|
16
go.mod
16
go.mod
|
@ -8,7 +8,7 @@ require (
|
||||||
git.jlel.se/jlelse/goldmark-mark v0.0.0-20210522162520-9788c89266a4
|
git.jlel.se/jlelse/goldmark-mark v0.0.0-20210522162520-9788c89266a4
|
||||||
git.jlel.se/jlelse/template-strings v0.0.0-20220211095702-c012e3b5045b
|
git.jlel.se/jlelse/template-strings v0.0.0-20220211095702-c012e3b5045b
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.8.1
|
||||||
github.com/alecthomas/chroma/v2 v2.5.0
|
github.com/alecthomas/chroma/v2 v2.7.0
|
||||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||||
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
|
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
|
||||||
github.com/carlmjohnson/requests v0.23.2
|
github.com/carlmjohnson/requests v0.23.2
|
||||||
|
@ -20,8 +20,8 @@ require (
|
||||||
github.com/dmulholl/mp3lib v1.0.0
|
github.com/dmulholl/mp3lib v1.0.0
|
||||||
github.com/elnormous/contenttype v1.0.4
|
github.com/elnormous/contenttype v1.0.4
|
||||||
github.com/emersion/go-smtp v0.16.0
|
github.com/emersion/go-smtp v0.16.0
|
||||||
github.com/go-ap/activitypub v0.0.0-20230317030458-892480c77bb6
|
github.com/go-ap/activitypub v0.0.0-20230323123728-77b329013634
|
||||||
github.com/go-ap/client v0.0.0-20230317030549-9bf6268ae536
|
github.com/go-ap/client v0.0.0-20230323123805-a1114dc5ba4f
|
||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||||
github.com/go-chi/chi/v5 v5.0.8
|
github.com/go-chi/chi/v5 v5.0.8
|
||||||
github.com/go-fed/httpsig v1.1.0
|
github.com/go-fed/httpsig v1.1.0
|
||||||
|
@ -46,7 +46,7 @@ require (
|
||||||
github.com/paulmach/go.geojson v1.4.0
|
github.com/paulmach/go.geojson v1.4.0
|
||||||
github.com/posener/wstest v1.2.0
|
github.com/posener/wstest v1.2.0
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/samber/lo v1.37.0
|
github.com/samber/lo v1.38.1
|
||||||
github.com/schollz/sqlite3dump v1.3.1
|
github.com/schollz/sqlite3dump v1.3.1
|
||||||
github.com/snabb/sitemap v1.0.4
|
github.com/snabb/sitemap v1.0.4
|
||||||
github.com/sourcegraph/conc v0.3.0
|
github.com/sourcegraph/conc v0.3.0
|
||||||
|
@ -57,7 +57,7 @@ require (
|
||||||
// master
|
// master
|
||||||
github.com/tkrajina/gpxgo v1.2.2-0.20220217201249-321f19554eec
|
github.com/tkrajina/gpxgo v1.2.2-0.20220217201249-321f19554eec
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||||
github.com/traefik/yaegi v0.15.0
|
github.com/traefik/yaegi v0.15.1
|
||||||
github.com/vcraescu/go-paginator/v2 v2.0.0
|
github.com/vcraescu/go-paginator/v2 v2.0.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0
|
github.com/xhit/go-simple-mail/v2 v2.13.0
|
||||||
github.com/yuin/goldmark v1.5.4
|
github.com/yuin/goldmark v1.5.4
|
||||||
|
@ -88,7 +88,7 @@ require (
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.7.7 // indirect
|
github.com/gin-gonic/gin v1.7.7 // indirect
|
||||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea // indirect
|
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea // indirect
|
||||||
github.com/golang/glog v1.1.0 // indirect
|
github.com/golang/glog v1.1.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.0 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
|
@ -100,7 +100,7 @@ require (
|
||||||
github.com/lestrrat-go/strftime v1.0.6 // indirect
|
github.com/lestrrat-go/strftime v1.0.6 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mmcdole/goxpp v1.1.0 // indirect
|
github.com/mmcdole/goxpp v1.1.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
@ -123,7 +123,7 @@ require (
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||||
golang.org/x/image v0.6.0 // indirect
|
golang.org/x/image v0.6.0 // indirect
|
||||||
golang.org/x/oauth2 v0.6.0 // indirect
|
golang.org/x/oauth2 v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
|
|
32
go.sum
32
go.sum
|
@ -53,8 +53,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||||
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
|
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
|
||||||
github.com/alecthomas/chroma/v2 v2.5.0 h1:CQCdj1BiBV17sD4Bd32b/Bzuiq/EqoNTrnIhyQAZ+Rk=
|
github.com/alecthomas/chroma/v2 v2.7.0 h1:hm1rY6c/Ob4eGclpQ7X/A3yhqBOZNUTk9q+yhyLIViI=
|
||||||
github.com/alecthomas/chroma/v2 v2.5.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
|
github.com/alecthomas/chroma/v2 v2.7.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
|
||||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||||
|
@ -128,10 +128,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
github.com/go-ap/activitypub v0.0.0-20230317030458-892480c77bb6 h1:I6l80Wy1UK0KZvK0xLho5FkiHp84f77RjgYOPThQ2I0=
|
github.com/go-ap/activitypub v0.0.0-20230323123728-77b329013634 h1:zD/tSS22PgVrJTJatsefCvug/RjabVy6JmshKYzOQok=
|
||||||
github.com/go-ap/activitypub v0.0.0-20230317030458-892480c77bb6/go.mod h1:1oVD0h0aPT3OEE1ZoSUoym/UGKzxe+e0y8K2AkQ1Hqs=
|
github.com/go-ap/activitypub v0.0.0-20230323123728-77b329013634/go.mod h1:qw0WNf+PTG69Xu6mVqUluDuKl1VwVYdgntOZQFBZQ48=
|
||||||
github.com/go-ap/client v0.0.0-20230317030549-9bf6268ae536 h1:+7v15882cEa9nRbjgk3D17qRcJgevDYvtcMUs5uvOkU=
|
github.com/go-ap/client v0.0.0-20230323123805-a1114dc5ba4f h1:ZOQfbSNAsQOLa/c3/mRCOMSSXjOnAyCMdiJ9myJiYBk=
|
||||||
github.com/go-ap/client v0.0.0-20230317030549-9bf6268ae536/go.mod h1:qgiGGIKang+sVcINaB3nN5uw4wZtaHHqp/qqtZ2HI2Y=
|
github.com/go-ap/client v0.0.0-20230323123805-a1114dc5ba4f/go.mod h1:ChxiPiPaRRYpsEFAX3KGAeE9P9upancoJTRSaaudpJE=
|
||||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea h1:ywGtLGVjJjMrq4mu35Qmu+NtlhlTk/gTayE6Bb4tQZk=
|
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea h1:ywGtLGVjJjMrq4mu35Qmu+NtlhlTk/gTayE6Bb4tQZk=
|
||||||
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea/go.mod h1:SaTNjEEkp0q+w3pUS1ccyEL/lUrHteORlDq/e21mCc8=
|
github.com/go-ap/errors v0.0.0-20221205040414-01c1adfc98ea/go.mod h1:SaTNjEEkp0q+w3pUS1ccyEL/lUrHteORlDq/e21mCc8=
|
||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||||
|
@ -163,8 +163,8 @@ github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
|
||||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -310,8 +310,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
|
@ -354,8 +354,8 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
|
||||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
||||||
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||||
github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw=
|
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA=
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/schollz/sqlite3dump v1.3.1 h1:QXizJ7XEJ7hggjqjZ3YRtF3+javm8zKtzNByYtEkPRA=
|
github.com/schollz/sqlite3dump v1.3.1 h1:QXizJ7XEJ7hggjqjZ3YRtF3+javm8zKtzNByYtEkPRA=
|
||||||
github.com/schollz/sqlite3dump v1.3.1/go.mod h1:mzSTjZpJH4zAb1FN3iNlhWPbbdyeBpOaTW0hukyMHyI=
|
github.com/schollz/sqlite3dump v1.3.1/go.mod h1:mzSTjZpJH4zAb1FN3iNlhWPbbdyeBpOaTW0hukyMHyI=
|
||||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||||
|
@ -412,8 +412,8 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJ
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
||||||
github.com/traefik/yaegi v0.15.0 h1:ScDDfQXTT75rKvcsMcP84rOxHsZ8b6NiQJyGocGDB7g=
|
github.com/traefik/yaegi v0.15.1 h1:YA5SbaL6HZA0Exh9T/oArRHqGN2HQ+zgmCY7dkoTXu4=
|
||||||
github.com/traefik/yaegi v0.15.0/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
|
github.com/traefik/yaegi v0.15.1/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
@ -465,8 +465,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
|
10
hooks.go
10
hooks.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.goblog.app/app/pkgs/bufferpool"
|
"go.goblog.app/app/pkgs/bufferpool"
|
||||||
|
"go.goblog.app/app/pkgs/plugintypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) preStartHooks() {
|
func (a *goBlog) preStartHooks() {
|
||||||
|
@ -35,6 +36,9 @@ func (a *goBlog) postPostHooks(p *post) {
|
||||||
for _, f := range a.pPostHooks {
|
for _, f := range a.pPostHooks {
|
||||||
go f(p)
|
go f(p)
|
||||||
}
|
}
|
||||||
|
for _, plugin := range a.getPlugins(pluginPostCreatedHookType) {
|
||||||
|
go plugin.(plugintypes.PostCreatedHook).PostCreated(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postUpdateHooks(p *post) {
|
func (a *goBlog) postUpdateHooks(p *post) {
|
||||||
|
@ -52,6 +56,9 @@ func (a *goBlog) postUpdateHooks(p *post) {
|
||||||
for _, f := range a.pUpdateHooks {
|
for _, f := range a.pUpdateHooks {
|
||||||
go f(p)
|
go f(p)
|
||||||
}
|
}
|
||||||
|
for _, plugin := range a.getPlugins(pluginPostUpdatedHookType) {
|
||||||
|
go plugin.(plugintypes.PostUpdatedHook).PostUpdated(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postDeleteHooks(p *post) {
|
func (a *goBlog) postDeleteHooks(p *post) {
|
||||||
|
@ -68,6 +75,9 @@ func (a *goBlog) postDeleteHooks(p *post) {
|
||||||
for _, f := range a.pDeleteHooks {
|
for _, f := range a.pDeleteHooks {
|
||||||
go f(p)
|
go f(p)
|
||||||
}
|
}
|
||||||
|
for _, plugin := range a.getPlugins(pluginPostDeletedHookType) {
|
||||||
|
go plugin.(plugintypes.PostDeletedHook).PostDeleted(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postUndeleteHooks(p *post) {
|
func (a *goBlog) postUndeleteHooks(p *post) {
|
||||||
|
|
18
markdown.go
18
markdown.go
|
@ -56,10 +56,7 @@ func (a *goBlog) initMarkdown() {
|
||||||
goldmark.WithParser(
|
goldmark.WithParser(
|
||||||
// Override, no need for special Markdown parsers
|
// Override, no need for special Markdown parsers
|
||||||
parser.NewParser(
|
parser.NewParser(
|
||||||
parser.WithBlockParsers(
|
parser.WithBlockParsers(util.Prioritized(parser.NewParagraphParser(), 1000)),
|
||||||
util.Prioritized(parser.NewParagraphParser(), 1000)),
|
|
||||||
parser.WithInlineParsers(),
|
|
||||||
parser.WithParagraphTransformers(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
goldmark.WithExtensions(
|
goldmark.WithExtensions(
|
||||||
|
@ -78,9 +75,9 @@ func (a *goBlog) renderMarkdownToWriter(w io.Writer, source string, absoluteLink
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) renderText(s string) string {
|
func (a *goBlog) renderText(s string) (string, error) {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
pr, pw := io.Pipe()
|
pr, pw := io.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -89,9 +86,14 @@ func (a *goBlog) renderText(s string) string {
|
||||||
text, err := htmlTextFromReader(pr)
|
text, err := htmlTextFromReader(pr)
|
||||||
_ = pr.CloseWithError(err)
|
_ = pr.CloseWithError(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
return text
|
return text, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) renderTextSafe(s string) string {
|
||||||
|
r, _ := a.renderText(s)
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) renderMdTitle(s string) string {
|
func (a *goBlog) renderMdTitle(s string) string {
|
||||||
|
|
|
@ -79,8 +79,9 @@ func Test_markdown(t *testing.T) {
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
|
|
||||||
renderedText := app.renderText("**This** *is* [text](/)")
|
renderedText, err := app.renderText("**This** *is* [text](/)")
|
||||||
assert.Equal(t, "This is text", renderedText)
|
assert.Equal(t, "This is text", renderedText)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ type App interface {
|
||||||
GetDatabase() Database
|
GetDatabase() Database
|
||||||
// Get a post from the database or an error when there is no post for the given path
|
// Get a post from the database or an error when there is no post for the given path
|
||||||
GetPost(path string) (Post, error)
|
GetPost(path string) (Post, error)
|
||||||
|
// Get a blog and a bool whether it exists
|
||||||
|
GetBlog(name string) (Blog, bool)
|
||||||
// Purge the rendering cache
|
// Purge the rendering cache
|
||||||
PurgeCache()
|
PurgeCache()
|
||||||
// Get the HTTP client used by GoBlog
|
// Get the HTTP client used by GoBlog
|
||||||
|
@ -21,6 +23,10 @@ type App interface {
|
||||||
CompileAsset(filename string, reader io.Reader) error
|
CompileAsset(filename string, reader io.Reader) error
|
||||||
// Get the asset path with the filename used when compiling the assert
|
// Get the asset path with the filename used when compiling the assert
|
||||||
AssetPath(filename string) string
|
AssetPath(filename string) string
|
||||||
|
// Set parameter values for a post path
|
||||||
|
SetPostParameter(path string, parameter string, values []string) error
|
||||||
|
// Render markdown as text (without HTML)
|
||||||
|
RenderMarkdownAsText(markdown string) (text string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database is used to provide access to GoBlog's database.
|
// Database is used to provide access to GoBlog's database.
|
||||||
|
@ -33,14 +39,18 @@ type Database interface {
|
||||||
QueryRowContext(context.Context, string, ...any) (*sql.Row, error)
|
QueryRowContext(context.Context, string, ...any) (*sql.Row, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post
|
// Post contains methods to access the post's data.
|
||||||
type Post interface {
|
type Post interface {
|
||||||
// Get the post path
|
// Get the post path
|
||||||
GetPath() string
|
GetPath() string
|
||||||
|
// Get the blog name
|
||||||
|
GetBlog() string
|
||||||
// Get a string array map with all the post's parameters
|
// Get a string array map with all the post's parameters
|
||||||
GetParameters() map[string][]string
|
GetParameters() map[string][]string
|
||||||
// Get a single parameter array (a parameter can have multiple values)
|
// Get a single parameter array (a parameter can have multiple values)
|
||||||
GetParameter(parameter string) []string
|
GetParameter(parameter string) []string
|
||||||
|
// Get the first value of a post parameter
|
||||||
|
GetFirstParameterValue(parameter string) string
|
||||||
// Get the post section name
|
// Get the post section name
|
||||||
GetSection() string
|
GetSection() string
|
||||||
// Get the published date string
|
// Get the published date string
|
||||||
|
@ -49,9 +59,17 @@ type Post interface {
|
||||||
GetUpdated() string
|
GetUpdated() string
|
||||||
// Get the post content (markdown)
|
// Get the post content (markdown)
|
||||||
GetContent() string
|
GetContent() string
|
||||||
|
// Get the post title
|
||||||
|
GetTitle() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderContext
|
// Blog contains methods to access the blog's configuration.
|
||||||
|
type Blog interface {
|
||||||
|
// Get the language
|
||||||
|
GetLanguage() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderContext gives some context of the current rendering.
|
||||||
type RenderContext interface {
|
type RenderContext interface {
|
||||||
// Get the path of the request
|
// Get the path of the request
|
||||||
GetPath() string
|
GetPath() string
|
||||||
|
|
|
@ -52,9 +52,35 @@ type UISummary interface {
|
||||||
RenderSummaryForPost(renderContext RenderContext, post Post, doc *goquery.Document)
|
RenderSummaryForPost(renderContext RenderContext, post Post, doc *goquery.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UIPost plugins get called when rendering the h-entry for a post. But only on the HTML frontend, not ActivityPub or feeds.
|
||||||
|
type UIPost interface {
|
||||||
|
// The renderContext provides information such as the path of the request or the blog name.
|
||||||
|
// The post contains information about the post for which to render the summary.
|
||||||
|
// The document can be used to add or modify the default HTML. But it only contains the HTML for the post, not for the whole page.
|
||||||
|
RenderPost(renderContext RenderContext, post Post, doc *goquery.Document)
|
||||||
|
}
|
||||||
|
|
||||||
// UIFooter plugins get called when rendering the footer on each HTML page.
|
// UIFooter plugins get called when rendering the footer on each HTML page.
|
||||||
type UIFooter interface {
|
type UIFooter interface {
|
||||||
// The renderContext provides information such as the path of the request or the blog name.
|
// The renderContext provides information such as the path of the request or the blog name.
|
||||||
// The document can be used to add or modify the default HTML.
|
// The document can be used to add or modify the default HTML.
|
||||||
RenderFooter(renderContext RenderContext, doc *goquery.Document)
|
RenderFooter(renderContext RenderContext, doc *goquery.Document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostCreatedHook plugins get called after a post is created.
|
||||||
|
type PostCreatedHook interface {
|
||||||
|
// Handle the post.
|
||||||
|
PostCreated(post Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostUpdatedHook plugins get called after a post is updated.
|
||||||
|
type PostUpdatedHook interface {
|
||||||
|
// Handle the post.
|
||||||
|
PostUpdated(post Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostUpdatedHook plugins get called after a post is deleted.
|
||||||
|
type PostDeletedHook interface {
|
||||||
|
// Handle the post.
|
||||||
|
PostDeleted(post Post)
|
||||||
|
}
|
||||||
|
|
|
@ -38,30 +38,40 @@ func init() {
|
||||||
Symbols["go.goblog.app/app/pkgs/plugintypes/plugintypes"] = map[string]reflect.Value{
|
Symbols["go.goblog.app/app/pkgs/plugintypes/plugintypes"] = map[string]reflect.Value{
|
||||||
// type definitions
|
// type definitions
|
||||||
"App": reflect.ValueOf((*plugintypes.App)(nil)),
|
"App": reflect.ValueOf((*plugintypes.App)(nil)),
|
||||||
|
"Blog": reflect.ValueOf((*plugintypes.Blog)(nil)),
|
||||||
"Database": reflect.ValueOf((*plugintypes.Database)(nil)),
|
"Database": reflect.ValueOf((*plugintypes.Database)(nil)),
|
||||||
"Exec": reflect.ValueOf((*plugintypes.Exec)(nil)),
|
"Exec": reflect.ValueOf((*plugintypes.Exec)(nil)),
|
||||||
"Middleware": reflect.ValueOf((*plugintypes.Middleware)(nil)),
|
"Middleware": reflect.ValueOf((*plugintypes.Middleware)(nil)),
|
||||||
"Post": reflect.ValueOf((*plugintypes.Post)(nil)),
|
"Post": reflect.ValueOf((*plugintypes.Post)(nil)),
|
||||||
|
"PostCreatedHook": reflect.ValueOf((*plugintypes.PostCreatedHook)(nil)),
|
||||||
|
"PostDeletedHook": reflect.ValueOf((*plugintypes.PostDeletedHook)(nil)),
|
||||||
|
"PostUpdatedHook": reflect.ValueOf((*plugintypes.PostUpdatedHook)(nil)),
|
||||||
"RenderContext": reflect.ValueOf((*plugintypes.RenderContext)(nil)),
|
"RenderContext": reflect.ValueOf((*plugintypes.RenderContext)(nil)),
|
||||||
"SetApp": reflect.ValueOf((*plugintypes.SetApp)(nil)),
|
"SetApp": reflect.ValueOf((*plugintypes.SetApp)(nil)),
|
||||||
"SetConfig": reflect.ValueOf((*plugintypes.SetConfig)(nil)),
|
"SetConfig": reflect.ValueOf((*plugintypes.SetConfig)(nil)),
|
||||||
"UI": reflect.ValueOf((*plugintypes.UI)(nil)),
|
"UI": reflect.ValueOf((*plugintypes.UI)(nil)),
|
||||||
"UI2": reflect.ValueOf((*plugintypes.UI2)(nil)),
|
"UI2": reflect.ValueOf((*plugintypes.UI2)(nil)),
|
||||||
"UIFooter": reflect.ValueOf((*plugintypes.UIFooter)(nil)),
|
"UIFooter": reflect.ValueOf((*plugintypes.UIFooter)(nil)),
|
||||||
|
"UIPost": reflect.ValueOf((*plugintypes.UIPost)(nil)),
|
||||||
"UISummary": reflect.ValueOf((*plugintypes.UISummary)(nil)),
|
"UISummary": reflect.ValueOf((*plugintypes.UISummary)(nil)),
|
||||||
|
|
||||||
// interface wrapper definitions
|
// interface wrapper definitions
|
||||||
"_App": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_App)(nil)),
|
"_App": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_App)(nil)),
|
||||||
|
"_Blog": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Blog)(nil)),
|
||||||
"_Database": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Database)(nil)),
|
"_Database": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Database)(nil)),
|
||||||
"_Exec": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Exec)(nil)),
|
"_Exec": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Exec)(nil)),
|
||||||
"_Middleware": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Middleware)(nil)),
|
"_Middleware": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Middleware)(nil)),
|
||||||
"_Post": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Post)(nil)),
|
"_Post": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_Post)(nil)),
|
||||||
|
"_PostCreatedHook": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_PostCreatedHook)(nil)),
|
||||||
|
"_PostDeletedHook": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_PostDeletedHook)(nil)),
|
||||||
|
"_PostUpdatedHook": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_PostUpdatedHook)(nil)),
|
||||||
"_RenderContext": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_RenderContext)(nil)),
|
"_RenderContext": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_RenderContext)(nil)),
|
||||||
"_SetApp": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_SetApp)(nil)),
|
"_SetApp": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_SetApp)(nil)),
|
||||||
"_SetConfig": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_SetConfig)(nil)),
|
"_SetConfig": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_SetConfig)(nil)),
|
||||||
"_UI": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UI)(nil)),
|
"_UI": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UI)(nil)),
|
||||||
"_UI2": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UI2)(nil)),
|
"_UI2": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UI2)(nil)),
|
||||||
"_UIFooter": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UIFooter)(nil)),
|
"_UIFooter": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UIFooter)(nil)),
|
||||||
|
"_UIPost": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UIPost)(nil)),
|
||||||
"_UISummary": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UISummary)(nil)),
|
"_UISummary": reflect.ValueOf((*_go_goblog_app_app_pkgs_plugintypes_UISummary)(nil)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,10 +81,13 @@ type _go_goblog_app_app_pkgs_plugintypes_App struct {
|
||||||
IValue interface{}
|
IValue interface{}
|
||||||
WAssetPath func(filename string) string
|
WAssetPath func(filename string) string
|
||||||
WCompileAsset func(filename string, reader io.Reader) error
|
WCompileAsset func(filename string, reader io.Reader) error
|
||||||
|
WGetBlog func(name string) (plugintypes.Blog, bool)
|
||||||
WGetDatabase func() plugintypes.Database
|
WGetDatabase func() plugintypes.Database
|
||||||
WGetHTTPClient func() *http.Client
|
WGetHTTPClient func() *http.Client
|
||||||
WGetPost func(path string) (plugintypes.Post, error)
|
WGetPost func(path string) (plugintypes.Post, error)
|
||||||
WPurgeCache func()
|
WPurgeCache func()
|
||||||
|
WRenderMarkdownAsText func(markdown string) (text string, err error)
|
||||||
|
WSetPostParameter func(path string, parameter string, values []string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_App) AssetPath(filename string) string {
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) AssetPath(filename string) string {
|
||||||
|
@ -83,6 +96,9 @@ func (W _go_goblog_app_app_pkgs_plugintypes_App) AssetPath(filename string) stri
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_App) CompileAsset(filename string, reader io.Reader) error {
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) CompileAsset(filename string, reader io.Reader) error {
|
||||||
return W.WCompileAsset(filename, reader)
|
return W.WCompileAsset(filename, reader)
|
||||||
}
|
}
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) GetBlog(name string) (plugintypes.Blog, bool) {
|
||||||
|
return W.WGetBlog(name)
|
||||||
|
}
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_App) GetDatabase() plugintypes.Database {
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) GetDatabase() plugintypes.Database {
|
||||||
return W.WGetDatabase()
|
return W.WGetDatabase()
|
||||||
}
|
}
|
||||||
|
@ -95,6 +111,22 @@ func (W _go_goblog_app_app_pkgs_plugintypes_App) GetPost(path string) (plugintyp
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_App) PurgeCache() {
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) PurgeCache() {
|
||||||
W.WPurgeCache()
|
W.WPurgeCache()
|
||||||
}
|
}
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) RenderMarkdownAsText(markdown string) (text string, err error) {
|
||||||
|
return W.WRenderMarkdownAsText(markdown)
|
||||||
|
}
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_App) SetPostParameter(path string, parameter string, values []string) error {
|
||||||
|
return W.WSetPostParameter(path, parameter, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_Blog is an interface wrapper for Blog type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_Blog struct {
|
||||||
|
IValue interface{}
|
||||||
|
WGetLanguage func() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_Blog) GetLanguage() string {
|
||||||
|
return W.WGetLanguage()
|
||||||
|
}
|
||||||
|
|
||||||
// _go_goblog_app_app_pkgs_plugintypes_Database is an interface wrapper for Database type
|
// _go_goblog_app_app_pkgs_plugintypes_Database is an interface wrapper for Database type
|
||||||
type _go_goblog_app_app_pkgs_plugintypes_Database struct {
|
type _go_goblog_app_app_pkgs_plugintypes_Database struct {
|
||||||
|
@ -153,18 +185,27 @@ func (W _go_goblog_app_app_pkgs_plugintypes_Middleware) Prio() int {
|
||||||
// _go_goblog_app_app_pkgs_plugintypes_Post is an interface wrapper for Post type
|
// _go_goblog_app_app_pkgs_plugintypes_Post is an interface wrapper for Post type
|
||||||
type _go_goblog_app_app_pkgs_plugintypes_Post struct {
|
type _go_goblog_app_app_pkgs_plugintypes_Post struct {
|
||||||
IValue interface{}
|
IValue interface{}
|
||||||
|
WGetBlog func() string
|
||||||
WGetContent func() string
|
WGetContent func() string
|
||||||
|
WGetFirstParameterValue func(parameter string) string
|
||||||
WGetParameter func(parameter string) []string
|
WGetParameter func(parameter string) []string
|
||||||
WGetParameters func() map[string][]string
|
WGetParameters func() map[string][]string
|
||||||
WGetPath func() string
|
WGetPath func() string
|
||||||
WGetPublished func() string
|
WGetPublished func() string
|
||||||
WGetSection func() string
|
WGetSection func() string
|
||||||
|
WGetTitle func() string
|
||||||
WGetUpdated func() string
|
WGetUpdated func() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetBlog() string {
|
||||||
|
return W.WGetBlog()
|
||||||
|
}
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetContent() string {
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetContent() string {
|
||||||
return W.WGetContent()
|
return W.WGetContent()
|
||||||
}
|
}
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetFirstParameterValue(parameter string) string {
|
||||||
|
return W.WGetFirstParameterValue(parameter)
|
||||||
|
}
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetParameter(parameter string) []string {
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetParameter(parameter string) []string {
|
||||||
return W.WGetParameter(parameter)
|
return W.WGetParameter(parameter)
|
||||||
}
|
}
|
||||||
|
@ -180,10 +221,43 @@ func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetPublished() string {
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetSection() string {
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetSection() string {
|
||||||
return W.WGetSection()
|
return W.WGetSection()
|
||||||
}
|
}
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetTitle() string {
|
||||||
|
return W.WGetTitle()
|
||||||
|
}
|
||||||
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetUpdated() string {
|
func (W _go_goblog_app_app_pkgs_plugintypes_Post) GetUpdated() string {
|
||||||
return W.WGetUpdated()
|
return W.WGetUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_PostCreatedHook is an interface wrapper for PostCreatedHook type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_PostCreatedHook struct {
|
||||||
|
IValue interface{}
|
||||||
|
WPostCreated func(post plugintypes.Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_PostCreatedHook) PostCreated(post plugintypes.Post) {
|
||||||
|
W.WPostCreated(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_PostDeletedHook is an interface wrapper for PostDeletedHook type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_PostDeletedHook struct {
|
||||||
|
IValue interface{}
|
||||||
|
WPostDeleted func(post plugintypes.Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_PostDeletedHook) PostDeleted(post plugintypes.Post) {
|
||||||
|
W.WPostDeleted(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_PostUpdatedHook is an interface wrapper for PostUpdatedHook type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_PostUpdatedHook struct {
|
||||||
|
IValue interface{}
|
||||||
|
WPostUpdated func(post plugintypes.Post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_PostUpdatedHook) PostUpdated(post plugintypes.Post) {
|
||||||
|
W.WPostUpdated(post)
|
||||||
|
}
|
||||||
|
|
||||||
// _go_goblog_app_app_pkgs_plugintypes_RenderContext is an interface wrapper for RenderContext type
|
// _go_goblog_app_app_pkgs_plugintypes_RenderContext is an interface wrapper for RenderContext type
|
||||||
type _go_goblog_app_app_pkgs_plugintypes_RenderContext struct {
|
type _go_goblog_app_app_pkgs_plugintypes_RenderContext struct {
|
||||||
IValue interface{}
|
IValue interface{}
|
||||||
|
@ -252,6 +326,16 @@ func (W _go_goblog_app_app_pkgs_plugintypes_UIFooter) RenderFooter(renderContext
|
||||||
W.WRenderFooter(renderContext, doc)
|
W.WRenderFooter(renderContext, doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _go_goblog_app_app_pkgs_plugintypes_UIPost is an interface wrapper for UIPost type
|
||||||
|
type _go_goblog_app_app_pkgs_plugintypes_UIPost struct {
|
||||||
|
IValue interface{}
|
||||||
|
WRenderPost func(renderContext plugintypes.RenderContext, post plugintypes.Post, doc *goquery.Document)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (W _go_goblog_app_app_pkgs_plugintypes_UIPost) RenderPost(renderContext plugintypes.RenderContext, post plugintypes.Post, doc *goquery.Document) {
|
||||||
|
W.WRenderPost(renderContext, post, doc)
|
||||||
|
}
|
||||||
|
|
||||||
// _go_goblog_app_app_pkgs_plugintypes_UISummary is an interface wrapper for UISummary type
|
// _go_goblog_app_app_pkgs_plugintypes_UISummary is an interface wrapper for UISummary type
|
||||||
type _go_goblog_app_app_pkgs_plugintypes_UISummary struct {
|
type _go_goblog_app_app_pkgs_plugintypes_UISummary struct {
|
||||||
IValue interface{}
|
IValue interface{}
|
||||||
|
|
37
plugins.go
37
plugins.go
|
@ -23,7 +23,11 @@ const (
|
||||||
pluginExecType = "exec"
|
pluginExecType = "exec"
|
||||||
pluginMiddlewareType = "middleware"
|
pluginMiddlewareType = "middleware"
|
||||||
pluginUiSummaryType = "uisummary"
|
pluginUiSummaryType = "uisummary"
|
||||||
|
pluginUiPostType = "uiPost"
|
||||||
pluginUiFooterType = "uifooter"
|
pluginUiFooterType = "uifooter"
|
||||||
|
pluginPostCreatedHookType = "postcreatedhook"
|
||||||
|
pluginPostUpdatedHookType = "postupdatedhook"
|
||||||
|
pluginPostDeletedHookType = "postdeletedhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) initPlugins() error {
|
func (a *goBlog) initPlugins() error {
|
||||||
|
@ -40,7 +44,11 @@ func (a *goBlog) initPlugins() error {
|
||||||
pluginExecType: reflect.TypeOf((*plugintypes.Exec)(nil)).Elem(),
|
pluginExecType: reflect.TypeOf((*plugintypes.Exec)(nil)).Elem(),
|
||||||
pluginMiddlewareType: reflect.TypeOf((*plugintypes.Middleware)(nil)).Elem(),
|
pluginMiddlewareType: reflect.TypeOf((*plugintypes.Middleware)(nil)).Elem(),
|
||||||
pluginUiSummaryType: reflect.TypeOf((*plugintypes.UISummary)(nil)).Elem(),
|
pluginUiSummaryType: reflect.TypeOf((*plugintypes.UISummary)(nil)).Elem(),
|
||||||
|
pluginUiPostType: reflect.TypeOf((*plugintypes.UIPost)(nil)).Elem(),
|
||||||
pluginUiFooterType: reflect.TypeOf((*plugintypes.UIFooter)(nil)).Elem(),
|
pluginUiFooterType: reflect.TypeOf((*plugintypes.UIFooter)(nil)).Elem(),
|
||||||
|
pluginPostCreatedHookType: reflect.TypeOf((*plugintypes.PostCreatedHook)(nil)).Elem(),
|
||||||
|
pluginPostUpdatedHookType: reflect.TypeOf((*plugintypes.PostUpdatedHook)(nil)).Elem(),
|
||||||
|
pluginPostDeletedHookType: reflect.TypeOf((*plugintypes.PostDeletedHook)(nil)).Elem(),
|
||||||
},
|
},
|
||||||
yaegiwrappers.Symbols,
|
yaegiwrappers.Symbols,
|
||||||
subFS,
|
subFS,
|
||||||
|
@ -86,6 +94,11 @@ func (a *goBlog) GetPost(path string) (plugintypes.Post, error) {
|
||||||
return a.getPost(path)
|
return a.getPost(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) GetBlog(name string) (plugintypes.Blog, bool) {
|
||||||
|
blog, ok := a.cfg.Blogs[name]
|
||||||
|
return blog, ok
|
||||||
|
}
|
||||||
|
|
||||||
func (a *goBlog) PurgeCache() {
|
func (a *goBlog) PurgeCache() {
|
||||||
a.cache.purge()
|
a.cache.purge()
|
||||||
}
|
}
|
||||||
|
@ -102,6 +115,14 @@ func (a *goBlog) AssetPath(filename string) string {
|
||||||
return a.assetFileName(filename)
|
return a.assetFileName(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) SetPostParameter(path string, parameter string, values []string) error {
|
||||||
|
return a.db.replacePostParam(path, parameter, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) RenderMarkdownAsText(markdown string) (text string, err error) {
|
||||||
|
return a.renderText(markdown)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *post) GetPath() string {
|
func (p *post) GetPath() string {
|
||||||
return p.Path
|
return p.Path
|
||||||
}
|
}
|
||||||
|
@ -114,6 +135,10 @@ func (p *post) GetParameter(parameter string) []string {
|
||||||
return p.Parameters[parameter]
|
return p.Parameters[parameter]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *post) GetFirstParameterValue(parameter string) string {
|
||||||
|
return p.firstParameter(parameter)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *post) GetSection() string {
|
func (p *post) GetSection() string {
|
||||||
return p.Section
|
return p.Section
|
||||||
}
|
}
|
||||||
|
@ -129,3 +154,15 @@ func (p *post) GetUpdated() string {
|
||||||
func (p *post) GetContent() string {
|
func (p *post) GetContent() string {
|
||||||
return p.Content
|
return p.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *post) GetTitle() string {
|
||||||
|
return p.Title()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *post) GetBlog() string {
|
||||||
|
return p.Blog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *configBlog) GetLanguage() string {
|
||||||
|
return b.Lang
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
package aitldr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
|
"github.com/carlmjohnson/requests"
|
||||||
|
"go.goblog.app/app/pkgs/bufferpool"
|
||||||
|
"go.goblog.app/app/pkgs/htmlbuilder"
|
||||||
|
"go.goblog.app/app/pkgs/plugintypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type plugin struct {
|
||||||
|
app plugintypes.App
|
||||||
|
|
||||||
|
config map[string]any
|
||||||
|
initCSS sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlugin() (
|
||||||
|
plugintypes.SetConfig, plugintypes.SetApp,
|
||||||
|
plugintypes.PostCreatedHook, plugintypes.PostUpdatedHook,
|
||||||
|
plugintypes.UIPost, plugintypes.UI2,
|
||||||
|
) {
|
||||||
|
p := &plugin{}
|
||||||
|
return p, p, p, p, p, p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) SetApp(app plugintypes.App) {
|
||||||
|
p.app = app
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) SetConfig(config map[string]any) {
|
||||||
|
p.config = config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) PostCreated(post plugintypes.Post) {
|
||||||
|
p.summarize(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) PostUpdated(post plugintypes.Post) {
|
||||||
|
p.summarize(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
const postParam = "aitldr"
|
||||||
|
|
||||||
|
func (p *plugin) RenderPost(renderContext plugintypes.RenderContext, post plugintypes.Post, doc *goquery.Document) {
|
||||||
|
tldr := post.GetFirstParameterValue(postParam)
|
||||||
|
if tldr == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
title := "AI generated summary:"
|
||||||
|
if blogConfig, ok := p.config[renderContext.GetBlog()]; ok {
|
||||||
|
if blogConfigAsMap, ok := blogConfig.(map[string]any); ok {
|
||||||
|
if blogSpecificTitle, ok := blogConfigAsMap["title"]; ok {
|
||||||
|
if blogSpecificTitleAsString, ok := blogSpecificTitle.(string); ok {
|
||||||
|
title = blogSpecificTitleAsString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bufferpool.Get()
|
||||||
|
defer bufferpool.Put(buf)
|
||||||
|
hw := htmlbuilder.NewHtmlBuilder(buf)
|
||||||
|
hw.WriteElementOpen("div", "class", "p aitldr")
|
||||||
|
hw.WriteElementOpen("b")
|
||||||
|
hw.WriteEscaped(title)
|
||||||
|
hw.WriteElementClose("b")
|
||||||
|
hw.WriteEscaped(" ")
|
||||||
|
hw.WriteElementOpen("i")
|
||||||
|
hw.WriteEscaped(tldr)
|
||||||
|
hw.WriteElementsClose("i", "div")
|
||||||
|
|
||||||
|
doc.Find(".e-content").BeforeHtml(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
const customCSS = ".aitldr { border: 1px dashed; padding: 1em; }"
|
||||||
|
|
||||||
|
func (p *plugin) RenderWithDocument(_ plugintypes.RenderContext, doc *goquery.Document) {
|
||||||
|
if p.app == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init custom CSS for plugin
|
||||||
|
p.initCSS.Do(func() {
|
||||||
|
_ = p.app.CompileAsset("aitldr.css", strings.NewReader(customCSS))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check if page has AI TLDR, then add the custom CSS
|
||||||
|
doc.Find(".aitldr").First().Each(func(_ int, _ *goquery.Selection) {
|
||||||
|
buf := bufferpool.Get()
|
||||||
|
defer bufferpool.Put(buf)
|
||||||
|
hb := htmlbuilder.NewHtmlBuilder(buf)
|
||||||
|
hb.WriteElementOpen("link", "rel", "stylesheet", "href", p.app.AssetPath("aitldr.css"))
|
||||||
|
doc.Find("head").AppendHtml(buf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiMessage struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiResponse struct {
|
||||||
|
Choices []struct {
|
||||||
|
Message apiMessage `json:"message"`
|
||||||
|
} `json:"choices"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) summarize(post plugintypes.Post) {
|
||||||
|
if post.GetFirstParameterValue("noaitldr") == "true" {
|
||||||
|
log.Println("aitldr: Skip summarizing", post.GetPath())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apikey := ""
|
||||||
|
if k, ok := p.config["apikey"]; ok {
|
||||||
|
if ks, ok := k.(string); ok {
|
||||||
|
apikey = ks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if apikey == "" {
|
||||||
|
log.Println("Config for aitldr plugin not correct! apikey missing!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response apiResponse
|
||||||
|
|
||||||
|
err := requests.URL("https://api.openai.com/v1/chat/completions").
|
||||||
|
Method(http.MethodPost).
|
||||||
|
Header("Authorization", "Bearer "+apikey).
|
||||||
|
BodyJSON(map[string]any{
|
||||||
|
"model": "gpt-3.5-turbo",
|
||||||
|
"temperature": 0,
|
||||||
|
"max_tokens": 200,
|
||||||
|
"messages": []apiMessage{
|
||||||
|
{
|
||||||
|
Role: "user",
|
||||||
|
Content: p.createPrompt(post),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
ToJSON(&response).
|
||||||
|
Fetch(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println("aitldr plugin:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(response.Choices) < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
summary := response.Choices[0].Message.Content
|
||||||
|
summary = strings.TrimSpace(summary)
|
||||||
|
|
||||||
|
err = p.app.SetPostParameter(post.GetPath(), postParam, []string{summary})
|
||||||
|
if err != nil {
|
||||||
|
log.Println("aitldr plugin:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.app.PurgeCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) createPrompt(post plugintypes.Post) string {
|
||||||
|
lang := "en"
|
||||||
|
if blog, ok := p.app.GetBlog(post.GetBlog()); ok {
|
||||||
|
if blogLang := blog.GetLanguage(); lang != "" {
|
||||||
|
lang = blogLang
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prompt := "Summarize the content of following text in one sentence in the language \"" + lang + "\". Answer with just the summary.\n\n\n"
|
||||||
|
if title, err := p.app.RenderMarkdownAsText(post.GetTitle()); err == nil && title != "" {
|
||||||
|
prompt += title + "\n\n"
|
||||||
|
} else if err != nil {
|
||||||
|
log.Println("aitldr plugin: Rendering markdown as text failed:", err.Error())
|
||||||
|
}
|
||||||
|
if text, err := p.app.RenderMarkdownAsText(post.GetContent()); err == nil && text != "" {
|
||||||
|
prompt += text + "\n\n"
|
||||||
|
} else if err != nil {
|
||||||
|
log.Println("aitldr plugin: Rendering markdown as text failed:", err.Error())
|
||||||
|
}
|
||||||
|
return prompt
|
||||||
|
}
|
|
@ -120,7 +120,7 @@ func (a *goBlog) postSummary(p *post) (summary string) {
|
||||||
splitted := strings.Split(p.Content, summaryDivider)
|
splitted := strings.Split(p.Content, summaryDivider)
|
||||||
hasDivider := len(splitted) > 1
|
hasDivider := len(splitted) > 1
|
||||||
markdown := splitted[0]
|
markdown := splitted[0]
|
||||||
summary = a.renderText(markdown)
|
summary = a.renderTextSafe(markdown)
|
||||||
if !hasDivider {
|
if !hasDivider {
|
||||||
summary = strings.Split(summary, "\n\n")[0]
|
summary = strings.Split(summary, "\n\n")[0]
|
||||||
}
|
}
|
||||||
|
|
10
ui.go
10
ui.go
|
@ -4,12 +4,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/hacdias/indieauth/v3"
|
"github.com/hacdias/indieauth/v3"
|
||||||
"github.com/kaorimatz/go-opml"
|
"github.com/kaorimatz/go-opml"
|
||||||
"github.com/mergestat/timediff"
|
"github.com/mergestat/timediff"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"go.goblog.app/app/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
"go.goblog.app/app/pkgs/htmlbuilder"
|
"go.goblog.app/app/pkgs/htmlbuilder"
|
||||||
|
"go.goblog.app/app/pkgs/plugintypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) renderEditorPreview(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *post) {
|
func (a *goBlog) renderEditorPreview(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *post) {
|
||||||
|
@ -847,7 +849,13 @@ func (a *goBlog) renderPost(hb *htmlbuilder.HtmlBuilder, rd *renderData) {
|
||||||
hb.WriteElementOpen("link", "rel", "shortlink", "href", su)
|
hb.WriteElementOpen("link", "rel", "shortlink", "href", su)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
func(hb *htmlbuilder.HtmlBuilder) {
|
func(origHb *htmlbuilder.HtmlBuilder) {
|
||||||
|
// Wrap plugins
|
||||||
|
hb, finish := a.wrapForPlugins(origHb, a.getPlugins(pluginUiPostType), func(plugin any, doc *goquery.Document) {
|
||||||
|
plugin.(plugintypes.UIPost).RenderPost(rd.prc, p, doc)
|
||||||
|
})
|
||||||
|
defer finish()
|
||||||
|
// Render...
|
||||||
hb.WriteElementOpen("main", "class", "h-entry")
|
hb.WriteElementOpen("main", "class", "h-entry")
|
||||||
// URL (hidden just for microformats)
|
// URL (hidden just for microformats)
|
||||||
hb.WriteElementOpen("data", "value", a.getFullAddress(p.Path), "class", "u-url hide")
|
hb.WriteElementOpen("data", "value", a.getFullAddress(p.Path), "class", "u-url hide")
|
||||||
|
|
Loading…
Reference in New Issue