diff --git a/Makefile b/Makefile index be52b7b..6e09d50 100644 --- a/Makefile +++ b/Makefile @@ -32,9 +32,10 @@ APP_MIME_SIG = application/x-vnd.mediamonitor # same name (source.c or source.cpp) are included from different directories. # Also note that spaces in folder names do not work well with this Makefile. SRCS = src/App.cpp \ - src/MainWindow.cpp \ src/CoverView.cpp \ src/LyricsView.cpp \ + src/MainWindow.cpp \ + src/MediaPlayer.cpp \ src/Song.cpp # Specify the resource definition files to use. Full or relative paths can be diff --git a/src/CoverView.cpp b/src/CoverView.cpp index 9ac36ba..73a11e1 100644 --- a/src/CoverView.cpp +++ b/src/CoverView.cpp @@ -9,7 +9,7 @@ #include #include -#include "Song.h" +#include "MediaPlayer.h" CoverView::CoverView(BRect frame) @@ -22,6 +22,8 @@ CoverView::CoverView(BRect frame) fDragger->SetViewColor(B_TRANSPARENT_COLOR); AddChild(fDragger); + fMediaPlayer = new MediaPlayer(0); + fCover = NULL; SetViewColor(B_TRANSPARENT_COLOR); Pulse(); @@ -32,6 +34,10 @@ CoverView::CoverView(BMessage* data) : BView(data) { + BMessage mediaplayer; + data->FindMessage("mediaplayer", &mediaplayer); + fMediaPlayer = new MediaPlayer(&mediaplayer); + fCover = NULL; SetViewColor(B_TRANSPARENT_COLOR); Pulse(); @@ -42,6 +48,10 @@ status_t CoverView::Archive(BMessage* data, bool deep) const { status_t status = BView::Archive(data, deep); + + BMessage mediaPlayer; + fMediaPlayer->Archive(&mediaPlayer); + data->AddMessage("mediaplayer", &mediaPlayer); data->AddString("class", "CoverView"); data->AddString("add_on", "application/x-vnd.mediamonitor"); return status; @@ -60,17 +70,18 @@ CoverView::Instantiate(BMessage* data) void CoverView::Pulse() { - BString path = _GetCurrentPath(); - if (path.IsEmpty() == false && path != fCurrentPath) { - fCurrentPath = path; - Song song(path.String()); + Song song; + if (fMediaPlayer->CurrentItem(&song, false) == false) { + if (fCurrentSong.InitCheck()) { + fCurrentSong = song; + delete fCover; + Invalidate(); + } + } else if (song != fCurrentSong) { + fCurrentSong = song; delete fCover; fCover = song.Cover(); Invalidate(); - } else if (path.IsEmpty() && path != fCurrentPath) { - fCurrentPath = path; - delete fCover; - Invalidate(); } } @@ -83,19 +94,3 @@ CoverView::Draw(BRect updateRect) if (fCover != NULL && fCover->IsValid()) DrawBitmap(fCover, Bounds()); } - - -BString -CoverView::_GetCurrentPath() -{ - BMessage message, reply; - message.what = B_GET_PROPERTY; - message.AddSpecifier("URI"); - message.AddSpecifier("CurrentTrack"); - message.AddSpecifier("Window", 0); - BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, &reply); - - BString result; - reply.FindString("result", &result); - return result.ReplaceAll("file://", ""); -} diff --git a/src/CoverView.h b/src/CoverView.h index 8157a05..5f57e1c 100644 --- a/src/CoverView.h +++ b/src/CoverView.h @@ -7,7 +7,10 @@ #include +#include "Song.h" + class BDragger; +class MediaPlayer; class CoverView : public BView { @@ -24,12 +27,12 @@ public: private: void _Init(BRect frame); - BString _GetCurrentPath(); - BString _GetCoverPath(); + + MediaPlayer* fMediaPlayer; + Song fCurrentSong; BDragger* fDragger; BBitmap* fCover; - BString fCurrentPath; }; #endif // COVERVIEW_H diff --git a/src/LyricsView.cpp b/src/LyricsView.cpp index 2e3fbdd..2e7fc69 100644 --- a/src/LyricsView.cpp +++ b/src/LyricsView.cpp @@ -5,8 +5,6 @@ #include "LyricsView.h" -#include - #include #include #include @@ -14,7 +12,7 @@ #include #include -#include "Song.h" +#include "MediaPlayer.h" LyricsTextView::LyricsTextView(BRect frame, const char* name, BRect textFrame, @@ -93,6 +91,8 @@ LyricsView::LyricsView(BRect frame) fFgColor = ui_color(B_PANEL_TEXT_COLOR); fBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); + fMediaPlayer = new MediaPlayer(0); + _Init(frame); } @@ -117,6 +117,10 @@ LyricsView::LyricsView(BMessage* data) data->FindBool("transparent_inactivity", &fTransparentInactivity); data->FindBool("transparent_dragger", &fTransparentDragger); + BMessage mediaplayer; + data->FindMessage("mediaplayer", &mediaplayer); + fMediaPlayer = new MediaPlayer(&mediaplayer); + _Init(Frame()); } @@ -125,15 +129,19 @@ status_t LyricsView::Archive(BMessage* data, bool deep) const { status_t status = BView::Archive(data, deep); + + BMessage mediaPlayer; + fMediaPlayer->Archive(&mediaPlayer); + data->AddMessage("mediaplayer", &mediaPlayer); data->AddColor("background_color", fBgColor); data->AddColor("foreground_color", fFgColor); data->AddBool("autoscroll", fAutoScroll); data->AddBool("transparent_inactivity", fTransparentInactivity); data->AddBool("transparent_dragger", fTransparentDragger); + data->AddString("class", "LyricsView"); data->AddString("add_on", "application/x-vnd.mediamonitor"); - data->PrintToStream(); return status; } @@ -178,7 +186,7 @@ LyricsView::MessageReceived(BMessage* msg) if (msg->what == LYRICS_TRANSPARENTLY_DRAG) fTransparentDragger = !fTransparentDragger; - if (fCurrentPath.IsEmpty()) + if (fCurrentSong.InitCheck() == false) _ClearText(); break; } @@ -192,16 +200,20 @@ LyricsView::MessageReceived(BMessage* msg) void LyricsView::Pulse() { - BString path = _GetCurrentPath(); - if (path.IsEmpty() == false && path != fCurrentPath) { - fCurrentPath = path; - Song song(path.String()); + Song song; + if (fMediaPlayer->CurrentItem(&song, fAutoScroll) == false) { + if (fCurrentSong.InitCheck()) { + fCurrentSong = song; + _ClearText(); + } + return; + } + + if (song != fCurrentSong) { + fCurrentSong = song; BString lyrics; song.Lyrics(&lyrics); _SetText(lyrics.String()); - } else if (path.IsEmpty() && path != fCurrentPath) { - fCurrentPath = path; - _ClearText(); } if (fAutoScroll) { @@ -334,45 +346,12 @@ LyricsView::_RightClickPopUp() } -BString -LyricsView::_GetCurrentPath() -{ - BMessage message, reply; - message.what = B_GET_PROPERTY; - message.AddSpecifier("URI"); - message.AddSpecifier("CurrentTrack"); - message.AddSpecifier("Window", 0); - BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, &reply); - - BString result; - reply.FindString("result", &result); - return result.ReplaceAll("file://", ""); -} - - float LyricsView::_GetPositionProportion() { - int64 position = _GetIntProperty("Position"); - int64 duration = _GetIntProperty("Duration", true); + int64 position = fMediaPlayer->Position(); + int64 duration = fCurrentSong.Duration(); if (position >= 0 && duration > 0) return (float)position / (float)duration; return -1.0; } - - -int64 -LyricsView::_GetIntProperty(const char* specifier, bool currentItem) -{ - BMessage message, reply; - message.what = B_GET_PROPERTY; - message.AddSpecifier(specifier); - if (currentItem) - message.AddSpecifier("CurrentTrack"); - message.AddSpecifier("Window", 0); - BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, &reply); - - int64 result = -1; - reply.FindInt64("result", &result); - return result; -} diff --git a/src/LyricsView.h b/src/LyricsView.h index 3e3440f..b80314e 100644 --- a/src/LyricsView.h +++ b/src/LyricsView.h @@ -7,9 +7,12 @@ #include +#include "Song.h" + class BDragger; class BPopUpMenu; class BScrollView; +class MediaPlayer; enum { @@ -55,9 +58,10 @@ private: BPopUpMenu* _RightClickPopUp(); - BString _GetCurrentPath(); float _GetPositionProportion(); - int64 _GetIntProperty(const char* specifier, bool currentTrack = false); + + MediaPlayer* fMediaPlayer; + Song fCurrentSong; LyricsTextView* fTextView; BScrollView* fScrollView; @@ -69,7 +73,6 @@ private: rgb_color fBgColor; rgb_color fFgColor; - BString fCurrentPath; }; #endif // LYRICSVIEW_H diff --git a/src/MediaPlayer.cpp b/src/MediaPlayer.cpp new file mode 100644 index 0000000..e4ed23c --- /dev/null +++ b/src/MediaPlayer.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2022, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "MediaPlayer.h" + +#include +#include + +#include "Song.h" + + +MediaPlayer::MediaPlayer(int32 window) +{ + fWindowIndex = window; +} + + +MediaPlayer::MediaPlayer(BMessage* data) + : + BArchivable(data) +{ + fWindowIndex = data->GetInt32("_window", 0); +} + + +status_t +MediaPlayer::Archive(BMessage* data, bool deep) const +{ + status_t status = BArchivable::Archive(data, deep); + data->AddInt32("_window", fWindowIndex); + data->AddString("class", "MediaPlayer"); + data->AddString("add_on", "application/x-vnd.mediamonitor"); + return status; +} + + +MediaPlayer* +MediaPlayer::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data, "MediaPlayer")) + return NULL; + return new MediaPlayer(data); +} + + +bool +MediaPlayer::IsPlaying() +{ + BMessage reply; + _GetResponse("IsPlaying", &reply); + return reply.GetBool("result", false); +} + + +int64 +MediaPlayer::Position() +{ + BMessage reply; + _GetResponse("Position", &reply); + return reply.GetInt64("result", -1); +} + + +bool +MediaPlayer::CurrentItem(Song* song, bool duration) +{ + return _GetSong(song, MP_CURRENT_TRACK, duration); +} + + +bool +MediaPlayer::PlaylistItem(Song* song, int32 index, bool duration) +{ + return _GetSong(song, index, duration); +} + + +int32 +MediaPlayer::SetWindow(int32 index) +{ + if (index < CountWindows()) + return fWindowIndex = index; + else + return -1; +} + + +int32 +MediaPlayer::CountWindows() +{ + BMessage reply; + _GetResponse("Window", &reply, MP_NO_TRACK, B_COUNT_PROPERTIES); + + int32 count; + if (reply.FindInt32("result", &count) == B_OK) + return count; + return -1; +} + + +bool +MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationRequired) +{ + BMessage reply; + _GetResponse("URI", &reply, trackIndex); + BString uriString; + if (reply.FindString("result", &uriString) != B_OK) + return false; + + int64 duration = -1; + if (durationRequired) { + _GetResponse("Duration", &reply, trackIndex); + if (reply.FindInt64("result", &duration) != B_OK) + return false; + } + + *song = Song(_UriToPath(uriString), duration); + return true; +} + + +void +MediaPlayer::_GetResponse(const char* attribute, BMessage* reply, int32 trackIndex, int32 what) +{ + BMessage message; + message.what = what; + message.AddSpecifier(attribute); + if (trackIndex > 0) + message.AddSpecifier("PlaylistTrack", trackIndex); + else if (trackIndex == MP_CURRENT_TRACK) + message.AddSpecifier("CurrentTrack"); + message.AddSpecifier("Window", fWindowIndex); + BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, reply); +} + + +const char* +MediaPlayer::_UriToPath(BString URI) +{ + if (URI.StartsWith("file://")) + return URI.ReplaceFirst("file://", "").String(); + else + return NULL; +} diff --git a/src/MediaPlayer.h b/src/MediaPlayer.h new file mode 100644 index 0000000..936cbf0 --- /dev/null +++ b/src/MediaPlayer.h @@ -0,0 +1,48 @@ +/* + * Copyright 2022, Jaidyn Levesque + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef MEDIAPLAYER_H +#define MEDIAPLAYER_H + +#include +#include +#include + +class BMessage; +class Song; + + +enum { + MP_CURRENT_TRACK = -1, + MP_NO_TRACK = -2 +}; + + +class MediaPlayer : public BArchivable { +public: + MediaPlayer(int32 window = 0); + MediaPlayer(BMessage* archive); + + virtual status_t Archive(BMessage* data, bool deep = true) const; + static MediaPlayer* Instantiate(BMessage* data); + + + bool IsPlaying(); + int64 Position(); + bool CurrentItem(Song* song, bool duration = true); + bool PlaylistItem(Song* song, int32 index, bool duration = true); + + int32 SetWindow(int32 index); + int32 CountWindows(); + +private: + bool _GetSong(Song* song, int32 trackIndex, bool durationRequired = true); + void _GetResponse(const char* attribute, BMessage* reply, + int32 trackIndex = MP_NO_TRACK, int32 what = B_GET_PROPERTY); + const char* _UriToPath(BString URI); + + int32 fWindowIndex; +}; + +#endif // MEDIAPLAYER_H diff --git a/src/Song.cpp b/src/Song.cpp index 68a824c..550d123 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -13,9 +13,22 @@ #include -Song::Song(const char* path) +Song::Song() +{ +} + + +Song::Song(const char* path, int64 duration) { fPath = BPath(path); + fDuration = duration; +} + + +bool +Song::InitCheck() +{ + return fPath.InitCheck() == B_OK && fDuration >= -1; } @@ -44,6 +57,20 @@ Song::Cover() } +BPath +Song::Path() +{ + return fPath; +} + + +int64 +Song::Duration() +{ + return fDuration; +} + + // Our song's leaf, sans file extension const char* Song::_FileLeaf() diff --git a/src/Song.h b/src/Song.h index 5b34647..a691df3 100644 --- a/src/Song.h +++ b/src/Song.h @@ -11,9 +11,31 @@ class BBitmap; class Song { public: - Song(const char* path); - status_t Lyrics(BString* buffer); - BBitmap* Cover(); + Song(); + Song(const char* path, int64 duration = -1); + + bool InitCheck(); + + status_t Lyrics(BString* buffer); + BBitmap* Cover(); + + BPath Path(); + int64 Duration(); + + int operator ==(Song a) + { + if (a.Path() == fPath) + return 1; + return 0; + } + + + int operator !=(Song a) + { + if (a.Path() != fPath) + return 1; + return 0; + } private: const char* _FileLeaf(); @@ -24,6 +46,7 @@ private: BPath _AnyFileOfType(const char* mimeRoot); BPath _FindFile(const char* mimeRoot, bool byName); + int64 fDuration; BPath fPath; };