Beispiel #1
0
// Watcher instances and connects via channels the go routines that contain the actual logic.
// It also triggers the logic by feeding mpd events to the go routine pipe.
func Watcher(client *mpd.Client, cfg *Config) error {
	// Watch for 'player' events:
	w, err := mpd.NewWatcher("tcp", fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), "", "player")
	if err != nil {
		log.Fatalf("Failed to create watcher: %v", err)
		return err
	}

	defer w.Close()

	// Log mpd errors, but don't handle them more than that:
	go func() {
		for err := range w.Error {
			log.Println("Error:", err)
		}
	}()

	// Watcher -> StatusUpdater
	updateCh := make(chan bool)

	// StatusUpdater -> MoodbarAdjuster
	eventCh := make(chan MPDEvent)

	// MoodbarAdjuster -> MoodbarRunner
	colorsCh := make(chan TimedColor)

	// Start the respective go routines:
	go MoodbarRunner(colorsCh)
	go MoodbarAdjuster(eventCh, colorsCh)
	go StatusUpdater(client, cfg, updateCh, eventCh)

	// Also sync extra every few seconds:
	go func() {
		for range time.NewTicker(2 * time.Second).C {
			updateCh <- true
		}
	}()

	// ..but directly react on a changed player event:
	go func() {
		for range w.Event {
			updateCh <- true
		}
	}()

	// Block until something fatal happens:
	sigint := make(chan os.Signal)
	signal.Notify(sigint, os.Interrupt)
	<-sigint

	// Attempt to clean up, this might not even be executed:
	close(colorsCh)
	close(eventCh)
	close(updateCh)
	return nil
}
Beispiel #2
0
// Opens a connection to MPD.
func (w *Watcher) dial() (watcher *mpd.Watcher, err error) {
	for {
		if watcher, err = mpd.NewWatcher("tcp", w.addr, w.passwd); err == nil {
			return
		}

		select {
		case <-w.done:
			return
		case <-time.After(time.Second):
			// retry
		}
	}
}
Beispiel #3
0
func (m *MPD) watch() (err error) {
	m.watcher, err = mpd.NewWatcher("tcp", configuration.MPDConf.Host, "")
	if err != nil {
		glog.Errorf("mpd.watch: connect to %v error: %v", configuration.MPDConf.Host, err.Error())
		return err
	}

	glog.Info("mpd.watch: connected to ", configuration.MPDConf.Host)
	glog.V(1).Infof("mpd.watch: starting watch")

	m.Message <- MPDGetStatus()

	for {
		if m.watcher == nil {
			break
		}
		select {
		case _ = <-m.end:
			glog.Info("mpd.watch: end")
			m.active = false
			return
		case subsystem := <-m.watcher.Event:
			if glog.V(1) {
				glog.Info("mpd.watch: event: ", subsystem)
			}
			m.Message <- MPDGetStatus()
			/*
				switch subsystem {
				case "player":
					m.Message <- MPDGetStatus()
				default:
					m.Message <- MPDGetStatus()
				}
			*/
		case err := <-m.watcher.Error:
			//glog.Errorf("mpd.watch: error event: %v", err)
			return err
		}
	}

	return nil
}
Beispiel #4
0
func main() {
	conn, err := mpd.Dial("tcp", "127.0.0.1:6600")

	if err != nil {
		fmt.Println("Error: could not connect to MPD, exiting")
		os.Exit(1)
	}
	defer conn.Close()

	w, err := mpd.NewWatcher("tcp", "127.0.0.1:6600", "", "player")
	if err != nil {
		fmt.Println("Error: could not connect to MPD, exiting")
		os.Exit(1)
	}
	defer w.Close()

	h := newHub()
	go h.run()

	// Log errors.
	go func() {
		for err := range w.Error {
			log.Println("Error:", err)
		}
	}()

	//Control song transitions -- During this time, update the websockets
	go func() {
		var status mpd.Attrs
		for _ = range w.Event {
			status, err = conn.Status()
			if err != nil {
				//Connections seem to drop often, so reconnect when this happens
				fmt.Println("Couldn't get current status! Error: " + err.Error())
				conn.Close()

				fmt.Println("Reconnecting...")
				conn, err = mpd.Dial("tcp", "127.0.0.1:6600")

				if err != nil {
					fmt.Println("Error: could not connect to MPD, exiting")
					os.Exit(1)
				}
				defer conn.Close()

				status, err = conn.Status()
			}
			pos, _ := strconv.ParseFloat(status["elapsed"], 64)
			fmt.Println(pos)
			if pos == 0.000 {
				//Stop us from getting into an infinite loop by waiting 25 ms
				time.Sleep(25 * time.Millisecond)
				//updateQueue <- &updateQueueMsg{Song: song["Title"], Artist: song["Artist"]}
				conn.Pause(true)
				//Wait 3 seconds then resume next song
				time.Sleep(3000 * time.Millisecond)
				conn.Pause(false)
				song, err := conn.CurrentSong()
				if err != nil {
					fmt.Println("Couldn't get current song! Error: " + err.Error())
				} else {
					//Serialize and send info
					msg := map[string]string{"cmd": "NP", "Title": song["Title"], "Artist": song["Artist"], "Album": song["Album"], "Cover": "/art/" + GetAlbumDir(song["file"])}
					jsonMsg, _ := json.Marshal(msg)
					h.broadcast <- []byte(jsonMsg)
				}
			}
		}
	}()

	song, err := conn.CurrentSong()
	if err != nil {
		fmt.Println("No Song!")
	} else {
		fmt.Println(song["Title"])
	}
	songs, err := conn.ListAllInfo("/")
	shuffle(songs)
	subset := songs[:20]

	//Searches for cover image
	web.Get("/art/(.+)", getCover)

	//Returns main page with custom selection of songs
	web.Get("/", func(ctx *web.Context) string {
		return getIndex(ctx, subset)
	})

	//Returns a raw song
	web.Get("/song/(.+)", getSong)

	//Returns the JSON info for the currently playing song
	web.Get("/np", func(ctx *web.Context) string {
		song, _ := conn.CurrentSong()
		jsonMsg, _ := json.Marshal(song)
		return string(jsonMsg)
	})

	//Handle the websocket
	web.Websocket("/ws", websocket.Handler(func(ws *websocket.Conn) {
		handleSocket(ws, h)
	}))
	web.Get("/library", func(ctx *web.Context) string {
		jsonMsg, _ := json.Marshal(subset)
		return string(jsonMsg)
	})
	web.Run("0.0.0.0:8080")
}