diff --git a/js/actions/webamp.ts b/js/actions/webamp.ts index e51d900..f547d69 100644 --- a/js/actions/webamp.ts +++ b/js/actions/webamp.ts @@ -1,12 +1,16 @@ import { Action, Dispatch } from "redux"; import Webamp, * as WebampInstance from "webamp"; import { AppState } from "../reducers"; -import { PLAY, SET_WEBAMP } from "../reducers/webamp"; +import { PLAY, SET_CURRENT_TRACK, SET_WEBAMP } from "../reducers/webamp"; import { CLOSE_WEBAMP, OPEN_WEBAMP } from "../reducers/windows"; import SpotifyMedia from "../spotifymedia"; import { TrackFile } from "../types"; import { formatMetaToWebampMeta } from "../utils/dataTransfer"; +export type SetTrackCallback = ( + trackInfo: WebampInstance.LoadedURLTrack | null +) => void; + export function setOfflineWebamp(): any { return (dispatch: Dispatch, getState: () => AppState) => { const WebampConstructor: any = WebampInstance; @@ -87,6 +91,26 @@ export function setConnectedWebamp(): any { }; } +export const setOnTrackChangedCallback = (callback: SetTrackCallback) => ( + dispatch: Dispatch, + getState: () => AppState +) => { + const { + webamp: { webampObject } + } = getState(); + if (!webampObject) return; + webampObject.onTrackDidChange(callback); +}; + +export const setCurrentPlayedTrack = (track: WebampInstance.TrackInfo) => ( + dispatch: Dispatch +) => { + dispatch({ + type: SET_CURRENT_TRACK, + payload: { track } + }); +}; + export function openWebamp() { return (dispatch: Dispatch, getState: () => AppState) => { const { webampObject } = getState().webamp; diff --git a/js/components/App.tsx b/js/components/App.tsx index be910fd..29223f6 100644 --- a/js/components/App.tsx +++ b/js/components/App.tsx @@ -5,6 +5,7 @@ import styled, { createGlobalStyle } from "styled-components"; import packageJson from "../../package.json"; import { AppState } from "../reducers"; import Desktop from "./Desktop"; +import { MetaServices } from "./MetaServices"; import SelectionBox from "./Reusables/SelectionBox"; import Settings from "./Settings"; import TaskBar from "./TaskBar"; @@ -64,6 +65,7 @@ export default () => { CHANGELOG - {packageJson.version} */} + ); }; diff --git a/js/components/MetaServices/WinampHiddenMetadata.tsx b/js/components/MetaServices/WinampHiddenMetadata.tsx new file mode 100644 index 0000000..b5d9d9d --- /dev/null +++ b/js/components/MetaServices/WinampHiddenMetadata.tsx @@ -0,0 +1,23 @@ +import React, { FC } from "react"; +import { TrackInfo } from "webamp"; + +interface HiddenMetadataProps { + track?: TrackInfo; +} + +/*** + * Metadata used in web-scrobbler plugin. + * Web-scrobbler connectors use DOM elements to figure out what's playing now + * @see https://github.com/web-scrobbler/web-scrobbler/wiki/Connectors-development + */ +export const HiddenMetadata: FC = ({ track }) => ( +
+ {track && ( + <> +

{track.metaData.artist}

+

{track.metaData.title}

+

{track.metaData.album}

+ + )} +
+); diff --git a/js/components/MetaServices/index.tsx b/js/components/MetaServices/index.tsx new file mode 100644 index 0000000..ba2d2e3 --- /dev/null +++ b/js/components/MetaServices/index.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { AppState } from "../../reducers"; +import { HiddenMetadata } from "./WinampHiddenMetadata"; + +export const MetaServices = () => { + const trackInfo = useSelector((x: AppState) => x.webamp.currentTrack); + return ( + <> + + + ); +}; diff --git a/js/components/TaskBar/index.tsx b/js/components/TaskBar/index.tsx index 02158be..46544b7 100644 --- a/js/components/TaskBar/index.tsx +++ b/js/components/TaskBar/index.tsx @@ -2,6 +2,7 @@ import React, { FunctionComponent } from "react"; import { FaFolder, FaImage } from "react-icons/fa"; import { useDispatch, useSelector } from "react-redux"; import styled from "styled-components"; +import { TrackInfo } from "webamp"; import { setOnTop, toggleMinimize } from "../../actions/windows"; import { AppState } from "../../reducers"; import { SingleExplorerState } from "../../reducers/explorer"; @@ -18,6 +19,7 @@ const TaskBar: FunctionComponent = props => { ); const images = useSelector(selectImages); const windows = useSelector((state: AppState) => state.windows.windows); + const trackInfo = useSelector((x: AppState) => x.webamp.currentTrack); const windowOnTop = windows.find( w => w.position === findHighestPosition(windows) @@ -60,7 +62,7 @@ const TaskBar: FunctionComponent = props => { ); }; - const renderWinamp = (w: Window) => { + const renderWinamp = (w: Window, t: TrackInfo) => { const otherWindowOnTop = windows .filter(win => win.id !== w.id) .find( @@ -68,6 +70,9 @@ const TaskBar: FunctionComponent = props => { win.position === findHighestPosition(windows.filter(win => win.id !== w.id)) ); + const titleString = t + ? `${t.metaData.artist} - ${t.metaData.title}` + : "Winamp"; return ( { marginRight: 4 }} /> - {"Winamp"} + {titleString} ); }; @@ -146,13 +151,12 @@ const TaskBar: FunctionComponent = props => { return renderExplorer(window); } if (window.type === WINDOW_TYPE.Webamp) { - return renderWinamp(window); + return renderWinamp(window, trackInfo); } if (window.type === WINDOW_TYPE.Image) { return renderImage(window); } })} - F ); }; diff --git a/js/components/Webamp/index.tsx b/js/components/Webamp/index.tsx index b1a93d7..95bc2d8 100644 --- a/js/components/Webamp/index.tsx +++ b/js/components/Webamp/index.tsx @@ -5,7 +5,9 @@ import { openWebamp, removeWebamp, setConnectedWebamp, - setOfflineWebamp + setCurrentPlayedTrack, + setOfflineWebamp, + setOnTrackChangedCallback } from "../../actions/webamp"; import { AppState } from "../../reducers"; @@ -23,6 +25,9 @@ export default () => { if (webampObject) { dispatch(removeWebamp()); dispatch(setConnectedWebamp()); + dispatch( + setOnTrackChangedCallback(x => dispatch(setCurrentPlayedTrack(x))) + ); } } else dispatch(setOfflineWebamp()); diff --git a/js/reducers/index.ts b/js/reducers/index.ts index 6f214a1..c4f823d 100644 --- a/js/reducers/index.ts +++ b/js/reducers/index.ts @@ -12,7 +12,7 @@ import searchPagination, { initialStateSearchPagination, SearchPaginationState } from "./search-pagination"; -import settings, { initialSettingsState } from "./settings"; +import settings, { initialSettingsState, SettingsState } from "./settings"; import theme, { ThemeState } from "./theme"; import user, { initialStateUser, UserState } from "./user"; import webamp, { initialStateWebamp, WebampState } from "./webamp"; diff --git a/js/reducers/webamp.ts b/js/reducers/webamp.ts index aa88a8f..82758c7 100644 --- a/js/reducers/webamp.ts +++ b/js/reducers/webamp.ts @@ -9,14 +9,17 @@ export enum WEBAMP_STATUS { export interface WebampState { webampObject: Webamp; status: WEBAMP_STATUS; + currentTrack?: WebampInstance.TrackInfo; } export const initialStateWebamp: WebampState = { webampObject: null, - status: WEBAMP_STATUS.STOPPED + status: WEBAMP_STATUS.STOPPED, + currentTrack: null }; export const SET_WEBAMP = "SET_WEBAMP"; +export const SET_CURRENT_TRACK = "SET_CURRENT_TRACK"; export const PLAY = "PLAY"; const webamp = (state: WebampState = initialStateWebamp, action: any) => { @@ -31,6 +34,11 @@ const webamp = (state: WebampState = initialStateWebamp, action: any) => { ...state, status: WEBAMP_STATUS.PLAYING }; + case SET_CURRENT_TRACK: + return { + ...state, + currentTrack: action.payload.track + }; default: return state; }