Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Livemetadata PR #1675

Closed
wants to merge 79 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
32cece7
Added .vscode on gitignore
davidhm May 5, 2018
ba829a2
First few files
davidhm May 14, 2018
5169748
So far manual tests are working
davidhm May 16, 2018
3d8c501
Pre automatic tests
davidhm May 18, 2018
523d09b
Using github as a backup
davidhm May 18, 2018
23ef862
Error when compiling moc generated cpp
davidhm May 20, 2018
0a4a4d6
WIP: Automatic tests
davidhm May 23, 2018
d203e85
Moved timers away from Track object
davidhm May 24, 2018
1a6bc0d
Pre volume scrobbling
davidhm May 26, 2018
ff27795
Pre tests, scrobbling manager
davidhm May 27, 2018
db2db23
Deadlock
davidhm May 30, 2018
7f55150
Solved the deadlock, simple tests pass
davidhm Jun 1, 2018
121443e
WIP: Adding file listener
davidhm Jun 2, 2018
2cd5bbc
Fixed file buffer, it's automatically updated now
davidhm Jun 3, 2018
b9c4a6c
[Untested] Fixed file info, modified metadatabroadcast
davidhm Jun 5, 2018
e10df9e
[WIP] Adding tests for scrobbling manager
davidhm Jun 7, 2018
c1de7db
Added first test for scrobbling manager
davidhm Jun 9, 2018
50019b0
File listener template + factory
davidhm Jun 10, 2018
d805306
Scrobbling tests done
davidhm Jun 12, 2018
4e714d5
[WIP] Adding file preferences
davidhm Jun 12, 2018
b3f8ea8
Preferences mock-up
davidhm Jun 13, 2018
8cd9c16
Changed everything to a weak pointer
davidhm Jun 13, 2018
d4b9aa5
Added file listener path in options
davidhm Jun 14, 2018
ec98ef6
[WIP] Persistent config now playing file
davidhm Jun 14, 2018
0209b4a
[WIP] Requested changes
davidhm Jun 15, 2018
2d8f4a2
Adding new tab
davidhm Jun 17, 2018
88c4819
Added mock-up in preferences
davidhm Jun 17, 2018
ab8b524
Table view mockup
davidhm Jun 18, 2018
97daf77
Pre changing prefmetadata class
davidhm Jun 19, 2018
4bc2de3
Added file settings
davidhm Jun 20, 2018
49b8b93
[Untested] Added options to file listener
davidhm Jun 20, 2018
567e9b5
Modified settings, added concurrency
davidhm Jun 23, 2018
5748fa9
Added dedicated thread
davidhm Jun 26, 2018
3a677b6
Modified author and title string
davidhm Jun 26, 2018
9c43d09
Merge branch 'master' into Livemetadata
davidhm Jun 26, 2018
2c21183
Added connections to lambda expressions in player manager, file liste…
davidhm Jun 28, 2018
a6d67d7
Fixed tests failing
davidhm Jun 29, 2018
ba8a6fc
Added mock network manager, gotta test with mock server
davidhm Jul 1, 2018
6b7f207
Now listening scrobbles work with ListenBrainz
davidhm Jul 5, 2018
f7c6a83
Deleted log file
davidhm Jul 5, 2018
1057b06
Merge branch 'master' into Livemetadata
davidhm Jul 6, 2018
152925c
ListenBrainz full scrobbles work now too
davidhm Jul 6, 2018
ad43628
Fixed double delete in developer mode
davidhm Jul 7, 2018
751f567
Forgot to compile
davidhm Jul 7, 2018
64d35c5
Modified metadata file options
davidhm Jul 7, 2018
ddfb859
Editable combobox
davidhm Jul 9, 2018
e4dc8df
Added mpris stub, not working
davidhm Jul 11, 2018
a1ad4c6
MPRIS now reflects the playback state
davidhm Jul 12, 2018
ee4c5a5
Disabled failing test until a solution is found
davidhm Jul 13, 2018
4571d43
Fixed broken tests, continuing MPRIS implementation
davidhm Jul 18, 2018
185d2f2
Fixed non compiling build
davidhm Jul 18, 2018
0bc22be
Segfault on weak_ptr
davidhm Jul 19, 2018
0af2279
Fixed eject bug
davidhm Jul 19, 2018
6be0042
Mpris reflects AutoDJ enabled
davidhm Jul 19, 2018
62eae49
Pause, play and go next MPRIS functions work
davidhm Jul 21, 2018
c2317c7
Fixed correct fade-in in MPRIS
davidhm Jul 22, 2018
8b5e54a
Added volume, playback status and loop status as well as a LINUX define
davidhm Jul 23, 2018
cac8c1f
Moved MPRIS into a feature
davidhm Jul 24, 2018
6807838
Added MPRIS macro in includes too
davidhm Jul 24, 2018
d6880a1
MPRIS is seekable now
davidhm Jul 24, 2018
32e565a
MPRIS broadcasts current track and rate works now too
davidhm Jul 25, 2018
1b77c8b
Modified linked lists into hash maps
davidhm Aug 1, 2018
7ba10a7
Added space after commas
davidhm Aug 1, 2018
94ab525
Changed ref ampersand and disabled non working test
davidhm Aug 1, 2018
5e8fb60
Added more button in encoding combo box
davidhm Aug 3, 2018
41bdfb9
Resized combobox
davidhm Aug 6, 2018
0def3e3
Merge remote-tracking branch 'upstream/master' into Livemetadata
davidhm Aug 6, 2018
9fe5277
Added few UI suggestions
davidhm Aug 6, 2018
97271d8
Missing include
davidhm Aug 7, 2018
f4b9649
Added cover art to mpris
davidhm Aug 11, 2018
dde6c47
Added cover art to MPRIS player
davidhm Aug 12, 2018
e1cfd7a
Fixed few things
davidhm Aug 14, 2018
69a3020
Deleting all cover art files
davidhm Aug 17, 2018
7af4dd7
Single file image
davidhm Aug 17, 2018
170e6c9
Cover art file is now QTemporaryFile
davidhm Aug 18, 2018
8c6fa58
Revamped encoding combobox
davidhm Aug 18, 2018
899f207
Fixed some cover URL generation issues
daschuer Aug 19, 2018
4a13665
Small fixes
davidhm Aug 20, 2018
39dc901
Merge pull request #1 from daschuer/Livemetadata
davidhm Aug 20, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ lib/*/*.lib
lib/*/lib/*.lib

lib/qtscript-bytearray/*.cc

nowListening.txt
7 changes: 7 additions & 0 deletions build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ def configure(self, build, conf):
class TestHeaders(Dependence):
def configure(self, build, conf):
build.env.Append(CPPPATH="#lib/gtest-1.7.0/include")
build.env.Append(CPPPATH="#lib/gmock-1.7.0/include")

class FidLib(Dependence):
def sources(self, build):
Expand Down Expand Up @@ -663,6 +664,10 @@ def sources(self, build):
"control/controlttrotary.cpp",
"control/controlencoder.cpp",

"broadcast/metadatabroadcast.cpp",
"broadcast/scrobblingmanager.cpp",
"broadcast/filelistener.cpp",

"controllers/dlgcontrollerlearning.cpp",
"controllers/dlgprefcontroller.cpp",
"controllers/dlgprefcontrollers.cpp",
Expand Down Expand Up @@ -1093,6 +1098,8 @@ def sources(self, build):
"track/trackinfo.cpp",
"track/trackrecord.cpp",
"track/trackref.cpp",
"track/trackplaytimers.cpp",
"track/tracktiminginfo.cpp",

"mixer/auxiliary.cpp",
"mixer/baseplayer.cpp",
Expand Down
32 changes: 32 additions & 0 deletions src/broadcast/filelistener.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#include "broadcast/filelistener.h"


FileListener::FileListener(const QString &path) :
m_file(path)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no new line before {

QFileInfo fileInfo(path);
qDebug() << "Absolute path " << fileInfo.absoluteFilePath();
qDebug() << "File exists: " << fileInfo.exists();
m_file.open(QIODevice::WriteOnly |
QIODevice::Text |
QIODevice::Unbuffered);

}

FileListener::~FileListener() {
m_file.resize(0);
}

void FileListener::broadcastCurrentTrack(TrackPointer pTrack) {
if (!pTrack)
return;
QTextStream stream(&m_file);
m_file.resize(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment helps here:
// clear file

stream << "Now listening " << pTrack->getTitle();
stream << " by " << pTrack->getArtist();
}

void FileListener::scrobbleTrack(TrackPointer pTrack) {

}
14 changes: 14 additions & 0 deletions src/broadcast/filelistener.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <QFile>
#include "broadcast/scrobblingservice.h"

class FileListener: public ScrobblingService {
public:
FileListener(const QString &path);
~FileListener();
void broadcastCurrentTrack(TrackPointer pTrack) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inheritance is unnecessary. The file listener could be implemented as a standalone class with 2 slots, connected to the ScrobblingService.

Copy link
Contributor Author

@davidhm davidhm Jun 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to have N services that connect to the scrobbling manager that answer to both slots. If I take one implementation out of the hierarchy then I have to update that separately. It also doesn't allow me to mock up the file listener. I don't see any advantage on breaking the inheritance. Can you elaborate on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scrobbling manager can offer 2 public signals for this purpose and dependent services can connect to them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but who owns the services? I was thinking of getting a list of services from the user settings, pass them to the scobbling manager and then simply keep them updated. I find the manager owning a list of services to be easier to mantain than creating a connection for every service and storing them somewhere else.

void scrobbleTrack(TrackPointer pTrack) override;
private:
QFile m_file;
};
77 changes: 77 additions & 0 deletions src/broadcast/metadatabroadcast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

#include <QLinkedListIterator>

#include "broadcast/metadatabroadcast.h"
#include "mixer/playerinfo.h"

MetadataBroadcaster::MetadataBroadcaster()
{

}

void MetadataBroadcaster::slotAttemptScrobble(TrackPointer pTrack) {
for (auto it = m_trackedTracks.begin();
it != m_trackedTracks.end();
++it) {
if (*it == GracePeriod(0,pTrack)) {
GracePeriod &trackPeriod = *it;
if (trackPeriod.hasBeenEjected &&
trackPeriod.m_msElapsed >
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use 8 space indent for line brakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean here, which line break? All of them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line brakes because of long lines = 8 spaces.
Parentheses alignment, does not work, because it is 4 spaces you cannot distinguish it from logical indent.

if (trackPeriod.hasBeenEjected &&
        trackPeriod.m_msElapsed > 

static_cast<double>(m_gracePeriodSeconds)*1000.0) {
for (auto &service : m_scrobblingServices) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use universal reference, for non const for loops: auto&& and const auto& for const loops. If the container is an implicit shared qt container you need also to ad as_const cast to avoid a deep copy of the container.

We allign & && and * with the type (no space) please check the whole PR for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, thanks.

service->scrobbleTrack(pTrack);
}
trackPeriod.hasBeenEjected = false;
trackPeriod.m_numberOfScrobbles++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please comment these conditions. They are hard to understand. Maybe we can optimize the variable names as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the names are ok? Do you have any proposal?

}
break;
}
}
}

void MetadataBroadcaster::slotNowListening(TrackPointer pTrack) {
for (auto &service : m_scrobblingServices) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is essentially a manually implemented synchronous pub/sub communication. Why don't you use Qt signal/slots for this purpose with all their thread-safety guarantees?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't use slots because I control when to call the services and I own the metadata broadcast object, which lives in the same thread as the scrobbling manager. Since I know when I will call the services and I don't need queued connections I didn't see any reason to use signals & slots.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Send everything that you need at the receiver side by value, i.e. wrap it into a queueable meta-type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean all the track metadata so the services don't have to store a pointer? Like a DTO?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto&

service->broadcastCurrentTrack(pTrack);
}
}

QLinkedList<TrackId> MetadataBroadcaster::getTrackedTracks() {
//Stub
return QLinkedList<TrackId>();
}

MetadataBroadcaster& MetadataBroadcaster::addNewScrobblingService(ScrobblingService *service) {
m_scrobblingServices.push_back(
std::move(std::unique_ptr<ScrobblingService>(service)));
return *this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does retiring this makes sense? The caller had it anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this was intended to chain adds, I guess it doesn't matter now.

}

void MetadataBroadcaster::newTrackLoaded(TrackPointer pTrack) {
QLinkedListIterator<GracePeriod> it(m_trackedTracks);
if (!it.findNext(GracePeriod(0,pTrack))) {
GracePeriod newPeriod(0,pTrack);
m_trackedTracks.append(newPeriod);
}
}

void MetadataBroadcaster::trackUnloaded(TrackPointer pTrack) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use one word for the same action
Unload vs eject.

for (auto it = m_trackedTracks.begin();
it != m_trackedTracks.end();
++it) {
if (*it == GracePeriod(0,pTrack)) {
it->hasBeenEjected = true;
it->m_msElapsed = 0;
}
break;
}
}

void MetadataBroadcaster::slotGuiTick(double timeSinceLastTick) {
for (auto it = m_trackedTracks.begin();
it != m_trackedTracks.end();
++it) {
if (it->hasBeenEjected) {
it->m_msElapsed += timeSinceLastTick;
}
}
}
43 changes: 43 additions & 0 deletions src/broadcast/metadatabroadcast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <QObject>
#include <QLinkedList>
#include <list>

#include "broadcast/scrobblingservice.h"
#include "track/track.h"
#include "track/trackid.h"
#include "track/trackplaytimers.h"

class MetadataBroadcaster : public QObject {
Q_OBJECT
private:
struct GracePeriod {
double m_msElapsed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since what?
Can this be m_msAge?
Any better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps m_msSinceEjection?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, if it count the time since ejection.

unsigned int m_numberOfScrobbles = 0;
TrackId m_trackId;
bool hasBeenEjected = false;
GracePeriod(double msElapsed,TrackPointer pTrack) :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please improve line breakers, to match the rest of Mixxx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry, I forgot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pass directly the Id, to document that this class ties not store a reference.
In general we should pass raw pointers if the function prommisses not to store the pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright.

m_msElapsed(msElapsed),m_trackId(pTrack->getId()) {}
bool operator==(const GracePeriod &other) const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is this used? It is not a fully compare of al elements so it requires some comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QLinkedListIterator uses it, I don't know if it's better to use that class or do a manual loop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to use a QHash with a m_trackId as key. That makes the code more explicit.

return m_trackId == other.m_trackId;
}
};
public:

MetadataBroadcaster();
QLinkedList<TrackId> getTrackedTracks();
MetadataBroadcaster& addNewScrobblingService(ScrobblingService *service);
void newTrackLoaded(TrackPointer pTrack);
void trackUnloaded(TrackPointer pTrack);
void setGracePeriod(unsigned int seconds);

public slots:
void slotAttemptScrobble(TrackPointer pTrack);
void slotNowListening(TrackPointer pTrack);
void slotGuiTick(double timeSinceLastTick);
private:
unsigned int m_gracePeriodSeconds;
QLinkedList<GracePeriod> m_trackedTracks;
std::list<std::unique_ptr<ScrobblingService>> m_scrobblingServices;
};
Loading