diff --git a/internal/web/chat.go b/internal/web/chat.go
index b8e2d80..71aaa31 100644
--- a/internal/web/chat.go
+++ b/internal/web/chat.go
@@ -6,6 +6,8 @@ import (
"net/http"
"strings"
+ "github.com/a-h/templ"
+
"git.d-ma.be/mathias/tapir/internal/adapters/chat"
"git.d-ma.be/mathias/tapir/internal/adapters/store"
)
@@ -43,6 +45,28 @@ type chatView struct {
History []chat.Turn
Truncated bool
Error string
+ // PostURL and Subject let the same chat panel serve an UPLOADED recording
+ // (ADR-033): where the form posts, and what the transcript is called. Empty
+ // means a YouTube video (/v/{VideoID}/chat, "video"), so existing callers are
+ // unchanged.
+ PostURL templ.SafeURL
+ Subject string
+}
+
+// postURL is where the chat form posts.
+func (v chatView) postURL() templ.SafeURL {
+ if v.PostURL != "" {
+ return v.PostURL
+ }
+ return chatURL(v.VideoID)
+}
+
+// subject is what the transcript is called in the panel's wording.
+func (v chatView) subject() string {
+ if v.Subject != "" {
+ return v.Subject
+ }
+ return "video"
}
// handleChat renders the chat page for a summarized video (GET). Entry is scoped
diff --git a/internal/web/handlers.go b/internal/web/handlers.go
index b297dce..b9b1ed2 100644
--- a/internal/web/handlers.go
+++ b/internal/web/handlers.go
@@ -113,6 +113,10 @@ type App struct {
// front rather than discovered by failing.
Uploads Uploader
UploadLimits uploads.Limits
+ // UploadChatMaxChars is the transcript budget for chat over an uploaded
+ // recording. The caption default (18,000 chars, ~22 minutes of speech) would
+ // keep only the first third of an hour-long meeting.
+ UploadChatMaxChars int
// Processing tracks in-flight immediate summarizations so the status endpoint
// shows the animation until the summary lands. The zero value is ready to use.
Processing ProcessingSet
@@ -186,6 +190,12 @@ func (a *App) Router() http.Handler {
app.HandleFunc("POST /uploads", a.handleUploadPost)
app.HandleFunc("GET /uploads/{id}", a.handleUploadDetail)
app.HandleFunc("GET /uploads/{id}/status", a.handleUploadStatus)
+ // Chat over the uploaded transcript reuses the ADR-027 Chatter; mounted only
+ // when one is wired.
+ if a.Chat != nil {
+ app.HandleFunc("GET /uploads/{id}/chat", a.handleUploadChat)
+ app.HandleFunc("POST /uploads/{id}/chat", a.handleUploadChatMessage)
+ }
}
app.HandleFunc("GET /register", a.handleRegisterForm)
app.HandleFunc("POST /register", a.handleRegister)
diff --git a/internal/web/uploads.go b/internal/web/uploads.go
index abb8711..295ced5 100644
--- a/internal/web/uploads.go
+++ b/internal/web/uploads.go
@@ -9,6 +9,9 @@ import (
"strings"
"unicode/utf8"
+ "github.com/a-h/templ"
+
+ "git.d-ma.be/mathias/tapir/internal/adapters/chat"
"git.d-ma.be/mathias/tapir/internal/adapters/store"
"git.d-ma.be/mathias/tapir/internal/domain"
"git.d-ma.be/mathias/tapir/internal/uploads"
@@ -129,7 +132,7 @@ func (a *App) handleUploadDetail(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
- a.render(w, r, UploadPage(*u))
+ a.render(w, r, UploadPage(*u, a.Chat != nil))
}
// handleUploadStatus renders the status fragment HTMX polls. Unfinished states
@@ -140,7 +143,7 @@ func (a *App) handleUploadStatus(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
- a.render(w, r, uploadStatus(*u))
+ a.render(w, r, uploadStatus(*u, a.Chat != nil))
}
func (a *App) loadOwnedUpload(w http.ResponseWriter, r *http.Request) (*domain.UploadedTranscript, bool) {
@@ -189,3 +192,79 @@ func uploadFailureMessage(k domain.UploadErrorKind) string {
return "This upload failed. Please upload it again."
}
}
+
+// handleUploadChat renders the chat page for a FINISHED upload (GET). The row is
+// read through the user-scoped store, so another user's id is a 404 before any
+// model is involved. An unfinished upload has no transcript to ask about yet, so
+// it goes back to its status page.
+func (a *App) handleUploadChat(w http.ResponseWriter, r *http.Request) {
+ u, ok := a.loadOwnedUpload(w, r)
+ if !ok {
+ return
+ }
+ if u.Status != domain.UploadDone {
+ http.Redirect(w, r, "/uploads/"+u.ID, http.StatusSeeOther)
+ return
+ }
+ a.render(w, r, UploadChatPage(*u, a.uploadChatView(*u, a.Chat.DefaultModel(""), nil, false, "")))
+}
+
+// handleUploadChatMessage answers one question against the owner's uploaded
+// transcript (POST), reusing the ADR-027 Chatter. Nothing is persisted: the prior
+// turns ride in the form. The transcript goes to the model with the UPLOAD budget,
+// not the caption default. A model failure is inline, not a 500.
+func (a *App) handleUploadChatMessage(w http.ResponseWriter, r *http.Request) {
+ u, ok := a.loadOwnedUpload(w, r)
+ if !ok {
+ return
+ }
+ if u.Status != domain.UploadDone {
+ http.Redirect(w, r, "/uploads/"+u.ID, http.StatusSeeOther)
+ return
+ }
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, "bad form", http.StatusBadRequest)
+ return
+ }
+ model := a.resolveModel(r.FormValue("model"), "")
+ history := parseHistory(r.Form["hq"], r.Form["ha"])
+ question := strings.TrimSpace(r.FormValue("question"))
+
+ view := a.uploadChatView(*u, model, history, false, "")
+ if question != "" {
+ reply, err := a.Chat.Answer(r.Context(), chat.Request{
+ Model: model,
+ Transcript: u.Content,
+ History: history,
+ Question: question,
+ MaxChars: a.UploadChatMaxChars,
+ })
+ if err != nil {
+ a.logger().Error("upload chat answer", "upload", u.ID, "model", model, "err", err)
+ view.Error = "That model couldn't answer just now. Try again, or switch models."
+ } else {
+ view.History = appendTurn(history, chat.Turn{Question: question, Answer: reply.Answer})
+ view.Truncated = reply.Truncated
+ }
+ }
+ if isHTMX(r) {
+ a.render(w, r, chatPanel(view))
+ return
+ }
+ a.render(w, r, UploadChatPage(*u, view))
+}
+
+func (a *App) uploadChatView(u domain.UploadedTranscript, model string, history []chat.Turn, truncated bool, errMsg string) chatView {
+ return chatView{
+ VideoID: u.ID,
+ Title: u.Title,
+ Available: true,
+ Models: a.Chat.Models(),
+ Selected: model,
+ History: history,
+ Truncated: truncated,
+ Error: errMsg,
+ PostURL: templ.SafeURL("/uploads/" + u.ID + "/chat"),
+ Subject: "recording",
+ }
+}
diff --git a/internal/web/uploads.templ b/internal/web/uploads.templ
index ffcb759..b084c10 100644
--- a/internal/web/uploads.templ
+++ b/internal/web/uploads.templ
@@ -44,11 +44,11 @@ templ UploadsPage(v uploadsView) {
}
// UploadPage is one upload's page: its title and the polling status region.
-templ UploadPage(u domain.UploadedTranscript) {
+templ UploadPage(u domain.UploadedTranscript, chatEnabled bool) {
@Layout("Tapir — " + u.Title) {
{ u.Title }
- @uploadStatus(u)
+ @uploadStatus(u, chatEnabled)
All recordings
}
@@ -56,7 +56,7 @@ templ UploadPage(u domain.UploadedTranscript) {
// uploadStatus is the region HTMX polls. Unfinished states carry hx-trigger so the
// page re-asks; done and failed render without it, so nothing polls forever.
-templ uploadStatus(u domain.UploadedTranscript) {
+templ uploadStatus(u domain.UploadedTranscript, chatEnabled bool) {
switch u.Status {
case domain.UploadDone:
@@ -64,6 +64,9 @@ templ uploadStatus(u domain.UploadedTranscript) {
Transcribed { uploads.FormatDuration(time.Duration(u.AudioSeconds * float64(time.Second))) }
of audio by
{ u.Endpoint } .
+ if chatEnabled {
+
Ask about this recording
+ }
Transcript
{ u.Content }
@@ -89,3 +92,19 @@ templ uploadStatus(u domain.UploadedTranscript) {
}
}
+
+// UploadChatPage is the no-JS full page for chatting with an uploaded transcript:
+// the same chat panel as a video's (ADR-027), scoped to this recording.
+templ UploadChatPage(u domain.UploadedTranscript, v chatView) {
+ @Layout("Tapir — Ask about " + u.Title) {
+
+ { u.Title }
+
+ Ask about this recording
+ Answers come only from this recording's transcript, which is private to you.
+ @chatPanel(v)
+
+ Back to the transcript
+
+ }
+}
diff --git a/internal/web/uploads_templ.go b/internal/web/uploads_templ.go
index a874853..c848d97 100644
--- a/internal/web/uploads_templ.go
+++ b/internal/web/uploads_templ.go
@@ -5,8 +5,10 @@ package web
//lint:file-ignore SA4006 This context is only used if a nested component is present.
-import "github.com/a-h/templ"
-import templruntime "github.com/a-h/templ/runtime"
+import (
+ "github.com/a-h/templ"
+ templruntime "github.com/a-h/templ/runtime"
+)
import (
"fmt"
@@ -173,7 +175,7 @@ func UploadsPage(v uploadsView) templ.Component {
}
// UploadPage is one upload's page: its title and the polling status region.
-func UploadPage(u domain.UploadedTranscript) templ.Component {
+func UploadPage(u domain.UploadedTranscript, chatEnabled bool) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -223,7 +225,7 @@ func UploadPage(u domain.UploadedTranscript) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = uploadStatus(u).Render(ctx, templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = uploadStatus(u, chatEnabled).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -243,7 +245,7 @@ func UploadPage(u domain.UploadedTranscript) templ.Component {
// uploadStatus is the region HTMX polls. Unfinished states carry hx-trigger so the
// page re-asks; done and failed render without it, so nothing polls forever.
-func uploadStatus(u domain.UploadedTranscript) templ.Component {
+func uploadStatus(u domain.UploadedTranscript, chatEnabled bool) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -292,84 +294,107 @@ func uploadStatus(u domain.UploadedTranscript) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, ".Transcript ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, ".")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var15 string
- templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(u.Content)
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 69, Col: 40}
+ if chatEnabled {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "Ask about this recording
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- case domain.UploadFailed:
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "Transcript ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
- templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(uploadFailureMessage(u.ErrorKind))
+ templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(u.Content)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 74, Col: 42}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 72, Col: 40}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- default:
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
- templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.ResolveAttributeValue("/uploads/" + u.ID + "/status")
+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(uploadFailureMessage(u.ErrorKind))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 80, Col: 43}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 77, Col: 42}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\" hx-trigger=\"")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ default:
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" hx-trigger=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var19 string
+ templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue("every " + uploadPollEvery)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 84, Col: 43}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\" hx-swap=\"outerHTML\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if u.Status == domain.UploadTranscribing {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
Transcribing… a long recording takes a few minutes.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
Transcribing… a long recording takes a few minutes.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
Queued — waiting for its turn to be transcribed.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
Queued — waiting for its turn to be transcribed.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -378,4 +403,87 @@ func uploadStatus(u domain.UploadedTranscript) templ.Component {
})
}
+// UploadChatPage is the no-JS full page for chatting with an uploaded transcript:
+// the same chat panel as a video's (ADR-027), scoped to this recording.
+func UploadChatPage(u domain.UploadedTranscript, v chatView) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var20 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var20 == nil {
+ templ_7745c5c3_Var20 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var21 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var22 string
+ templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(u.Title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 101, Col: 16}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, " Ask about this recording Answers come only from this recording's transcript, which is private to you.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = chatPanel(v).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "Back to the transcript
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = Layout("Tapir — Ask about "+u.Title).Render(templ.WithChildren(ctx, templ_7745c5c3_Var21), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
var _ = templruntime.GeneratedTemplate
diff --git a/internal/web/views.templ b/internal/web/views.templ
index 602dafd..55d9c9b 100644
--- a/internal/web/views.templ
+++ b/internal/web/views.templ
@@ -583,7 +583,7 @@ templ chatPanel(v chatView) {
}
if v.Truncated {
- Working from a bounded portion of a long transcript — answers about the end of the video may be incomplete.
+ Working from a bounded portion of a long transcript — answers about the end of the { v.subject() } may be incomplete.
}
if v.Error != "" {
{ v.Error }
@@ -591,8 +591,8 @@ templ chatPanel(v chatView) {
diff --git a/internal/web/views_templ.go b/internal/web/views_templ.go
index 1a0562b..8f2732f 100644
--- a/internal/web/views_templ.go
+++ b/internal/web/views_templ.go
@@ -5,8 +5,10 @@ package web
//lint:file-ignore SA4006 This context is only used if a nested component is present.
-import "github.com/a-h/templ"
-import templruntime "github.com/a-h/templ/runtime"
+import (
+ "github.com/a-h/templ"
+ templruntime "github.com/a-h/templ/runtime"
+)
import (
"fmt"
@@ -292,7 +294,7 @@ func flashBanner(code string) templ.Component {
}
ctx = templ.ClearChildren(ctx)
if f, ok := flashFor(code); ok {
- var templ_7745c5c3_Var9 = []any{"flash", "flash-" + f.Kind}
+ templ_7745c5c3_Var9 := []any{"flash", "flash-" + f.Kind}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
@@ -824,7 +826,7 @@ func VideoCard(r store.SummaryRow) templ.Component {
templ_7745c5c3_Var25 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- var templ_7745c5c3_Var26 = []any{"card", templ.KV("card-pending", !r.Summarized)}
+ templ_7745c5c3_Var26 := []any{"card", templ.KV("card-pending", !r.Summarized)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var26...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
@@ -2152,148 +2154,174 @@ func chatPanel(v chatView) templ.Component {
return templ_7745c5c3_Err
}
if v.Truncated {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "Working from a bounded portion of a long transcript — answers about the end of the video may be incomplete.
")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- if v.Error != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 175, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 173, "
Working from a bounded portion of a long transcript — answers about the end of the ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var88 string
- templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(v.Error)
+ templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(v.subject())
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 589, Col: 48}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 586, Col: 129}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 176, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 174, " may be incomplete.")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var89 string
+ templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(v.Error)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 589, Col: 48}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 177, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89))
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 178, " ")
+ var templ_7745c5c3_Var91 string
+ templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.ResolveAttributeValue(string(v.postURL()))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 595, Col: 33}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var91)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, "\" hx-target=\"#chat-panel\" hx-swap=\"outerHTML\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, t := range v.History {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 180, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 183, "Model ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- for _, m := range v.Models {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if m == v.Selected {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, " selected")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, ">")
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 184, "Model ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for _, m := range v.Models {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 185, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 186, "\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if m == v.Selected {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 187, " selected")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 188, ">")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var95 string
+ templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(m)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 607, Col: 60}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 189, " Switch models to compare answers on the same transcript. Ask thinking… ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, " Switch models to compare answers on the same transcript. Ask thinking… ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 190, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2320,12 +2348,12 @@ func RegisterPage(email, errMsg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var95 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var95 == nil {
- templ_7745c5c3_Var95 = templ.NopComponent
+ templ_7745c5c3_Var97 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var97 == nil {
+ templ_7745c5c3_Var97 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var96 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var98 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -2337,59 +2365,59 @@ func RegisterPage(email, errMsg string) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 191, "Complete your registration ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, "Complete your registration ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if email != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 192, "Signed in as ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "
Signed in as ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var97 string
- templ_7745c5c3_Var97, templ_7745c5c3_Err = templ.JoinStringErrs(email)
+ var templ_7745c5c3_Var99 string
+ templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 628, Col: 40}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var97))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 193, ".
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, ".")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 194, "Choose a display name to finish setting up your Tapir account.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "Choose a display name to finish setting up your Tapir account.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if errMsg != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 195, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var98 string
- templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(errMsg)
+ var templ_7745c5c3_Var100 string
+ templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(errMsg)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 632, Col: 42}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 196, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 197, "Display name Register ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, "Display name Register ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = Layout("Tapir — Register").Render(templ.WithChildren(ctx, templ_7745c5c3_Var96), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = Layout("Tapir — Register").Render(templ.WithChildren(ctx, templ_7745c5c3_Var98), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2417,12 +2445,12 @@ func AccountPage(displayName, email string, conns []store.Connection, autoSummar
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var99 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var99 == nil {
- templ_7745c5c3_Var99 = templ.NopComponent
+ templ_7745c5c3_Var101 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var101 == nil {
+ templ_7745c5c3_Var101 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Var100 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Var102 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
@@ -2438,43 +2466,43 @@ func AccountPage(displayName, email string, conns []store.Connection, autoSummar
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 198, " Account Display name ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, " Account Display name ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var101 string
- templ_7745c5c3_Var101, templ_7745c5c3_Err = templ.JoinStringErrs(displayNameOr(displayName))
+ var templ_7745c5c3_Var103 string
+ templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(displayNameOr(displayName))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 656, Col: 36}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var101))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 199, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if email != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 200, "Signed in as ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, " Signed in as ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var102 string
- templ_7745c5c3_Var102, templ_7745c5c3_Err = templ.JoinStringErrs(email)
+ var templ_7745c5c3_Var104 string
+ templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 659, Col: 16}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var102))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 201, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 202, "Summarization Automatic summarizes new videos from about the last week as they are discovered. Older videos stay browsable — summarize them on demand. Manual lets you pick which videos to summarize — every new video appears in your list with a Summarize button.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "Summarization Automatic summarizes new videos from about the last week as they are discovered. Older videos stay browsable — summarize them on demand. Manual lets you pick which videos to summarize — every new video appears in your list with a Summarize button.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2482,178 +2510,178 @@ func AccountPage(displayName, email string, conns []store.Connection, autoSummar
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 203, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(channelErrors) > 0 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 204, "Unavailable channels ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "Unavailable channels ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var103 string
- templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d channel(s) returned errors on the last discovery pass.", len(channelErrors)))
+ var templ_7745c5c3_Var105 string
+ templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d channel(s) returned errors on the last discovery pass.", len(channelErrors)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 676, Col: 100}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 205, " These may have been deleted or made private on YouTube.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, " These may have been deleted or made private on YouTube.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, ce := range channelErrors {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 206, "")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var104 string
- templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(ce.ChannelName)
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 682, Col: 57}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 207, " unavailable since ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var105 string
- templ_7745c5c3_Var105, templ_7745c5c3_Err = templ.JoinStringErrs(ce.FirstSeen.Format("2006-01-02"))
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 684, Col: 89}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var105))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, "Connected accounts ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- if len(conns) == 0 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "No connected video accounts yet.
")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- } else {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- for _, c := range conns {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 208, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var106 string
- templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.JoinStringErrs(providerLabel(c.Provider))
+ templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.JoinStringErrs(ce.ChannelName)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 699, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 682, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 209, " unavailable since ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if c.ProviderAccount != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var107 string
- templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(c.ProviderAccount)
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 701, Col: 49}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, " ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
+ var templ_7745c5c3_Var107 string
+ templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(ce.FirstSeen.Format("2006-01-02"))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 684, Col: 89}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 210, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 211, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 212, "Connected accounts ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if len(conns) == 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 213, "No connected video accounts yet.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 214, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for _, c := range conns {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 215, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var108 string
- templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(c.Status)
+ templ_7745c5c3_Var108, templ_7745c5c3_Err = templ.JoinStringErrs(providerLabel(c.Provider))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 703, Col: 38}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 699, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var108))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, "
connected ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 216, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var109 string
- templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.ConnectedAt.Format("2006-01-02"))
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 705, Col: 83}
+ if c.ProviderAccount != "" {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 217, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var109 string
+ templ_7745c5c3_Var109, templ_7745c5c3_Err = templ.JoinStringErrs(c.ProviderAccount)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 701, Col: 49}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 218, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var109))
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 219, "
Disconnect ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 220, " connected ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var111 string
+ templ_7745c5c3_Var111, templ_7745c5c3_Err = templ.JoinStringErrs(c.ConnectedAt.Format("2006-01-02"))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 705, Col: 83}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var111))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, "
Disconnect ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 221, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if !hasYouTube(conns) {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 222, "Connect YouTube
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "Connect YouTube
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 223, "Delete account Permanently remove your Tapir account and all of its data — summaries, watch/skip/save actions, and connected accounts. This cannot be undone.
Delete account… This permanently deletes your account and all data. Are you sure?
Yes, permanently delete my account ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "Delete account Permanently remove your Tapir account and all of its data — summaries, watch/skip/save actions, and connected accounts. This cannot be undone.
Delete account… This permanently deletes your account and all data. Are you sure?
Yes, permanently delete my account ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
- templ_7745c5c3_Err = Layout("Tapir — Account").Render(templ.WithChildren(ctx, templ_7745c5c3_Var100), templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = Layout("Tapir — Account").Render(templ.WithChildren(ctx, templ_7745c5c3_Var102), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2681,51 +2709,51 @@ func summarizeModeControl(auto bool) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var111 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var111 == nil {
- templ_7745c5c3_Var111 = templ.NopComponent
+ templ_7745c5c3_Var113 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var113 == nil {
+ templ_7745c5c3_Var113 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 224, "Current mode: ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- var templ_7745c5c3_Var112 string
- templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(summarizeModeLabel(auto))
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 743, Col: 53}
- }
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 225, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 226, "Current mode: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var114 string
- templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(summarizeModeToggleLabel(auto))
+ templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(summarizeModeLabel(auto))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 752, Col: 79}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 743, Col: 53}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 227, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var116 string
+ templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(summarizeModeToggleLabel(auto))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 752, Col: 79}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 229, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2753,38 +2781,38 @@ func ActionButtons(videoID string, active map[string]bool) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var115 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var115 == nil {
- templ_7745c5c3_Var115 = templ.NopComponent
+ templ_7745c5c3_Var117 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var117 == nil {
+ templ_7745c5c3_Var117 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 228, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, "\" hx-target=\"#action-buttons\" hx-swap=\"outerHTML\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2796,7 +2824,7 @@ func ActionButtons(videoID string, active map[string]bool) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 231, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2804,7 +2832,7 @@ func ActionButtons(videoID string, active map[string]bool) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 232, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 234, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -2830,81 +2858,81 @@ func actionButton(verb string, isActive bool) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var118 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var118 == nil {
- templ_7745c5c3_Var118 = templ.NopComponent
+ templ_7745c5c3_Var120 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var120 == nil {
+ templ_7745c5c3_Var120 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- var templ_7745c5c3_Var119 = []any{"action", templ.KV("active", isActive)}
- templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var119...)
+ templ_7745c5c3_Var121 := []any{"action", templ.KV("active", isActive)}
+ templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var121...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 233, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 236, "\" class=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var123 string
+ templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var121).String())
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 1, Col: 0}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var123)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 237, "\" aria-pressed=\"")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var124 string
+ templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.ResolveAttributeValue(ariaPressed(isActive))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 790, Col: 38}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var124)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 238, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if isActive {
- var templ_7745c5c3_Var123 string
- templ_7745c5c3_Var123, templ_7745c5c3_Err = templ.JoinStringErrs("✓ " + actionLabel(verb))
+ var templ_7745c5c3_Var125 string
+ templ_7745c5c3_Var125, templ_7745c5c3_Err = templ.JoinStringErrs("✓ " + actionLabel(verb))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 793, Col: 31}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var123))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var125))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
- var templ_7745c5c3_Var124 string
- templ_7745c5c3_Var124, templ_7745c5c3_Err = templ.JoinStringErrs(actionLabel(verb))
+ var templ_7745c5c3_Var126 string
+ templ_7745c5c3_Var126, templ_7745c5c3_Err = templ.JoinStringErrs(actionLabel(verb))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/views.templ`, Line: 795, Col: 22}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var124))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var126))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 237, " ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 239, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}