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{ | |||
&cmdServe, | |||
&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}).+") | |||
func NewTrack(file string) *Track { | |||
func NewTrack(file string) (*Track, error) { | |||
f, err := os.Open(file) | |||
if err != nil { | |||
fmt.Printf("error loading file: %v", err) | |||
return nil | |||
return nil, fmt.Errorf("error loading file: %v", err) | |||
} | |||
defer f.Close() | |||
m, err := tag.ReadFrom(f) | |||
if err != nil { | |||
return nil | |||
return nil, fmt.Errorf("unable to read file: %v", err) | |||
} | |||
return &Track{ | |||
@@ -36,7 +35,10 @@ func NewTrack(file string) *Track { | |||
// RenameTrack takes a filename, opens it, reads the metadata, and returns both | |||
// the old and new filename. | |||
func RenameTrack(file string) string { | |||
t := NewTrack(file) | |||
t, err := NewTrack(file) | |||
if err != nil { | |||
return "" | |||
} | |||
// Extract playlist track number from 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}}`, | |||
} |