diff --git a/pkg/app/app.go b/pkg/app/app.go index e423359..1de26ce 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -17,6 +17,7 @@ import ( "github.com/wybiral/tube/pkg/media" ) +// App represents main application. type App struct { Config *Config Library *media.Library @@ -26,6 +27,7 @@ type App struct { Router *mux.Router } +// NewApp returns a new instance of App from Config. func NewApp(cfg *Config) (*App, error) { if cfg == nil { cfg = DefaultConfig() @@ -33,24 +35,30 @@ func NewApp(cfg *Config) (*App, error) { a := &App{ Config: cfg, } + // Setup Library a.Library = media.NewLibrary() + // Setup Watcher w, err := fsnotify.NewWatcher() if err != nil { return nil, err } a.Watcher = w + // Setup Listener ln, err := newListener(cfg.Server) if err != nil { return nil, err } a.Listener = ln + // Setup Templates a.Templates = template.Must(template.ParseGlob("templates/*")) + // Setup Router r := mux.NewRouter().StrictSlash(true) r.HandleFunc("/", a.indexHandler).Methods("GET") r.HandleFunc("/v/{id}.mp4", a.videoHandler).Methods("GET") r.HandleFunc("/t/{id}", a.thumbHandler).Methods("GET") r.HandleFunc("/v/{id}", a.pageHandler).Methods("GET") r.HandleFunc("/feed.xml", a.rssHandler).Methods("GET") + // Static file handler fsHandler := http.StripPrefix( "/static/", http.FileServer(http.Dir("./static/")), @@ -60,6 +68,7 @@ func NewApp(cfg *Config) (*App, error) { return a, nil } +// Run imports the library and starts server. func (a *App) Run() error { path := a.Config.LibraryPath err := a.Library.Import(path) @@ -71,6 +80,7 @@ func (a *App) Run() error { return http.Serve(a.Listener, a.Router) } +// Watch the library path and update Library with changes. func (a *App) watch() { for { e, ok := <-a.Watcher.Events @@ -92,6 +102,7 @@ func (a *App) watch() { } } +// HTTP handler for / func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) { log.Printf("/") pl := a.Library.Playlist() @@ -108,6 +119,7 @@ func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) { } } +// HTTP handler for /v/id func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] @@ -133,6 +145,7 @@ func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) { }) } +// HTTP handler for /v/id.mp4 func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] @@ -149,6 +162,7 @@ func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, path) } +// HTTP handler for /t/id func (a *App) thumbHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] @@ -167,6 +181,7 @@ func (a *App) thumbHandler(w http.ResponseWriter, r *http.Request) { } } +// HTTP handler for /feed.xml func (a *App) rssHandler(w http.ResponseWriter, r *http.Request) { cfg := a.Config.Feed now := time.Now() diff --git a/pkg/app/config.go b/pkg/app/config.go index 12cf21d..f8ca2e8 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -5,17 +5,20 @@ import ( "os" ) +// Config settings for main App. type Config struct { LibraryPath string `json:"library"` Server *ServerConfig `json:"server"` Feed *FeedConfig `json:"feed"` } +// ServerConfig settings for App Server. type ServerConfig struct { Host string `json:"host"` Port int `json:"port"` } +// FeedConfig settings for App Feed. type FeedConfig struct { ExternalURL string `json:"external_url"` Title string `json:"title"` @@ -28,6 +31,7 @@ type FeedConfig struct { Copyright string `json:"copyright"` } +// DefaultConfig returns Config initialized with default values. func DefaultConfig() *Config { return &Config{ LibraryPath: "videos", @@ -41,6 +45,7 @@ func DefaultConfig() *Config { } } +// ReadFile reads a JSON file into Config. func (c *Config) ReadFile(path string) error { f, err := os.Open(path) if err != nil { diff --git a/pkg/app/listener.go b/pkg/app/listener.go index 7d42290..a4236d8 100644 --- a/pkg/app/listener.go +++ b/pkg/app/listener.go @@ -1,3 +1,7 @@ +// Instead of using the default new.Listener this file will construct a custom +// one. The main purpose for this is to have more control over the settings +// (like keep-alive) and to retrieve the assigned port when using port 0. + package app import ( diff --git a/pkg/media/library.go b/pkg/media/library.go index 337907d..c0d79eb 100644 --- a/pkg/media/library.go +++ b/pkg/media/library.go @@ -9,11 +9,13 @@ import ( "sync" ) +// Library manages importing and retrieving video data. type Library struct { mu sync.RWMutex Videos map[string]*Video } +// NewLibrary returns new instance of Library. func NewLibrary() *Library { lib := &Library{ Videos: make(map[string]*Video), @@ -21,6 +23,7 @@ func NewLibrary() *Library { return lib } +// Import adds all valid videos from a given path. func (lib *Library) Import(path string) error { files, err := ioutil.ReadDir(path) if err != nil { @@ -36,6 +39,7 @@ func (lib *Library) Import(path string) error { return nil } +// Add adds a single video from a given file path. func (lib *Library) Add(path string) error { v, err := ParseVideo(path) if err != nil { @@ -48,6 +52,7 @@ func (lib *Library) Add(path string) error { return nil } +// Remove removes a single video from a given file path. func (lib *Library) Remove(path string) { name := filepath.Base(path) // ID is name without extension @@ -65,6 +70,7 @@ func (lib *Library) Remove(path string) { } } +// Playlist returns a sorted Playlist of all videos. func (lib *Library) Playlist() Playlist { lib.mu.RLock() defer lib.mu.RUnlock() diff --git a/pkg/media/playlist.go b/pkg/media/playlist.go index 86dcb76..cf8edcf 100644 --- a/pkg/media/playlist.go +++ b/pkg/media/playlist.go @@ -1,15 +1,19 @@ package media +// Playlist holds an array of videos capable of sorting by Timestamp. type Playlist []*Video +// Len returns length of array (for sorting). func (p Playlist) Len() int { return len(p) } +// Swap swaps two values in array by index (for sorting). func (p Playlist) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +// Less returns true if p[i] Timestamp is after p[j] (for sorting). func (p Playlist) Less(i, j int) bool { return p[i].Timestamp.After(p[j].Timestamp) } diff --git a/pkg/media/video.go b/pkg/media/video.go index 2499433..90ec595 100644 --- a/pkg/media/video.go +++ b/pkg/media/video.go @@ -8,6 +8,7 @@ import ( "github.com/dhowden/tag" ) +// Video represents metadata for a single video. type Video struct { ID string Title string @@ -20,6 +21,7 @@ type Video struct { Timestamp time.Time } +// ParseVideo parses a video file's metadata and returns a Video. func ParseVideo(path string) (*Video, error) { f, err := os.Open(path) if err != nil {