VideoTools/vendor/github.com/yuin/goldmark/ast/block.go
Stu Leak bdc27c2253 Fix player frame generation and video playback
Major improvements to UnifiedPlayer:

1. GetFrameImage() now works when paused for responsive UI updates
2. Play() method properly starts FFmpeg process
3. Frame display loop runs continuously for smooth video display
4. Disabled audio temporarily to fix video playback fundamentals
5. Simplified FFmpeg command to focus on video stream only

Player now:
- Generates video frames correctly
- Shows video when paused
- Has responsive progress tracking
- Starts playback properly

Next steps: Re-enable audio playback once video is stable
2026-01-07 22:20:00 -05:00

548 lines
13 KiB
Go

package ast
import (
"fmt"
"strings"
textm "github.com/yuin/goldmark/text"
)
// A BaseBlock struct implements the Node interface partialliy.
type BaseBlock struct {
BaseNode
blankPreviousLines bool
lines *textm.Segments
}
// Type implements Node.Type.
func (b *BaseBlock) Type() NodeType {
return TypeBlock
}
// IsRaw implements Node.IsRaw.
func (b *BaseBlock) IsRaw() bool {
return false
}
// HasBlankPreviousLines implements Node.HasBlankPreviousLines.
func (b *BaseBlock) HasBlankPreviousLines() bool {
return b.blankPreviousLines
}
// SetBlankPreviousLines implements Node.SetBlankPreviousLines.
func (b *BaseBlock) SetBlankPreviousLines(v bool) {
b.blankPreviousLines = v
}
// Lines implements Node.Lines.
func (b *BaseBlock) Lines() *textm.Segments {
if b.lines == nil {
b.lines = textm.NewSegments()
}
return b.lines
}
// SetLines implements Node.SetLines.
func (b *BaseBlock) SetLines(v *textm.Segments) {
b.lines = v
}
// A Document struct is a root node of Markdown text.
type Document struct {
BaseBlock
meta map[string]interface{}
}
// KindDocument is a NodeKind of the Document node.
var KindDocument = NewNodeKind("Document")
// Dump implements Node.Dump .
func (n *Document) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// Type implements Node.Type .
func (n *Document) Type() NodeType {
return TypeDocument
}
// Kind implements Node.Kind.
func (n *Document) Kind() NodeKind {
return KindDocument
}
// OwnerDocument implements Node.OwnerDocument.
func (n *Document) OwnerDocument() *Document {
return n
}
// Meta returns metadata of this document.
func (n *Document) Meta() map[string]interface{} {
if n.meta == nil {
n.meta = map[string]interface{}{}
}
return n.meta
}
// SetMeta sets given metadata to this document.
func (n *Document) SetMeta(meta map[string]interface{}) {
if n.meta == nil {
n.meta = map[string]interface{}{}
}
for k, v := range meta {
n.meta[k] = v
}
}
// AddMeta adds given metadata to this document.
func (n *Document) AddMeta(key string, value interface{}) {
if n.meta == nil {
n.meta = map[string]interface{}{}
}
n.meta[key] = value
}
// NewDocument returns a new Document node.
func NewDocument() *Document {
return &Document{
BaseBlock: BaseBlock{},
meta: nil,
}
}
// A TextBlock struct is a node whose lines
// should be rendered without any containers.
type TextBlock struct {
BaseBlock
}
// Dump implements Node.Dump .
func (n *TextBlock) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// KindTextBlock is a NodeKind of the TextBlock node.
var KindTextBlock = NewNodeKind("TextBlock")
// Kind implements Node.Kind.
func (n *TextBlock) Kind() NodeKind {
return KindTextBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. TextBlock.Lines).
func (n *TextBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewTextBlock returns a new TextBlock node.
func NewTextBlock() *TextBlock {
return &TextBlock{
BaseBlock: BaseBlock{},
}
}
// A Paragraph struct represents a paragraph of Markdown text.
type Paragraph struct {
BaseBlock
}
// Dump implements Node.Dump .
func (n *Paragraph) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// KindParagraph is a NodeKind of the Paragraph node.
var KindParagraph = NewNodeKind("Paragraph")
// Kind implements Node.Kind.
func (n *Paragraph) Kind() NodeKind {
return KindParagraph
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Paragraph.Lines).
func (n *Paragraph) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewParagraph returns a new Paragraph node.
func NewParagraph() *Paragraph {
return &Paragraph{
BaseBlock: BaseBlock{},
}
}
// IsParagraph returns true if the given node implements the Paragraph interface,
// otherwise false.
func IsParagraph(node Node) bool {
_, ok := node.(*Paragraph)
return ok
}
// A Heading struct represents headings like SetextHeading and ATXHeading.
type Heading struct {
BaseBlock
// Level returns a level of this heading.
// This value is between 1 and 6.
Level int
}
// Dump implements Node.Dump .
func (n *Heading) Dump(source []byte, level int) {
m := map[string]string{
"Level": fmt.Sprintf("%d", n.Level),
}
DumpHelper(n, source, level, m, nil)
}
// KindHeading is a NodeKind of the Heading node.
var KindHeading = NewNodeKind("Heading")
// Kind implements Node.Kind.
func (n *Heading) Kind() NodeKind {
return KindHeading
}
// NewHeading returns a new Heading node.
func NewHeading(level int) *Heading {
return &Heading{
BaseBlock: BaseBlock{},
Level: level,
}
}
// A ThematicBreak struct represents a thematic break of Markdown text.
type ThematicBreak struct {
BaseBlock
}
// Dump implements Node.Dump .
func (n *ThematicBreak) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// KindThematicBreak is a NodeKind of the ThematicBreak node.
var KindThematicBreak = NewNodeKind("ThematicBreak")
// Kind implements Node.Kind.
func (n *ThematicBreak) Kind() NodeKind {
return KindThematicBreak
}
// NewThematicBreak returns a new ThematicBreak node.
func NewThematicBreak() *ThematicBreak {
return &ThematicBreak{
BaseBlock: BaseBlock{},
}
}
// A CodeBlock interface represents an indented code block of Markdown text.
type CodeBlock struct {
BaseBlock
}
// IsRaw implements Node.IsRaw.
func (n *CodeBlock) IsRaw() bool {
return true
}
// Dump implements Node.Dump .
func (n *CodeBlock) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// KindCodeBlock is a NodeKind of the CodeBlock node.
var KindCodeBlock = NewNodeKind("CodeBlock")
// Kind implements Node.Kind.
func (n *CodeBlock) Kind() NodeKind {
return KindCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. CodeBlock.Lines).
func (n *CodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewCodeBlock returns a new CodeBlock node.
func NewCodeBlock() *CodeBlock {
return &CodeBlock{
BaseBlock: BaseBlock{},
}
}
// A FencedCodeBlock struct represents a fenced code block of Markdown text.
type FencedCodeBlock struct {
BaseBlock
// Info returns a info text of this fenced code block.
Info *Text
language []byte
}
// Language returns an language in an info string.
// Language returns nil if this node does not have an info string.
func (n *FencedCodeBlock) Language(source []byte) []byte {
if n.language == nil && n.Info != nil {
segment := n.Info.Segment
info := segment.Value(source)
i := 0
for ; i < len(info); i++ {
if info[i] == ' ' {
break
}
}
n.language = info[:i]
}
return n.language
}
// IsRaw implements Node.IsRaw.
func (n *FencedCodeBlock) IsRaw() bool {
return true
}
// Dump implements Node.Dump .
func (n *FencedCodeBlock) Dump(source []byte, level int) {
m := map[string]string{}
if n.Info != nil {
m["Info"] = fmt.Sprintf("\"%s\"", n.Info.Text(source))
}
DumpHelper(n, source, level, m, nil)
}
// KindFencedCodeBlock is a NodeKind of the FencedCodeBlock node.
var KindFencedCodeBlock = NewNodeKind("FencedCodeBlock")
// Kind implements Node.Kind.
func (n *FencedCodeBlock) Kind() NodeKind {
return KindFencedCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. FencedCodeBlock.Lines).
func (n *FencedCodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewFencedCodeBlock return a new FencedCodeBlock node.
func NewFencedCodeBlock(info *Text) *FencedCodeBlock {
return &FencedCodeBlock{
BaseBlock: BaseBlock{},
Info: info,
}
}
// A Blockquote struct represents an blockquote block of Markdown text.
type Blockquote struct {
BaseBlock
}
// Dump implements Node.Dump .
func (n *Blockquote) Dump(source []byte, level int) {
DumpHelper(n, source, level, nil, nil)
}
// KindBlockquote is a NodeKind of the Blockquote node.
var KindBlockquote = NewNodeKind("Blockquote")
// Kind implements Node.Kind.
func (n *Blockquote) Kind() NodeKind {
return KindBlockquote
}
// NewBlockquote returns a new Blockquote node.
func NewBlockquote() *Blockquote {
return &Blockquote{
BaseBlock: BaseBlock{},
}
}
// A List struct represents a list of Markdown text.
type List struct {
BaseBlock
// Marker is a marker character like '-', '+', ')' and '.'.
Marker byte
// IsTight is a true if this list is a 'tight' list.
// See https://spec.commonmark.org/0.30/#loose for details.
IsTight bool
// Start is an initial number of this ordered list.
// If this list is not an ordered list, Start is 0.
Start int
}
// IsOrdered returns true if this list is an ordered list, otherwise false.
func (l *List) IsOrdered() bool {
return l.Marker == '.' || l.Marker == ')'
}
// CanContinue returns true if this list can continue with
// the given mark and a list type, otherwise false.
func (l *List) CanContinue(marker byte, isOrdered bool) bool {
return marker == l.Marker && isOrdered == l.IsOrdered()
}
// Dump implements Node.Dump.
func (l *List) Dump(source []byte, level int) {
m := map[string]string{
"Ordered": fmt.Sprintf("%v", l.IsOrdered()),
"Marker": fmt.Sprintf("%c", l.Marker),
"Tight": fmt.Sprintf("%v", l.IsTight),
}
if l.IsOrdered() {
m["Start"] = fmt.Sprintf("%d", l.Start)
}
DumpHelper(l, source, level, m, nil)
}
// KindList is a NodeKind of the List node.
var KindList = NewNodeKind("List")
// Kind implements Node.Kind.
func (l *List) Kind() NodeKind {
return KindList
}
// NewList returns a new List node.
func NewList(marker byte) *List {
return &List{
BaseBlock: BaseBlock{},
Marker: marker,
IsTight: true,
}
}
// A ListItem struct represents a list item of Markdown text.
type ListItem struct {
BaseBlock
// Offset is an offset position of this item.
Offset int
}
// Dump implements Node.Dump.
func (n *ListItem) Dump(source []byte, level int) {
m := map[string]string{
"Offset": fmt.Sprintf("%d", n.Offset),
}
DumpHelper(n, source, level, m, nil)
}
// KindListItem is a NodeKind of the ListItem node.
var KindListItem = NewNodeKind("ListItem")
// Kind implements Node.Kind.
func (n *ListItem) Kind() NodeKind {
return KindListItem
}
// NewListItem returns a new ListItem node.
func NewListItem(offset int) *ListItem {
return &ListItem{
BaseBlock: BaseBlock{},
Offset: offset,
}
}
// HTMLBlockType represents kinds of an html blocks.
// See https://spec.commonmark.org/0.30/#html-blocks
type HTMLBlockType int
const (
// HTMLBlockType1 represents type 1 html blocks.
HTMLBlockType1 HTMLBlockType = iota + 1
// HTMLBlockType2 represents type 2 html blocks.
HTMLBlockType2
// HTMLBlockType3 represents type 3 html blocks.
HTMLBlockType3
// HTMLBlockType4 represents type 4 html blocks.
HTMLBlockType4
// HTMLBlockType5 represents type 5 html blocks.
HTMLBlockType5
// HTMLBlockType6 represents type 6 html blocks.
HTMLBlockType6
// HTMLBlockType7 represents type 7 html blocks.
HTMLBlockType7
)
// An HTMLBlock struct represents an html block of Markdown text.
type HTMLBlock struct {
BaseBlock
// Type is a type of this html block.
HTMLBlockType HTMLBlockType
// ClosureLine is a line that closes this html block.
ClosureLine textm.Segment
}
// IsRaw implements Node.IsRaw.
func (n *HTMLBlock) IsRaw() bool {
return true
}
// HasClosure returns true if this html block has a closure line,
// otherwise false.
func (n *HTMLBlock) HasClosure() bool {
return n.ClosureLine.Start >= 0
}
// Dump implements Node.Dump.
func (n *HTMLBlock) Dump(source []byte, level int) {
indent := strings.Repeat(" ", level)
fmt.Printf("%s%s {\n", indent, "HTMLBlock")
indent2 := strings.Repeat(" ", level+1)
fmt.Printf("%sRawText: \"", indent2)
for i := 0; i < n.Lines().Len(); i++ {
s := n.Lines().At(i)
fmt.Print(string(source[s.Start:s.Stop]))
}
fmt.Printf("\"\n")
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
c.Dump(source, level+1)
}
if n.HasClosure() {
cl := n.ClosureLine
fmt.Printf("%sClosure: \"%s\"\n", indent2, string(cl.Value(source)))
}
fmt.Printf("%s}\n", indent)
}
// KindHTMLBlock is a NodeKind of the HTMLBlock node.
var KindHTMLBlock = NewNodeKind("HTMLBlock")
// Kind implements Node.Kind.
func (n *HTMLBlock) Kind() NodeKind {
return KindHTMLBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. HTMLBlock.Lines).
func (n *HTMLBlock) Text(source []byte) []byte {
ret := n.Lines().Value(source)
if n.HasClosure() {
ret = append(ret, n.ClosureLine.Value(source)...)
}
return ret
}
// NewHTMLBlock returns a new HTMLBlock node.
func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock {
return &HTMLBlock{
BaseBlock: BaseBlock{},
HTMLBlockType: typ,
ClosureLine: textm.NewSegment(-1, -1),
}
}