Browse Source

Restructure code + switch to RWMutex

master
PrivateGER 3 years ago
parent
commit
979f59a13d
Signed by: PrivateGER GPG Key ID: CAE625C962F94C67
  1. 24
      DirectoryIndexers/DirectoryIndexer.go
  2. 43
      PageHandlers/Index.go
  3. 66
      PageHandlers/Search.go
  4. 58
      PageHandlers/View.go
  5. 0
      PageHandlers/templates/index.html
  6. 0
      PageHandlers/templates/search.html
  7. 11
      PageHandlers/templates/view.html
  8. 4
      go.mod
  9. 139
      main.go

24
DirectoryIndexer.go → DirectoryIndexers/DirectoryIndexer.go

@ -1,4 +1,4 @@
package main package DirectoryIndexers
import ( import (
"fmt" "fmt"
@ -11,8 +11,8 @@ import (
) )
type FileList struct { type FileList struct {
files map[string]VideoFile Files map[string]VideoFile
mu sync.Mutex *sync.RWMutex
} }
type VideoFile struct { type VideoFile struct {
@ -22,13 +22,12 @@ type VideoFile struct {
Id string Id string
} }
func Index(path string, results chan FileList) {
var FL FileList var FL FileList
func ScanDirectory(group *sync.WaitGroup, path string) { // Initialize the RWMutex HERE manually because *IT IS A POINTER TO A MUTEX*, so it defaults to a nil value
defer group.Done() FL.RWMutex = &sync.RWMutex{}
FL.Lock()
FL.mu.Lock()
defer FL.mu.Unlock()
fmt.Println("Scanning archive...") fmt.Println("Scanning archive...")
@ -38,7 +37,7 @@ func ScanDirectory(group *sync.WaitGroup, path string) {
return return
} }
FL.files = make(map[string]VideoFile) FL.Files = make(map[string]VideoFile)
for _, video := range fileList { for _, video := range fileList {
extension := filepath.Ext(video.Name())[1:] extension := filepath.Ext(video.Name())[1:]
// check if extension is one of valid yt-dlp extensions, if not ignore file // check if extension is one of valid yt-dlp extensions, if not ignore file
@ -57,7 +56,7 @@ func ScanDirectory(group *sync.WaitGroup, path string) {
id := filenameToID(video.Name()) id := filenameToID(video.Name())
FL.files[id] = VideoFile{ FL.Files[id] = VideoFile{
Filename: video.Name(), Filename: video.Name(),
Extension: extension, Extension: extension,
Title: filenameToTitle(video.Name(), extension), Title: filenameToTitle(video.Name(), extension),
@ -65,6 +64,11 @@ func ScanDirectory(group *sync.WaitGroup, path string) {
} }
} }
FL.Unlock()
results <- FL
close(results)
fmt.Println("Archive scan finished.") fmt.Println("Archive scan finished.")
} }

43
PageHandlers/Index.go

@ -0,0 +1,43 @@
package PageHandlers
import (
_ "embed"
"fmt"
"html/template"
"net/http"
"strconv"
"ytdlp-viewer/DirectoryIndexers"
)
//go:embed templates/index.html
var indexTmplSource string
var indexTmpl *template.Template
type IndexPageData struct {
FileCount string
Files map[string]DirectoryIndexers.VideoFile
}
func init() {
var err error
indexTmpl = template.New("index.tmpl")
indexTmpl, err = indexTmpl.Parse(indexTmplSource)
if err != nil {
fmt.Println(err)
}
}
func Index(writer http.ResponseWriter, request *http.Request, FL *DirectoryIndexers.FileList) {
FL.RLock()
defer FL.RUnlock()
data := IndexPageData{
FileCount: strconv.Itoa(len(FL.Files)),
Files: FL.Files,
}
err := indexTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}

66
PageHandlers/Search.go

@ -0,0 +1,66 @@
package PageHandlers
import (
_ "embed"
"fmt"
"html/template"
"log"
"net/http"
"strconv"
"strings"
"ytdlp-viewer/DirectoryIndexers"
)
//go:embed templates/search.html
var searchTmplSource string
var searchTmpl *template.Template
func init() {
var err error
searchTmpl = template.New("search.tmpl")
searchTmpl, err = searchTmpl.Parse(searchTmplSource)
if err != nil {
fmt.Println(err)
}
}
type SearchPageData struct {
Results []DirectoryIndexers.VideoFile
ResultCount string
SearchTerm string
}
func SearchHandler(writer http.ResponseWriter, request *http.Request, FL *DirectoryIndexers.FileList) {
FL.RLock()
defer FL.RUnlock()
keys, ok := request.URL.Query()["term"]
if !ok || len(keys[0]) < 1 {
log.Println("Url Param 'term' is missing")
return
}
var results []DirectoryIndexers.VideoFile
for _, video := range FL.Files {
if video.Id == keys[0] {
results = append(results, video)
break
}
if strings.Contains(strings.ToUpper(video.Title), strings.ToUpper(keys[0])) {
results = append(results, video)
continue
}
}
data := SearchPageData{
Results: results,
ResultCount: strconv.Itoa(len(results)),
SearchTerm: keys[0],
}
err := searchTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}

58
PageHandlers/View.go

@ -0,0 +1,58 @@
package PageHandlers
import (
_ "embed"
"fmt"
"html/template"
"log"
"net/http"
"ytdlp-viewer/DirectoryIndexers"
)
//go:embed templates/view.html
var viewTmplSource string
var viewTmpl *template.Template
type ViewPageData struct {
Title string
Filename string
Id string
Extension string
}
func init() {
var err error
viewTmpl = template.New("view.tmpl")
viewTmpl, err = viewTmpl.Parse(viewTmplSource)
if err != nil {
fmt.Println(err)
}
}
func View(writer http.ResponseWriter, request *http.Request, FL *DirectoryIndexers.FileList) {
FL.RLock()
defer FL.RUnlock()
keys, ok := request.URL.Query()["id"]
if !ok || len(keys[0]) < 1 {
log.Println("Url Param 'id' is missing")
return
}
if _, ok := FL.Files[keys[0]]; !ok {
return
}
video := FL.Files[keys[0]]
data := ViewPageData{
Title: video.Title,
Filename: video.Filename,
Id: video.Id,
Extension: video.Extension,
}
err := viewTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}

0
templates/index.html → PageHandlers/templates/index.html

0
templates/search.html → PageHandlers/templates/search.html

11
templates/view.html → PageHandlers/templates/view.html

@ -5,16 +5,23 @@
<title>{{.Title}} | {{.Id}}</title> <title>{{.Title}} | {{.Id}}</title>
<link href="https://vjs.zencdn.net/7.15.4/video-js.css" rel="stylesheet" /> <link href="https://vjs.zencdn.net/7.15.4/video-js.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.css" rel="stylesheet">
<style>
.centeredvideo {
display: block;
margin-left: auto;
margin-right: auto
}
</style>
</head> </head>
<body> <body>
<video class="video-js vjs-big-play-centered" id="player" height="480" width="720" controls autoplay data-setup="{}"> <video class="video-js vjs-big-play-centered centeredvideo" id="player" height="480" width="720" controls autoplay data-setup="{}">
<source src="/videos/{{.Filename}}"> <source src="/videos/{{.Filename}}">
</video> </video>
<h1>{{.Title}}</h1> <h1>{{.Title}}</h1>
<p>Filetype: {{.Extension}}</p> <p>Filetype: {{.Extension}}</p>
<p>Youtube ID: {{.Id}}</p> <p>Youtube ID: {{.Id}}</p>
<p>Filename: {{.Filename}}</p> <p>Filename: {{.Filename}}</p>
<a href="/videos/{{.Filename}}">direct video link</a> <a href="/videos/{{.Filename}}">Direct video link</a>
<script src="https://vjs.zencdn.net/7.15.4/video.min.js"></script> <script src="https://vjs.zencdn.net/7.15.4/video.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.min.js"></script>

4
go.mod

@ -2,6 +2,4 @@ module ytdlp-viewer
go 1.17 go 1.17
require github.com/dlclark/regexp v1.4.0 require github.com/dlclark/regexp2 v1.4.0
require github.com/dlclark/regexp2 v1.4.0 // indirect

139
main.go

@ -3,154 +3,45 @@ package main
import ( import (
_ "embed" _ "embed"
"fmt" "fmt"
"log"
"net/http" "net/http"
"os" "os"
"strconv" "ytdlp-viewer/DirectoryIndexers"
"strings" "ytdlp-viewer/PageHandlers"
"sync"
"text/template"
) )
//go:embed templates/index.html
var indexTmplSource string
//go:embed templates/search.html
var searchTmplSource string
//go:embed templates/view.html
var viewTmplSource string
type IndexPageData struct {
FileCount string
Files map[string]VideoFile
}
type SearchPageData struct {
Results []VideoFile
ResultCount string
SearchTerm string
}
type ViewPageData struct {
Title string
Filename string
Id string
Extension string
}
func main() { func main() {
path := os.Getenv("directory") path := os.Getenv("directory")
if path == "" { if path == "" {
path = "Z:/MainArchive" path = "/home/latte/NFS/MainArchive/"
} }
var wg sync.WaitGroup var FL DirectoryIndexers.FileList
wg.Add(1) resultChannel := make(chan DirectoryIndexers.FileList)
fmt.Println("Starting scanner at", path) fmt.Println("Starting scanner at", path)
go ScanDirectory(&wg, path) go DirectoryIndexers.Index(path, resultChannel)
wg.Wait() FL = <-resultChannel
FL.mu.Lock() /*FL.RLock()
fmt.Println(strconv.Itoa(len(FL.files))) fmt.Println(strconv.Itoa(len(FL.Files)))
for _, file := range FL.files { for _, file := range FL.Files {
fmt.Println("Name:", file.Title,"Extension:", file.Extension, "ID:", file.Id) fmt.Println("Name:", file.Title,"Extension:", file.Extension, "ID:", file.Id)
} }
FL.mu.Unlock() FL.RUnlock()*/
indexTmpl, err := template.New("index.tmpl").Parse(indexTmplSource)
if err != nil {
fmt.Println(err)
}
searchTmpl, err := template.New("search.tmpl").Parse(searchTmplSource)
if err != nil {
fmt.Println(err)
}
viewTmpl, err := template.New("view.tmpl").Parse(viewTmplSource)
if err != nil {
fmt.Println(err)
}
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
FL.mu.Lock() PageHandlers.Index(writer, request, &FL)
defer FL.mu.Unlock()
data := IndexPageData{
FileCount: strconv.Itoa(len(FL.files)),
Files: FL.files,
}
err := indexTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}) })
http.HandleFunc("/search", func(writer http.ResponseWriter, request *http.Request) { http.HandleFunc("/search", func(writer http.ResponseWriter, request *http.Request) {
FL.mu.Lock() PageHandlers.SearchHandler(writer, request, &FL)
defer FL.mu.Unlock()
keys, ok := request.URL.Query()["term"]
if !ok || len(keys[0]) < 1 {
log.Println("Url Param 'term' is missing")
return
}
var results []VideoFile
for _, video := range FL.files {
if video.Id == keys[0] {
results = append(results, video)
break
}
if strings.Contains(strings.ToUpper(video.Title), strings.ToUpper(keys[0])) {
results = append(results, video)
continue
}
}
data := SearchPageData{
Results: results,
ResultCount: strconv.Itoa(len(results)),
SearchTerm: keys[0],
}
err := searchTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}) })
http.HandleFunc("/view", func(writer http.ResponseWriter, request *http.Request) { http.HandleFunc("/view", func(writer http.ResponseWriter, request *http.Request) {
FL.mu.Lock() PageHandlers.View(writer, request, &FL)
defer FL.mu.Unlock()
keys, ok := request.URL.Query()["id"]
if !ok || len(keys[0]) < 1 {
log.Println("Url Param 'id' is missing")
return
}
if _, ok := FL.files[keys[0]]; !ok {
return
}
video := FL.files[keys[0]]
data := ViewPageData{
Title: video.Title,
Filename: video.Filename,
Id: video.Id,
Extension: video.Extension,
}
err := viewTmpl.Execute(writer, data)
if err != nil {
fmt.Println(err)
}
}) })
http.Handle("/videos/", http.StripPrefix("/videos/", http.FileServer(http.Dir(path)))) http.Handle("/videos/", http.StripPrefix("/videos/", http.FileServer(http.Dir(path))))
err = http.ListenAndServe(":8000", nil) err := http.ListenAndServe(":8000", nil)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

Loading…
Cancel
Save