offlineState.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package core
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "github.com/grafov/m3u8"
  7. "github.com/owncast/owncast/config"
  8. "github.com/owncast/owncast/static"
  9. "github.com/owncast/owncast/utils"
  10. log "github.com/sirupsen/logrus"
  11. )
  12. func appendOfflineToVariantPlaylist(index int, playlistFilePath string) {
  13. existingPlaylistContents, err := os.ReadFile(playlistFilePath) // nolint: gosec
  14. if err != nil {
  15. log.Debugln("unable to read existing playlist file", err)
  16. return
  17. }
  18. tmpFileName := fmt.Sprintf("tmp-stream-%d.m3u8", index)
  19. atomicWriteTmpPlaylistFile, err := os.CreateTemp(config.TempDir, tmpFileName)
  20. if err != nil {
  21. log.Errorln("error creating tmp playlist file to write to", playlistFilePath, err)
  22. return
  23. }
  24. // Write the existing playlist contents
  25. if _, err := atomicWriteTmpPlaylistFile.Write(existingPlaylistContents); err != nil {
  26. log.Debugln("error writing existing playlist contents to tmp playlist file", err)
  27. return
  28. }
  29. // Manually append the offline clip to the end of the media playlist.
  30. _, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-DISCONTINUITY\n")
  31. // If "offline" content gets changed then change the duration below
  32. _, _ = atomicWriteTmpPlaylistFile.WriteString("#EXTINF:8.000000,\n")
  33. _, _ = atomicWriteTmpPlaylistFile.WriteString("offline-v2.ts\n")
  34. _, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-ENDLIST\n")
  35. if err := atomicWriteTmpPlaylistFile.Close(); err != nil {
  36. log.Errorln(err)
  37. }
  38. if err := utils.Move(atomicWriteTmpPlaylistFile.Name(), playlistFilePath); err != nil {
  39. log.Errorln("error moving temp playlist to overwrite existing one", err)
  40. }
  41. }
  42. func makeVariantIndexOffline(index int, offlineFilePath string, offlineFilename string) {
  43. playlistFilePath := fmt.Sprintf(filepath.Join(config.HLSStoragePath, "%d/stream.m3u8"), index)
  44. segmentFilePath := fmt.Sprintf(filepath.Join(config.HLSStoragePath, "%d/%s"), index, offlineFilename)
  45. if err := utils.Copy(offlineFilePath, segmentFilePath); err != nil {
  46. log.Warnln(err)
  47. }
  48. if _, err := _storage.Save(segmentFilePath, 0); err != nil {
  49. log.Warnln(err)
  50. }
  51. if utils.DoesFileExists(playlistFilePath) {
  52. appendOfflineToVariantPlaylist(index, playlistFilePath)
  53. } else {
  54. createEmptyOfflinePlaylist(playlistFilePath, offlineFilename)
  55. }
  56. if _, err := _storage.Save(playlistFilePath, 0); err != nil {
  57. log.Warnln(err)
  58. }
  59. }
  60. func createEmptyOfflinePlaylist(playlistFilePath string, offlineFilename string) {
  61. p, err := m3u8.NewMediaPlaylist(1, 1)
  62. if err != nil {
  63. log.Errorln(err)
  64. }
  65. // If "offline" content gets changed then change the duration below
  66. if err := p.Append(offlineFilename, 8.0, ""); err != nil {
  67. log.Errorln(err)
  68. }
  69. p.Close()
  70. f, err := os.Create(playlistFilePath) //nolint:gosec
  71. if err != nil {
  72. log.Errorln(err)
  73. }
  74. defer f.Close()
  75. if _, err := f.Write(p.Encode().Bytes()); err != nil {
  76. log.Errorln(err)
  77. }
  78. }
  79. func saveOfflineClipToDisk(offlineFilename string) (string, error) {
  80. offlineFileData := static.GetOfflineSegment()
  81. offlineTmpFile, err := os.CreateTemp(config.TempDir, offlineFilename)
  82. if err != nil {
  83. log.Errorln("unable to create temp file for offline video segment", err)
  84. }
  85. if _, err = offlineTmpFile.Write(offlineFileData); err != nil {
  86. return "", fmt.Errorf("unable to write offline segment to disk: %s", err)
  87. }
  88. offlineFilePath := offlineTmpFile.Name()
  89. return offlineFilePath, nil
  90. }