Embed static resources (#1466)
* Replace pkger with go:embed for bundling the admin. Closes #844 * Remove references to pkged.go * Point tests to use an updated version of Go * Add comment to new exported function * Cleanup * Add a dummy pkged.go to alert people to stop using it. * Add simple browser test to make sure the admin is available and renders * Don't panic * Embed bot/scraper metadata template. Add browser test to validate the rendering of this template. * Use embedded offline.ts segment * Remove placeholder thumbnail as its unnecessary * Remove copying the static directory into the release * Cleanup
This commit is contained in:
parent
f0bd7d2528
commit
ca9d5de192
@ -23,6 +23,5 @@ RUN apk update && apk add --no-cache ffmpeg ffmpeg-libs ca-certificates && updat
|
||||
WORKDIR /app
|
||||
COPY --from=build /build/owncast /app/owncast
|
||||
COPY --from=build /build/webroot /app/webroot
|
||||
COPY --from=build /build/static /app/static
|
||||
RUN mkdir /app/data
|
||||
CMD ["/app/owncast"]
|
||||
|
@ -67,7 +67,6 @@ build() {
|
||||
|
||||
# Copy the production pruned+minified css to the build's directory.
|
||||
cp "${TMPDIR}tailwind.min.css" ./dist/${NAME}/webroot/js/web_modules/tailwindcss/dist/tailwind.min.css
|
||||
cp -R static/ dist/${NAME}/static
|
||||
cp README.md dist/${NAME}
|
||||
|
||||
pushd dist/${NAME} >> /dev/null
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@ -17,6 +16,7 @@ import (
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
"github.com/owncast/owncast/static"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
@ -74,7 +74,12 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Return a basic HTML page with server-rendered metadata from the config file
|
||||
// to give to Opengraph clients and web scrapers (bots, web crawlers, etc).
|
||||
func handleScraperMetadataPage(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl := template.Must(template.ParseFiles(path.Join("static", "metadata.html")))
|
||||
tmpl, err := static.GetBotMetadataTemplate()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
scheme := "http"
|
||||
|
||||
|
23
core/core.go
23
core/core.go
@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@ -14,6 +15,7 @@ import (
|
||||
"github.com/owncast/owncast/core/transcoder"
|
||||
"github.com/owncast/owncast/core/user"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/static"
|
||||
"github.com/owncast/owncast/utils"
|
||||
"github.com/owncast/owncast/yp"
|
||||
)
|
||||
@ -79,13 +81,6 @@ func Start() error {
|
||||
}
|
||||
|
||||
func createInitialOfflineState() error {
|
||||
// Provide default files
|
||||
if !utils.DoesFileExists(filepath.Join(config.WebRoot, "thumbnail.jpg")) {
|
||||
if err := utils.Copy("static/logo.png", filepath.Join(config.WebRoot, "thumbnail.jpg")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
transitionToOfflineVideoStreamContent()
|
||||
|
||||
return nil
|
||||
@ -97,12 +92,18 @@ func createInitialOfflineState() error {
|
||||
func transitionToOfflineVideoStreamContent() {
|
||||
log.Traceln("Firing transcoder with offline stream state")
|
||||
|
||||
offlineFilename := "offline.ts"
|
||||
offlineFilePath := "static/" + offlineFilename
|
||||
r, w := io.Pipe()
|
||||
|
||||
_transcoder := transcoder.NewTranscoder()
|
||||
_transcoder.SetInput(offlineFilePath)
|
||||
_transcoder.SetInput("pipe:0")
|
||||
_transcoder.SetStdin(r)
|
||||
_transcoder.SetIdentifier("offline")
|
||||
_transcoder.Start()
|
||||
go _transcoder.Start()
|
||||
|
||||
d := static.GetOfflineSegment()
|
||||
if _, err := w.Write(d); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
// Copy the logo to be the thumbnail
|
||||
logo := data.GetLogoPath()
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@ -17,6 +18,7 @@ import (
|
||||
"github.com/owncast/owncast/core/transcoder"
|
||||
"github.com/owncast/owncast/core/webhooks"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/static"
|
||||
"github.com/owncast/owncast/utils"
|
||||
|
||||
"github.com/grafov/m3u8"
|
||||
@ -84,8 +86,18 @@ func SetStreamAsDisconnected() {
|
||||
_stats.LastConnectTime = nil
|
||||
_broadcaster = nil
|
||||
|
||||
offlineFileData := static.GetOfflineSegment()
|
||||
offlineFilename := "offline.ts"
|
||||
offlineFilePath := "static/" + offlineFilename
|
||||
offlineTmpFile, err := ioutil.TempFile(os.TempDir(), offlineFilename)
|
||||
if err != nil {
|
||||
log.Errorln("unable to create temp file for offline video segment")
|
||||
}
|
||||
|
||||
if _, err = offlineTmpFile.Write(offlineFileData); err != nil {
|
||||
log.Errorln("unable to write offline segment to disk", err)
|
||||
}
|
||||
|
||||
offlineFilePath := offlineTmpFile.Name()
|
||||
|
||||
transcoder.StopThumbnailGenerator()
|
||||
rtmp.Disconnect()
|
||||
|
@ -386,8 +386,8 @@ func (t *Transcoder) SetInput(input string) {
|
||||
}
|
||||
|
||||
// SetStdin sets the Stdin of the ffmpeg command.
|
||||
func (t *Transcoder) SetStdin(rtmp *io.PipeReader) {
|
||||
t.stdin = rtmp
|
||||
func (t *Transcoder) SetStdin(pipe *io.PipeReader) {
|
||||
t.stdin = pipe
|
||||
}
|
||||
|
||||
// SetOutputPath sets the root directory that should include playlists and video segments.
|
||||
|
BIN
static/logo.png
BIN
static/logo.png
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
@ -1,6 +1,9 @@
|
||||
package static
|
||||
|
||||
import "embed"
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
//go:embed admin/*
|
||||
//go:embed admin/_next/static
|
||||
@ -12,3 +15,22 @@ var adminFiles embed.FS
|
||||
func GetAdmin() embed.FS {
|
||||
return adminFiles
|
||||
}
|
||||
|
||||
//go:embed metadata.html.tmpl
|
||||
var botMetadataTemplate embed.FS
|
||||
|
||||
// GetBotMetadataTemplate will return the bot/scraper metadata template.
|
||||
func GetBotMetadataTemplate() (*template.Template, error) {
|
||||
name := "metadata.html.tmpl"
|
||||
t, err := template.ParseFS(botMetadataTemplate, name)
|
||||
tmpl := template.Must(t, err)
|
||||
return tmpl, err
|
||||
}
|
||||
|
||||
//go:embed offline.ts
|
||||
var offlineVideoSegment []byte
|
||||
|
||||
// GetOfflineSegment will return the offline video segment data.
|
||||
func GetOfflineSegment() []byte {
|
||||
return offlineVideoSegment
|
||||
}
|
||||
|
48
test/automated/browser/bot-share-search-scrapers.test.js
Normal file
48
test/automated/browser/bot-share-search-scrapers.test.js
Normal file
@ -0,0 +1,48 @@
|
||||
const listenForErrors = require('./lib/errors.js').listenForErrors;
|
||||
|
||||
describe('Video embed page', () => {
|
||||
|
||||
async function getMetaTagContent(property) {
|
||||
const selector = `meta[property="${property}"]`;
|
||||
|
||||
const tag = await page.evaluate((selector) => {
|
||||
return document.head.querySelector(selector).getAttribute("content");
|
||||
}, selector);
|
||||
return tag;
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await page.setViewport({ width: 1080, height: 720 });
|
||||
listenForErrors(browser, page);
|
||||
page.setUserAgent(
|
||||
"Mastodon"
|
||||
);
|
||||
await page.goto('http://localhost:5309');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await page.waitForTimeout(3000);
|
||||
await page.screenshot({ path: 'screenshots/screenshot_bots_share_search_scrapers.png', fullPage: true });
|
||||
});
|
||||
|
||||
it('should have rendered the simple bot accessible html page', async () => {
|
||||
await page.waitForSelector('h1');
|
||||
await page.waitForSelector('h3');
|
||||
|
||||
const ogVideo = await getMetaTagContent('og:video');
|
||||
expect(ogVideo).toBe('http://localhost:5309/hls/stream.m3u8');
|
||||
|
||||
const ogVideoType = await getMetaTagContent('og:video:type');
|
||||
expect(ogVideoType).toBe('application/x-mpegURL');
|
||||
|
||||
// When stream is live the thumbnail is provided as the image.
|
||||
const ogImage = await getMetaTagContent('og:image');
|
||||
expect(ogImage).toBe('http://localhost:5309/thumbnail.jpg');
|
||||
|
||||
const twitterUrl = await getMetaTagContent('twitter:url');
|
||||
expect(twitterUrl).toBe('http://localhost:5309/');
|
||||
|
||||
const twitterImage = await getMetaTagContent('twitter:image');
|
||||
expect(twitterImage).toBe('http://localhost:5309/logo/external');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user