stationCurrentSong.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { Map, List } from "immutable";
  2. import store from "../index.js";
  3. function calculateTimeElapsed() {
  4. const state = store.getState();
  5. const
  6. paused = state.station.info.get("paused"),
  7. songId = state.station.currentSong.get("songId"),
  8. pausedAt = state.station.currentSong.getIn(["timings", "pausedAt"]),
  9. startedAt = state.station.currentSong.getIn(["timings", "startedAt"]),
  10. timePaused = state.station.currentSong.getIn(["timings", "timePaused"]);
  11. if (songId !== "") {
  12. let timePausedNow = (paused) ? Date.now() - pausedAt : 0;
  13. //TODO Fix this function. It's accurate, but sometimes if paused at the wrong moment (e.g. 10 seconds to the milisecond) the display can flicker between 9 and 10 seconds every .5s.
  14. return (Date.now() - startedAt - timePaused - timePausedNow) / 1000;
  15. } else return 0;
  16. }
  17. const NEXT_SONG = "STATION_CURRENT_SONG::NEXT_SONG";
  18. const LIKE_UPDATE = "STATION_CURRENT_SONG::LIKE_UPDATE";
  19. const DISLIKE_UPDATE = "STATION_CURRENT_SONG::DISLIKE_UPDATE";
  20. const LIKED_UPDATE = "STATION_CURRENT_SONG::LIKED_UPDATE";
  21. const DISLIKED_UPDATE = "STATION_CURRENT_SONG::DISLIKED_UPDATE";
  22. const PAUSE_TIME = "STATION_CURRENT_SONG::PAUSE_TIME";
  23. const RESUME_TIME = "STATION_CURRENT_SONG::RESUME_TIME";
  24. const TIME_ELAPSED_UPDATE = "STATION_CURRENT_SONG::TIME_ELAPSED_UPDATE";
  25. function nextSong(song) {
  26. return {
  27. type: NEXT_SONG,
  28. song,
  29. }
  30. }
  31. function likeUpdate(likes) {
  32. return {
  33. type: LIKE_UPDATE,
  34. likes,
  35. }
  36. }
  37. function dislikeUpdate(dislikes) {
  38. return {
  39. type: DISLIKE_UPDATE,
  40. dislikes,
  41. }
  42. }
  43. function likedUpdate(liked) {
  44. return {
  45. type: LIKED_UPDATE,
  46. liked,
  47. }
  48. }
  49. function dislikedUpdate(disliked) {
  50. return {
  51. type: DISLIKED_UPDATE,
  52. disliked,
  53. }
  54. }
  55. function pauseTime(pausedAt) {
  56. return {
  57. type: PAUSE_TIME,
  58. pausedAt,
  59. }
  60. }
  61. function resumeTime(timePaused) {
  62. return {
  63. type: RESUME_TIME,
  64. timePaused,
  65. }
  66. }
  67. function timeElapsedUpdate() {
  68. return {
  69. type: TIME_ELAPSED_UPDATE,
  70. timeElapsed: calculateTimeElapsed(),
  71. }
  72. }
  73. const initialState = Map({
  74. "songId": "",
  75. "timings": Map({
  76. "duration": 0,
  77. "skipDuration": 0,
  78. "timeElapsed": 0,
  79. "timePaused": 0,
  80. "pausedAt": 0,
  81. "startedAt": 0,
  82. }),
  83. "title": "",
  84. "artists": [],
  85. "thumbnail": "",
  86. "playlists": List([]),
  87. "ratings": Map({
  88. "enabled": false,
  89. "likes": 0,
  90. "dislikes": 0,
  91. "liked": false,
  92. "disliked": false,
  93. }),
  94. });
  95. function reducer(state = initialState, action) {
  96. switch (action.type) {
  97. case NEXT_SONG:
  98. const { song } = action;
  99. if (song === null) return initialState;
  100. //TODO Handle no song event / Song being null event (so no song)
  101. const previousState = state;
  102. state = initialState;
  103. return state.merge({
  104. songId: song.songId,
  105. timings: Map({
  106. duration: song.timings.duration,
  107. skipDuration: song.timings.skipDuration,
  108. timeElapsed: 0,
  109. pausedAt: previousState.getIn(["timings", "pausedAt"]),
  110. timePaused: song.timings.timePaused,
  111. startedAt: song.timings.startedAt,
  112. }),
  113. title: song.title,
  114. artists: List(song.artists),
  115. thumbnail: song.thumbnail,
  116. ratings: Map({
  117. enabled: !(song.ratings.likes === -1 && song.ratings.dislikes === -1),
  118. likes: song.ratings.likes,
  119. dislikes: song.ratings.dislikes,
  120. liked: false,
  121. disliked: false,
  122. }),
  123. });
  124. case LIKE_UPDATE:
  125. const { likes } = action;
  126. state = state.setIn(["ratings", "likes"], likes);
  127. return state;
  128. case DISLIKE_UPDATE:
  129. const { dislikes } = action;
  130. state = state.setIn(["ratings", "dislikes"], dislikes);
  131. return state;
  132. case LIKED_UPDATE:
  133. const { liked } = action;
  134. state = state.setIn(["ratings", "liked"], liked);
  135. return state;
  136. case DISLIKED_UPDATE:
  137. const { disliked } = action;
  138. state = state.setIn(["ratings", "disliked"], disliked);
  139. return state;
  140. case PAUSE_TIME:
  141. const { pausedAt } = action;
  142. state = state.setIn(["timings", "pausedAt"], pausedAt);
  143. return state;
  144. case RESUME_TIME:
  145. const { timePaused } = action;
  146. state = state.setIn(["timings", "timePaused"], timePaused);
  147. return state;
  148. case TIME_ELAPSED_UPDATE:
  149. const { timeElapsed } = action;
  150. return state.setIn(["timings", "timeElapsed"], timeElapsed);
  151. }
  152. return state;
  153. }
  154. const actionCreators = {
  155. nextSong,
  156. likeUpdate,
  157. dislikeUpdate,
  158. likedUpdate,
  159. dislikedUpdate,
  160. pauseTime,
  161. resumeTime,
  162. timeElapsedUpdate,
  163. };
  164. const actionTypes = {
  165. NEXT_SONG,
  166. LIKE_UPDATE,
  167. DISLIKE_UPDATE,
  168. LIKED_UPDATE,
  169. DISLIKED_UPDATE,
  170. PAUSE_TIME,
  171. RESUME_TIME,
  172. TIME_ELAPSED_UPDATE,
  173. };
  174. export {
  175. actionCreators,
  176. actionTypes,
  177. };
  178. export default reducer;