Skip to content

Commit

Permalink
Merge pull request #19 from jmillerv/14-convert-time-slot-to-a-config
Browse files Browse the repository at this point in the history
14 convert time slot to a config
  • Loading branch information
jmillerv authored Dec 6, 2022
2 parents f83e0be + 91e7908 commit 29e26a4
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 93 deletions.
5 changes: 4 additions & 1 deletion config.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ content:
Programs:
- Name: "gettysburg10"
Type: "file"
Timeslot: "afternoon"
Source: "./static/gettysburg10.wav"
Timeslot:
Begin: "11:00PM"
End: "11:30PM"

7 changes: 0 additions & 7 deletions config_sample.yml

This file was deleted.

2 changes: 1 addition & 1 deletion content/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
type Program struct {
Name string
Source string
Timeslot Timeslot
Timeslot *Timeslot
Type MediaType
}

Expand Down
66 changes: 42 additions & 24 deletions content/program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,69 @@ func TestProgram_GetMedia(t *testing.T) {
name: "Success: returns folder",
fields: fields{
program: &Program{
Name: "David Rovics Folder",
Source: "./static/david_rovics",
Timeslot: "early",
Type: "folder",
Name: "David Rovics Folder",
Source: "./static/david_rovics",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "folder",
},
},
want: (&Program{
Name: "David Rovics Folder",
Source: "./static/david_rovics",
Timeslot: "early",
Type: "folder",
Name: "David Rovics Folder",
Source: "./static/david_rovics",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "folder",
}).GetMedia(),
},
{
name: "Success: returns file",
fields: fields{
program: &Program{
Name: "Piano Six Seconds",
Source: "./static/piano_six_seconds.mp3",
Timeslot: "afternoon",
Type: "file",
Name: "Piano Six Seconds",
Source: "./static/piano_six_seconds.mp3",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "file",
},
},
want: (&Program{
Name: "Piano Six Seconds",
Source: "./static/piano_six_seconds.mp3",
Timeslot: "afternoon",
Type: "file",
Name: "Piano Six Seconds",
Source: "./static/piano_six_seconds.mp3",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "file",
}).GetMedia(),
},
{
name: "Success: returns web radio",
fields: fields{
program: &Program{
Name: "Indie Pop Rocks",
Source: "https://somafm.com/indiepop.pls",
Timeslot: "any",
Type: "web_radio",
Name: "Indie Pop Rocks",
Source: "https://somafm.com/indiepop.pls",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "web_radio",
},
},
want: (&Program{
Name: "Indie Pop Rocks",
Source: "https://somafm.com/indiepop.pls",
Timeslot: "any",
Type: "web_radio",
Name: "Indie Pop Rocks",
Source: "https://somafm.com/indiepop.pls",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: "web_radio",
}).GetMedia(),
},
{
Expand Down
73 changes: 21 additions & 52 deletions content/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,18 @@ import (
"time"
)

const (
Early Timeslot = "early"
Morning Timeslot = "morning"
Breakfast Timeslot = "breakfast"
Midmorning Timeslot = "midmorning"
Afternoon Timeslot = "afternoon"
Commute Timeslot = "commute"
Evening Timeslot = "evening"
Late Timeslot = "late"
Overnight Timeslot = "overnight"
All Timeslot = "all"
)

type Timeslot string

type Slot struct {
Begin string
End string
}

var Shuffled bool

var TimeslotMap = map[Timeslot]*Slot{
Early: {"4:00 AM", "6:00 AM"},
Morning: {"6:00 AM", "8:00 AM"},
Breakfast: {"8:00 AM", "11:00 AM"},
Midmorning: {"11:00 AM", "2:00 PM"},
Afternoon: {"2:00 PM", "5:00 PM"},
Commute: {"5:00 PM", "7:00 PM"},
Evening: {"7:00 PM", "11:00 PM"},
Late: {"11:00 PM", "2:00 AM"},
Overnight: {"2:00 AM", "4:00 AM"},
All: {"12:00 AM", "12:00 PM"},
}

type Scheduler struct {
Content struct {
Programs []*Program
}
}

func (s *Scheduler) Run() error {
func (s *Scheduler) Run(currentTime time.Time) error {
log.Info("Starting Daemon")

log.Infof("Press ESC to quit")
// set up the loop to continuously check for key entries
now := time.Now()
ts := getTimeSlot(&now)
// if randomized mode do x

// setup signal listeners
sigchnl := make(chan os.Signal, 1)
Expand All @@ -70,31 +33,37 @@ func (s *Scheduler) Run() error {

// check content from scheduler and run through it
for _, p := range s.Content.Programs {
now := currentTime
log.Debugf("program %v", formatter.StructToIndentedString(p))
// Check Timeslots
if ts == p.Timeslot || ts == All {

if p.Timeslot.IsScheduledNow(now) {
log.Infof("getting media type: %v", p.Type)
content := p.GetMedia()
log.Debugf("media struct: %v", content)
content.Get()
err := content.Get() // retrieve contents from file
if err != nil {
return err
}
go func() {
for {
stop := <-sigchnl
s.Stop(stop, content)
}
}()
err := content.Play()
err = content.Play()
if err != nil {
return err
} // play will block until done
}

if !p.Timeslot.IsScheduledNow(now) {
log.WithField("IsScheduledNow", p.Timeslot.IsScheduledNow(now)).
WithField("current time", time.Now().
Format(time.Kitchen)).Infof("media not scheduled")
}
// TODO make these checks run in a loop and always check if programs should be playing
}
// if radio station start 30 minute counter.
// smartly allocate programs to timeslots based on length if known
// if time between TimeSlotMap do x
// play program from that slot.
// wait for program to finish
// get next

exitcode := <-exitchnl
os.Exit(exitcode)
return nil
Expand Down Expand Up @@ -154,10 +123,10 @@ func (s *Scheduler) Stop(signal os.Signal, media Media) {
}
}

func getTimeSlot(t *time.Time) Timeslot {
// if t between certain times return Timeslot
return All
}
//func getTimeSlot(t *time.Time) Timeslot {
// // if t between certain times return Timeslot
// return All
//}

func NewScheduler(file string) (*Scheduler, error) {
log.Info("Loading Config File from: ", file)
Expand Down
15 changes: 8 additions & 7 deletions content/schedule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestNewScheduler(t *testing.T) {
t.Parallel()
type args struct {
file string
}
Expand All @@ -30,10 +29,13 @@ func TestNewScheduler(t *testing.T) {
scheduler: &Scheduler{
Content: struct{ Programs []*Program }{Programs: []*Program{
{
Name: "gettysburg10",
Source: "./static/gettysburg10.wav",
Timeslot: Timeslot("afternoon"),
Type: MediaType("file"),
Name: "gettysburg10",
Source: "./static/gettysburg10.wav",
Timeslot: &Timeslot{
Begin: "11:00PM",
End: "11:30PM",
},
Type: MediaType("file"),
},
}},
},
Expand All @@ -57,10 +59,9 @@ func TestNewScheduler(t *testing.T) {
wantErr: true,
},
}
// TODO make test pass when running in parallel and troubleshoot race condition.
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := NewScheduler(tt.args.file)
if err != nil && tt.wantErr {
assert.Error(t, err)
Expand Down
46 changes: 46 additions & 0 deletions content/timeslot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package content

import (
"github.com/araddon/dateparse"
log "github.com/sirupsen/logrus"
"strconv"
"time"
)

// Times represents timeslots and are parsed in a 24hour format
type Timeslot struct {
Begin string
End string
}

// IsScheduledNow checks the current time and returns a bool if the time falls within the range
func (t *Timeslot) IsScheduledNow(current time.Time) bool {
// get date info for string
date := time.Date(current.Year(), current.Month(), current.Day(), 0, 0, 0, 0, time.Local)
year, month, day := date.Date()

// convert ints to dateString
dateString := strconv.Itoa(year) + "-" + strconv.Itoa(int(month)) + "-" + strconv.Itoa(day)

// parse the date and the config time
// parsed times are returned in 2022-12-05 15:05:00 +0000 UTC format which doesn't appear to have a const in the time package
parsedStartTime, _ := dateparse.ParseAny(dateString + " " + t.Begin)
parsedEndTime, _ := dateparse.ParseAny(dateString + " " + t.End)

// matched parse time to fixed zone time
startTime := time.Date(parsedStartTime.Year(), parsedStartTime.Month(), parsedStartTime.Day(), parsedStartTime.Hour(), parsedStartTime.Minute(), parsedStartTime.Second(), parsedStartTime.Nanosecond(), time.Local)
endTime := time.Date(parsedEndTime.Year(), parsedEndTime.Month(), parsedEndTime.Day(), parsedEndTime.Hour(), parsedEndTime.Minute(), parsedEndTime.Second(), parsedEndTime.Nanosecond(), time.Local)

return inTimeSpan(startTime, endTime, current)
}

func inTimeSpan(start, end, current time.Time) bool {
log.WithField("start", start).WithField("current", current).WithField("end", end).Info("timeslot::inTimeSpan: configured times")
// handle scheduling that traverses days.
tz, _ := time.LoadLocation("UTC")
if end.Before(start) && current.After(start) {
return true
}

return current.In(tz).After(start) && current.In(tz).Before(end)
}
73 changes: 73 additions & 0 deletions content/timeslot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package content

import (
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"testing"
"time"
)

type TimeProvider interface {
Now() time.Time
}

type testTime struct {
TimeProvider
}

func (testTime *testTime) Now() time.Time {
tz, _ := time.LoadLocation("EST")
now := time.Date(2022, 12, 05, 23, 27, 0, 0, tz)
log.Infof("testTime %v", now)
return now
}

func TestTimes_IsScheduledNow(t *testing.T) {
t.Parallel()
type fields struct {
Current time.Time
Begin string
End string
}
tests := []struct {
name string
fields fields
want bool
}{
{
name: "Returns True",
fields: fields{
Begin: "11:00 PM",
End: "11:59 PM",
},
want: true,
},
{
name: "Returns False",
fields: fields{
Begin: "11:28 PM",
End: "10:47 PM",
},
want: false,
},
{
name: "Success: evaluates true for times that traverse days",
fields: fields{
Begin: "11:00 PM",
End: "2:30 AM",
},
want: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t1 *testing.T) {
t1.Parallel()
t := &Timeslot{
Begin: tt.fields.Begin,
End: tt.fields.End,
}
assert.Equalf(t1, tt.want, t.IsScheduledNow((&testTime{}).Now()), "IsScheduledNow()")
})
}
}
Loading

0 comments on commit 29e26a4

Please sign in to comment.