This serves the mixtape site by running `cdr preview`main
@@ -0,0 +1,66 @@ | |||||
package main | |||||
import ( | |||||
"log" | |||||
"net/http" | |||||
"os" | |||||
"path/filepath" | |||||
"strings" | |||||
"github.com/thebaer/cdr" | |||||
"github.com/urfave/cli" | |||||
) | |||||
var ( | |||||
cmdServe = cli.Command{ | |||||
Name: "preview", | |||||
Usage: "serve the mixtape site", | |||||
Action: serveAction, | |||||
} | |||||
) | |||||
func newMixtape(wd string) (*cdr.Mixtape, error) { | |||||
m := &cdr.Mixtape{Tracks: []cdr.Track{}} | |||||
filepath.Walk(wd, func(path string, i os.FileInfo, err error) error { | |||||
if !i.IsDir() && !strings.HasPrefix(i.Name(), ".") && i.Name() != "index.html" { | |||||
t, err := cdr.NewTrack(i.Name()) | |||||
if err == nil { | |||||
log.Printf("Skipping track %s: %v", i.Name(), err) | |||||
return nil | |||||
} | |||||
log.Println("Adding track", t.Title) | |||||
m.Tracks = append(m.Tracks, *t) | |||||
} | |||||
return nil | |||||
}) | |||||
return m, nil | |||||
} | |||||
func serveAction(c *cli.Context) error { | |||||
wd, err := os.Getwd() | |||||
if err != nil { | |||||
return err | |||||
} | |||||
m, err := newMixtape(wd) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | |||||
if r.RequestURI != "/" { | |||||
log.Printf("GET %s", r.RequestURI) | |||||
http.ServeFile(w, r, filepath.Join(wd, r.RequestURI)) | |||||
return | |||||
} | |||||
err := cdr.Render(m, w) | |||||
if err != nil { | |||||
log.Printf("[ERROR] Render failed! %s", err) | |||||
} | |||||
log.Printf("GET /") | |||||
}) | |||||
return http.ListenAndServe(":9991", nil) | |||||
} |
@@ -16,6 +16,7 @@ func main() { | |||||
} | } | ||||
app.Commands = []*cli.Command{ | app.Commands = []*cli.Command{ | ||||
&cmdServe, | |||||
&cmdClean, | &cmdClean, | ||||
} | } | ||||
@@ -0,0 +1,26 @@ | |||||
//go:generate inline -o templates.go -p cdr templates/parts.tmpl | |||||
package cdr | |||||
import ( | |||||
"html/template" | |||||
"io" | |||||
"io/ioutil" | |||||
) | |||||
func Render(m *Mixtape, w io.Writer) error { | |||||
partsRawTmpl, err := ReadAsset("templates/parts.tmpl", false) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
mixtapeRawTmpl, err := ioutil.ReadFile("mixtape.tmpl") | |||||
if err != nil { | |||||
return err | |||||
} | |||||
t, err := template.New("mixtape").Parse(string(mixtapeRawTmpl) + string(partsRawTmpl)) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
t.ExecuteTemplate(w, "mixtape", m) | |||||
return nil | |||||
} |
@@ -13,17 +13,16 @@ import ( | |||||
var trackNameReg = regexp.MustCompile("^([0-9]{2}).+") | var trackNameReg = regexp.MustCompile("^([0-9]{2}).+") | ||||
func NewTrack(file string) *Track { | |||||
func NewTrack(file string) (*Track, error) { | |||||
f, err := os.Open(file) | f, err := os.Open(file) | ||||
if err != nil { | if err != nil { | ||||
fmt.Printf("error loading file: %v", err) | |||||
return nil | |||||
return nil, fmt.Errorf("error loading file: %v", err) | |||||
} | } | ||||
defer f.Close() | defer f.Close() | ||||
m, err := tag.ReadFrom(f) | m, err := tag.ReadFrom(f) | ||||
if err != nil { | if err != nil { | ||||
return nil | |||||
return nil, fmt.Errorf("unable to read file: %v", err) | |||||
} | } | ||||
return &Track{ | return &Track{ | ||||
@@ -36,7 +35,10 @@ func NewTrack(file string) *Track { | |||||
// RenameTrack takes a filename, opens it, reads the metadata, and returns both | // RenameTrack takes a filename, opens it, reads the metadata, and returns both | ||||
// the old and new filename. | // the old and new filename. | ||||
func RenameTrack(file string) string { | func RenameTrack(file string) string { | ||||
t := NewTrack(file) | |||||
t, err := NewTrack(file) | |||||
if err != nil { | |||||
return "" | |||||
} | |||||
// Extract playlist track number from filename | // Extract playlist track number from filename | ||||
fMatch := trackNameReg.FindStringSubmatch(t.Filename) | fMatch := trackNameReg.FindStringSubmatch(t.Filename) | ||||
@@ -0,0 +1,81 @@ | |||||
// Code generated by "inline -o templates.go -p cdr templates/parts.tmpl" -- DO NOT EDIT -- | |||||
package cdr | |||||
import ( | |||||
"fmt" | |||||
"io/ioutil" | |||||
) | |||||
func ReadAsset(file string, useLocal bool) ([]byte, error) { | |||||
if useLocal { | |||||
return ioutil.ReadFile(file) | |||||
} | |||||
if f, ok := files[file]; ok { | |||||
return []byte(f), nil | |||||
} | |||||
return nil, fmt.Errorf("file doesn't exist.") | |||||
} | |||||
var files = map[string]string{ | |||||
"templates/parts.tmpl": `{{define "player"}} | |||||
{{with $x := index . 0}} | |||||
<audio id="player" preload="auto" tabindex="0" controls> | |||||
<source src="{{$x.Filename}}"> | |||||
</audio> | |||||
{{end}} | |||||
<ol id="playlist"> | |||||
{{range $i, $el := .}} | |||||
<li{{if eq $i 0}} class="active"{{end}}> | |||||
<a href="{{$el.Filename}}">{{$el.Artist}} - {{$el.Title}}</a> | |||||
</li> | |||||
{{end}} | |||||
</ol> | |||||
{{end}} | |||||
{{define "full-player"}} | |||||
{{template "player" .}} | |||||
{{template "playlist-js"}} | |||||
{{end}} | |||||
{{define "playlist-js"}} | |||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> | |||||
<script type="text/javascript"> | |||||
$(document).ready(function() { | |||||
init(); | |||||
function init() { | |||||
var current = 0; | |||||
var $audio = $('#player'); | |||||
var $playlist = $('#playlist'); | |||||
var $tracks = $playlist.find('li a'); | |||||
var len = $tracks.length - 1; | |||||
$playlist.on('click', 'a', function (e) { | |||||
e.preventDefault(); | |||||
link = $(this); | |||||
current = link.parent().index(); | |||||
run(link, $audio[0]); | |||||
}); | |||||
$audio[0].addEventListener('ended', function (e) { | |||||
current++; | |||||
if (current == len) { | |||||
current = 0; | |||||
link = $playlist.find('a')[0]; | |||||
} else { | |||||
link = $playlist.find('a')[current]; | |||||
} | |||||
run($(link), $audio[0]); | |||||
}); | |||||
} | |||||
function run($link, $player) { | |||||
$player.src = $link.attr('href'); | |||||
par = $link.parent(); | |||||
par.addClass('active').siblings().removeClass('active'); | |||||
$player.load(); | |||||
$player.play(); | |||||
} | |||||
}); | |||||
</script> | |||||
{{end}}`, | |||||
} |