121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
)
|
|
|
|
type playbackRunContext struct {
|
|
id string
|
|
index int
|
|
run uint64
|
|
session *playbackSession
|
|
task Task
|
|
downloadID string
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
stop context.CancelFunc
|
|
cache *playbackPrefetch
|
|
offset float64
|
|
}
|
|
|
|
func (app *UIApp) beginPlayback(parent context.Context, id string, index int, offset float64, quality int, version uint64, native bool) (*playbackRunContext, int, error) {
|
|
app.playbackMu.Lock()
|
|
session := app.playbacks[id]
|
|
if !viewerOwnsPlayback(parent, session) {
|
|
app.playbackMu.Unlock()
|
|
return nil, http.StatusGone, errors.New("播放会话已过期,请重新打开本剧")
|
|
}
|
|
if index < 1 || index > len(session.tasks) {
|
|
app.playbackMu.Unlock()
|
|
return nil, http.StatusBadRequest, errors.New("分集不存在")
|
|
}
|
|
if version > 0 && version <= session.streamVersion {
|
|
app.playbackMu.Unlock()
|
|
return nil, http.StatusConflict, errors.New("播放请求已更新")
|
|
}
|
|
downloadID := ""
|
|
if len(session.downloadIDs) > 0 {
|
|
if !session.prepared[index] {
|
|
app.playbackMu.Unlock()
|
|
return nil, http.StatusConflict, errors.New("请先选择要播放的分集")
|
|
}
|
|
downloadID = session.downloadIDs[index-1]
|
|
}
|
|
previousCancel := session.cancel
|
|
cache := session.prefetch
|
|
session.prefetch, session.native, session.media = nil, nil, nil
|
|
remux, _ := parent.Value(playbackRemuxKey{}).(bool)
|
|
if cache != nil && (offset != 0 && !cache.planOnly || cache.episode != index || cache.fromRun != session.run || cache.quality != quality || (cache.native != nil) != native || !native && cache.remux != remux) {
|
|
cache.cancel()
|
|
cache = nil
|
|
}
|
|
ctx := context.WithValue(parent, playbackQualityKey{}, quality)
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
stop := func() {
|
|
cancel()
|
|
if cache != nil {
|
|
cache.cancel()
|
|
}
|
|
}
|
|
session.cancel = stop
|
|
session.run++
|
|
session.currentIndex, session.quality = index, quality
|
|
if version > 0 {
|
|
session.streamVersion = version
|
|
}
|
|
if session.historyRuns == nil {
|
|
session.historyRuns = make(map[uint64]playbackHistoryRun)
|
|
}
|
|
session.historyRuns[session.run] = playbackHistoryRun{episode: index}
|
|
for oldRun := range session.historyRuns {
|
|
if session.run > oldRun && session.run-oldRun > 8 {
|
|
delete(session.historyRuns, oldRun)
|
|
}
|
|
}
|
|
session.prefetchVersion = 0
|
|
session.state, session.error, session.duration = "buffering", "", 0
|
|
app.touchPlaybackLocked(session)
|
|
run := &playbackRunContext{id: id, index: index, run: session.run, session: session, task: session.tasks[index-1], downloadID: downloadID, ctx: ctx, cancel: cancel, stop: stop, cache: cache, offset: offset}
|
|
app.playbackMu.Unlock()
|
|
if previousCancel != nil {
|
|
previousCancel()
|
|
}
|
|
app.downloader.recordDiagnostic(diagnosticEvent{Level: "info", Event: "playback.started", Source: sourceFromDramaID(run.task.DramaID),
|
|
DramaID: run.task.DramaID, DramaTitle: run.task.DramaTitle, Episode: index, Run: run.run, StartSeconds: offset, Message: "开始播放"})
|
|
return run, http.StatusOK, nil
|
|
}
|
|
|
|
func (app *UIApp) playbackRunReady(run *playbackRunContext, duration float64) {
|
|
app.playbackMu.Lock()
|
|
if current := app.playbacks[run.id]; current == run.session && current.run == run.run {
|
|
current.state, current.duration = "streaming", duration
|
|
current.historyRuns[run.run] = playbackHistoryRun{episode: run.index, duration: duration}
|
|
}
|
|
app.playbackMu.Unlock()
|
|
}
|
|
|
|
func (app *UIApp) finishPlaybackRun(run *playbackRunContext, err error, stopped bool) {
|
|
failed := false
|
|
app.playbackMu.Lock()
|
|
if current := app.playbacks[run.id]; current == run.session && current.run == run.run {
|
|
if current.native == nil {
|
|
current.cancel = nil
|
|
}
|
|
current.state = "ended"
|
|
if err != nil {
|
|
current.state, current.error = "failed", app.redactError(err)
|
|
if stopped {
|
|
current.state = "stopped"
|
|
} else {
|
|
failed = true
|
|
}
|
|
}
|
|
}
|
|
app.playbackMu.Unlock()
|
|
if failed {
|
|
app.downloader.recordTaskFailure("playback.failed", run.task, run.offset, err)
|
|
}
|
|
}
|