Compare commits

..

141 Commits
0.2.1 ... 0.3.3

Author SHA1 Message Date
Jonas Kvinge
50e3eeaafd Release 0.3.3 2018-09-24 19:13:45 +02:00
Jonas Kvinge
843f528ebc Revert change to Tidal login using clientUniqueKey 2018-09-24 19:10:49 +02:00
Jonas Kvinge
faa0076988 Turn back git revision 2018-09-24 19:10:15 +02:00
Jonas Kvinge
59622c52ad Release 0.3.2 2018-09-24 18:42:21 +02:00
Jonas Kvinge
a8e9aba58b Save password as QString 2018-09-24 18:40:05 +02:00
Jonas Kvinge
36563cd1e1 Fix compile 2018-09-22 23:32:11 +02:00
Jonas Kvinge
072e712f0d Add missing QUrl include 2018-09-22 23:30:19 +02:00
Jonas Kvinge
121a186160 Improve contextview and engine code 2018-09-22 23:13:56 +02:00
Jonas Kvinge
15a2ccc21e Change size of comboxes in device settings 2018-09-22 15:54:38 +02:00
Jonas Kvinge
dbd8ea69eb Turn off debug about in Tidal 2018-09-22 15:39:24 +02:00
Jonas Kvinge
8a57356f64 More Tidal fixes 2018-09-22 15:37:42 +02:00
Jonas Kvinge
c77cb002f3 Add support for both ALSA hw and plughw 2018-09-21 23:29:00 +02:00
Jonas Kvinge
aa83a2b40b Add option to change url stream scheme for Tidal 2018-09-21 18:53:27 +02:00
Jonas Kvinge
65b04cac6e Update changelog 2018-09-21 01:20:16 +02:00
Jonas Kvinge
5e577190a8 Fix some copyrights 2018-09-21 01:12:21 +02:00
Jonas Kvinge
0143617056 Fix bug setting wrong temp metadata and bug in pipeline 2018-09-21 00:34:02 +02:00
Jonas Kvinge
a77dde7d3b Fix some includes 2018-09-20 22:48:52 +02:00
Jonas Kvinge
7dcdb7c673 Might be a good idea to actually add the URL Handler :) 2018-09-20 22:37:38 +02:00
Jonas Kvinge
6de8eb56cd Remove dead code in Tidal 2018-09-20 22:29:35 +02:00
Jonas Kvinge
04e272d9bc Fix mistake 2018-09-20 22:22:48 +02:00
Jonas Kvinge
17fe201473 Use URL Handler for Tidal 2018-09-20 22:13:30 +02:00
Jonas Kvinge
25249be37f Change orange to red 2018-09-20 17:44:31 +02:00
Jonas Kvinge
97ec12b5b3 Don't compile devices on windows 2018-09-20 17:36:23 +02:00
Jonas Kvinge
246f82bfad Replace obsolete QStyleOptionViewItemV2-4 2018-09-18 22:17:28 +02:00
Jonas Kvinge
db5679bbe9 Fix lsb-release command 2018-09-18 19:01:59 +02:00
Jonas Kvinge
feb0e1c45b Fix Fedora RPM suffix 2018-09-18 18:43:04 +02:00
Jonas Kvinge
edba837295 Fix RPM Suffix 2018-09-18 17:28:49 +02:00
Jonas Kvinge
55882360ef Fix RPM suffix 2018-09-18 00:45:33 +02:00
Jonas Kvinge
6039370ad6 Fix exclude 2018-09-18 00:45:07 +02:00
Jonas Kvinge
2d238c08d3 Change output filename 2018-09-18 00:31:21 +02:00
Jonas Kvinge
9b337b6a34 Add missing nsi 2018-09-17 19:30:23 +02:00
Jonas Kvinge
370db791aa Add nsi files for x86_64-w64-mingw32 2018-09-17 01:02:48 +02:00
Jonas Kvinge
9e3c547580 Turn back on git revision 2018-09-16 23:13:30 +02:00
Jonas Kvinge
ab5d9b62b8 Fix search error not shown in Tidal search 2018-09-15 22:34:44 +02:00
Jonas Kvinge
8e35e0c476 Release 0.3.1 2018-09-15 19:22:55 +02:00
Jonas Kvinge
9d9492b528 Update README.md 2018-09-15 13:46:29 +02:00
Jonas Kvinge
9732cc2ce2 Update README.md 2018-09-15 13:45:26 +02:00
Jonas Kvinge
a4beea3f34 Update README.md 2018-09-15 13:43:33 +02:00
Jonas Kvinge
c9256c52bf Check for QT version 2018-09-15 13:35:03 +02:00
Jonas Kvinge
6563bec7e4 Remove builtin qtwin and use WinExtras, replace some macros 2018-09-15 13:07:51 +02:00
Jonas Kvinge
072facdf7b Update features 2018-09-15 00:22:10 +02:00
Jonas Kvinge
a0f07a7a67 Update about 2018-09-14 23:58:58 +02:00
Jonas Kvinge
1a7465ba94 Formatting and remove unused icons 2018-09-14 23:05:58 +02:00
Jonas Kvinge
be3862ec40 Add missing signal 2018-09-12 22:55:53 +02:00
Jonas Kvinge
a5276a3b7e Merge branch 'master' of github.com:jonaski/strawberry 2018-09-12 22:52:09 +02:00
Jonas Kvinge
fc8a27f55b Fix some compiler warnings 2018-09-12 22:51:10 +02:00
Jonas Kvinge
87718bee24 Update .travis.yml 2018-09-12 22:15:19 +02:00
Jonas Kvinge
56f2e00990 Update .travis.yml 2018-09-12 22:14:37 +02:00
Jonas Kvinge
27e3448dda Merge branch 'master' of github.com:jonaski/strawberry 2018-09-12 21:52:52 +02:00
Jonas Kvinge
9404e40cad Fix song.h 2018-09-12 21:52:30 +02:00
Jonas Kvinge
982f399aff Update .travis.yml 2018-09-12 21:17:45 +02:00
Jonas Kvinge
6d373737db Update .travis.yml 2018-09-12 21:09:00 +02:00
Jonas Kvinge
7f9e196234 Update .travis.yml 2018-09-12 20:56:51 +02:00
Jonas Kvinge
95d03de160 Update .travis.yml 2018-09-12 20:12:34 +02:00
Jonas Kvinge
d43190a41f Update .travis.yml 2018-09-12 19:45:46 +02:00
Jonas Kvinge
b5c0529969 Update .travis.yml 2018-09-12 19:42:04 +02:00
Jonas Kvinge
621a5b1de8 Update Dockerfile 2018-09-12 19:32:13 +02:00
Jonas Kvinge
e30f269412 Update .travis.yml 2018-09-11 23:32:19 +02:00
Jonas Kvinge
494ac20cca Create Dockerfile 2018-09-11 23:13:58 +02:00
Jonas Kvinge
bf997a6d2e Don't show error when there was no match from API Seeds 2018-09-11 00:38:06 +02:00
Jonas Kvinge
bc0c0b7950 Extract error from Json data in API Seeds 2018-09-11 00:20:24 +02:00
Jonas Kvinge
f202cf6988 Don't use lyrics from AudD if title and artist don't match 2018-09-11 00:01:17 +02:00
Jonas Kvinge
e62fb964ff Improve lyrics providers 2018-09-10 23:46:01 +02:00
Jonas Kvinge
9014781336 Fix Tidal authentication 2018-09-10 22:22:00 +02:00
Jonas Kvinge
e479e7e113 Fix show album cover from Tidal 2018-09-10 21:58:57 +02:00
Jonas Kvinge
f9379961e9 Fix Tidal authentication 2018-09-10 21:23:50 +02:00
Jonas Kvinge
e5e6cbf6e4 Hide samplerate, bitdepth and bitrate when not set 2018-09-08 13:25:40 +02:00
Jonas Kvinge
6d686ee66a Add source to songs and playlist_items 2018-09-08 12:38:02 +02:00
Jonas Kvinge
19b645d731 Show filetype for Tidal 2018-09-06 22:34:18 +02:00
Jonas Kvinge
28c685dcd8 Ops I did it again... 2018-09-06 20:51:14 +02:00
Jonas Kvinge
0abeefd470 Fixed saving (APE) tags for WavPack files 2018-09-06 20:49:05 +02:00
Jonas Kvinge
1562585561 Added support for reading lyrics from tags
Also fixed tagreader crash when saving tags to MP3 files
2018-09-06 20:04:29 +02:00
Jonas Kvinge
0a64a2a394 Finish Tidal
- Add configurable settings
- Add progressbar
- Simplify code
2018-09-06 17:39:26 +02:00
Jonas Kvinge
440a223bfb Fix saving search_for_cover_auto 2018-09-06 17:37:50 +02:00
Jonas Kvinge
36b0a22c79 Fix saving above_status_bar 2018-09-06 17:37:03 +02:00
Jonas Kvinge
032022c246 Add "Show above status bar" as an option 2018-09-05 19:03:21 +02:00
Jonas Kvinge
9e4f3f9867 Fix qocoa mac build 2018-09-05 18:15:28 +02:00
Jonas Kvinge
1119c87b2f Fix clear search box 2018-09-04 22:55:38 +02:00
Jonas Kvinge
36ab26c49a Fix automatic album cover fetching
- Moved Album Choice Controller to mainwindow to use common for both
PlayingWidget and ContextView.
- Fixed a bug I created that caused fetching album covers in a loop
2018-09-04 21:43:44 +02:00
Jonas Kvinge
460cddb3dc Add ResetWarning() to make sure label is hidden 2018-09-04 20:52:47 +02:00
Jonas Kvinge
a5c2dfacf0 Don't use discogs for automatic album cover search 2018-09-04 20:51:47 +02:00
Jonas Kvinge
b9788ef4b5 Update .travis.yml 2018-09-02 23:49:28 +02:00
Jonas Kvinge
4a124e596e Update .travis.yml 2018-09-02 17:04:58 +02:00
Jonas Kvinge
994a400ac9 Update nsi files 2018-09-02 16:20:48 +02:00
Jonas Kvinge
d08e6a1dca Remove libmpcdec-5.dll 2018-09-02 16:00:48 +02:00
Jonas Kvinge
154136185b Remove libxine from nsi file 2018-09-02 12:56:31 +02:00
Jonas Kvinge
f86b10c71f Add bold to albums by label 2018-09-02 12:50:28 +02:00
Jonas Kvinge
0b3d84a65e Update changelog 2018-09-02 12:50:12 +02:00
Jonas Kvinge
ee78b6f2bb Add DSF and DSDIFF/DFF support 2018-09-02 01:40:14 +02:00
Jonas Kvinge
521d5cf4fa Add DSF and DSDIFF support to taglib 2018-09-02 01:39:02 +02:00
Jonas Kvinge
52cf4412c8 Update changelog 2018-09-01 22:22:12 +02:00
Jonas Kvinge
dcae67ac7b Change search limit 2018-09-01 22:21:45 +02:00
Jonas Kvinge
cd0ee282c6 Add dist/windows/strawberry-debug.nsi.in to cmake 2018-09-01 22:14:59 +02:00
Jonas Kvinge
9d7e5864de Merge branch 'master' of github.com:jonaski/strawberry 2018-09-01 22:00:44 +02:00
Jonas Kvinge
d426eb2e07 Add seperate nsi file for debug 2018-09-01 22:00:06 +02:00
Jonas Kvinge
06bed7feb7 Update README.md 2018-08-29 23:26:14 +02:00
Jonas Kvinge
adc38c4b12 Disable Amazon cover provider (API key revoked) 2018-08-29 22:27:26 +02:00
Jonas Kvinge
5af58c19ae Remove some unused variables 2018-08-29 22:17:23 +02:00
Jonas Kvinge
ac6cac8da1 New context with albums and lyrics +++ much more
* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
* Fixed playing and context widget getting stuck in play mode when there was an error
* Changed icons for artists in collection, tidal and cover manager
* Removed "search" icon from "Search automatically" checkbox (right click) that looked ugly
* Removed some unused widgets from the src/widgets directory
* Fixed initial size of window and side panel
* Fixed saving window size correctly
2018-08-29 21:42:24 +02:00
Jonas Kvinge
3b30e66e87 Fix DB schema 2018-08-15 01:28:37 +02:00
Jonas Kvinge
41b0b1efd4 Remove broken xine fader until it's properly fixed 2018-08-12 15:05:34 +02:00
Jonas Kvinge
099d098dc7 Remove install log 2018-08-10 22:01:59 +02:00
Jonas Kvinge
1a55b7f1b2 Add DLL's required for Tidal to windows installer 2018-08-09 23:31:24 +02:00
Jonas Kvinge
f5ba8da3c7 Remove info frame from DeviceViewContainer
Was broken and caused yellow background on windows
2018-08-09 22:30:18 +02:00
Jonas Kvinge
08fcedd925 Rename some UI stuff 2018-08-09 21:49:18 +02:00
Jonas Kvinge
57f6f40e7d Fix missing icons and rework some UI stuff 2018-08-09 21:04:30 +02:00
Jonas Kvinge
4ca99dde43 Remove bak file 2018-08-09 18:41:43 +02:00
Jonas Kvinge
c518e42e18 Remove whitespace 2018-08-09 18:39:44 +02:00
Jonas Kvinge
0c329e6d83 Update README.md 2018-08-09 18:21:57 +02:00
Jonas Kvinge
820124f9e1 Add tidal support 2018-08-09 18:10:03 +02:00
Jonas Kvinge
26062bd07b Remove unneeded include 2018-07-28 00:16:56 +02:00
Jonas Kvinge
73029ab7a2 Remove dead analyzer code from VLC engine 2018-07-28 00:09:39 +02:00
Jonas Kvinge
c3e916d945 Add some missing e-mails in about 2018-07-20 02:28:42 +02:00
Jonas Kvinge
6ee9f9d1ad Add some missing names to about 2018-07-20 02:07:47 +02:00
Jonas Kvinge
b2c26eb4ed Make chromaprint optional 2018-07-16 07:23:37 +02:00
Jonas Kvinge
e181b47e3f Add 'make deb' 2018-07-16 02:57:57 +02:00
Jonas Kvinge
dc91f19f30 Just use PkgConfig to find dbus
- dbus was not found on debian based distros, because they had the library in a different location
- Not sure why I added the find package cmake file in the first place, will fix it and readd it if this causes problems
2018-07-16 01:20:29 +02:00
Jonas Kvinge
e260fc5057 Add check for qpa/qplatformnativeinterface.h in qxt 2018-07-16 01:18:58 +02:00
Jonas Kvinge
2368fff243 Fix mistake 2018-07-12 17:17:20 +02:00
Jonas Kvinge
70db0a33d1 Add debian package 2018-07-12 17:10:38 +02:00
Jonas Kvinge
56f47909f4 Fix Fedora build 2018-07-12 01:51:31 +02:00
Jonas Kvinge
e22b47a9d1 Revert git version off for Windows 2018-07-12 00:18:55 +02:00
Jonas Kvinge
e32ed02a24 Fix RPM build 2018-07-12 00:07:29 +02:00
Jonas Kvinge
eb5d72a940 Fix build with cmake with < 3.1 2018-07-11 17:23:44 +02:00
Jonas Kvinge
cbd809621a Update README.md 2018-07-08 19:50:16 +02:00
Jonas Kvinge
ad5d5d0ecd Correct Qt 5 dependencies 2018-07-06 21:56:13 +02:00
Jonas Kvinge
6bc948453c Update README.md 2018-07-05 19:47:18 +02:00
Jonas Kvinge
803590daa8 Fix Travis-CI build 2018-07-05 19:11:47 +02:00
Jonas Kvinge
c63399ee98 Update .travis.yml 2018-07-05 18:56:14 +02:00
Jonas Kvinge
f5ff95dca4 Update .travis.yml 2018-07-05 18:44:46 +02:00
Jonas Kvinge
998357c0bb Update .travis.yml 2018-07-05 18:33:50 +02:00
Jonas Kvinge
b43331bc3c Update .travis.yml 2018-07-05 18:17:36 +02:00
Jonas Kvinge
ecfeb17869 Update .travis.yml 2018-07-05 18:08:18 +02:00
Jonas Kvinge
9d2c9c732e Update .travis.yml 2018-07-05 18:02:24 +02:00
Jonas Kvinge
6478fadedc Update .travis.yml 2018-07-05 17:58:53 +02:00
Jonas Kvinge
a62eaa919d Update README.md 2018-07-05 17:56:25 +02:00
Jonas Kvinge
328a86288c Update .travis.yml 2018-07-05 17:52:32 +02:00
Jonas Kvinge
f1902a5b63 Update .travis.yml 2018-07-05 17:42:16 +02:00
Jonas Kvinge
693bade5a6 Update .travis.yml 2018-07-05 17:34:58 +02:00
Jonas Kvinge
ca2acb177a Create .travis.yml 2018-07-05 17:18:49 +02:00
Jonas Kvinge
670cd4e081 Remove unused variable 2018-07-05 03:28:32 +02:00
628 changed files with 16602 additions and 6283 deletions

4
.gitignore vendored
View File

@@ -34,6 +34,10 @@ Thumbs.db
*.rc
/.qmake.cache
/.qmake.stash
*.spec
*.nsi
*.plist
maketarball.sh
# qtcreator generated files
*.pro.user*

30
.travis.yml Normal file
View File

@@ -0,0 +1,30 @@
sudo: required
language: C++
os:
- linux
- osx
services:
- docker
compiler:
- gcc
- clang
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -f Dockerfile -t strawberry-build . ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run --name build -itd strawberry-build /bin/bash ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build git clone https://github.com/jonaski/strawberry ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink python ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib pkgconfig protobuf protobuf-c qt ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sqlite --with-fts ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gstreamer gst-plugins-base ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-good --with-flac ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gst-plugins-bad gst-plugins-ugly ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install chromaprint ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export Qt5_DIR=/usr/local/opt/qt5/lib/cmake ; fi
before_script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DFORCE_GIT_REVISION="0.0.0-0-g0000000"; fi
script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make -j8 ; fi

View File

@@ -6,43 +6,38 @@
#include <QMenu>
class QSearchFieldPrivate;
class QSearchField : public QWidget
{
Q_OBJECT
class QSearchField : public QWidget {
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true);
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true);
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText);
public:
explicit QSearchField(QWidget *parent);
explicit QSearchField(QWidget *parent);
QString text() const;
QString placeholderText() const;
void setFocus(Qt::FocusReason);
void setMenu(QMenu *menu);
QString text() const;
QString placeholderText() const;
void setFocus(Qt::FocusReason);
public slots:
void setText(const QString &text);
void setPlaceholderText(const QString &text);
void clear();
void selectAll();
void setFocus();
void setText(const QString &text);
void setPlaceholderText(const QString &text);
void clear();
void selectAll();
void setFocus();
signals:
void textChanged(const QString &text);
void editingFinished();
void returnPressed();
private slots:
void popupMenu();
void textChanged(const QString &text);
void editingFinished();
void returnPressed();
protected:
void changeEvent(QEvent*);
void resizeEvent(QResizeEvent*);
void resizeEvent(QResizeEvent*);
bool eventFilter(QObject*, QEvent*);
private:
friend class QSearchFieldPrivate;
QPointer <QSearchFieldPrivate> pimpl;
friend class QSearchFieldPrivate;
QPointer <QSearchFieldPrivate> pimpl;
};
#endif // QSEARCHFIELD_H

View File

@@ -32,57 +32,50 @@ THE SOFTWARE.
#include <QKeyEvent>
#include <QClipboard>
class QSearchFieldPrivate : public QObject
{
class QSearchFieldPrivate : public QObject {
public:
QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField)
: QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {}
QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField)
: QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {}
void textDidChange(const QString &text)
{
if (qSearchField)
emit qSearchField->textChanged(text);
void textDidChange(const QString &text) {
if (qSearchField) emit qSearchField->textChanged(text);
}
void textDidEndEditing() {
if (qSearchField)
emit qSearchField->editingFinished();
}
void textDidEndEditing()
{
if (qSearchField)
emit qSearchField->editingFinished();
void returnPressed() {
if (qSearchField) {
emit qSearchField->returnPressed();
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void returnPressed()
{
if (qSearchField) {
emit qSearchField->returnPressed();
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
void keyDownPressed() {
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void keyDownPressed()
{
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
void keyUpPressed() {
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
void keyUpPressed()
{
if (qSearchField) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QApplication::postEvent(qSearchField, event);
}
}
QPointer<QSearchField> qSearchField;
NSSearchField *nsSearchField;
QPointer<QSearchField> qSearchField;
NSSearchField *nsSearchField;
};
@interface QSearchFieldDelegate : NSObject<NSTextFieldDelegate>
{
@interface QSearchFieldDelegate : NSObject<NSTextFieldDelegate> {
@public
QPointer<QSearchFieldPrivate> pimpl;
QPointer<QSearchFieldPrivate> pimpl;
}
-(void)controlTextDidChange:(NSNotification*)notification;
-(void)controlTextDidEndEditing:(NSNotification*)notification;
@@ -90,35 +83,33 @@ public:
@implementation QSearchFieldDelegate
-(void)controlTextDidChange:(NSNotification*)notification {
Q_ASSERT(pimpl);
if (pimpl)
pimpl->textDidChange(toQString([[notification object] stringValue]));
Q_ASSERT(pimpl);
if (pimpl) pimpl->textDidChange(toQString([[notification object] stringValue]));
}
-(void)controlTextDidEndEditing:(NSNotification*)notification {
Q_UNUSED(notification);
// No Q_ASSERT here as it is called on destruction.
if (pimpl)
pimpl->textDidEndEditing();
if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
pimpl->returnPressed();
Q_UNUSED(notification);
// No Q_ASSERT here as it is called on destruction.
if (!pimpl) return;
pimpl->textDidEndEditing();
if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
pimpl->returnPressed();
}
-(BOOL)control: (NSControl *)control textView:
(NSTextView *)textView doCommandBySelector:
(SEL)commandSelector {
Q_ASSERT(pimpl);
if (!pimpl) return NO;
if (commandSelector == @selector(moveDown:)) {
pimpl->keyDownPressed();
return YES;
} else if (commandSelector == @selector(moveUp:)) {
pimpl->keyUpPressed();
return YES;
}
return NO;
(NSTextView *)textView doCommandBySelector:
(SEL)commandSelector {
Q_ASSERT(pimpl);
if (!pimpl) return NO;
if (commandSelector == @selector(moveDown:)) {
pimpl->keyDownPressed();
return YES;
}
else if (commandSelector == @selector(moveUp:)) {
pimpl->keyUpPressed();
return YES;
}
return NO;
}
@end
@@ -129,169 +120,109 @@ public:
@implementation QocoaSearchField
-(BOOL)performKeyEquivalent:(NSEvent*)event {
// First, check if we have the focus.
// If no, it probably means this event isn't for us.
NSResponder* firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] &&
[(NSText*)firstResponder delegate] == self) {
// First, check if we have the focus.
// If no, it probably means this event isn't for us.
NSResponder* firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] && [(NSText*)firstResponder delegate] == self) {
if ([event type] == NSEventTypeKeyDown && [event modifierFlags] & NSEventModifierFlagCommand)
{
QString keyString = toQString([event characters]);
if (keyString == "a") // Cmd+a
{
[self performSelector:@selector(selectText:)];
return YES;
}
else if (keyString == "c") // Cmd+c
{
[[self currentEditor] copy: nil];
return YES;
}
else if (keyString == "v") // Cmd+v
{
[[self currentEditor] paste: nil];
return YES;
}
else if (keyString == "x") // Cmd+x
{
[[self currentEditor] cut: nil];
return YES;
}
}
if ([event type] == NSEventTypeKeyDown && [event modifierFlags] & NSEventModifierFlagCommand) {
QString keyString = toQString([event characters]);
if (keyString == "a") // Cmd+a
{
[self performSelector:@selector(selectText:)];
return YES;
}
else if (keyString == "c") // Cmd+c
{
[[self currentEditor] copy: nil];
return YES;
}
else if (keyString == "v") // Cmd+v
{
[[self currentEditor] paste: nil];
return YES;
}
else if (keyString == "x") // Cmd+x
{
[[self currentEditor] cut: nil];
return YES;
}
}
}
return NO;
return NO;
}
@end
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSearchField *search = [[QocoaSearchField alloc] init];
QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
[search setDelegate:delegate];
setupLayout(search, this);
setFixedHeight(24);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
[search release];
[pool drain];
QSearchField::QSearchField(QWidget *parent) : QWidget(parent) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSearchField *search = [[QocoaSearchField alloc] init];
QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
[search setDelegate:delegate];
setupLayout(search, this);
setFixedHeight(24);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
[search release];
[pool drain];
}
void QSearchField::setMenu(QMenu *menu)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
void QSearchField::setText(const QString &text) {
Q_ASSERT(pimpl);
if (!pimpl) return;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
NSMenu *nsMenu = menu->macMenu();
#else
NSMenu *nsMenu = menu->toNSMenu();
#endif
[[pimpl->nsSearchField cell] setSearchMenuTemplate:nsMenu];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pimpl->nsSearchField setStringValue:fromQString(text)];
if (!text.isEmpty()) {
[pimpl->nsSearchField selectText:pimpl->nsSearchField];
[[pimpl->nsSearchField currentEditor] setSelectedRange:NSMakeRange([[pimpl->nsSearchField stringValue] length], 0)];
}
[pool drain];
}
void QSearchField::popupMenu()
{
void QSearchField::setPlaceholderText(const QString &text) {
Q_ASSERT(pimpl);
if (!pimpl) return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)];
[pool drain];
}
void QSearchField::setText(const QString &text)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pimpl->nsSearchField setStringValue:fromQString(text)];
[pool drain];
void QSearchField::clear() {
Q_ASSERT(pimpl);
if (!pimpl) return;
[pimpl->nsSearchField setStringValue:@""];
emit textChanged(QString());
}
void QSearchField::setPlaceholderText(const QString &text)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)];
[pool drain];
void QSearchField::selectAll() {
Q_ASSERT(pimpl);
if (!pimpl) return;
[pimpl->nsSearchField performSelector:@selector(selectText:)];
}
void QSearchField::clear()
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
[pimpl->nsSearchField setStringValue:@""];
emit textChanged(QString());
QString QSearchField::text() const {
Q_ASSERT(pimpl);
if (!pimpl) return QString();
return toQString([pimpl->nsSearchField stringValue]);
}
void QSearchField::selectAll()
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
[pimpl->nsSearchField performSelector:@selector(selectText:)];
QString QSearchField::placeholderText() const {
Q_ASSERT(pimpl);
return toQString([[pimpl->nsSearchField cell] placeholderString]);
}
QString QSearchField::text() const
{
Q_ASSERT(pimpl);
if (!pimpl)
return QString();
void QSearchField::setFocus(Qt::FocusReason) {}
return toQString([pimpl->nsSearchField stringValue]);
void QSearchField::setFocus() {
setFocus(Qt::OtherFocusReason);
}
QString QSearchField::placeholderText() const
{
Q_ASSERT(pimpl);
if (!pimpl)
return QString();
return toQString([[pimpl->nsSearchField cell] placeholderString]);
void QSearchField::resizeEvent(QResizeEvent *resizeEvent) {
QWidget::resizeEvent(resizeEvent);
}
void QSearchField::setFocus(Qt::FocusReason)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
if ([pimpl->nsSearchField acceptsFirstResponder])
[[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField];
bool QSearchField::eventFilter(QObject *o, QEvent *e) {
return QWidget::eventFilter(o, e);
}
void QSearchField::setFocus()
{
setFocus(Qt::OtherFocusReason);
}
void QSearchField::changeEvent(QEvent* event)
{
if (event->type() == QEvent::EnabledChange) {
Q_ASSERT(pimpl);
if (!pimpl)
return;
const bool enabled = isEnabled();
[pimpl->nsSearchField setEnabled: enabled];
}
QWidget::changeEvent(event);
}
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
QWidget::resizeEvent(resizeEvent);
}

View File

@@ -22,235 +22,140 @@ THE SOFTWARE.
#include "qsearchfield.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QToolButton>
#include <QStyle>
#include <QApplication>
#include <QDesktopWidget>
#include <QEvent>
#include <QDir>
#include <QDebug>
class QSearchFieldPrivate : public QObject
{
#include "../../src/core/iconloader.h"
class QSearchFieldPrivate : public QObject {
public:
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton, QToolButton *searchButton)
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton), searchButton(searchButton) {}
QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
: QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
int lineEditFrameWidth() const {
return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
}
int lineEditFrameWidth() const {
return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
}
int clearButtonPaddedWidth() const {
return clearButton->width() + lineEditFrameWidth() * 2;
}
int clearButtonPaddedWidth() const {
return clearButton->width() + lineEditFrameWidth() * 2;
}
int clearButtonPaddedHeight() const {
return clearButton->height() + lineEditFrameWidth() * 2;
}
int clearButtonPaddedHeight() const {
return clearButton->height() + lineEditFrameWidth() * 2;
}
int searchButtonPaddedWidth() const {
return searchButton->width() + lineEditFrameWidth() * 2;
}
int searchButtonPaddedHeight() const {
return searchButton->height() + lineEditFrameWidth() * 2;
}
QPointer<QLineEdit> lineEdit;
QPointer<QToolButton> clearButton;
QPointer<QToolButton> searchButton;
QPointer<QMenu> searchMenu;
QPointer<QLineEdit> lineEdit;
QPointer<QToolButton> clearButton;
};
QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
QLineEdit *lineEdit = new QLineEdit(this);
connect(lineEdit, SIGNAL(textChanged(QString)),
this, SIGNAL(textChanged(QString)));
connect(lineEdit, SIGNAL(editingFinished()),
this, SIGNAL(editingFinished()));
connect(lineEdit, SIGNAL(returnPressed()),
this, SIGNAL(returnPressed()));
connect(lineEdit, SIGNAL(textChanged(QString)),
this, SLOT(setText(QString)));
QSearchField::QSearchField(QWidget *parent) : QWidget(parent) {
int iconsize = style()->pixelMetric(QStyle::PM_SmallIconSize);
QToolButton *clearButton = new QToolButton(this);
QIcon clearIcon = QIcon::fromTheme(QLatin1String("edit-clear"),
QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_clear.png")));
clearButton->setIcon(clearIcon);
clearButton->setIconSize(QSize(iconsize, iconsize));
clearButton->setFixedSize(QSize(iconsize, iconsize));
clearButton->setStyleSheet("border: none;");
clearButton->hide();
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
QLineEdit *lineEdit = new QLineEdit(this);
connect(lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
connect(lineEdit, SIGNAL(editingFinished()), this, SIGNAL(editingFinished()));
connect(lineEdit, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()));
connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(setText(QString)));
QToolButton *searchButton = new QToolButton(this);
QIcon searchIcon = QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png"));
searchButton->setIcon(searchIcon);
searchButton->setIconSize(QSize(iconsize, iconsize));
searchButton->setFixedSize(QSize(iconsize, iconsize));
searchButton->setStyleSheet("border: none;");
searchButton->setPopupMode(QToolButton::InstantPopup);
searchButton->setEnabled(false);
connect(searchButton, SIGNAL(clicked()), this, SLOT(popupMenu()));
QToolButton *clearButton = new QToolButton(this);
QIcon clearIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton, searchButton);
clearButton->setIcon(clearIcon);
clearButton->setIconSize(QSize(16, 16));
clearButton->setStyleSheet("border: none; padding: 0px;");
clearButton->resize(clearButton->sizeHint());
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; padding-right: %2px; } ")
.arg(pimpl->searchButtonPaddedWidth())
.arg(pimpl->clearButtonPaddedWidth()));
const int width = qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth() + pimpl->searchButtonPaddedWidth());
const int height = qMax(lineEdit->minimumSizeHint().height(),
qMax(pimpl->clearButtonPaddedHeight(),
pimpl->searchButtonPaddedHeight()));
lineEdit->setMinimumSize(width, height);
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);
const int frame_width = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
lineEdit->setStyleSheet(QString("QLineEdit { padding-left: %1px; } ").arg(clearButton->width()));
const int width = frame_width + qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
const int height = frame_width + qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
lineEdit->setMinimumSize(width, height);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(lineEdit);
lineEdit->installEventFilter(this);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->addWidget(lineEdit);
}
void QSearchField::setMenu(QMenu *menu)
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
void QSearchField::setText(const QString &text) {
pimpl->searchMenu = menu;
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
if (text != this->text()) pimpl->lineEdit->setText(text);
QIcon searchIcon = menu ? QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier_menu.png"))
: QIcon(QLatin1String(":/Qocoa/qsearchfield_nonmac_magnifier.png"));
pimpl->searchButton->setIcon(searchIcon);
pimpl->searchButton->setEnabled(isEnabled() && menu);
}
void QSearchField::popupMenu()
{
Q_ASSERT(pimpl);
if (!pimpl)
return;
if (pimpl->searchMenu) {
const QRect screenRect = qApp->desktop()->availableGeometry(pimpl->searchButton);
const QSize sizeHint = pimpl->searchMenu->sizeHint();
const QRect rect = pimpl->searchButton->rect();
const int x = pimpl->searchButton->isRightToLeft()
? rect.right() - sizeHint.width()
: rect.left();
const int y = pimpl->searchButton->mapToGlobal(QPoint(0, rect.bottom())).y() + sizeHint.height() <= screenRect.height()
? rect.bottom()
: rect.top() - sizeHint.height();
QPoint point = pimpl->searchButton->mapToGlobal(QPoint(x, y));
point.rx() = qMax(screenRect.left(), qMin(point.x(), screenRect.right() - sizeHint.width()));
point.ry() += 1;
pimpl->searchMenu->popup(point);
}
}
void QSearchField::changeEvent(QEvent* event)
{
if (event->type() == QEvent::EnabledChange) {
Q_ASSERT(pimpl);
if (!pimpl)
return;
const bool enabled = isEnabled();
pimpl->searchButton->setEnabled(enabled && pimpl->searchMenu);
pimpl->lineEdit->setEnabled(enabled);
pimpl->clearButton->setEnabled(enabled);
}
QWidget::changeEvent(event);
}
void QSearchField::setText(const QString &text)
{
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
return;
pimpl->clearButton->setVisible(!text.isEmpty());
if (text != this->text())
pimpl->lineEdit->setText(text);
}
void QSearchField::setPlaceholderText(const QString &text)
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
#if QT_VERSION >= 0x040700
pimpl->lineEdit->setPlaceholderText(text);
#endif
}
void QSearchField::clear()
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
pimpl->lineEdit->clear();
}
void QSearchField::selectAll()
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return;
pimpl->lineEdit->selectAll();
}
QString QSearchField::text() const
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return QString();
return pimpl->lineEdit->text();
void QSearchField::setPlaceholderText(const QString &text) {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->setPlaceholderText(text);
}
QString QSearchField::placeholderText() const {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit))
return QString();
#if QT_VERSION >= 0x040700
return pimpl->lineEdit->placeholderText();
#else
return QString();
#endif
return pimpl->lineEdit->placeholderText();
}
void QSearchField::setFocus(Qt::FocusReason reason)
{
Q_ASSERT(pimpl && pimpl->lineEdit);
if (pimpl && pimpl->lineEdit)
pimpl->lineEdit->setFocus(reason);
void QSearchField::setFocus(Qt::FocusReason reason) {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (pimpl && pimpl->lineEdit) pimpl->lineEdit->setFocus(reason);
}
void QSearchField::setFocus()
{
setFocus(Qt::OtherFocusReason);
void QSearchField::setFocus() {
setFocus(Qt::OtherFocusReason);
}
void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
return;
QWidget::resizeEvent(resizeEvent);
const int x = width() - pimpl->clearButtonPaddedWidth();
const int y = (height() - pimpl->clearButton->height())/2;
pimpl->clearButton->move(x, y);
pimpl->searchButton->move(pimpl->lineEditFrameWidth() * 2,
(height() - pimpl->searchButton->height())/2);
void QSearchField::clear() {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->clear();
}
void QSearchField::selectAll() {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return;
pimpl->lineEdit->selectAll();
}
QString QSearchField::text() const {
Q_ASSERT(pimpl && pimpl->lineEdit);
if (!(pimpl && pimpl->lineEdit)) return QString();
return pimpl->lineEdit->text();
}
void QSearchField::resizeEvent(QResizeEvent *resizeEvent) {
Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
if (!(pimpl && pimpl->clearButton && pimpl->lineEdit)) return;
QWidget::resizeEvent(resizeEvent);
const int x = pimpl->lineEditFrameWidth();
const int y = (height() - pimpl->clearButton->height())/2;
pimpl->clearButton->move(x, y);
}
bool QSearchField::eventFilter(QObject *o, QEvent *e) {
if (pimpl && pimpl->lineEdit && o == pimpl->lineEdit) {
// Forward some lineEdit events to QSearchField (only those we need for
// now, but some might be added later if needed)
switch (e->type()) {
case QEvent::FocusIn:
case QEvent::FocusOut:
QApplication::sendEvent(this, e);
break;
}
}
return QWidget::eventFilter(o, e);
}

View File

@@ -27,3 +27,5 @@ ADD_LIBRARY(qtsingleapplication STATIC
)
target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network)
include_directories(${CMAKE_BINARY_DIR}/src)

View File

@@ -45,7 +45,7 @@
#include <QVector>
#endif
#if defined(Q_WS_WIN) || defined(Q_OS_WIN)
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)

View File

@@ -37,6 +37,7 @@
**
****************************************************************************/
#include "config.h"
#include "qtsingleapplication.h"
@@ -44,6 +45,10 @@
#include <QWidget>
#include <QString>
#ifdef HAVE_X11_ // FIXME
# include <X11/Xlib.h>
#endif
#include "qtlocalpeer.h"
/*!
@@ -173,14 +178,14 @@ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char *
}
#if defined(Q_WS_X11)
#if defined(HAVE_X11_) // FIXME
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
QtSingleApplication::QtSingleApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap)
{
sysInit();
@@ -206,7 +211,7 @@ QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Q
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
QtSingleApplication::QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit(appId);

View File

@@ -40,14 +40,21 @@
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QApplication>
#include <QString>
#if defined(HAVE_X11_) // FIXME
# include <X11/Xlib.h>
#endif
class QtLocalPeer;
#if defined(Q_WS_WIN) || defined(Q_OS_WIN32)
#if defined(Q_OS_WIN) || defined(Q_OS_WIN32)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
@@ -70,10 +77,10 @@ class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
#if defined(HAVE_X11_) // FIXME
QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
#endif
bool isRunning();

View File

@@ -40,6 +40,8 @@
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include "config.h"
#include <QCoreApplication>
#include <QObject>
#include <QString>

View File

@@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 11)
set(QTWIN-SOURCES
qtwin.cpp
)
ADD_LIBRARY(qtwin STATIC
${QTWIN-SOURCES}
)
target_link_libraries(qtwin
Qt5::Widgets
)

View File

@@ -1,229 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#include "qtwin.h"
#include <QLibrary>
#include <QApplication>
#include <QWidget>
#include <QList>
#include <QPointer>
#ifdef Q_WS_WIN
#include <qt_windows.h>
// Blur behind data structures
#define DWM_BB_ENABLE 0x00000001 // fEnable has been specified
#define DWM_BB_BLURREGION 0x00000002 // hRgnBlur has been specified
#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 // fTransitionOnMaximized has been specified
#define WM_DWMCOMPOSITIONCHANGED 0x031E // Composition changed window message
typedef struct _DWM_BLURBEHIND
{
DWORD dwFlags;
BOOL fEnable;
HRGN hRgnBlur;
BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND, *PDWM_BLURBEHIND;
typedef struct _MARGINS
{
int cxLeftWidth;
int cxRightWidth;
int cyTopHeight;
int cyBottomHeight;
} MARGINS, *PMARGINS;
typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
typedef HRESULT (WINAPI *PtrDwmGetColorizationColor)(DWORD *pcrColorization, BOOL *pfOpaqueBlend);
static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled= 0;
static PtrDwmEnableBlurBehindWindow pDwmEnableBlurBehindWindow = 0;
static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
static PtrDwmGetColorizationColor pDwmGetColorizationColor = 0;
/*
* Internal helper class that notifies windows if the
* DWM compositing state changes and updates the widget
* flags correspondingly.
*/
class WindowNotifier : public QWidget
{
public:
WindowNotifier() { winId(); }
void addWidget(QWidget *widget) { widgets.append(widget); }
void removeWidget(QWidget *widget) { widgets.removeAll(widget); }
bool winEvent(MSG *message, long *result);
private:
QWidgetList widgets;
};
static bool resolveLibs()
{
if (!pDwmIsCompositionEnabled) {
QLibrary dwmLib(QString::toLatin1("dwmapi"));
pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow");
pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib.resolve("DwmGetColorizationColor");
}
return pDwmIsCompositionEnabled != 0;
}
#endif
/*!
* Chekcs and returns true if Windows DWM composition
* is currently enabled on the system.
*
* To get live notification on the availability of
* this feature, you will currently have to
* reimplement winEvent() on your widget and listen
* for the WM_DWMCOMPOSITIONCHANGED event to occur.
*
*/
bool QtWin::isCompositionEnabled()
{
#ifdef Q_WS_WIN
if (resolveLibs()) {
HRESULT hr = S_OK;
BOOL isEnabled = false;
hr = pDwmIsCompositionEnabled(&isEnabled);
if (SUCCEEDED(hr))
return isEnabled;
}
#endif
return false;
}
/*!
* Enables Blur behind on a Widget.
*
* \a enable tells if the blur should be enabled or not
*/
bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable,
const QRegion &region)
{
Q_ASSERT(widget);
bool result = false;
#ifdef Q_WS_WIN
if (resolveLibs()) {
DWM_BLURBEHIND bb = {0};
HRESULT hr = S_OK;
bb.fEnable = enable;
bb.dwFlags = DWM_BB_ENABLE;
bb.hRgnBlur = NULL;
if (!region.isEmpty()) {
bb.dwFlags |= DWM_BB_BLURREGION;
bb.hRgnBlur = region.handle();
}
widget->setAttribute(Qt::WA_TranslucentBackground, enable);
widget->setAttribute(Qt::WA_NoSystemBackground, enable);
hr = pDwmEnableBlurBehindWindow(widget->winId(), &bb);
if (SUCCEEDED(hr)) {
result = true;
windowNotifier()->addWidget(widget);
}
}
#endif
return result;
}
/*!
* ExtendFrameIntoClientArea.
*
* This controls the rendering of the frame inside the window.
* Note that passing margins of -1 (the default value) will completely
* remove the frame from the window.
*
* \note you should not call enableBlurBehindWindow before calling
* this functions
*
* \a enable tells if the blur should be enabled or not
*/
bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int right, int bottom)
{
Q_ASSERT(widget);
Q_UNUSED(left);
Q_UNUSED(top);
Q_UNUSED(right);
Q_UNUSED(bottom);
bool result = false;
#ifdef Q_WS_WIN
if (resolveLibs()) {
QLibrary dwmLib(QString::toLatin1("dwmapi"));
HRESULT hr = S_OK;
MARGINS m = {left, top, right, bottom};
hr = pDwmExtendFrameIntoClientArea(widget->winId(), &m);
if (SUCCEEDED(hr)) {
result = true;
windowNotifier()->addWidget(widget);
}
widget->setAttribute(Qt::WA_TranslucentBackground, result);
}
#endif
return result;
}
/*!
* Returns the current colorizationColor for the window.
*
* \a enable tells if the blur should be enabled or not
*/
QColor QtWin::colorizatinColor()
{
QColor resultColor = QApplication::palette().window().color();
#ifdef Q_WS_WIN
if (resolveLibs()) {
DWORD color = 0;
BOOL opaque = FALSE;
QLibrary dwmLib(QString::toLatin1("dwmapi"));
HRESULT hr = S_OK;
hr = pDwmGetColorizationColor(&color, &opaque);
if (SUCCEEDED(hr))
resultColor = QColor(color);
}
#endif
return resultColor;
}
#ifdef Q_WS_WIN
WindowNotifier *QtWin::windowNotifier()
{
static WindowNotifier *windowNotifierInstance = 0;
if (!windowNotifierInstance)
windowNotifierInstance = new WindowNotifier;
return windowNotifierInstance;
}
/* Notify all enabled windows that the DWM state changed */
bool WindowNotifier::winEvent(MSG *message, long *result)
{
if (message && message->message == WM_DWMCOMPOSITIONCHANGED) {
bool compositionEnabled = QtWin::isCompositionEnabled();
foreach(QWidget * widget, widgets) {
if (widget) {
widget->setAttribute(Qt::WA_NoSystemBackground, compositionEnabled);
}
widget->update();
}
}
return QWidget::winEvent(message, result);
}
#endif

View File

@@ -1,38 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/
#ifndef QTWIN_H
#define QTWIN_H
#include <QColor>
#include <QWidget>
/**
* This is a helper class for using the Desktop Window Manager
* functionality on Windows 7 and Windows Vista. On other platforms
* these functions will simply not do anything.
*/
class WindowNotifier;
class QtWin
{
public:
static bool enableBlurBehindWindow(QWidget *widget, bool enable = true,
const QRegion& region = QRegion());
static bool extendFrameIntoClientArea(QWidget *widget,
int left = -1, int top = -1,
int right = -1, int bottom = -1);
static bool isCompositionEnabled();
static QColor colorizatinColor();
private:
static WindowNotifier *windowNotifier();
};
#endif // QTWIN_H

View File

@@ -1,6 +1,14 @@
cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 11)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if (NOT WIN32 AND NOT APPLE)
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
message(FATAL_ERROR "Missing qpa/qplatformnativeinterface.h, check that you got the QT private headers installed (package libQt5Gui-private-headers-devel, qtbase5-private-dev or similar)")
endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
endif(NOT WIN32 AND NOT APPLE)
set(QXT-SOURCES
qxtglobal.cpp
qxtglobalshortcut.cpp
@@ -12,7 +20,6 @@ set(QXT-MOC-HEADERS
find_package(X11)
include_directories(${X11_INCLUDE_DIR})
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)

View File

@@ -38,36 +38,36 @@
#include "qxtglobalshortcut_p.h"
bool QxtGlobalShortcutPrivate::error = false;
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
int QxtGlobalShortcutPrivate::ref = 0;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
{
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
if (!ref++)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
#else
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
}
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
{
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
if (!--ref)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
#else
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#endif
#endif // Q_WS_MAC
#endif // Q_OS_MAC
}
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)

View File

@@ -59,7 +59,7 @@ public:
bool unsetShortcut();
static bool error;
#ifndef Q_WS_MAC
#ifndef Q_OS_MAC
static int ref;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
static QAbstractEventDispatcher::EventFilter prevEventFilter;
@@ -67,7 +67,7 @@ public:
#else
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
#endif // Q_WS_MAC
#endif // Q_OS_MAC
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);

View File

@@ -1,7 +1,7 @@
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
@@ -16,7 +16,7 @@
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@@ -1,7 +1,7 @@
/*
* FILE: sha2.h
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
@@ -16,7 +16,7 @@
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

View File

@@ -47,6 +47,8 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/s3m
${CMAKE_CURRENT_SOURCE_DIR}/it
${CMAKE_CURRENT_SOURCE_DIR}/xm
${CMAKE_CURRENT_SOURCE_DIR}/dsf
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
${CMAKE_SOURCE_DIR}/3rdparty
)
@@ -161,6 +163,11 @@ set(tag_HDRS
s3m/s3mproperties.h
xm/xmfile.h
xm/xmproperties.h
dsf/dsffile.h
dsf/dsfproperties.h
dsdiff/dsdifffile.h
dsdiff/dsdiffproperties.h
dsdiff/dsdiffdiintag.h
)
set(mpeg_SRCS
@@ -316,6 +323,17 @@ set(xm_SRCS
xm/xmproperties.cpp
)
set(dsf_SRCS
dsf/dsffile.cpp
dsf/dsfproperties.cpp
)
set(dsdiff_SRCS
dsdiff/dsdifffile.cpp
dsdiff/dsdiffproperties.cpp
dsdiff/dsdiffdiintag.cpp
)
set(toolkit_SRCS
toolkit/tstring.cpp
toolkit/tstringlist.cpp
@@ -347,7 +365,7 @@ set(tag_LIB_SRCS
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} ${dsf_SRCS} ${dsdiff_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp

View File

@@ -38,6 +38,8 @@
#include "vorbisproperties.h"
#include "wavproperties.h"
#include "wavpackproperties.h"
#include "dsfproperties.h"
#include "dsdiffproperties.h"
#include "audioproperties.h"
@@ -73,6 +75,10 @@ using namespace TagLib;
return dynamic_cast<const Vorbis::Properties*>(this)->function_name(); \
else if(dynamic_cast<const WavPack::Properties*>(this)) \
return dynamic_cast<const WavPack::Properties*>(this)->function_name(); \
else if(dynamic_cast<const DSF::Properties*>(this)) \
return dynamic_cast<const DSF::Properties*>(this)->function_name(); \
else if(dynamic_cast<const DSDIFF::Properties*>(this)) \
return dynamic_cast<const DSDIFF::Properties*>(this)->function_name(); \
else \
return (default_value);

162
3rdparty/taglib/dsdiff/dsdiffdiintag.cpp vendored Normal file
View File

@@ -0,0 +1,162 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "dsdiffdiintag.h"
#include "tstringlist.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace DSDIFF::DIIN;
class DSDIFF::DIIN::Tag::TagPrivate
{
public:
TagPrivate()
{
}
String title;
String artist;
};
DSDIFF::DIIN::Tag::Tag() : TagLib::Tag()
{
d = new TagPrivate;
}
DSDIFF::DIIN::Tag::~Tag()
{
delete d;
}
String DSDIFF::DIIN::Tag::title() const
{
return d->title;
}
String DSDIFF::DIIN::Tag::artist() const
{
return d->artist;
}
String DSDIFF::DIIN::Tag::album() const
{
return String();
}
String DSDIFF::DIIN::Tag::comment() const
{
return String();
}
String DSDIFF::DIIN::Tag::genre() const
{
return String();
}
unsigned int DSDIFF::DIIN::Tag::year() const
{
return 0;
}
unsigned int DSDIFF::DIIN::Tag::track() const
{
return 0;
}
void DSDIFF::DIIN::Tag::setTitle(const String &title)
{
if(title.isNull() || title.isEmpty())
d->title = String();
else
d->title = title;
}
void DSDIFF::DIIN::Tag::setArtist(const String &artist)
{
if(artist.isNull() || artist.isEmpty())
d->artist = String();
else
d->artist = artist;
}
void DSDIFF::DIIN::Tag::setAlbum(const String &)
{
}
void DSDIFF::DIIN::Tag::setComment(const String &)
{
}
void DSDIFF::DIIN::Tag::setGenre(const String &)
{
}
void DSDIFF::DIIN::Tag::setYear(unsigned int)
{
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int)
{
}
PropertyMap DSDIFF::DIIN::Tag::properties() const
{
PropertyMap properties;
properties["TITLE"] = d->title;
properties["ARTIST"] = d->artist;
return properties;
}
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap properties(origProps);
properties.removeEmpty();
StringList oneValueSet;
if(properties.contains("TITLE")) {
d->title = properties["TITLE"].front();
oneValueSet.append("TITLE");
} else
d->title = String();
if(properties.contains("ARTIST")) {
d->artist = properties["ARTIST"].front();
oneValueSet.append("ARTIST");
} else
d->artist = String();
// for each tag that has been set above, remove the first entry in the corresponding
// value list. The others will be returned as unsupported by this format.
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
properties.erase(*it);
else
properties[*it].erase(properties[*it].begin());
}
return properties;
}

150
3rdparty/taglib/dsdiff/dsdiffdiintag.h vendored Normal file
View File

@@ -0,0 +1,150 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFDIINTAG_H
#define TAGLIB_DSDIFFDIINTAG_H
#include "tag.h"
namespace TagLib {
namespace DSDIFF {
namespace DIIN {
/*!
* Tags from the Edited Master Chunk Info
*
* Only Title and Artist tags are supported
*/
class TAGLIB_EXPORT Tag : public TagLib::Tag
{
public:
Tag();
virtual ~Tag();
/*!
* Returns the track name; if no track name is present in the tag
* String() will be returned.
*/
String title() const;
/*!
* Returns the artist name; if no artist name is present in the tag
* String() will be returned.
*/
String artist() const;
/*!
* Not supported. Therefore always returns String().
*/
String album() const;
/*!
* Not supported. Therefore always returns String().
*/
String comment() const;
/*!
* Not supported. Therefore always returns String().
*/
String genre() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int year() const;
/*!
* Not supported. Therefore always returns 0.
*/
unsigned int track() const;
/*!
* Sets the title to \a title. If \a title is String() then this
* value will be cleared.
*/
void setTitle(const String &title);
/*!
* Sets the artist to \a artist. If \a artist is String() then this
* value will be cleared.
*/
void setArtist(const String &artist);
/*!
* Not supported and therefore ignored.
*/
void setAlbum(const String &album);
/*!
* Not supported and therefore ignored.
*/
void setComment(const String &comment);
/*!
* Not supported and therefore ignored.
*/
void setGenre(const String &genre);
/*!
* Not supported and therefore ignored.
*/
void setYear(unsigned int year);
/*!
* Not supported and therefore ignored.
*/
void setTrack(unsigned int track);
/*!
* Implements the unified property interface -- export function.
* Since the DIIN tag is very limited, the exported map is as well.
*/
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* Because of the limitations of the DIIN file tag, any tags besides
* TITLE and ARTIST, will be
* returned. Additionally, if the map contains tags with multiple values,
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
}
#endif

799
3rdparty/taglib/dsdiff/dsdifffile.cpp vendored Normal file
View File

@@ -0,0 +1,799 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include "tagunion.h"
#include "dsdifffile.h"
using namespace TagLib;
struct Chunk64
{
ByteVector name;
unsigned long long offset;
unsigned long long size;
char padding;
};
namespace
{
enum {
ID3v2Index = 0,
DIINIndex = 1
};
enum {
PROPChunk = 0,
DIINChunk = 1
};
}
class DSDIFF::File::FilePrivate
{
public:
FilePrivate() :
endianness(BigEndian),
size(0),
isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1),
properties(0),
id3v2TagChunkID("ID3 "),
hasID3v2(false),
hasDiin(false)
{
childChunkIndex[ID3v2Index] = -1;
childChunkIndex[DIINIndex] = -1;
}
~FilePrivate()
{
delete properties;
}
Endianness endianness;
ByteVector type;
unsigned long long size;
ByteVector format;
std::vector<Chunk64> chunks;
std::vector<Chunk64> childChunks[2];
int childChunkIndex[2];
bool isID3InPropChunk; // Two possibilities can be found: ID3V2 chunk inside PROP chunk or at root level
int duplicateID3V2chunkIndex; // 2 ID3 chunks are present. This is then the index of the one in
// PROP chunk that will be removed upon next save to remove duplicates.
Properties *properties;
TagUnion tag;
ByteVector id3v2TagChunkID;
bool hasID3v2;
bool hasDiin;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::~File()
{
delete d;
}
TagLib::Tag *DSDIFF::File::tag() const
{
return &d->tag;
}
ID3v2::Tag *DSDIFF::File::ID3v2Tag() const
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, false);
}
bool DSDIFF::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
DSDIFF::DIIN::Tag *DSDIFF::File::DIINTag() const
{
return d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
}
bool DSDIFF::File::hasDIINTag() const
{
return d->hasDiin;
}
PropertyMap DSDIFF::File::properties() const
{
if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
return PropertyMap();
}
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
if(d->hasID3v2)
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
if(d->hasDiin)
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
}
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties)
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
}
DSDIFF::Properties *DSDIFF::File::audioProperties() const
{
return d->properties;
}
bool DSDIFF::File::save()
{
if(readOnly()) {
debug("DSDIFF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSDIFF::File::save() -- Trying to save invalid file.");
return false;
}
// First: save ID3V2 chunk
ID3v2::Tag *id3v2Tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false);
if(d->isID3InPropChunk) {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setChildChunkData(d->id3v2TagChunkID, id3v2Tag->render(), PROPChunk);
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setChildChunkData(d->id3v2TagChunkID, ByteVector(), PROPChunk);
d->hasID3v2 = false;
}
}
else {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setRootChunkData(d->id3v2TagChunkID, id3v2Tag->render());
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setRootChunkData(d->id3v2TagChunkID, ByteVector());
d->hasID3v2 = false;
}
}
// Second: save the DIIN chunk
if(d->hasDiin) {
DSDIFF::DIIN::Tag *diinTag = d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
if(!diinTag->title().isNull() && !diinTag->title().isEmpty()) {
ByteVector diinTitle;
diinTitle.append(ByteVector::fromUInt(diinTag->title().size(), d->endianness == BigEndian));
diinTitle.append(ByteVector::fromCString(diinTag->title().toCString()));
setChildChunkData("DITI", diinTitle, DIINChunk);
}
else
setChildChunkData("DITI", ByteVector(), DIINChunk);
if(!diinTag->artist().isNull() && !diinTag->artist().isEmpty()) {
ByteVector diinArtist;
diinArtist.append(ByteVector::fromUInt(diinTag->artist().size(), d->endianness == BigEndian));
diinArtist.append(ByteVector::fromCString(diinTag->artist().toCString()));
setChildChunkData("DIAR", diinArtist, DIINChunk);
}
else
setChildChunkData("DIAR", ByteVector(), DIINChunk);
}
// Third: remove the duplicate ID3V2 chunk (inside PROP chunk) if any
if(d->duplicateID3V2chunkIndex>=0) {
setChildChunkData(d->duplicateID3V2chunkIndex, ByteVector(), PROPChunk);
d->duplicateID3V2chunkIndex = -1;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
{
if(data.isNull() || data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = d->chunks[i].size + d->chunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
removeBlock(d->chunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
for(unsigned long r = i + 1; r < d->chunks.size(); r++)
d->chunks[r].offset = d->chunks[r - 1].offset + 12
+ d->chunks[r - 1].size + d->chunks[r - 1].padding;
d->chunks.erase(d->chunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Now update the specific chunk
writeChunk(d->chunks[i].name,
data,
d->chunks[i].offset - 12,
d->chunks[i].size + d->chunks[i].padding + 12);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Finally update the internal offsets
updateRootChunksStructure(i + 1);
}
}
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data)
{
if(d->chunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
setRootChunkData(i, data);
return;
}
}
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = d->chunks.size() - 1;
unsigned long offset = d->chunks[i].offset + d->chunks[i].size + d->chunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Now add the chunk to the file
writeChunk(name,
data,
offset,
std::max<unsigned long long>(0, length() - offset),
(offset & 1) ? 1 : 0);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
d->chunks.push_back(chunk);
}
void DSDIFF::File::setChildChunkData(unsigned int i,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(data.isNull() || data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12;
d->size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// Update child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Remove the chunk
removeBlock(childChunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
// For child chunks
if((i + 1) < childChunks.size()) {
childChunks[i + 1].offset = childChunks[i].offset;
i++;
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
}
// And for root chunks
for(i = d->childChunkIndex[childChunkNum] + 1; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
childChunks.erase(childChunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding);
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// And the PROP chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += ((data.size() + 1) & ~1)
- (childChunks[i].size + childChunks[i].padding);
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now update the specific chunk
writeChunk(childChunks[i].name,
data,
childChunks[i].offset - 12,
childChunks[i].size + childChunks[i].padding + 12);
childChunks[i].size = data.size();
childChunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
// For child Chunks
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
// And for root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
}
}
void DSDIFF::File::setChildChunkData(const ByteVector &name,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(childChunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < childChunks.size(); i++) {
if(childChunks[i].name == name) {
setChildChunkData(i, data, childChunkNum);
return;
}
}
// Do not attempt to remove a non existing chunk
if(data.isNull() || data.isEmpty())
return;
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = childChunks.size() - 1;
unsigned long offset = childChunks[i].offset + childChunks[i].size + childChunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->size, d->endianness == BigEndian), 4, 8);
// And the child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1)
+ ((data.size() + 1) & ~1) + 12;
insert(ByteVector::fromLongLong(d->chunks[d->childChunkIndex[childChunkNum]].size,
d->endianness == BigEndian),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now add the chunk to the file
unsigned long long nextRootChunkIdx = length();
if((d->childChunkIndex[childChunkNum] + 1) < static_cast<int>(d->chunks.size()))
nextRootChunkIdx = d->chunks[d->childChunkIndex[childChunkNum] + 1].offset - 12;
writeChunk(name, data, offset,
std::max<unsigned long long>(0, nextRootChunkIdx - offset),
(offset & 1) ? 1 : 0);
// For root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
childChunks.push_back(chunk);
}
static bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4)
return false;
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127)
return false;
}
return true;
}
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk)
{
for(unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
// Update childchunks structure as well
if(d->childChunkIndex[PROPChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[PROPChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[PROPChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
if(d->childChunkIndex[DIINChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[DIINChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[DIINChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
}
void DSDIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
bool bigEndian = (d->endianness == BigEndian);
d->type = readBlock(4);
d->size = readBlock(8).toLongLong(bigEndian);
d->format = readBlock(4);
// + 12: chunk header at least, fix for additional junk bytes
while(tell() + 12 <= length()) {
ByteVector chunkName = readBlock(4);
unsigned long long chunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(chunkName)) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<unsigned long long>(tell()) + chunkSize > static_cast<unsigned long long>(length())) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName
+ "' has invalid size (larger than the file size)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = chunkName;
chunk.size = chunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->chunks.push_back(chunk);
}
unsigned long long lengthDSDSamplesTimeChannels = 0; // For DSD uncompressed
unsigned long long audioDataSizeinBytes = 0; // For computing bitrate
unsigned long dstNumFrames = 0; // For DST compressed frames
unsigned short dstFrameRate = 0; // For DST compressed frames
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == "DSD ") {
lengthDSDSamplesTimeChannels = d->chunks[i].size * 8;
audioDataSizeinBytes = d->chunks[i].size;
}
else if(d->chunks[i].name == "DST ") {
// Now decode the chunks inside the DST chunk to read the DST Frame Information one
long long dstChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
audioDataSizeinBytes = d->chunks[i].size;
while(tell() + 12 <= dstChunkEnd) {
ByteVector dstChunkName = readBlock(4);
long long dstChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(dstChunkName)) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + dstChunkSize > dstChunkEnd) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName
+ "' has invalid size (larger than the DST chunk)");
setValid(false);
break;
}
if(dstChunkName == "FRTE") {
// Found the DST frame information chunk
dstNumFrames = readBlock(4).toUInt(bigEndian);
dstFrameRate = readBlock(2).toUShort(bigEndian);
break; // Found the wanted one, no need to look at the others
}
seek(dstChunkSize, Current);
// Check padding
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
}
}
}
else if(d->chunks[i].name == "PROP") {
d->childChunkIndex[PROPChunk] = i;
// Now decodes the chunks inside the PROP chunk
long long propChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset + 4); // +4 to remove the 'SND ' marker at beginning of 'PROP' chunk
while(tell() + 12 <= propChunkEnd) {
ByteVector propChunkName = readBlock(4);
long long propChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(propChunkName)) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + propChunkSize > propChunkEnd) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName
+ "' has invalid size (larger than the PROP chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = propChunkName;
chunk.size = propChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[PROPChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "DIIN") {
d->childChunkIndex[DIINChunk] = i;
d->hasDiin = true;
// Now decode the chunks inside the DIIN chunk
long long diinChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
while(tell() + 12 <= diinChunkEnd) {
ByteVector diinChunkName = readBlock(4);
long long diinChunkSize = readBlock(8).toLongLong(bigEndian);
if(!isValidChunkID(diinChunkName)) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + diinChunkSize > diinChunkEnd) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName
+ "' has invalid size (larger than the DIIN chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = diinChunkName;
chunk.size = diinChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[DIINChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "ID3 " || d->chunks[i].name == "id3 ") {
d->id3v2TagChunkID = d->chunks[i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->chunks[i].offset));
d->isID3InPropChunk = false;
d->hasID3v2 = true;
}
}
if(!isValid())
return;
if(d->childChunkIndex[PROPChunk] < 0) {
debug("DSDIFF::File::read() -- no PROP chunk found");
setValid(false);
return;
}
// Read properties
unsigned int sampleRate=0;
unsigned short channels=0;
for(unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) {
if(d->childChunks[PROPChunk][i].name == "ID3 " || d->childChunks[PROPChunk][i].name == "id3 ") {
if(d->hasID3v2) {
d->duplicateID3V2chunkIndex = i;
continue; // ID3V2 tag has already been found at root level
}
d->id3v2TagChunkID = d->childChunks[PROPChunk][i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->childChunks[PROPChunk][i].offset));
d->isID3InPropChunk = true;
d->hasID3v2 = true;
}
else if(d->childChunks[PROPChunk][i].name == "FS ") {
// Sample rate
seek(d->childChunks[PROPChunk][i].offset);
sampleRate = readBlock(4).toUInt(0, 4, bigEndian);
}
else if(d->childChunks[PROPChunk][i].name == "CHNL") {
// Channels
seek(d->childChunks[PROPChunk][i].offset);
channels = readBlock(2).toShort(0, bigEndian);
}
}
// Read title & artist from DIIN chunk
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, true);
if(d->hasDiin) {
for(unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) {
if(d->childChunks[DIINChunk][i].name == "DITI") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int titleStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(titleStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector titleStr = readBlock(titleStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setTitle(titleStr);
}
}
else if(d->childChunks[DIINChunk][i].name == "DIAR") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int artistStrLength = readBlock(4).toUInt(0, 4, bigEndian);
if(artistStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector artistStr = readBlock(artistStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setArtist(artistStr);
}
}
}
}
if(readProperties) {
if(lengthDSDSamplesTimeChannels == 0) {
// DST compressed signal : need to compute length of DSD uncompressed frames
if(dstFrameRate > 0)
lengthDSDSamplesTimeChannels = (unsigned long long)dstNumFrames
* (unsigned long long)sampleRate / (unsigned long long)dstFrameRate;
else
lengthDSDSamplesTimeChannels = 0;
}
else {
// In DSD uncompressed files, the read number of samples is the total for each channel
if(channels > 0)
lengthDSDSamplesTimeChannels /= channels;
}
int bitrate = 0;
if(lengthDSDSamplesTimeChannels > 0)
bitrate = (audioDataSizeinBytes*8*sampleRate) / lengthDSDSamplesTimeChannels / 1000;
d->properties = new Properties(sampleRate,
channels,
lengthDSDSamplesTimeChannels,
bitrate,
propertiesStyle);
}
if(!ID3v2Tag()) {
d->tag.access<ID3v2::Tag>(ID3v2Index, true);
d->isID3InPropChunk = false; // By default, ID3 chunk is at root level
d->hasID3v2 = false;
}
}
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding)
{
ByteVector combined;
if(leadingPadding)
combined.append(ByteVector(leadingPadding, '\x00'));
combined.append(name);
combined.append(ByteVector::fromLongLong(data.size(), d->endianness == BigEndian));
combined.append(data);
if((data.size() & 0x01) != 0)
combined.append('\x00');
insert(combined, offset, replace);
}

251
3rdparty/taglib/dsdiff/dsdifffile.h vendored Normal file
View File

@@ -0,0 +1,251 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFFILE_H
#define TAGLIB_DSDIFFFILE_H
#include "rifffile.h"
#include "id3v2tag.h"
#include "dsdiffproperties.h"
#include "dsdiffdiintag.h"
namespace TagLib {
//! An implementation of DSDIFF metadata
/*!
* This is implementation of DSDIFF metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* chunk as well as properties from the file.
* Description of the DSDIFF format is available
* at http://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
* DSDIFF standard does not explictly specify the ID3V2 chunk
* It can be found at the root level, but also sometimes inside the PROP chunk
* In addition, title and artist info are stored as part of the standard
*/
namespace DSDIFF {
//! An implementation of TagLib::File with DSDIFF specific methods
/*!
* This implements and provides an interface for DSDIFF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSDIFF files.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Constructs an DSDIFF file from \a file. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Constructs an DSDIFF file from \a stream. If \a readProperties is true
* the file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
* tags. The ID3v2 tag is given priority in reading the information -- if
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
* the information from the ID3v2 tag will be returned.
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use the tag-type specific calls.
*
* \note As this tag is not implemented as an ID3v2 tag or a DIIN tag,
* but a union of the two this pointer may not be cast to the specific
* tag types.
*
* \see ID3v2Tag()
* \see DIINTag()
*/
virtual Tag *tag() const;
/*!
* Returns the ID3V2 Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the
* file on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
virtual ID3v2::Tag *ID3v2Tag() const;
/*!
* Returns the DSDIFF DIIN Tag for this file
*
*/
DSDIFF::DIIN::Tag *DIINTag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the AIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
* will duplicate its content into the other tag. This returns true
* if saving was successful.
*
* If neither exists or if both tags are empty, this will strip the tags
* from the file.
*
* This is the same as calling save(AllTags);
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use paramaterized save call below.
*
* \see save(int tags)
*/
virtual bool save();
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
*
* This strips all tags not included in the mask, but does not modify them
* in memory, so later calls to save() which make use of these tags will
* remain valid. This also strips empty tags.
*/
bool save(int tags);
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* Title & Artist tag.
*
* \see DIINTag()
*/
bool hasDIINTag() const;
protected:
enum Endianness { BigEndian, LittleEndian };
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
private:
File(const File &);
File &operator=(const File &);
/*!
* Sets the data for the the specified chunk at root level to \a data.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(unsigned int i, const ByteVector &data);
/*!
* Sets the data for the root-level chunk \a name to \a data.
* If a root-level chunk with the given name already exists
* it will be overwritten, otherwise it will be
* created after the existing chunks.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(const ByteVector &name, const ByteVector &data);
/*!
* Sets the data for the the specified child chunk to \a data.
*
* If data is null, then remove the chunk
*
* \warning This will update the file immediately.
*/
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
/*!
* Sets the data for the child chunk \a name to \a data. If a chunk with
* the given name already exists it will be overwritten, otherwise it will
* be created after the existing chunks inside child chunk.
*
* If data is null, then remove the chunks with \a name name
*
* \warning This will update the file immediately.
*/
void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum);
void updateRootChunksStructure(unsigned int startingChunk);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace = 0,
unsigned int leadingPadding = 0);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,120 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsdiffproperties.h"
using namespace TagLib;
class DSDIFF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
sampleWidth(0),
sampleCount(0)
{
}
int length;
int bitrate;
int sampleRate;
int channels;
int sampleWidth;
unsigned long long sampleCount;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::Properties::Properties(const unsigned int sampleRate,
const unsigned short channels,
const unsigned long long samplesCount,
const int bitrate,
ReadStyle style) : AudioProperties(style)
{
d = new PropertiesPrivate;
d->channels = channels;
d->sampleCount = samplesCount;
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5)
: 0;
}
DSDIFF::Properties::~Properties()
{
delete d;
}
int DSDIFF::Properties::length() const
{
return lengthInSeconds();
}
int DSDIFF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSDIFF::Properties::lengthInMilliseconds() const
{
return d->length;
}
int DSDIFF::Properties::bitrate() const
{
return d->bitrate;
}
int DSDIFF::Properties::sampleRate() const
{
return d->sampleRate;
}
int DSDIFF::Properties::channels() const
{
return d->channels;
}
int DSDIFF::Properties::bitsPerSample() const
{
return d->sampleWidth;
}
long long DSDIFF::Properties::sampleCount() const
{
return d->sampleCount;
}

View File

@@ -0,0 +1,83 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFPROPERTIES_H
#define TAGLIB_DSDIFFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSDIFF {
class File;
//! An implementation of audio property reading for DSDIFF
/*!
* This reads the data from an DSDIFF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
* Create an instance of DSDIFF::Properties with the data read from the
* ByteVector \a data.
*/
Properties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*!
* Destroys this DSDIFF::Properties instance.
*/
virtual ~Properties();
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int bitsPerSample() const;
long long sampleCount() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

229
3rdparty/taglib/dsf/dsffile.cpp vendored Normal file
View File

@@ -0,0 +1,229 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include "dsffile.h"
using namespace TagLib;
// The DSF specification is located at http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
class DSF::File::FilePrivate
{
public:
FilePrivate() :
properties(0),
tag(0)
{
}
~FilePrivate()
{
delete properties;
delete tag;
}
long long fileSize;
long long metadataOffset;
Properties *properties;
ID3v2::Tag *tag;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) :
TagLib::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
DSF::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
DSF::File::~File()
{
delete d;
}
ID3v2::Tag *DSF::File::tag() const
{
return d->tag;
}
PropertyMap DSF::File::properties() const
{
return d->tag->properties();
}
PropertyMap DSF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
DSF::Properties *DSF::File::audioProperties() const
{
return d->properties;
}
bool DSF::File::save()
{
if(readOnly()) {
debug("DSF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSF::File::save() -- Trying to save invalid file.");
return false;
}
// Three things must be updated: the file size, the tag data, and the metadata offset
if(d->tag->isEmpty()) {
long long newFileSize = d->metadataOffset ? d->metadataOffset : d->fileSize;
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset to 0 since there is no longer a tag
if(d->metadataOffset) {
insert(ByteVector::fromLongLong(0ULL, false), 20, 8);
d->metadataOffset = 0;
}
// Delete the old tag
truncate(newFileSize);
}
else {
ByteVector tagData = d->tag->render();
long long newMetadataOffset = d->metadataOffset ? d->metadataOffset : d->fileSize;
long long newFileSize = newMetadataOffset + tagData.size();
long long oldTagSize = d->fileSize - newMetadataOffset;
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromLongLong(newFileSize, false), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset
if(d->metadataOffset != newMetadataOffset) {
insert(ByteVector::fromLongLong(newMetadataOffset, false), 20, 8);
d->metadataOffset = newMetadataOffset;
}
// Delete the old tag and write the new one
insert(tagData, newMetadataOffset, static_cast<size_t>(oldTagSize));
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
// A DSF file consists of four chunks: DSD chunk, format chunk, data chunk, and metadata chunk
// The file format is not chunked in the sense of a RIFF File, though
// DSD chunk
ByteVector chunkName = readBlock(4);
if(chunkName != "DSD ") {
debug("DSF::File::read() -- Not a DSF file.");
setValid(false);
return;
}
long long chunkSize = readBlock(8).toLongLong(false);
// Integrity check
if(28 != chunkSize) {
debug("DSF::File::read() -- File is corrupted, wrong chunk size");
setValid(false);
return;
}
d->fileSize = readBlock(8).toLongLong(false);
// File is malformed or corrupted
if(d->fileSize != length()) {
debug("DSF::File::read() -- File is corrupted wrong length");
setValid(false);
return;
}
d->metadataOffset = readBlock(8).toLongLong(false);
// File is malformed or corrupted
if(d->metadataOffset > d->fileSize) {
debug("DSF::File::read() -- Invalid metadata offset.");
setValid(false);
return;
}
// Format chunk
chunkName = readBlock(4);
if(chunkName != "fmt ") {
debug("DSF::File::read() -- Missing 'fmt ' chunk.");
setValid(false);
return;
}
chunkSize = readBlock(8).toLongLong(false);
d->properties = new Properties(readBlock(chunkSize), propertiesStyle);
// Skip the data chunk
// A metadata offset of 0 indicates the absence of an ID3v2 tag
if(0 == d->metadataOffset)
d->tag = new ID3v2::Tag();
else
d->tag = new ID3v2::Tag(this, d->metadataOffset);
}

119
3rdparty/taglib/dsf/dsffile.h vendored Normal file
View File

@@ -0,0 +1,119 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFFILE_H
#define TAGLIB_DSFFILE_H
#include "tfile.h"
#include "id3v2tag.h"
#include "dsfproperties.h"
namespace TagLib {
//! An implementation of DSF metadata
/*!
* This is implementation of DSF metadata.
*
* This supports an ID3v2 tag as well as properties from the file.
*/
namespace DSF {
//! An implementation of TagLib::File with DSF specific methods
/*!
* This implements and provides an interface for DSF files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to DSF files.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an DSF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the Tag for this file.
*/
ID3v2::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the DSF::AudioProperties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
/*!
* Saves the file.
*/
virtual bool save();
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

161
3rdparty/taglib/dsf/dsfproperties.cpp vendored Normal file
View File

@@ -0,0 +1,161 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsfproperties.h"
using namespace TagLib;
class DSF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
formatVersion(0),
formatID(0),
channelType(0),
channelNum(0),
samplingFrequency(0),
bitsPerSample(0),
sampleCount(0),
blockSizePerChannel(0),
bitrate(0),
length(0)
{
}
// Nomenclature is from DSF file format specification
unsigned int formatVersion;
unsigned int formatID;
unsigned int channelType;
unsigned int channelNum;
unsigned int samplingFrequency;
unsigned int bitsPerSample;
long long sampleCount;
unsigned int blockSizePerChannel;
// Computed
unsigned int bitrate;
unsigned int length;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::Properties::Properties(const ByteVector &data, ReadStyle style) : TagLib::AudioProperties(style)
{
d = new PropertiesPrivate;
read(data);
}
DSF::Properties::~Properties()
{
delete d;
}
int DSF::Properties::length() const
{
return lengthInSeconds();
}
int DSF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSF::Properties::lengthInMilliseconds() const
{
return d->length;
}
int DSF::Properties::bitrate() const
{
return d->bitrate;
}
int DSF::Properties::sampleRate() const
{
return d->samplingFrequency;
}
int DSF::Properties::channels() const
{
return d->channelNum;
}
// DSF specific
int DSF::Properties::formatVersion() const
{
return d->formatVersion;
}
int DSF::Properties::formatID() const
{
return d->formatID;
}
int DSF::Properties::channelType() const
{
return d->channelType;
}
int DSF::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
long long DSF::Properties::sampleCount() const
{
return d->sampleCount;
}
int DSF::Properties::blockSizePerChannel() const
{
return d->blockSizePerChannel;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::Properties::read(const ByteVector &data)
{
d->formatVersion = data.toUInt(0U,false);
d->formatID = data.toUInt(4U,false);
d->channelType = data.toUInt(8U,false);
d->channelNum = data.toUInt(12U,false);
d->samplingFrequency = data.toUInt(16U,false);
d->bitsPerSample = data.toUInt(20U,false);
d->sampleCount = data.toLongLong(24U,false);
d->blockSizePerChannel = data.toUInt(32U,false);
d->bitrate
= static_cast<unsigned int>((d->samplingFrequency * d->bitsPerSample * d->channelNum) / 1000.0 + 0.5);
d->length
= d->samplingFrequency > 0 ? static_cast<unsigned int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5) : 0;
}

92
3rdparty/taglib/dsf/dsfproperties.h vendored Normal file
View File

@@ -0,0 +1,92 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFPROPERTIES_H
#define TAGLIB_DSFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSF {
class File;
//! An implementation of audio property reading for DSF
/*!
* This reads the data from a DSF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of DSF::AudioProperties with the data read from the
* ByteVector \a data.
*/
Properties(const ByteVector &data, ReadStyle style);
/*!
* Destroys this DSF::AudioProperties instance.
*/
virtual ~Properties();
// Reimplementations.
virtual int length() const;
virtual int lengthInSeconds() const;
virtual int lengthInMilliseconds() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
int formatVersion() const;
int formatID() const;
/*!
* Channel type values: 1 = mono, 2 = stereo, 3 = 3 channels,
* 4 = quad, 5 = 4 channels, 6 = 5 channels, 7 = 5.1 channels
*/
int channelType() const;
int bitsPerSample() const;
long long sampleCount() const;
int blockSizePerChannel() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(const ByteVector &data);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

View File

@@ -52,6 +52,8 @@
#include "s3mfile.h"
#include "itfile.h"
#include "xmfile.h"
#include "dsffile.h"
#include "dsdifffile.h"
using namespace TagLib;
@@ -135,6 +137,10 @@ namespace
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
return 0;
}
@@ -174,6 +180,10 @@ namespace
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
//else if(DSF::File::isSupported(stream))
//return new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
//else if(DSDIFF::File::isSupported(stream))
//return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
// isSupported() only does a quick check, so double check the file here.
@@ -255,6 +265,10 @@ namespace
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle);
return 0;
}
@@ -387,6 +401,9 @@ StringList FileRef::defaultFileExtensions()
l.append("s3m");
l.append("it");
l.append("xm");
l.append("dsf");
l.append("dff");
l.append("dsdiff"); // alias for "dff"
return l;
}

View File

@@ -63,6 +63,8 @@
#include "itfile.h"
#include "xmfile.h"
#include "mp4file.h"
#include "dsffile.h"
#include "dsdifffile.h"
using namespace TagLib;
@@ -148,6 +150,10 @@ PropertyMap File::properties() const
return dynamic_cast<const MP4::File* >(this)->properties();
if(dynamic_cast<const ASF::File* >(this))
return dynamic_cast<const ASF::File* >(this)->properties();
if(dynamic_cast<const DSF::File* >(this))
return dynamic_cast<const DSF::File* >(this)->properties();
if(dynamic_cast<const DSDIFF::File* >(this))
return dynamic_cast<const DSDIFF::File* >(this)->properties();
return tag()->properties();
}
@@ -177,6 +183,10 @@ void File::removeUnsupportedProperties(const StringList &properties)
dynamic_cast<MP4::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<ASF::File* >(this))
dynamic_cast<ASF::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<DSF::File* >(this))
dynamic_cast<DSF::File* >(this)->removeUnsupportedProperties(properties);
else if(dynamic_cast<DSDIFF::File* >(this))
dynamic_cast<DSDIFF::File* >(this)->removeUnsupportedProperties(properties);
else
tag()->removeUnsupportedProperties(properties);
}
@@ -219,6 +229,10 @@ PropertyMap File::setProperties(const PropertyMap &properties)
return dynamic_cast<MP4::File* >(this)->setProperties(properties);
else if(dynamic_cast<ASF::File* >(this))
return dynamic_cast<ASF::File* >(this)->setProperties(properties);
else if(dynamic_cast<DSF::File* >(this))
return dynamic_cast<DSF::File* >(this)->setProperties(properties);
else if(dynamic_cast<DSDIFF::File* >(this))
return dynamic_cast<DSDIFF::File* >(this)->setProperties(properties);
else
return tag()->setProperties(properties);
}

View File

@@ -18,7 +18,9 @@
project(strawberry)
cmake_minimum_required(VERSION 2.8.11)
cmake_policy(SET CMP0054 NEW)
if(${CMAKE_VERSION} VERSION_GREATER "3.0")
cmake_policy(SET CMP0054 NEW)
endif()
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
cmake_policy(SET CMP0072 NEW)
endif()
@@ -32,6 +34,7 @@ include(cmake/Summary.cmake)
include(cmake/OptionalSource.cmake)
include(cmake/ParseArguments.cmake)
include(cmake/Rpm.cmake)
include(cmake/Deb.cmake)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(LINUX 1)
@@ -82,18 +85,21 @@ find_package(Protobuf REQUIRED)
find_library(PROTOBUF_STATIC_LIBRARY libprotobuf.a libprotobuf)
if(LINUX)
find_package(ALSA REQUIRED)
find_package(DBus REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
else(LINUX)
find_package(ALSA)
find_package(DBus)
pkg_check_modules(DBUS dbus-1)
endif(LINUX)
if(ALSA_FOUND)
set(HAVE_ALSA ON)
endif()
find_package(X11)
if (NOT APPLE)
find_package(X11)
endif()
if(X11_FOUND)
set(HAVE_X11 ON)
endif()
find_package(OpenGL REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
@@ -103,9 +109,11 @@ pkg_check_modules(LIBXINE libxine)
pkg_check_modules(LIBVLC libvlc)
pkg_check_modules(PHONON phonon4qt5)
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.7)
find_package(OpenGL REQUIRED)
pkg_check_modules(CHROMAPRINT REQUIRED libchromaprint)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(CHROMAPRINT libchromaprint)
#if(CHROMAPRINT_FOUND)
# set(HAVE_CHROMAPRINT ON)
#endif()
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0)
@@ -129,6 +137,9 @@ endif()
if(APPLE)
find_package(Qt5 REQUIRED COMPONENTS MacExtras)
endif()
if(WIN32)
find_package(Qt5 REQUIRED COMPONENTS WinExtras)
endif()
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml)
@@ -141,11 +152,9 @@ endif()
if(APPLE)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::MacExtras)
endif()
# Don't try to use webkit if their include directories couldn't be found.
if (NOT QT_QTWEBKIT_INCLUDE_DIR)
set (QT_USE_QTWEBKIT 0)
endif (NOT QT_QTWEBKIT_INCLUDE_DIR)
if(WIN32)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras)
endif()
# TAGLIB
pkg_check_modules(TAGLIB taglib)
@@ -162,6 +171,10 @@ if (TAGLIB_FOUND AND USE_SYSTEM_TAGLIB)
set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}")
set(CMAKE_REQUIRED_INCLUDES)
set(CMAKE_REQUIRED_LIBRARIES)
find_path(HAVE_TAGLIB_DSFFILE_H taglib/dsffile.h)
if(HAVE_TAGLIB_DSFFILE_H)
set(HAVE_TAGLIB_DSFFILE ON)
endif(HAVE_TAGLIB_DSFFILE_H)
else()
message(STATUS "Using builtin taglib library")
set(TAGLIB_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/taglib/;${CMAKE_BINARY_DIR}/3rdparty/taglib/headers/")
@@ -169,6 +182,7 @@ else()
set(TAGLIB_LIBRARIES tag)
add_subdirectory(3rdparty/utf8-cpp)
add_subdirectory(3rdparty/taglib)
set(HAVE_TAGLIB_DSFFILE ON)
endif()
# LASTFM
@@ -179,9 +193,6 @@ if(LASTFM5_INCLUDE_DIRS AND LASTFM51_INCLUDE_DIRS)
set(HAVE_LIBLASTFM1 ON)
endif()
# CHECK INCLUDES
CHECK_INCLUDE_FILES(chromaprint.h CHROMAPRINT_H)
# Use system sha2 if it's available
find_path(SHA2_INCLUDE_DIRS sha2.h)
find_library(SHA2_LIBRARIES sha2)
@@ -233,11 +244,6 @@ endif (USE_SYSTEM_QXT)
set(QOCOA_LIBRARIES Qocoa)
add_subdirectory(3rdparty/qocoa)
# Windows
if (WIN32)
add_subdirectory(3rdparty/qtwin)
endif (WIN32)
if (APPLE)
find_library(SPARKLE Sparkle)
add_subdirectory(3rdparty/SPMediaKeyTap)
@@ -281,34 +287,22 @@ optional_component(PHONON OFF "Engine: Phonon backend"
DEPENDS "phonon4qt5" PHONON_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
optional_component(LIBGPOD ON "Devices: iPod classic support"
DEPENDS "libgpod" LIBGPOD_FOUND
)
optional_component(GIO ON "Devices: GIO device backend"
DEPENDS "libgio" GIO_FOUND
DEPENDS "Unix or Windows" "NOT APPLE"
)
optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND
DEPENDS "libplist" PLIST_FOUND
DEPENDS "libusbmuxd" USBMUXD_FOUND
DEPENDS "iPod classic support" HAVE_LIBGPOD
)
optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
)
optional_component(LIBLASTFM ON "Last.fm album cover provider"
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS
)
optional_component(CHROMAPRINT ON "Chromaprint support / Tag fetching from Musicbrainz"
DEPENDS "chromaprint" CHROMAPRINT_FOUND
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
optional_component(DEVICEKIT ON "Devices: DeviceKit backend"
DEPENDS "D-Bus support" DBUS_FOUND
)
@@ -317,8 +311,24 @@ optional_component(UDISKS2 ON "Devices: UDisks2 backend"
DEPENDS "D-Bus support" DBUS_FOUND
)
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
optional_component(GIO ON "Devices: GIO device backend"
DEPENDS "libgio" GIO_FOUND
DEPENDS "Unix or Windows" "NOT APPLE"
)
optional_component(LIBGPOD ON "Devices: iPod classic support"
DEPENDS "libgpod" LIBGPOD_FOUND
)
optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
)
optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND
DEPENDS "libplist" PLIST_FOUND
DEPENDS "libusbmuxd" USBMUXD_FOUND
DEPENDS "iPod classic support" LIBGPOD_FOUND
)
optional_component(SPARKLE ON "Sparkle integration"

View File

@@ -2,6 +2,44 @@ Strawberry Music Player
=======================
ChangeLog
Version 0.3.3:
* Fixed Tidal login
Version 0.3.2:
* Fixed search error not shown in Tidal search
* Added URL handler for Tidal, now retriving URL's when playing instead of when searching
* Fixed bug in pipeline not setting url
* Fixed bug setting wrong temporary metadata
* Removed device module from windows, since it's not implemented for windows
* Added support for both ALSA hw and plughw
* Added option to change url stream scheme for Tidal
* Added encoding of Tidal token in the source code
* Added encoding of Tidal password in the configuration
Version 0.3.1:
* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
* Fixed playing and context widget getting stuck in play mode when there was an error
* Changed icons for artists in collection, tidal and cover manager
* Removed "search" icon from "Search automatically" checkbox (right click) that looked ugly
* Removed some unused widgets from the src/widgets directory
* Fixed initial size of window and side panel
* Fixed saving window size correctly
* Added Tidal support
* Disabled Amazon cover provider because of revoked API key
* Removed broken xine fader
* Made chromeprint optional
* Added missing names to about dialog
* Made xine enabled only for window debug
* Removed dead code
* Added DSF and DSDIFF/DFF support
* Fixed tagreader crash when saving tags to MP3 files
* Added support for reading/writing lyrics to tags
* Fixed saving tags (APE) for WavPack files
Version 0.2.1:
* Fixed crash with newer Qt

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
from opensuse:tumbleweed
run zypper --non-interactive --gpg-auto-import-keys ref
run zypper --non-interactive --gpg-auto-import-keys dup -l -y
run zypper --non-interactive --gpg-auto-import-keys install \
lsb-release \
git tar make cmake gcc gcc-c++ pkg-config \
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
boost-devel protobuf-devel sqlite3-devel taglib-devel \
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-devel \
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5OpenGL-devel libQt5Sql-devel \
libqt5-qtx11extras-devel libQt5Gui-private-headers-devel libqt5-qtbase-common-devel liblastfm-qt5-devel \
libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel
run mkdir -p /usr/src/app
workdir /usr/src/app
copy . /usr/src/app

View File

@@ -1,22 +1,33 @@
:strawberry: Strawberry Music Player
:strawberry: Strawberry Music Player [![Build Status](https://travis-ci.org/jonaski/strawberry.svg?branch=master)](https://travis-ci.org/jonaski/strawberry)
=======================
Strawberry is a audio player and music collection organizer. It is a fork of Clementine created in 2013 with a diffrent goal.
It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
* Website: http://www.strawbs.org/
* Github: https://github.com/jonaski/strawberry
* Buildbot: http://buildbot.strawbs.net/
* Latest builds: http://builds.strawbs.org/
### :heavy_check_mark: Features:
* Play and organize music
* Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
* Audio CD playback
* Native desktop notifications
* Playlists in multiple formats
* Advanced output and device options with support for bit perfect playback on Linux
* Edit tags on music files
* Fetch tags from MusicBrainz
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
* Album cover art from Last.fm, Musicbrainz and Discogs
* Song lyrics from AudD and API Seeds
* Support for multiple backends
* Audio analyzer
* Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support
It has so far been tested to work on Linux, OpenBSD and Windows (cross compiled using mingw).
It has so far been tested to work on Linux, OpenBSD, MacOs and Windows.
### :heavy_exclamation_mark: Requirements
@@ -28,7 +39,7 @@ To build Strawberry from source you need the following installed on your system
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* [Protobuf library and compiler](https://developers.google.com/protocol-buffers/)
* [Boost development headers](https://www.boost.org/)
* [Qt 5 with components Core, Widgets, Network, Sql, Xml, OpenGL, Concurrent, Test, WebKitWidget, X11Extras and DBus](https://www.qt.io/)
* [Qt 5 with components Core, Gui, Widgets, Concurrent, Network, Sql, Xml, OpenGL, X11Extras and DBus](https://www.qt.io/)
* [SQLite3](https://www.sqlite.org)
* [TagLib 1.11.1 or higher](http://taglib.org/)
* [Chromaprint library](https://acoustid.org/chromaprint)

6
cmake/Deb.cmake Normal file
View File

@@ -0,0 +1,6 @@
add_custom_target(deb
#COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/dist/debian ${CMAKE_BINARY_DIR}/debian
COMMAND cp -r -p ${CMAKE_SOURCE_DIR}/dist/debian ${CMAKE_BINARY_DIR}/
COMMAND dpkg-buildpackage -b -d -uc -us
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

View File

@@ -1,43 +0,0 @@
if(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
# Already in cache, be silent
set(DBUS_FIND_QUIETLY TRUE)
endif(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
set(DBUS_LIBRARY)
set(DBUS_INCLUDE_DIR)
set(DBUS_ARCH_INCLUDE_DIR)
FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h
/usr/include
/usr/include/dbus-1.0
/usr/local/include
/usr/local/include/dbus-1.0
)
FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h
/usr/lib/include
/usr/lib/dbus-1.0/include
/usr/lib64/include
/usr/lib64/dbus-1.0/include
/usr/local/lib/include
/usr/local/lib/dbus-1.0/include
/usr/local/lib64/include
/usr/local/lib64/dbus-1.0/include
)
FIND_LIBRARY(DBUS_LIBRARY NAMES dbus-1 dbus
PATHS
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
)
if(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MESSAGE(STATUS "D-Bus found: includes in ${DBUS_INCLUDE_DIR}, library in ${DBUS_LIBRARY}")
set(DBUS_FOUND TRUE)
else(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MESSAGE(STATUS "D-Bus not found")
endif(DBUS_INCLUDE_DIR AND DBUS_LIBRARY AND DBUS_ARCH_INCLUDE_DIR)
MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_LIBRARY DBUS_ARCH_INCLUDE_DIR)

View File

@@ -1,12 +1,65 @@
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
set(MOCK_COMMAND mock CACHE STRING "Command to use for running mock")
set(MOCK_CHROOT suse-x86_64 CACHE STRING "Chroot to use when building an rpm with mock")
set(RPM_DISTRO suse CACHE STRING "Suffix of the rpm file")
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
find_program(LSB_RELEASE_EXEC lsb_release)
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/rpm/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/rpm/strawberry.spec
)
if (LSB_RELEASE_EXEC)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -is | tr '[:upper:]' '[:lower:]' | cut -d' ' -f1"
OUTPUT_VARIABLE DIST_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | cut -d' ' -f2"
OUTPUT_VARIABLE DIST_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
OUTPUT_VARIABLE DIST_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (DIST_NAME)
message(STATUS "Distro Name: ${DIST_NAME}")
if (DIST_RELEASE)
message(STATUS "Distro Release: ${DIST_RELEASE}")
endif()
if (DIST_VERSION)
message(STATUS "Distro Version: ${DIST_VERSION}")
endif()
set(RPM_ARCH x86_64 CACHE STRING "Architecture of the rpm file")
set(RPMBUILD_DIR ~/rpmbuild CACHE STRING "Rpmbuild directory, for the rpm target")
if (${DIST_NAME} STREQUAL "opensuse")
if (DIST_RELEASE)
if (${DIST_RELEASE} STREQUAL "leap")
if (DIST_VERSION)
set(RPM_DISTRO "lp${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
else()
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
endif()
elseif (${DIST_RELEASE} STREQUAL "tumbleweed")
set(RPM_DISTRO ${DIST_RELEASE} CACHE STRING "Suffix of the rpm file")
else ()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
else()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
)
elseif (${DIST_NAME} STREQUAL "fedora")
if (DIST_VERSION)
set(RPM_DISTRO "${DIST_NAME}${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
else ()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/fedora/strawberry.spec
)
else()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif()
message(STATUS "RPM Suffix: ${RPM_DISTRO}")
endif()
endif()

View File

@@ -1,14 +1,10 @@
set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 2)
set(STRAWBERRY_VERSION_PATCH 1)
set(STRAWBERRY_VERSION_MINOR 3)
set(STRAWBERRY_VERSION_PATCH 3)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)
if (WIN32)
set(INCLUDE_GIT_REVISION OFF)
endif()
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
@@ -26,10 +22,11 @@ if(STRAWBERRY_VERSION_PRERELEASE)
set(STRAWBERRY_VERSION_PACKAGE "${STRAWBERRY_VERSION_PACKAGE}${STRAWBERRY_VERSION_PRERELEASE}")
endif(STRAWBERRY_VERSION_PRERELEASE)
if(INCLUDE_GIT_REVISION)
if(INCLUDE_GIT_REVISION AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
find_program(GIT_EXECUTABLE git)
if(GIT_EXECUTABLE-NOTFOUND)
if(NOT GIT_EXECUTABLE OR GIT_EXECUTABLE-NOTFOUND)
message(FATAL_ERROR "Missing GIT executable." )
endif()
@@ -56,6 +53,14 @@ if(INCLUDE_GIT_REVISION)
message(FATAL_ERROR "GIT command failed to get revision string '${GIT_REVISION}'")
endif()
endif()
if(FORCE_GIT_REVISION)
set(GIT_REVISION ${FORCE_GIT_REVISION})
endif()
if(GIT_REVISION)
string(REGEX REPLACE "^(.+)-([0-9]+)-(g[a-f0-9]+)$" "\\1;\\2;\\3" GIT_PARTS ${GIT_REVISION})
if(NOT GIT_PARTS)

View File

@@ -1,9 +1,11 @@
<RCC>
<qresource prefix="/">
<file>schema/schema.sql</file>
<file>schema/schema-1.sql</file>
<file>schema/schema-2.sql</file>
<file>schema/schema-3.sql</file>
<file>schema/device-schema.sql</file>
<file>style/mainwindow.css</file>
<file>style/statusview.css</file>
<file>style/strawberry.css</file>
<file>misc/playing_tooltip.txt</file>
<file>pictures/strawberry.png</file>
<file>pictures/strawbs-transparent.png</file>
@@ -72,7 +74,6 @@
<file>icons/128x128/go-previous.png</file>
<file>icons/128x128/go-up.png</file>
<file>icons/128x128/gstreamer.png</file>
<file>icons/128x128/guitar.png</file>
<file>icons/128x128/headset.png</file>
<file>icons/128x128/help-hint.png</file>
<file>icons/128x128/intel.png</file>
@@ -92,13 +93,10 @@
<file>icons/128x128/play2.png</file>
<file>icons/128x128/realtek.png</file>
<file>icons/128x128/search.png</file>
<file>icons/128x128/soundcard2.png</file>
<file>icons/128x128/soundcard.png</file>
<file>icons/128x128/speaker.png</file>
<file>icons/128x128/star-grey.png</file>
<file>icons/128x128/star.png</file>
<file>icons/128x128/strawberry-panel-grey.png</file>
<file>icons/128x128/strawberry-panel.png</file>
<file>icons/128x128/strawberry.png</file>
<file>icons/128x128/strawberry.svg</file>
<file>icons/128x128/tools-wizard.png</file>
@@ -113,6 +111,7 @@
<file>icons/128x128/xine.png</file>
<file>icons/128x128/zoom-in.png</file>
<file>icons/128x128/zoom-out.png</file>
<file>icons/128x128/tidal.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
@@ -160,7 +159,6 @@
<file>icons/64x64/go-previous.png</file>
<file>icons/64x64/go-up.png</file>
<file>icons/64x64/gstreamer.png</file>
<file>icons/64x64/guitar.png</file>
<file>icons/64x64/headset.png</file>
<file>icons/64x64/help-hint.png</file>
<file>icons/64x64/intel.png</file>
@@ -181,13 +179,10 @@
<file>icons/64x64/pulseaudio.png</file>
<file>icons/64x64/realtek.png</file>
<file>icons/64x64/search.png</file>
<file>icons/64x64/soundcard2.png</file>
<file>icons/64x64/soundcard.png</file>
<file>icons/64x64/speaker.png</file>
<file>icons/64x64/star-grey.png</file>
<file>icons/64x64/star.png</file>
<file>icons/64x64/strawberry-panel-grey.png</file>
<file>icons/64x64/strawberry-panel.png</file>
<file>icons/64x64/strawberry.png</file>
<file>icons/64x64/tools-wizard.png</file>
<file>icons/64x64/view-choose.png</file>
@@ -201,6 +196,7 @@
<file>icons/64x64/xine.png</file>
<file>icons/64x64/zoom-in.png</file>
<file>icons/64x64/zoom-out.png</file>
<file>icons/64x64/tidal.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
@@ -248,7 +244,6 @@
<file>icons/48x48/go-previous.png</file>
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/gstreamer.png</file>
<file>icons/48x48/guitar.png</file>
<file>icons/48x48/headset.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/intel.png</file>
@@ -272,13 +267,10 @@
<file>icons/48x48/pulseaudio.png</file>
<file>icons/48x48/realtek.png</file>
<file>icons/48x48/search.png</file>
<file>icons/48x48/soundcard2.png</file>
<file>icons/48x48/soundcard.png</file>
<file>icons/48x48/speaker.png</file>
<file>icons/48x48/star-grey.png</file>
<file>icons/48x48/star.png</file>
<file>icons/48x48/strawberry-panel-grey.png</file>
<file>icons/48x48/strawberry-panel.png</file>
<file>icons/48x48/strawberry.png</file>
<file>icons/48x48/tools-wizard.png</file>
<file>icons/48x48/view-choose.png</file>
@@ -292,6 +284,7 @@
<file>icons/48x48/xine.png</file>
<file>icons/48x48/zoom-in.png</file>
<file>icons/48x48/zoom-out.png</file>
<file>icons/48x48/tidal.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
@@ -339,7 +332,6 @@
<file>icons/32x32/go-previous.png</file>
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/gstreamer.png</file>
<file>icons/32x32/guitar.png</file>
<file>icons/32x32/headset.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/intel.png</file>
@@ -363,13 +355,10 @@
<file>icons/32x32/pulseaudio.png</file>
<file>icons/32x32/realtek.png</file>
<file>icons/32x32/search.png</file>
<file>icons/32x32/soundcard2.png</file>
<file>icons/32x32/soundcard.png</file>
<file>icons/32x32/speaker.png</file>
<file>icons/32x32/star-grey.png</file>
<file>icons/32x32/star.png</file>
<file>icons/32x32/strawberry-panel-grey.png</file>
<file>icons/32x32/strawberry-panel.png</file>
<file>icons/32x32/strawberry.png</file>
<file>icons/32x32/strawberry.svg</file>
<file>icons/32x32/tools-wizard.png</file>
@@ -384,6 +373,7 @@
<file>icons/32x32/xine.png</file>
<file>icons/32x32/zoom-in.png</file>
<file>icons/32x32/zoom-out.png</file>
<file>icons/32x32/tidal.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
@@ -431,7 +421,6 @@
<file>icons/22x22/go-previous.png</file>
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/gstreamer.png</file>
<file>icons/22x22/guitar.png</file>
<file>icons/22x22/headset.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/intel.png</file>
@@ -455,13 +444,10 @@
<file>icons/22x22/pulseaudio.png</file>
<file>icons/22x22/realtek.png</file>
<file>icons/22x22/search.png</file>
<file>icons/22x22/soundcard2.png</file>
<file>icons/22x22/soundcard.png</file>
<file>icons/22x22/speaker.png</file>
<file>icons/22x22/star-grey.png</file>
<file>icons/22x22/star.png</file>
<file>icons/22x22/strawberry-panel-grey.png</file>
<file>icons/22x22/strawberry-panel.png</file>
<file>icons/22x22/strawberry.png</file>
<file>icons/22x22/strawberry.svg</file>
<file>icons/22x22/tools-wizard.png</file>
@@ -476,5 +462,7 @@
<file>icons/22x22/xine.png</file>
<file>icons/22x22/zoom-in.png</file>
<file>icons/22x22/zoom-out.png</file>
<file>icons/22x22/tidal.png</file>
<file>fonts/HumongousofEternitySt.ttf</file>
</qresource>
</RCC>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
data/icons/22x22/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

BIN
data/icons/32x32/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

BIN
data/icons/48x48/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

BIN
data/icons/64x64/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 KiB

BIN
data/icons/full/tidal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -11,8 +11,6 @@ CREATE TABLE device_%deviceid_subdirectories (
CREATE TABLE device_%deviceid_songs (
/* Metadata from taglib */
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
@@ -27,6 +25,7 @@ CREATE TABLE device_%deviceid_songs (
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -35,8 +34,7 @@ CREATE TABLE device_%deviceid_songs (
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
/* Information about the file on disk */
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
@@ -45,8 +43,6 @@ CREATE TABLE device_%deviceid_songs (
ctime INTEGER NOT NULL,
unavailable INTEGER DEFAULT 0,
/* Other */
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,

3
data/schema/schema-1.sql Normal file
View File

@@ -0,0 +1,3 @@
ALTER TABLE playlist_items ADD COLUMN internet_service TEXT;
UPDATE schema_version SET version=1;

5
data/schema/schema-2.sql Normal file
View File

@@ -0,0 +1,5 @@
ALTER TABLE songs ADD COLUMN lyrics TEXT;
ALTER TABLE playlist_items ADD COLUMN lyrics TEXT;
UPDATE schema_version SET version=2;

65
data/schema/schema-3.sql Normal file
View File

@@ -0,0 +1,65 @@
ALTER TABLE songs ADD COLUMN source INTEGER NOT NULL DEFAULT 0;
UPDATE songs SET source = 2 WHERE source = 0;
DROP TABLE playlist_items;
CREATE TABLE IF NOT EXISTS playlist_items (
playlist INTEGER NOT NULL,
type INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER,
url TEXT,
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
albumartist TEXT NOT NULL,
track INTEGER NOT NULL DEFAULT -1,
disc INTEGER NOT NULL DEFAULT -1,
year INTEGER NOT NULL DEFAULT -1,
originalyear INTEGER NOT NULL DEFAULT 0,
genre TEXT NOT NULL,
compilation INTEGER NOT NULL DEFAULT -1,
composer TEXT NOT NULL,
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
bitrate INTEGER NOT NULL DEFAULT 0,
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER,
filename TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
filesize INTEGER,
mtime INTEGER,
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
compilation_detected INTEGER DEFAULT 0,
compilation_on INTEGER NOT NULL DEFAULT 0,
compilation_off INTEGER NOT NULL DEFAULT 0,
compilation_effective INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
UPDATE schema_version SET version=3;

View File

@@ -1,23 +1,23 @@
CREATE TABLE schema_version (
CREATE TABLE IF NOT EXISTS schema_version (
version INTEGER NOT NULL
);
INSERT INTO schema_version (version) VALUES (0);
DELETE FROM schema_version;
CREATE TABLE directories (
INSERT INTO schema_version (version) VALUES (3);
CREATE TABLE IF NOT EXISTS directories (
path TEXT NOT NULL,
subdirs INTEGER NOT NULL
);
CREATE TABLE subdirectories (
CREATE TABLE IF NOT EXISTS subdirectories (
directory_id INTEGER NOT NULL,
path TEXT NOT NULL,
mtime INTEGER NOT NULL
);
CREATE TABLE songs (
/* Metadata from taglib */
CREATE TABLE IF NOT EXISTS songs (
title TEXT NOT NULL,
album TEXT NOT NULL,
@@ -33,6 +33,7 @@ CREATE TABLE songs (
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -41,8 +42,7 @@ CREATE TABLE songs (
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
/* Information about the file on disk */
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER NOT NULL,
filename TEXT NOT NULL,
filetype INTEGER NOT NULL DEFAULT 0,
@@ -51,8 +51,6 @@ CREATE TABLE songs (
ctime INTEGER NOT NULL,
unavailable INTEGER DEFAULT 0,
/* Other */
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
@@ -67,12 +65,12 @@ CREATE TABLE songs (
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);
CREATE TABLE playlists (
CREATE TABLE IF NOT EXISTS playlists (
name TEXT NOT NULL,
last_played INTEGER NOT NULL DEFAULT -1,
@@ -83,15 +81,13 @@ CREATE TABLE playlists (
);
CREATE TABLE playlist_items (
CREATE TABLE IF NOT EXISTS playlist_items (
playlist INTEGER NOT NULL,
type TEXT NOT NULL,
type INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER,
url TEXT,
/* Metadata from taglib */
title TEXT NOT NULL,
album TEXT NOT NULL,
artist TEXT NOT NULL,
@@ -106,6 +102,7 @@ CREATE TABLE playlist_items (
performer TEXT NOT NULL,
grouping TEXT NOT NULL,
comment TEXT NOT NULL,
lyrics TEXT NOT NULL,
beginning INTEGER NOT NULL DEFAULT 0,
length INTEGER NOT NULL DEFAULT 0,
@@ -114,8 +111,7 @@ CREATE TABLE playlist_items (
samplerate INTEGER NOT NULL DEFAULT 0,
bitdepth INTEGER NOT NULL DEFAULT 0,
/* Information about the file on disk */
source INTEGER NOT NULL DEFAULT 0,
directory_id INTEGER,
filename TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
@@ -124,8 +120,6 @@ CREATE TABLE playlist_items (
ctime INTEGER,
unavailable INTEGER DEFAULT 0,
/* Other */
playcount INTEGER NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER NOT NULL DEFAULT 0,
@@ -145,7 +139,7 @@ CREATE TABLE playlist_items (
);
CREATE TABLE devices (
CREATE TABLE IF NOT EXISTS devices (
unique_id TEXT NOT NULL,
friendly_name TEXT,
size INTEGER,
@@ -155,17 +149,17 @@ CREATE TABLE devices (
transcode_format NOT NULL DEFAULT 5
);
CREATE INDEX idx_filename ON songs (filename);
CREATE INDEX IF NOT EXISTS idx_filename ON songs (filename);
CREATE INDEX idx_comp_artist ON songs (compilation_effective, artist);
CREATE INDEX IF NOT EXISTS idx_comp_artist ON songs (compilation_effective, artist);
CREATE INDEX idx_album ON songs (album);
CREATE INDEX IF NOT EXISTS idx_album ON songs (album);
CREATE INDEX idx_title ON songs (title);
CREATE INDEX IF NOT EXISTS idx_title ON songs (title);
CREATE VIEW duplicated_songs as select artist dup_artist, album dup_album, title dup_title from songs as inner_songs where artist != '' and album != '' and title != '' and unavailable = 0 group by artist, album , title having count(*) > 1;
CREATE VIEW IF NOT EXISTS duplicated_songs as select artist dup_artist, album dup_album, title dup_title from songs as inner_songs where artist != '' and album != '' and title != '' and unavailable = 0 group by artist, album , title having count(*) > 1;
CREATE VIRTUAL TABLE songs_fts USING fts3(
CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts3(
ftstitle,
ftsalbum,
@@ -180,7 +174,7 @@ CREATE VIRTUAL TABLE songs_fts USING fts3(
);
CREATE VIRTUAL TABLE playlist_items_fts_ USING fts3(
CREATE VIRTUAL TABLE IF NOT EXISTS playlist_items_fts_ USING fts3(
ftstitle,
ftsalbum,
@@ -195,7 +189,7 @@ CREATE VIRTUAL TABLE playlist_items_fts_ USING fts3(
);
CREATE VIRTUAL TABLE %allsongstables_fts USING fts3(
CREATE VIRTUAL TABLE IF NOT EXISTS %allsongstables_fts USING fts3(
ftstitle,
ftsalbum,
@@ -211,7 +205,7 @@ CREATE VIRTUAL TABLE %allsongstables_fts USING fts3(
);
INSERT INTO songs_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
INSERT INTO songs_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM songs;
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)

View File

@@ -1,11 +0,0 @@
StatusView {
background: white;
background-color: white;
}
QVBoxLayout {
background: white;
background-color: white;
}
QScrollArea {
background: qpalette(base);
}

View File

@@ -52,3 +52,20 @@ darwin {
darwin QMenu {
font-size: 13pt;
}
#scrollarea_play {
background-color: white;
font: 11pt;
}
#scrollarea_stop {
background-color: white;
font: 11pt;
}
#scrollAreaWidgetContents_stop {
background-color: white;
}
#scrollAreaWidgetContents_play {
background-color: white;
}

14
dist/CMakeLists.txt vendored
View File

@@ -1,9 +1,17 @@
set(ENV{LC_ALL} "en_US.utf8")
execute_process(COMMAND date "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND env LC_ALL="en_US.utf8" date "+%a %b %d %Y" OUTPUT_VARIABLE RPM_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/rpm/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/rpm/strawberry.spec @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh @ONLY)
if (RPM_DISTRO)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/opensuse/strawberry.spec @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec @ONLY)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug.nsi @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug-64.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-debug-64.nsi @ONLY)
if (UNIX AND NOT APPLE)
install(FILES ../data/icons/48x48/strawberry.png DESTINATION share/icons/hicolor/48x48/apps/)

5
dist/debian/changelog.in vendored Normal file
View File

@@ -0,0 +1,5 @@
strawberry (${STRAWBERRY_VERSION_DISPLAY}) unstable; urgency=low
* Version ${STRAWBERRY_VERSION_DISPLAY}
-- Jonas Kvinge <jonas@jkvinge.net> ${DEB_DATE}

1
dist/debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

70
dist/debian/control vendored Normal file
View File

@@ -0,0 +1,70 @@
Source: strawberry
Section: sound
Priority: optional
Maintainer: "Jonas Kvinge" <jonas@jkvinge.net>
Build-Depends: debhelper (>= 7),
make,
cmake,
gcc,
protobuf-compiler,
libglib2.0-dev,
libdbus-1-dev,
libprotobuf-dev,
libboost-dev,
libsqlite3-dev,
libasound2-dev,
libpulse-dev,
libtag1-dev,
libqt5-dev,
qtbase5-dev,
qtbase5-dev-tools,
qtbase5-private-dev,
qt5-dev-tools,
libqt5opengl5-dev,
libqt5x11extras5-dev,
libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev,
libxine2-dev,
libvlc-dev,
libphonon4qt5-dev,
libcdio-dev,
libgpod-dev,
libimobiledevice-dev,
libmtp-dev,
libplist-dev,
libusbmuxd-dev,
libchromaprint-dev,
liblastfm5-dev
Standards-Version: 3.9.8
Package: strawberry
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
libsqlite3-0,
gstreamer1.0-plugins-base,
gstreamer1.0-plugins-good,
gstreamer1.0-alsa,
gstreamer1.0-pulseaudio
Homepage: http://www.strawbs.org/
Description: Audio player and music collection organizer
Strawberry is a audio player especially aimed at audiophiles.
.
Features:
- Play and organize music
- Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
- Audio CD playback
- Native desktop notifications
- Playlists in multiple formats
- Advanced output and device options with support for bit perfect playback on Linux
- Edit tags on music files
- Fetch tags from MusicBrainz
- Album cover art from Lastfm, Musicbrainz and Discogs
- Song lyrics from AudD and API Seeds
- Support for multiple backends
- Audio analyzer
- Equalizer
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
- Integrated Tidal support
.
It is a fork of Clementine. The name is inspired by the band Strawbs.

61
dist/debian/rules vendored Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/make -f
# -*- makefile -*-
MY_MAKEFLAGS=
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
NUMJOBS=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
MY_MAKEFLAGS=-j$(NUMJOBS)
endif
configure: configure-stamp
configure-stamp:
dh_testdir
cmake .. \
-DCMAKE_INSTALL_PREFIX=$(CURDIR)/debian/strawberry/usr
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
make $(MY_MAKEFLAGS)
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
-make clean
-rm Makefile src/Makefile
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
make install
binary-indep: install
binary-arch: install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installmenu
dh_installdocs
dh_gconf
dh_link
dh_strip
dh_compress
dh_fixperms
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

118
dist/fedora/strawberry.spec.in vendored Normal file
View File

@@ -0,0 +1,118 @@
Name: strawberry
Version: @STRAWBERRY_VERSION_RPM_V@
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
Summary: A audio player and music collection organiser
Group: Applications/Multimedia
License: GPL-3.0+
URL: http://www.strawbs.org/
Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
BuildRequires: boost-devel
BuildRequires: cmake
BuildRequires: desktop-file-utils
BuildRequires: gcc-c++
BuildRequires: hicolor-icon-theme
BuildRequires: liblastfm-qt5-devel
BuildRequires: make
BuildRequires: git
BuildRequires: pkgconfig
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(gio-unix-2.0)
BuildRequires: pkgconfig(gthread-2.0)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(protobuf)
BuildRequires: pkgconfig(sqlite3) >= 3.7
BuildRequires: pkgconfig(taglib) >= 1.11
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Gui)
BuildRequires: pkgconfig(Qt5Widgets)
BuildRequires: pkgconfig(Qt5Concurrent)
BuildRequires: pkgconfig(Qt5Sql)
BuildRequires: pkgconfig(Qt5Network)
BuildRequires: pkgconfig(Qt5Xml)
BuildRequires: pkgconfig(Qt5X11Extras)
BuildRequires: pkgconfig(Qt5DBus)
BuildRequires: pkgconfig(Qt5OpenGL)
BuildRequires: pkgconfig(gstreamer-1.0)
BuildRequires: pkgconfig(gstreamer-app-1.0)
BuildRequires: pkgconfig(gstreamer-audio-1.0)
BuildRequires: pkgconfig(gstreamer-base-1.0)
BuildRequires: pkgconfig(gstreamer-tag-1.0)
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(libcdio)
BuildRequires: pkgconfig(libchromaprint)
BuildRequires: pkgconfig(libgpod-1.0)
BuildRequires: pkgconfig(libmtp)
BuildRequires: pkgconfig(libnotify)
BuildRequires: pkgconfig(libudf)
%description
Strawberry is a audio player and music collection organizer.
It is a fork of Clementine. The name is inspired by the band Strawbs.
Features:
* Play and organize music
* Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
* Audio CD playback
* Native desktop notifications
* Playlists in multiple formats
* Advanced output and device options with support for bit perfect playback on Linux
* Edit tags on music files
* Fetch tags from MusicBrainz
* Album cover art from Last.fm, Musicbrainz and Discogs
* Song lyrics from AudD and API Seeds
* Support for multiple backends
* Audio analyzer
* Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support
%prep
%setup -qn %{name}-@STRAWBERRY_VERSION_PACKAGE@
%build
%if 0%{?fedora} > 27
# workaround FTBFS
export CXXFLAGS="%{optflags} -fpermissive"
%endif
mkdir %{_target_platform}
pushd %{_target_platform}
%{cmake} \
-DBUILD_WERROR:BOOL=OFF \
-DCMAKE_BUILD_TYPE:STRING=Release \
..
popd
%make_build -C %{_target_platform}
%install
make install DESTDIR=%{buildroot} -C %{_target_platform}
rm -rf %{buildroot}%{_datadir}/man
%check
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
pushd %{_target_platform}
popd
%clean
%files
%defattr(-,root,root,-)
%doc
%{_bindir}/strawberry
%{_bindir}/strawberry-tagreader
%{_datadir}/applications/strawberry.desktop
%{_datadir}/icons/hicolor/48x48/apps/strawberry.png
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
%changelog
* @RPM_DATE@ Jonas Kvinge <jonas@strawbs.net> - @STRAWBERRY_VERSION_RPM_V@
- Version @STRAWBERRY_VERSION_PACKAGE@

View File

@@ -9,7 +9,11 @@ URL: http://www.strawbs.org/
Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%if 0%{?suse_version} > 1325
BuildRequires: libboost_headers-devel
%else
BuildRequires: boost-devel
%endif
BuildRequires: cmake
BuildRequires: desktop-file-utils
BuildRequires: gcc-c++
@@ -27,32 +31,30 @@ BuildRequires: pkgconfig(gthread-2.0)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(protobuf)
BuildRequires: pkgconfig(Qt5Concurrent)
BuildRequires: pkgconfig(sqlite3) >= 3.7
BuildRequires: pkgconfig(taglib) >= 1.11
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Gui)
BuildRequires: pkgconfig(Qt5Network)
BuildRequires: pkgconfig(Qt5OpenGL)
BuildRequires: pkgconfig(Qt5Sql)
BuildRequires: pkgconfig(Qt5Test)
BuildRequires: pkgconfig(Qt5WebKit)
BuildRequires: pkgconfig(Qt5WebKitWidgets)
BuildRequires: pkgconfig(Qt5Widgets)
BuildRequires: pkgconfig(Qt5Concurrent)
BuildRequires: pkgconfig(Qt5Sql)
BuildRequires: pkgconfig(Qt5Network)
BuildRequires: pkgconfig(Qt5Xml)
BuildRequires: pkgconfig(Qt5X11Extras)
BuildRequires: pkgconfig(Qt5DBus)
BuildRequires: pkgconfig(Qt5OpenGL)
BuildRequires: pkgconfig(gstreamer-1.0)
BuildRequires: pkgconfig(gstreamer-app-1.0)
BuildRequires: pkgconfig(gstreamer-audio-1.0)
BuildRequires: pkgconfig(gstreamer-base-1.0)
BuildRequires: pkgconfig(gstreamer-tag-1.0)
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(libcdio)
BuildRequires: pkgconfig(libchromaprint)
BuildRequires: pkgconfig(libgpod-1.0)
BuildRequires: pkgconfig(libmtp)
BuildRequires: pkgconfig(libnotify)
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(libudf)
BuildRequires: pkgconfig(libxml-2.0)
BuildRequires: pkgconfig(sqlite3) >= 3.7
BuildRequires: pkgconfig(taglib) >= 1.11
BuildRequires: pkgconfig(libxine)
BuildRequires: pkgconfig(libvlc)
@@ -62,13 +64,20 @@ It is a fork of Clementine. The name is inspired by the band Strawbs.
Features:
* Play and organize music
* Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
* Audio CD playback
* Native desktop notifications
* Playlists in multiple formats
* Advanced output and device options with support for bit perfect playback on Linux
* Edit tags on music files
* Fetch tags from MusicBrainz
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Album cover art from Last.fm, Musicbrainz and Discogs
* Song lyrics from AudD and API Seeds
* Support for multiple backends
* Audio analyzer
* Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support
%prep
%setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@
@@ -101,3 +110,4 @@ make clean
%changelog
* @RPM_DATE@ Jonas Kvinge <jonas@strawbs.net> - @STRAWBERRY_VERSION_RPM_V@
- Version @STRAWBERRY_VERSION_PACKAGE@

View File

@@ -16,12 +16,14 @@ echo "Creating $name-$version.tar.xz..."
rm -f "$name-$version.tar.xz"
tar -cJf $name-$version.tar.xz \
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
--exclude "*.tar" \
--exclude "*.tar.*" \
--exclude "*.bz" \
--exclude "*.bz2" \
--exclude "*.xz" \
--exclude ".directory" \
--exclude "$root/CMakeLists.txt.user" \
--exclude "$root/build" \
--exclude="*.tar" \
--exclude="*.tar.*" \
--exclude="*.bz" \
--exclude="*.bz2" \
--exclude="*.xz" \
--exclude=".directory" \
--exclude="*.spec" \
--exclude="*.nsi" \
--exclude="$root/CMakeLists.txt.user" \
--exclude="$root/build" \
"$root"

445
dist/windows/strawberry-64.nsi.in vendored Normal file
View File

@@ -0,0 +1,445 @@
!define PRODUCT_NAME "Strawberry"
!define PRODUCT_PUBLISHER "Strawberry"
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
; Set Application Capabilities info
!define CAPABILITIES_NAME "Strawberry Music Player"
!define CAPABILITIES_LOCAL_NAME "Strawberry"
!define CAPABILITIES_PROGID "Strawberry Music Player"
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
!define CAPABILITIES_REINSTALL "Command to reinstall"
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
SetCompressor /SOLID lzma
!addplugindir nsisplugins
!include "MUI2.nsh"
!include "FileAssociation.nsh"
!include "Capabilities.nsh"
!define MUI_ICON "strawberry.ico"
!define MUI_COMPONENTSPAGE_SMALLDESC
;!define MUI_FINISHPAGE_RUN
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
; Installer pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Release-x64.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
; Get the path where Strawberry was installed previously and set it as default path
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
ShowInstDetails show
ShowUnInstDetails show
RequestExecutionLevel admin
;RequestExecutionLevel user
; Check for previous installation, and call the uninstaller if any
Function CheckPreviousInstall
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
StrCmp $R0 "" done
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
previous version or `Cancel` to cancel this upgrade." \
IDOK uninst
Abort
; Run the uninstaller
uninst:
ClearErrors
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
done:
FunctionEnd
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
Call CheckPreviousInstall
FunctionEnd
;Function RunStrawberry
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
;FunctionEnd
Section "Delete old files" oldfiles
SectionEnd
Section "Strawberry" Strawberry
SetOutPath "$INSTDIR"
File "strawberry.exe"
File "strawberry-tagreader.exe"
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libchromaprint.dll"
File "libcrypto-1_1-x64.dll"
File "libfaad-2.dll"
File "libffi-6.dll"
File "libFLAC-8.dll"
File "libfreetype-6.dll"
File "libgcc_s_seh-1.dll"
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "libgmodule-2.0-0.dll"
File "libgobject-2.0-0.dll"
File "libgstapp-1.0-0.dll"
File "libgstaudio-1.0-0.dll"
File "libgstbase-1.0-0.dll"
File "libgstfft-1.0-0.dll"
File "libgstpbutils-1.0-0.dll"
File "libgstreamer-1.0-0.dll"
File "libgstriff-1.0-0.dll"
File "libgstrtp-1.0-0.dll"
File "libgstrtsp-1.0-0.dll"
File "libgstsdp-1.0-0.dll"
File "libgsttag-1.0-0.dll"
File "libgstvideo-1.0-0.dll"
File "libgstnet-1.0-0.dll"
File "libharfbuzz-0.dll"
File "libiconv-2.dll"
File "libintl-8.dll"
File "libjpeg-9.dll"
File "liblastfm5.dll"
File "libmp3lame-0.dll"
File "libogg-0.dll"
File "libopus-0.dll"
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-15.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
File "libssl-1_1-x64.dll"
File "libstdc++-6.dll"
File "libtag.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
File "libwavpack-1.dll"
File "libwinpthread-1.dll"
File "Qt5Concurrent.dll"
File "Qt5Core.dll"
File "Qt5Gui.dll"
File "Qt5Network.dll"
File "Qt5Sql.dll"
File "Qt5Widgets.dll"
File "Qt5Xml.dll"
File "Qt5WinExtras.dll"
File "zlib1.dll"
;File "libmpcdec-5.dll"
;File "libtheora-0.dll"
File "libfftw3-3.dll"
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
Var /GLOBAL AppExe
StrCpy $AppExe "$INSTDIR\strawberry.exe"
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
${RegisterCapabilities}
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
SectionEnd
Section "Qt Platforms" platforms
SetOutPath "$INSTDIR\platforms"
File "/oname=qwindows.dll" "platforms\qwindows.dll"
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
SectionEnd
Section "Qt image format plugins" imageformats
SetOutPath "$INSTDIR\imageformats"
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
SetOutPath "$INSTDIR\gstreamer-plugins"
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
SectionEnd
Section "Start menu items" startmenu
; Create Start Menu folders and shortcuts.
SetShellVarContext all
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
; Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Section "Uninstall"
; Kill strawberry.exe if it's running
; This calling convention is retarded...
;StrCpy $0 "strawberry.exe"
;KillProc::FindProcesses
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
;KillProc::KillProcesses
;StrCmp $1 "-1" wooops
;Sleep 2000
;Goto completed
;wooops:
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
;Abort
;completed:
; Delete all the files
Delete "$INSTDIR\strawberry.ico"
Delete "$INSTDIR\strawberry.exe"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libffi-6.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll"
Delete "$INSTDIR\libgobject-2.0-0.dll"
Delete "$INSTDIR\libgstapp-1.0-0.dll"
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
Delete "$INSTDIR\libgstbase-1.0-0.dll"
Delete "$INSTDIR\libgstfft-1.0-0.dll"
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
Delete "$INSTDIR\libgstriff-1.0-0.dll"
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
Delete "$INSTDIR\libgsttag-1.0-0.dll"
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
Delete "$INSTDIR\libgstnet-1.0-0.dll"
Delete "$INSTDIR\libharfbuzz-0.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libintl-8.dll"
Delete "$INSTDIR\libjpeg-9.dll"
Delete "$INSTDIR\liblastfm5.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libopus-0.dll"
Delete "$INSTDIR\libpcre-1.dll"
Delete "$INSTDIR\libpcre2-16-0.dll"
Delete "$INSTDIR\libpng16-16.dll"
Delete "$INSTDIR\libprotobuf-15.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
Delete "$INSTDIR\libssl-1_1.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
Delete "$INSTDIR\libwavpack-1.dll"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\Qt5Concurrent.dll"
Delete "$INSTDIR\Qt5Core.dll"
Delete "$INSTDIR\Qt5Gui.dll"
Delete "$INSTDIR\Qt5Network.dll"
Delete "$INSTDIR\Qt5Sql.dll"
Delete "$INSTDIR\Qt5Widgets.dll"
Delete "$INSTDIR\Qt5Xml.dll"
Delete "$INSTDIR\Qt5WinExtras.dll"
Delete "$INSTDIR\zlib1.dll"
;Delete "$INSTDIR\libmpcdec-5.dll"
;Delete "$INSTDIR\libtheora-0.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
Delete "$INSTDIR\imageformats\qgif.dll"
Delete "$INSTDIR\imageformats\qico.dll"
Delete "$INSTDIR\imageformats\qjpeg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\Uninstall.exe"
; Remove the installation folders.
RMDir "$INSTDIR\platforms"
RMDir "$INSTDIR\sqldrivers"
RMDir "$INSTDIR\imageformats"
RMDir "$INSTDIR\gstreamer-plugins"
RMDir "$INSTDIR\xine-plugins"
RMDir "$INSTDIR"
; Remove the Shortcuts
SetShellVarContext all
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
; Remove the entry from 'installed programs list'
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
; Unregister from Default Programs
${UnRegisterCapabilities}
SectionEnd

505
dist/windows/strawberry-debug-64.nsi.in vendored Normal file
View File

@@ -0,0 +1,505 @@
!define PRODUCT_NAME "Strawberry"
!define PRODUCT_PUBLISHER "Strawberry"
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
; Set Application Capabilities info
!define CAPABILITIES_NAME "Strawberry Music Player"
!define CAPABILITIES_LOCAL_NAME "Strawberry"
!define CAPABILITIES_PROGID "Strawberry Music Player"
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
!define CAPABILITIES_REINSTALL "Command to reinstall"
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
SetCompressor /SOLID lzma
!addplugindir nsisplugins
!include "MUI2.nsh"
!include "FileAssociation.nsh"
!include "Capabilities.nsh"
!define MUI_ICON "strawberry.ico"
!define MUI_COMPONENTSPAGE_SMALLDESC
;!define MUI_FINISHPAGE_RUN
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
; Installer pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Debug-x64.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
; Get the path where Strawberry was installed previously and set it as default path
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
ShowInstDetails show
ShowUnInstDetails show
RequestExecutionLevel admin
;RequestExecutionLevel user
; Check for previous installation, and call the uninstaller if any
Function CheckPreviousInstall
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
StrCmp $R0 "" done
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
previous version or `Cancel` to cancel this upgrade." \
IDOK uninst
Abort
; Run the uninstaller
uninst:
ClearErrors
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
done:
FunctionEnd
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
Call CheckPreviousInstall
FunctionEnd
;Function RunStrawberry
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
;FunctionEnd
Section "Delete old files" oldfiles
SectionEnd
Section "Strawberry" Strawberry
SetOutPath "$INSTDIR"
File "strawberry.exe"
File "strawberry-tagreader.exe"
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libchromaprint.dll"
File "libcrypto-1_1-x64.dll"
File "libfaad-2.dll"
File "libffi-6.dll"
File "libFLAC-8.dll"
File "libfreetype-6.dll"
File "libgcc_s_seh-1.dll"
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "libgmodule-2.0-0.dll"
File "libgobject-2.0-0.dll"
File "libgstapp-1.0-0.dll"
File "libgstaudio-1.0-0.dll"
File "libgstbase-1.0-0.dll"
File "libgstfft-1.0-0.dll"
File "libgstpbutils-1.0-0.dll"
File "libgstreamer-1.0-0.dll"
File "libgstriff-1.0-0.dll"
File "libgstrtp-1.0-0.dll"
File "libgstrtsp-1.0-0.dll"
File "libgstsdp-1.0-0.dll"
File "libgsttag-1.0-0.dll"
File "libgstvideo-1.0-0.dll"
File "libgstnet-1.0-0.dll"
File "libharfbuzz-0.dll"
File "libiconv-2.dll"
File "libintl-8.dll"
File "libjpeg-9.dll"
File "liblastfm5.dll"
File "libmp3lame-0.dll"
File "libogg-0.dll"
File "libopus-0.dll"
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-15.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
File "libssl-1_1-x64.dll"
File "libstdc++-6.dll"
File "libtag.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
File "libwavpack-1.dll"
File "libwinpthread-1.dll"
File "Qt5Concurrent.dll"
File "Qt5Core.dll"
File "Qt5Gui.dll"
File "Qt5Network.dll"
File "Qt5Sql.dll"
File "Qt5Widgets.dll"
File "Qt5Xml.dll"
File "Qt5WinExtras.dll"
File "zlib1.dll"
File "libxine-2.dll"
File "libmpcdec-5.dll"
File "libtheora-0.dll"
File "libfftw3-3.dll"
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
Var /GLOBAL AppExe
StrCpy $AppExe "$INSTDIR\strawberry.exe"
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
${RegisterCapabilities}
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
SectionEnd
Section "Qt Platforms" platforms
SetOutPath "$INSTDIR\platforms"
File "/oname=qwindows.dll" "platforms\qwindows.dll"
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
SectionEnd
Section "Qt image format plugins" imageformats
SetOutPath "$INSTDIR\imageformats"
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
SetOutPath "$INSTDIR\gstreamer-plugins"
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
SectionEnd
Section "Xine plugins" xine-plugins
SetOutPath "$INSTDIR\xine-plugins"
File "/oname=xineplug_ao_out_directx2.dll" "xine-plugins\xineplug_ao_out_directx2.dll"
File "/oname=xineplug_ao_out_directx.dll" "xine-plugins\xineplug_ao_out_directx.dll"
File "/oname=xineplug_decode_dts.dll" "xine-plugins\xineplug_decode_dts.dll"
File "/oname=xineplug_decode_dvaudio.dll" "xine-plugins\xineplug_decode_dvaudio.dll"
File "/oname=xineplug_decode_faad.dll" "xine-plugins\xineplug_decode_faad.dll"
File "/oname=xineplug_decode_gsm610.dll" "xine-plugins\xineplug_decode_gsm610.dll"
File "/oname=xineplug_decode_lpcm.dll" "xine-plugins\xineplug_decode_lpcm.dll"
File "/oname=xineplug_decode_mad.dll" "xine-plugins\xineplug_decode_mad.dll"
File "/oname=xineplug_decode_mpc.dll" "xine-plugins\xineplug_decode_mpc.dll"
File "/oname=xineplug_decode_mpeg2.dll" "xine-plugins\xineplug_decode_mpeg2.dll"
File "/oname=xineplug_dmx_asf.dll" "xine-plugins\xineplug_dmx_asf.dll"
File "/oname=xineplug_dmx_audio.dll" "xine-plugins\xineplug_dmx_audio.dll"
File "/oname=xineplug_dmx_playlist.dll" "xine-plugins\xineplug_dmx_playlist.dll"
File "/oname=xineplug_dmx_slave.dll" "xine-plugins\xineplug_dmx_slave.dll"
File "/oname=xineplug_flac.dll" "xine-plugins\xineplug_flac.dll"
File "/oname=xineplug_wavpack.dll" "xine-plugins\xineplug_wavpack.dll"
File "/oname=xineplug_xiph.dll" "xine-plugins\xineplug_xiph.dll"
File "/oname=xineplug_inp_cdda.dll" "xine-plugins\xineplug_inp_cdda.dll"
File "/oname=xineplug_post_audio_filters.dll" "xine-plugins\xineplug_post_audio_filters.dll"
File "/oname=xineplug_post_goom.dll" "xine-plugins\xineplug_post_goom.dll"
File "/oname=xineplug_post_mosaico.dll" "xine-plugins\xineplug_post_mosaico.dll"
File "/oname=xineplug_post_planar.dll" "xine-plugins\xineplug_post_planar.dll"
File "/oname=xineplug_post_switch.dll" "xine-plugins\xineplug_post_switch.dll"
File "/oname=xineplug_post_tvtime.dll" "xine-plugins\xineplug_post_tvtime.dll"
File "/oname=xineplug_post_visualizations.dll" "xine-plugins\xineplug_post_visualizations.dll"
SectionEnd
Section "Start menu items" startmenu
; Create Start Menu folders and shortcuts.
SetShellVarContext all
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
; Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Section "Uninstall"
; Kill strawberry.exe if it's running
; This calling convention is retarded...
;StrCpy $0 "strawberry.exe"
;KillProc::FindProcesses
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
;KillProc::KillProcesses
;StrCmp $1 "-1" wooops
;Sleep 2000
;Goto completed
;wooops:
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
;Abort
;completed:
; Delete all the files
Delete "$INSTDIR\strawberry.ico"
Delete "$INSTDIR\strawberry.exe"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libffi-6.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll"
Delete "$INSTDIR\libgobject-2.0-0.dll"
Delete "$INSTDIR\libgstapp-1.0-0.dll"
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
Delete "$INSTDIR\libgstbase-1.0-0.dll"
Delete "$INSTDIR\libgstfft-1.0-0.dll"
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
Delete "$INSTDIR\libgstriff-1.0-0.dll"
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
Delete "$INSTDIR\libgsttag-1.0-0.dll"
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
Delete "$INSTDIR\libgstnet-1.0-0.dll"
Delete "$INSTDIR\libharfbuzz-0.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libintl-8.dll"
Delete "$INSTDIR\libjpeg-9.dll"
Delete "$INSTDIR\liblastfm5.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libopus-0.dll"
Delete "$INSTDIR\libpcre-1.dll"
Delete "$INSTDIR\libpcre2-16-0.dll"
Delete "$INSTDIR\libpng16-16.dll"
Delete "$INSTDIR\libprotobuf-15.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
Delete "$INSTDIR\libssl-1_1.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
Delete "$INSTDIR\libwavpack-1.dll"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\Qt5Concurrent.dll"
Delete "$INSTDIR\Qt5Core.dll"
Delete "$INSTDIR\Qt5Gui.dll"
Delete "$INSTDIR\Qt5Network.dll"
Delete "$INSTDIR\Qt5Sql.dll"
Delete "$INSTDIR\Qt5Widgets.dll"
Delete "$INSTDIR\Qt5Xml.dll"
Delete "$INSTDIR\Qt5WinExtras.dll"
Delete "$INSTDIR\zlib1.dll"
Delete "$INSTDIR\libxine-2.dll"
Delete "$INSTDIR\libmpcdec-5.dll"
Delete "$INSTDIR\libtheora-0.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
Delete "$INSTDIR\imageformats\qgif.dll"
Delete "$INSTDIR\imageformats\qico.dll"
Delete "$INSTDIR\imageformats\qjpeg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx2.dll"
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_dts.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_dvaudio.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_faad.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_gsm610.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_lpcm.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_mad.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpc.dll"
Delete "$INSTDIR\xine-plugins\xineplug_decode_mpeg2.dll"
Delete "$INSTDIR\xine-plugins\xineplug_dmx_asf.dll"
Delete "$INSTDIR\xine-plugins\xineplug_dmx_audio.dll"
Delete "$INSTDIR\xine-plugins\xineplug_dmx_playlist.dll"
Delete "$INSTDIR\xine-plugins\xineplug_dmx_slave.dll"
Delete "$INSTDIR\xine-plugins\xineplug_flac.dll"
Delete "$INSTDIR\xine-plugins\xineplug_wavpack.dll"
Delete "$INSTDIR\xine-plugins\xineplug_xiph.dll"
Delete "$INSTDIR\xine-plugins\xineplug_inp_cdda.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_audio_filters.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_goom.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_mosaico.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_planar.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_switch.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_tvtime.dll"
Delete "$INSTDIR\xine-plugins\xineplug_post_visualizations.dll"
Delete "$INSTDIR\Uninstall.exe"
; Remove the installation folders.
RMDir "$INSTDIR\platforms"
RMDir "$INSTDIR\sqldrivers"
RMDir "$INSTDIR\imageformats"
RMDir "$INSTDIR\gstreamer-plugins"
RMDir "$INSTDIR\xine-plugins"
RMDir "$INSTDIR"
; Remove the Shortcuts
SetShellVarContext all
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
; Remove the entry from 'installed programs list'
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
; Unregister from Default Programs
${UnRegisterCapabilities}
SectionEnd

View File

@@ -1,10 +1,10 @@
!define PRODUCT_NAME "Strawberry"
!define PRODUCT_PUBLISHER "Strawberry"
!define PRODUCT_VERSION_MAJOR 0
!define PRODUCT_VERSION_MINOR 2
!define PRODUCT_VERSION_PATCH 1
!define PRODUCT_DISPLAY_VERSION "0.2.1"
!define PRODUCT_DISPLAY_VERSION_SHORT "0.2.1"
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
@@ -48,7 +48,7 @@ SetCompressor /SOLID lzma
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME}Setup-0.2.1.exe"
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Debug.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
; Get the path where Strawberry was installed previously and set it as default path
@@ -87,50 +87,6 @@ Function .onInit
FunctionEnd
;!define LVM_GETITEMCOUNT 0x1004
!define LVM_GETITEMTEXT 0x102D
Function DumpLog
Exch $5
Push $0
Push $1
Push $2
Push $3
Push $4
Push $6
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 1016
StrCmp $0 0 exit
FileOpen $5 $5 "w"
StrCmp $5 "" exit
SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
System::Alloc ${NSIS_MAX_STRLEN}
Pop $3
StrCpy $2 0
System::Call "*(i, i, i, i, i, i, i, i, i) i \
(0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
loop: StrCmp $2 $6 done
System::Call "User32::SendMessageA(i, i, i, i) i \
($0, ${LVM_GETITEMTEXT}, $2, r1)"
System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
FileWrite $5 "$4$\r$\n"
IntOp $2 $2 + 1
Goto loop
done:
FileClose $5
System::Free $1
System::Free $3
exit:
Pop $6
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
Exch $5
FunctionEnd
;Function RunStrawberry
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
;FunctionEnd
@@ -170,6 +126,7 @@ Section "Strawberry" Strawberry
File "libgstsdp-1.0-0.dll"
File "libgsttag-1.0-0.dll"
File "libgstvideo-1.0-0.dll"
File "libgstnet-1.0-0.dll"
File "libharfbuzz-0.dll"
File "libiconv-2.dll"
File "libintl-8.dll"
@@ -198,11 +155,15 @@ Section "Strawberry" Strawberry
File "Qt5Sql.dll"
File "Qt5Widgets.dll"
File "Qt5Xml.dll"
File "Qt5WinExtras.dll"
File "zlib1.dll"
File "libxine-2.dll"
File "libmpcdec-5.dll"
File "libtheora-0.dll"
File "libfftw3-3.dll"
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -233,31 +194,17 @@ Section "Strawberry" Strawberry
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Qt Platforms" platforms
SetOutPath "$INSTDIR\platforms"
File "/oname=qwindows.dll" "platforms\qwindows.dll"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Qt image format plugins" imageformats
@@ -265,11 +212,6 @@ Section "Qt image format plugins" imageformats
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
@@ -308,10 +250,10 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
SectionEnd
@@ -344,10 +286,6 @@ Section "Xine plugins" xine-plugins
File "/oname=xineplug_post_tvtime.dll" "xine-plugins\xineplug_post_tvtime.dll"
File "/oname=xineplug_post_visualizations.dll" "xine-plugins\xineplug_post_visualizations.dll"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Start menu items" startmenu
@@ -357,10 +295,6 @@ Section "Start menu items" startmenu
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
@@ -377,10 +311,6 @@ Section "Uninstaller"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
StrCpy $0 "$EXEDIR\install.log"
Push $0
Call DumpLog
SectionEnd
Section "Uninstall"
@@ -409,8 +339,6 @@ Section "Uninstall"
; Delete all the files
;Delete "$EXEDIR\install.log"
Delete "$INSTDIR\strawberry.ico"
Delete "$INSTDIR\strawberry.exe"
Delete "$INSTDIR\strawberry-tagreader.exe"
@@ -440,6 +368,7 @@ Section "Uninstall"
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
Delete "$INSTDIR\libgsttag-1.0-0.dll"
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
Delete "$INSTDIR\libgstnet-1.0-0.dll"
Delete "$INSTDIR\libharfbuzz-0.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libintl-8.dll"
@@ -468,11 +397,15 @@ Section "Uninstall"
Delete "$INSTDIR\Qt5Sql.dll"
Delete "$INSTDIR\Qt5Widgets.dll"
Delete "$INSTDIR\Qt5Xml.dll"
Delete "$INSTDIR\Qt5WinExtras.dll"
Delete "$INSTDIR\zlib1.dll"
Delete "$INSTDIR\libxine-2.dll"
Delete "$INSTDIR\libmpcdec-5.dll"
Delete "$INSTDIR\libtheora-0.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
@@ -514,6 +447,10 @@ Section "Uninstall"
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx2.dll"
Delete "$INSTDIR\xine-plugins\xineplug_ao_out_directx.dll"

445
dist/windows/strawberry.nsi.in vendored Normal file
View File

@@ -0,0 +1,445 @@
!define PRODUCT_NAME "Strawberry"
!define PRODUCT_PUBLISHER "Strawberry"
!define PRODUCT_VERSION_MAJOR @STRAWBERRY_VERSION_MAJOR@
!define PRODUCT_VERSION_MINOR @STRAWBERRY_VERSION_MINOR@
!define PRODUCT_VERSION_PATCH @STRAWBERRY_VERSION_PATCH@
!define PRODUCT_DISPLAY_VERSION "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_DISPLAY_VERSION_SHORT "@STRAWBERRY_VERSION_PACKAGE@"
!define PRODUCT_WEB_SITE "http://www.strawbs.org/"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Strawberry Music Player"
; Set Application Capabilities info
!define CAPABILITIES_NAME "Strawberry Music Player"
!define CAPABILITIES_LOCAL_NAME "Strawberry"
!define CAPABILITIES_PROGID "Strawberry Music Player"
!define CAPABILITIES_PATH "Software\Clients\Media\Strawberry"
!define CAPABILITIES_DESCRIPTION "Strawberry Music Player"
!define CAPABILITIES_ICON "$INSTDIR\strawberry.ico"
!define CAPABILITIES_REINSTALL "Command to reinstall"
!define CAPABILITIES_HIDE_ICONS "Command to hide icons"
!define CAPABILITIES_SHOW_ICONS "Command to show icons"
SetCompressor /SOLID lzma
!addplugindir nsisplugins
!include "MUI2.nsh"
!include "FileAssociation.nsh"
!include "Capabilities.nsh"
!define MUI_ICON "strawberry.ico"
!define MUI_COMPONENTSPAGE_SMALLDESC
;!define MUI_FINISHPAGE_RUN
;!define MUI_FINISHPAGE_RUN_TEXT "Run Strawberry"
;!define MUI_FINISHPAGE_RUN_FUNCTION "RunStrawberry"
; Installer pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
Name "${PRODUCT_NAME}"
OutFile "${PRODUCT_NAME}Setup-${PRODUCT_DISPLAY_VERSION}-Release.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
; Get the path where Strawberry was installed previously and set it as default path
InstallDirRegKey ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
ShowInstDetails show
ShowUnInstDetails show
RequestExecutionLevel admin
;RequestExecutionLevel user
; Check for previous installation, and call the uninstaller if any
Function CheckPreviousInstall
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
StrCmp $R0 "" done
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
previous version or `Cancel` to cancel this upgrade." \
IDOK uninst
Abort
; Run the uninstaller
uninst:
ClearErrors
ExecWait '$R0' ; Do not copy the uninstaller to a temp file
done:
FunctionEnd
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
Call CheckPreviousInstall
FunctionEnd
;Function RunStrawberry
;ShellExecAsUser::ShellExecAsUser "" "$INSTDIR/strawberry.exe" ""
;FunctionEnd
Section "Delete old files" oldfiles
SectionEnd
Section "Strawberry" Strawberry
SetOutPath "$INSTDIR"
File "strawberry.exe"
File "strawberry-tagreader.exe"
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libchromaprint.dll"
File "libcrypto-1_1.dll"
File "libfaad-2.dll"
File "libffi-6.dll"
File "libFLAC-8.dll"
File "libfreetype-6.dll"
File "libgcc_s_sjlj-1.dll"
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "libgmodule-2.0-0.dll"
File "libgobject-2.0-0.dll"
File "libgstapp-1.0-0.dll"
File "libgstaudio-1.0-0.dll"
File "libgstbase-1.0-0.dll"
File "libgstfft-1.0-0.dll"
File "libgstpbutils-1.0-0.dll"
File "libgstreamer-1.0-0.dll"
File "libgstriff-1.0-0.dll"
File "libgstrtp-1.0-0.dll"
File "libgstrtsp-1.0-0.dll"
File "libgstsdp-1.0-0.dll"
File "libgsttag-1.0-0.dll"
File "libgstvideo-1.0-0.dll"
File "libgstnet-1.0-0.dll"
File "libharfbuzz-0.dll"
File "libiconv-2.dll"
File "libintl-8.dll"
File "libjpeg-9.dll"
File "liblastfm5.dll"
File "libmp3lame-0.dll"
File "libogg-0.dll"
File "libopus-0.dll"
File "libpcre-1.dll"
File "libpcre2-16-0.dll"
File "libpng16-16.dll"
File "libprotobuf-15.dll"
File "libspeex-1.dll"
File "libsqlite3-0.dll"
File "libssl-1_1.dll"
File "libstdc++-6.dll"
File "libtag.dll"
File "libvorbis-0.dll"
File "libvorbisenc-2.dll"
File "libwavpack-1.dll"
File "libwinpthread-1.dll"
File "Qt5Concurrent.dll"
File "Qt5Core.dll"
File "Qt5Gui.dll"
File "Qt5Network.dll"
File "Qt5Sql.dll"
File "Qt5Widgets.dll"
File "Qt5Xml.dll"
File "Qt5WinExtras.dll"
File "zlib1.dll"
;File "libmpcdec-5.dll"
;File "libtheora-0.dll"
File "libfftw3-3.dll"
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
Var /GLOBAL AppExe
StrCpy $AppExe "$INSTDIR\strawberry.exe"
StrCpy $AppIcon "$INSTDIR\strawberry.ico"
${RegisterCapabilities}
${RegisterMediaType} ".mp3" $AppExe $AppIcon "MP3 Audio File"
${RegisterMediaType} ".flac" $AppExe $AppIcon "FLAC Audio File"
${RegisterMediaType} ".ogg" $AppExe $AppIcon "OGG Audio File"
${RegisterMediaType} ".spx" $AppExe $AppIcon "OGG Speex Audio File"
${RegisterMediaType} ".m4a" $AppExe $AppIcon "MP4 Audio File"
${RegisterMediaType} ".aac" $AppExe $AppIcon "AAC Audio File"
${RegisterMediaType} ".wma" $AppExe $AppIcon "WMA Audio File"
${RegisterMediaType} ".wav" $AppExe $AppIcon "WAV Audio File"
${RegisterMediaType} ".pls" $AppExe $AppIcon "PLS Audio File"
${RegisterMediaType} ".m3u" $AppExe $AppIcon "M3U Audio File"
${RegisterMediaType} ".xspf" $AppExe $AppIcon "XSPF Audio File"
${RegisterMediaType} ".asx" $AppExe $AppIcon "Windows Media Audio/Video playlist"
${RegisterMimeType} "audio/mp3" "mp3" "{cd3afa76-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mp4" "m4a" "{cd3afa7c-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/x-ms-wma" "wma" "{cd3afa84-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/wav" "wav" "{cd3afa7b-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "audio/mpegurl" "m3u" "{cd3afa78-b84f-48f0-9393-7edc34128127}"
${RegisterMimeType} "application/x-wmplayer" "asx" "{cd3afa96-b84f-48f0-9393-7edc34128127}"
SectionEnd
Section "Qt Platforms" platforms
SetOutPath "$INSTDIR\platforms"
File "/oname=qwindows.dll" "platforms\qwindows.dll"
SectionEnd
Section "Qt SQL Drivers" sqldrivers
SetOutPath "$INSTDIR\sqldrivers"
File "/oname=qsqlite.dll" "sqldrivers\qsqlite.dll"
SectionEnd
Section "Qt image format plugins" imageformats
SetOutPath "$INSTDIR\imageformats"
File "/oname=qgif.dll" "imageformats\qgif.dll"
File "/oname=qico.dll" "imageformats\qico.dll"
File "/oname=qjpeg.dll" "imageformats\qjpeg.dll"
SectionEnd
Section "Gstreamer plugins" gstreamer-plugins
SetOutPath "$INSTDIR\gstreamer-plugins"
File "/oname=libgstapetag.dll" "gstreamer-plugins\libgstapetag.dll"
File "/oname=libgstapp.dll" "gstreamer-plugins\libgstapp.dll"
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
File "/oname=libgstaiff.dll" "gstreamer-plugins\libgstaiff.dll"
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdirectsound.dll" "gstreamer-plugins\libgstdirectsound.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstopusparse.dll" "gstreamer-plugins\libgstopusparse.dll"
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
File "/oname=libgstspeex.dll" "gstreamer-plugins\libgstspeex.dll"
File "/oname=libgsttaglib.dll" "gstreamer-plugins\libgsttaglib.dll"
File "/oname=libgsttypefindfunctions.dll" "gstreamer-plugins\libgsttypefindfunctions.dll"
File "/oname=libgstvolume.dll" "gstreamer-plugins\libgstvolume.dll"
File "/oname=libgstvorbis.dll" "gstreamer-plugins\libgstvorbis.dll"
File "/oname=libgstwavpack.dll" "gstreamer-plugins\libgstwavpack.dll"
File "/oname=libgstwavparse.dll" "gstreamer-plugins\libgstwavparse.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgsttcp.dll" "gstreamer-plugins\libgsttcp.dll"
File "/oname=libgstudp.dll" "gstreamer-plugins\libgstudp.dll"
File "/oname=libgstsoup.dll" "gstreamer-plugins\libgstsoup.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
SectionEnd
Section "Start menu items" startmenu
; Create Start Menu folders and shortcuts.
SetShellVarContext all
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
; Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\strawberry.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Section "Uninstall"
; Kill strawberry.exe if it's running
; This calling convention is retarded...
;StrCpy $0 "strawberry.exe"
;KillProc::FindProcesses
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
;KillProc::KillProcesses
;StrCmp $1 "-1" wooops
;Sleep 2000
;Goto completed
;wooops:
;DetailPrint "-> Error: Something went wrong while killing running strawberry.exe"
;Abort
;completed:
; Delete all the files
Delete "$INSTDIR\strawberry.ico"
Delete "$INSTDIR\strawberry.exe"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
Delete "$INSTDIR\libffi-6.dll"
Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.dll"
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll"
Delete "$INSTDIR\libgobject-2.0-0.dll"
Delete "$INSTDIR\libgstapp-1.0-0.dll"
Delete "$INSTDIR\libgstaudio-1.0-0.dll"
Delete "$INSTDIR\libgstbase-1.0-0.dll"
Delete "$INSTDIR\libgstfft-1.0-0.dll"
Delete "$INSTDIR\libgstpbutils-1.0-0.dll"
Delete "$INSTDIR\libgstreamer-1.0-0.dll"
Delete "$INSTDIR\libgstriff-1.0-0.dll"
Delete "$INSTDIR\libgstrtp-1.0-0.dll"
Delete "$INSTDIR\libgstrtsp-1.0-0.dll"
Delete "$INSTDIR\libgstsdp-1.0-0.dll"
Delete "$INSTDIR\libgsttag-1.0-0.dll"
Delete "$INSTDIR\libgstvideo-1.0-0.dll"
Delete "$INSTDIR\libgstnet-1.0-0.dll"
Delete "$INSTDIR\libharfbuzz-0.dll"
Delete "$INSTDIR\libiconv-2.dll"
Delete "$INSTDIR\libintl-8.dll"
Delete "$INSTDIR\libjpeg-9.dll"
Delete "$INSTDIR\liblastfm5.dll"
Delete "$INSTDIR\libmp3lame-0.dll"
Delete "$INSTDIR\libogg-0.dll"
Delete "$INSTDIR\libopus-0.dll"
Delete "$INSTDIR\libpcre-1.dll"
Delete "$INSTDIR\libpcre2-16-0.dll"
Delete "$INSTDIR\libpng16-16.dll"
Delete "$INSTDIR\libprotobuf-15.dll"
Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.dll"
Delete "$INSTDIR\libssl-1_1.dll"
Delete "$INSTDIR\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libvorbis-0.dll"
Delete "$INSTDIR\libvorbisenc-2.dll"
Delete "$INSTDIR\libwavpack-1.dll"
Delete "$INSTDIR\libwinpthread-1.dll"
Delete "$INSTDIR\Qt5Concurrent.dll"
Delete "$INSTDIR\Qt5Core.dll"
Delete "$INSTDIR\Qt5Gui.dll"
Delete "$INSTDIR\Qt5Network.dll"
Delete "$INSTDIR\Qt5Sql.dll"
Delete "$INSTDIR\Qt5Widgets.dll"
Delete "$INSTDIR\Qt5Xml.dll"
Delete "$INSTDIR\Qt5WinExtras.dll"
Delete "$INSTDIR\zlib1.dll"
;Delete "$INSTDIR\libmpcdec-5.dll"
;Delete "$INSTDIR\libtheora-0.dll"
Delete "$INSTDIR\libfftw3-3.dll"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"
Delete "$INSTDIR\imageformats\qgif.dll"
Delete "$INSTDIR\imageformats\qico.dll"
Delete "$INSTDIR\imageformats\qjpeg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapetag.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstapp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstasf.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaiff.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioconvert.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiofx.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioparsers.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudioresample.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstaudiotestsrc.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstautodetect.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcoreelements.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdirectsound.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstequalizer.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstfaad.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstflac.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstgio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsticydemux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstid3demux.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstisomp4.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlame.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstopusparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstplayback.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspectrum.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstspeex.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttaglib.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttypefindfunctions.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvolume.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstvorbis.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavpack.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstwavparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstcdio.dll"
Delete "$INSTDIR\gstreamer-plugins\libgsttcp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstudp.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstlibav.dll"
Delete "$INSTDIR\Uninstall.exe"
; Remove the installation folders.
RMDir "$INSTDIR\platforms"
RMDir "$INSTDIR\sqldrivers"
RMDir "$INSTDIR\imageformats"
RMDir "$INSTDIR\gstreamer-plugins"
RMDir "$INSTDIR\xine-plugins"
RMDir "$INSTDIR"
; Remove the Shortcuts
SetShellVarContext all
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
; Remove the entry from 'installed programs list'
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
; Unregister from Default Programs
${UnRegisterCapabilities}
SectionEnd

View File

@@ -11,7 +11,6 @@ BEGIN
VALUE "FileDescription", "Strawberry Music Player"
VALUE "FileVersion", "${STRAWBERRY_VERSION_DISPLAY}"
VALUE "InternalName", "strawberry"
VALUE "LegalCopyright", "David Sansome / Jonas Kvinge"
VALUE "OriginalFilename", "strawberry.exe"
VALUE "ProductName", "Strawberry"
VALUE "ProductVersion", "${STRAWBERRY_VERSION_DISPLAY}"
@@ -20,6 +19,6 @@ BEGIN
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1252
VALUE "Translation", 0x0809, 1252
END
END

View File

@@ -1,5 +1,6 @@
/* This file is part of Strawberry.
Copyright 2013, David Sansome <me@davidsansome.com>
Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
Strawberry is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,12 +35,13 @@
#include <taglib/tstring.h>
#include <taglib/tstringlist.h>
#include <taglib/audioproperties.h>
#include <taglib/trueaudiofile.h>
#include <taglib/attachedpictureframe.h>
#include <taglib/textidentificationframe.h>
#include <taglib/unsynchronizedlyricsframe.h>
#include <taglib/xiphcomment.h>
#include <taglib/commentsframe.h>
#include <taglib/tag.h>
#include <taglib/apetag.h>
#include <taglib/id3v2tag.h>
#include "taglib/id3v2frame.h"
#include <taglib/flacfile.h>
@@ -63,6 +65,11 @@
#include <taglib/mpcfile.h>
#include <taglib/mpegfile.h>
#include <taglib/opusfile.h>
#include <taglib/trueaudiofile.h>
#ifdef HAVE_TAGLIB_DSFFILE
# include <taglib/dsffile.h>
# include <taglib/dsdifffile.h>
#endif
#include <QtGlobal>
#include <QFile>
@@ -89,8 +96,6 @@
# define TAGLIB_HAS_FLAC_PICTURELIST
#endif
#define NumberToASFAttribute(x) TagLib::ASF::Attribute(QStringToTaglibString(QString::number(x)))
class FileRefFactory {
public:
virtual ~FileRefFactory() {}
@@ -135,7 +140,7 @@ TagReader::TagReader()
kEmbeddedCover("(embedded)") {}
void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *song) const {
const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
const QFileInfo info(filename);
@@ -149,19 +154,18 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
if (fileref->isNull()) {
qLog(Info) << "TagLib hasn't been able to read " << filename << " file";
qLog(Info) << "TagLib hasn't been able to read" << filename << "file";
return;
}
song->set_filetype(GuessFileType(fileref.get()));
if (fileref->audioProperties()) {
song->set_bitrate(fileref->audioProperties()->bitrate());
song->set_samplerate(fileref->audioProperties()->sampleRate());
song->set_length_nanosec(fileref->audioProperties()->length() * kNsecPerSec);
}
// Get the filetype if we can
song->set_filetype(GuessFileType(fileref.get()));
TagLib::Tag *tag = fileref->tag();
if (tag) {
Decode(tag->title(), nullptr, song->mutable_title());
@@ -175,20 +179,39 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
QString disc;
QString compilation;
QString lyrics;
// Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same way;
// apart, so we keep specific behavior for some formats by adding another
// "else if" block below.
// apart, so we keep specific behavior for some formats by adding another "else if" block below.
if (TagLib::Ogg::XiphComment *tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song);
#if TAGLIB_MAJOR_VERSION >= 1 && TAGLIB_MINOR_VERSION >= 11
if (!tag->pictureList().isEmpty()) song->set_art_automatic(kEmbeddedCover);
#endif
}
if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
if ( file->xiphComment() ) {
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
if (!file->pictureList().isEmpty()) {
song->set_art_automatic(kEmbeddedCover);
}
#endif
}
if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
}
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File *>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
//if (tag) Decode(tag->comment(), nullptr, song->mutable_comment());
}
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (file->ID3v2Tag()) {
const TagLib::ID3v2::FrameListMap &map = file->ID3v2Tag()->frameListMap();
@@ -242,22 +265,9 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
}
}
else if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
if ( file->xiphComment() ) {
ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song);
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
if (!file->pictureList().isEmpty()) {
song->set_art_automatic(kEmbeddedCover);
}
#endif
}
Decode(tag->comment(), nullptr, song->mutable_comment());
}
else if (TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
if (file->tag()) {
@@ -292,41 +302,33 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
if (items.contains(kMP4_OriginalYear_ID)) {
song->set_originalyear(
TStringToQString(
items[kMP4_OriginalYear_ID].toStringList().toString('\n'))
.left(4)
.toInt());
TStringToQString(items[kMP4_OriginalYear_ID].toStringList().toString('\n')).left(4).toInt());
}
Decode(mp4_tag->comment(), nullptr, song->mutable_comment());
}
}
#ifdef TAGLIB_WITH_ASF
else if (TagLib::ASF::File *file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
const TagLib::ASF::AttributeListMap &attributes_map = file->tag()->attributeListMap();
if (attributes_map.contains(kASF_OriginalDate_ID)) {
const TagLib::ASF::AttributeList &attributes =
attributes_map[kASF_OriginalDate_ID];
const TagLib::ASF::AttributeList &attributes = attributes_map[kASF_OriginalDate_ID];
if (!attributes.isEmpty()) {
song->set_originalyear(
TStringToQString(attributes.front().toString()).left(4).toInt());
song->set_originalyear(TStringToQString(attributes.front().toString()).left(4).toInt());
}
}
else if (attributes_map.contains(kASF_OriginalYear_ID)) {
const TagLib::ASF::AttributeList &attributes =
attributes_map[kASF_OriginalYear_ID];
const TagLib::ASF::AttributeList &attributes = attributes_map[kASF_OriginalYear_ID];
if (!attributes.isEmpty()) {
song->set_originalyear(
TStringToQString(attributes.front().toString()).left(4).toInt());
song->set_originalyear(TStringToQString(attributes.front().toString()).left(4).toInt());
}
}
}
#endif
else if (tag) {
Decode(tag->comment(), nullptr, song->mutable_comment());
}
@@ -352,7 +354,7 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
song->set_compilation(compilation.toInt() == 1);
}
if (!lyrics.isEmpty()) song->set_lyrics(lyrics.toStdString());
// Set integer fields to -1 if they're not valid
#define SetDefault(field) if (song->field() <= 0) { song->set_##field(-1); }
@@ -364,11 +366,12 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
SetDefault(bitdepth);
SetDefault(lastplayed);
#undef SetDefault
}
void TagReader::Decode(const TagLib::String &tag, const QTextCodec *codec, std::string *output) {
QString tmp;
if (codec && tag.isLatin1()) { // Never override UTF-8.
@@ -380,6 +383,7 @@ void TagReader::Decode(const TagLib::String &tag, const QTextCodec *codec, std::
}
output->assign(DataCommaSizeFromQString(tmp));
}
void TagReader::Decode(const QString &tag, const QTextCodec *codec, std::string *output) {
@@ -391,6 +395,7 @@ void TagReader::Decode(const QString &tag, const QTextCodec *codec, std::string
const QString decoded(codec->toUnicode(tag.toUtf8()));
output->assign(DataCommaSizeFromQString(decoded));
}
}
void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const {
@@ -445,6 +450,11 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCod
if (!map["FMPS_PLAYCOUNT"].isEmpty() && song->playcount() <= 0) song->set_playcount(TStringToQString( map["FMPS_PLAYCOUNT"].front() ).trimmed().toFloat());
if (!map["LYRICS"].isEmpty())
Decode(map["LYRICS"].front(), codec, song->mutable_lyrics());
else if (!map["UNSYNCEDLYRICS"].isEmpty())
Decode(map["UNSYNCEDLYRICS"].front(), codec, song->mutable_lyrics());
}
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const {
@@ -460,43 +470,41 @@ void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, con
vorbis_comments->addField("ALBUMARTIST", StdStringToTaglibString(song.albumartist()), true);
vorbis_comments->removeField("ALBUM ARTIST");
vorbis_comments->addField("LYRICS", StdStringToTaglibString(song.lyrics()), true);
vorbis_comments->removeField("UNSYNCEDLYRICS");
}
pb::tagreader::SongMetadata_Type TagReader::GuessFileType(TagLib::FileRef *fileref) const {
pb::tagreader::SongMetadata_FileType TagReader::GuessFileType(TagLib::FileRef *fileref) const {
if (dynamic_cast<TagLib::RIFF::WAV::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_WAV;
if (dynamic_cast<TagLib::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_FLAC;
if (dynamic_cast<TagLib::WavPack::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_WAVPACK;
if (dynamic_cast<TagLib::Ogg::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_OGGFLAC;
if (dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_OGGVORBIS;
if (dynamic_cast<TagLib::Ogg::Opus::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_OGGOPUS;
if (dynamic_cast<TagLib::Ogg::Speex::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_OGGSPEEX;
if (dynamic_cast<TagLib::MPEG::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_MPEG;
#ifdef TAGLIB_WITH_MP4
if (dynamic_cast<TagLib::MP4::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_MP4;
if (dynamic_cast<TagLib::RIFF::WAV::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAV;
if (dynamic_cast<TagLib::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_FLAC;
if (dynamic_cast<TagLib::WavPack::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_WAVPACK;
if (dynamic_cast<TagLib::Ogg::FLAC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGFLAC;
if (dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGVORBIS;
if (dynamic_cast<TagLib::Ogg::Opus::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGOPUS;
if (dynamic_cast<TagLib::Ogg::Speex::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_OGGSPEEX;
if (dynamic_cast<TagLib::MPEG::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPEG;
if (dynamic_cast<TagLib::MP4::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MP4;
if (dynamic_cast<TagLib::ASF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_ASF;
if (dynamic_cast<TagLib::RIFF::AIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_AIFF;
if (dynamic_cast<TagLib::MPC::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_MPC;
if (dynamic_cast<TagLib::TrueAudio::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_TRUEAUDIO;
#ifdef HAVE_TAGLIB_DSFFILE
if (dynamic_cast<TagLib::DSF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSF;
if (dynamic_cast<TagLib::DSDIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_FileType_DSDIFF;
#endif
#ifdef TAGLIB_WITH_ASF
if (dynamic_cast<TagLib::ASF::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_ASF;
#endif
if (dynamic_cast<TagLib::RIFF::AIFF::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_AIFF;
if (dynamic_cast<TagLib::MPC::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_MPC;
if (dynamic_cast<TagLib::TrueAudio::File*>(fileref->file())) return pb::tagreader::SongMetadata_Type_TRUEAUDIO;
return pb::tagreader::SongMetadata_Type_UNKNOWN;
return pb::tagreader::SongMetadata_FileType_UNKNOWN;
}
bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetadata &song) const {
if (filename.isNull()) return false;
if (filename.isNull() || filename.isEmpty()) return false;
qLog(Debug) << "Saving tags to" << filename;
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
if (!fileref || fileref->isNull()) // The file probably doesn't exist
return false;
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));;
if (!fileref || fileref->isNull()) return false;
fileref->tag()->setTitle(StdStringToTaglibString(song.title()));
fileref->tag()->setArtist(StdStringToTaglibString(song.artist()));
@@ -506,8 +514,24 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
fileref->tag()->setYear(song.year());
fileref->tag()->setTrack(song.track());
if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
TagLib::Ogg::XiphComment *tag = file->xiphComment();
SetVorbisComments(tag, song);
}
else if (TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File*>(fileref->file())) {
TagLib::APE::Tag *tag = file->APETag(true);
if (!tag) return false;
tag->setArtist(StdStringToTaglibString(song.artist()));
tag->setAlbum(StdStringToTaglibString(song.album()));
tag->setTitle(StdStringToTaglibString(song.title()));
tag->setGenre(StdStringToTaglibString(song.genre()));
tag->setComment(StdStringToTaglibString(song.comment()));
tag->setYear(song.year());
tag->setTrack(song.track());
}
else if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
TagLib::ID3v2::Tag *tag = file->ID3v2Tag(true);
if (!tag) return false;
SetTextFrame("TPOS", song.disc() <= 0 -1 ? QString() : QString::number(song.disc()), tag);
SetTextFrame("TCOM", song.composer(), tag);
SetTextFrame("TIT1", song.grouping(), tag);
@@ -515,10 +539,7 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
// Skip TPE1 (which is the artist) here because we already set it
SetTextFrame("TPE2", song.albumartist(), tag);
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
}
else if (TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
TagLib::Ogg::XiphComment *tag = file->xiphComment();
SetVorbisComments(tag, song);
SetUnsyncLyricsFrame(song.lyrics(), tag);
}
else if (TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
TagLib::MP4::Tag *tag = file->tag();
@@ -571,6 +592,7 @@ void TagReader::SetUserTextFrame(const std::string &description, const std::stri
frame->setDescription(t_description);
frame->setText(StdStringToTaglibString(value));
tag->addFrame(frame);
}
void TagReader::SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const {
@@ -596,10 +618,15 @@ void TagReader::SetTextFrame(const char *id, const std::string &value, TagLib::I
frames_buffer.push_back(frame.render());
}
// add frame takes ownership and clears the memory
TagLib::ID3v2::TextIdentificationFrame *frame;
frame->setText(StdStringToTaglibString(value));
tag->addFrame(frame);
// Update and add the frames
for (int lyrics_index = 0; lyrics_index < frames_buffer.size(); lyrics_index++) {
TagLib::ID3v2::TextIdentificationFrame* frame = new TagLib::ID3v2::TextIdentificationFrame(frames_buffer.at(lyrics_index));
if (lyrics_index == 0) {
frame->setText(StdStringToTaglibString(value));
}
// add frame takes ownership and clears the memory
tag->addFrame(frame);
}
}
@@ -626,23 +653,26 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
if (ref.isNull() || !ref.file()) return QByteArray();
// MP3
TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(ref.file());
if (file && file->ID3v2Tag()) {
TagLib::ID3v2::FrameList apic_frames = file->ID3v2Tag()->frameListMap()["APIC"];
if (apic_frames.isEmpty())
return QByteArray();
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
// FLAC
TagLib::FLAC::File *flac_file = dynamic_cast<TagLib::FLAC::File*>(ref.file());
if (flac_file && flac_file->xiphComment()) {
TagLib::List<TagLib::FLAC::Picture*> pics = flac_file->pictureList();
if (!pics.isEmpty()) {
// Use the first picture in the file - this could be made cleverer and
// pick the front cover if it's present.
TagLib::ID3v2::AttachedPictureFrame *pic = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(apic_frames.front());
std::list<TagLib::FLAC::Picture*>::iterator it = pics.begin();
TagLib::FLAC::Picture *picture = *it;
return QByteArray((const char*) pic->picture().data(), pic->picture().size());
return QByteArray(picture->data().data(), picture->data().size());
}
}
#endif
// Ogg vorbis/speex
// Ogg Vorbis / Speex
TagLib::Ogg::XiphComment *xiph_comment = dynamic_cast<TagLib::Ogg::XiphComment*>(ref.file()->tag());
if (xiph_comment) {
TagLib::Ogg::FieldListMap map = xiph_comment->fieldListMap();
#if TAGLIB_MAJOR_VERSION <= 1 && TAGLIB_MINOR_VERSION < 11
@@ -685,22 +715,17 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
return QByteArray::fromBase64(map["COVERART"].toString().toCString());
}
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
// Flac
TagLib::FLAC::File *flac_file = dynamic_cast<TagLib::FLAC::File*>(ref.file());
if (flac_file && flac_file->xiphComment()) {
TagLib::List<TagLib::FLAC::Picture*> pics = flac_file->pictureList();
if (!pics.isEmpty()) {
// Use the first picture in the file - this could be made cleverer and
// pick the front cover if it's present.
// MP3
TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File*>(ref.file());
if (file && file->ID3v2Tag()) {
TagLib::ID3v2::FrameList apic_frames = file->ID3v2Tag()->frameListMap()["APIC"];
if (apic_frames.isEmpty())
return QByteArray();
std::list<TagLib::FLAC::Picture*>::iterator it = pics.begin();
TagLib::FLAC::Picture *picture = *it;
TagLib::ID3v2::AttachedPictureFrame *pic = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(apic_frames.front());
return QByteArray(picture->data().data(), picture->data().size());
}
return QByteArray((const char*) pic->picture().data(), pic->picture().size());
}
#endif
// MP4/AAC
TagLib::MP4::File *aac_file = dynamic_cast<TagLib::MP4::File*>(ref.file());
@@ -722,3 +747,33 @@ QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
return QByteArray();
}
void TagReader::SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const {
TagLib::ByteVector id_vector("USLT");
QVector<TagLib::ByteVector> frames_buffer;
// Store and clear existing frames
while (tag->frameListMap().contains(id_vector) && tag->frameListMap()[id_vector].size() != 0) {
frames_buffer.push_back(tag->frameListMap()[id_vector].front()->render());
tag->removeFrame(tag->frameListMap()[id_vector].front());
}
// If no frames stored create empty frame
if (frames_buffer.isEmpty()) {
TagLib::ID3v2::UnsynchronizedLyricsFrame frame(TagLib::String::UTF8);
frame.setDescription("Clementine editor");
frames_buffer.push_back(frame.render());
}
// Update and add the frames
for (int lyrics_index = 0; lyrics_index < frames_buffer.size(); lyrics_index++) {
TagLib::ID3v2::UnsynchronizedLyricsFrame* frame = new TagLib::ID3v2::UnsynchronizedLyricsFrame(frames_buffer.at(lyrics_index));
if (lyrics_index == 0) {
frame->setText(StdStringToTaglibString(value));
}
// add frame takes ownership and clears the memory
tag->addFrame(frame);
}
}

View File

@@ -1,5 +1,6 @@
/* This file is part of Strawberry.
Copyright 2013, David Sansome <me@davidsansome.com>
Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
Strawberry is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -64,13 +65,14 @@ class TagReader {
void ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const;
void SetVorbisComments(TagLib::Ogg::XiphComment *vorbis_comments, const pb::tagreader::SongMetadata &song) const;
pb::tagreader::SongMetadata_Type GuessFileType(TagLib::FileRef *fileref) const;
pb::tagreader::SongMetadata_FileType GuessFileType(TagLib::FileRef *fileref) const;
void SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const;
void SetUserTextFrame(const std::string &description, const std::string& value, TagLib::ID3v2::Tag *tag) const;
void SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const;
void SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const;
void SetUnsyncLyricsFrame(const std::string& value, TagLib::ID3v2::Tag* tag) const;
private:

View File

@@ -4,7 +4,7 @@ package pb.tagreader;
message SongMetadata {
enum Type {
enum FileType {
UNKNOWN = 0;
WAV = 1;
FLAC = 2;
@@ -19,12 +19,14 @@ message SongMetadata {
AIFF = 11;
MPC = 12;
TRUEAUDIO = 13;
DSF = 14;
DSDIFF = 15;
CDDA = 90;
STREAM = 91;
}
optional bool valid = 1;
optional string title = 2;
optional string album = 3;
optional string artist = 4;
@@ -39,26 +41,27 @@ message SongMetadata {
optional string performer = 13;
optional string grouping = 14;
optional string comment = 15;
optional uint64 length_nanosec = 16;
optional int32 bitrate = 17;
optional int32 samplerate = 18;
optional int32 bitdepth = 19;
optional string lyrics = 16;
optional string url = 20;
optional string basefilename = 21;
optional Type filetype = 22;
optional int32 filesize = 23;
optional int32 mtime = 24;
optional int32 ctime = 25;
optional uint64 length_nanosec = 17;
optional int32 playcount = 26;
optional int32 skipcount = 27;
optional int32 lastplayed = 28;
optional int32 bitrate = 18;
optional int32 samplerate = 19;
optional int32 bitdepth = 20;
optional bool suspicious_tags = 29;
optional string art_automatic = 30;
optional string url = 21;
optional string basefilename = 22;
optional FileType filetype = 23;
optional int32 filesize = 24;
optional int32 mtime = 25;
optional int32 ctime = 26;
optional int32 playcount = 27;
optional int32 skipcount = 28;
optional int32 lastplayed = 29;
optional bool suspicious_tags = 30;
optional string art_automatic = 31;
}

View File

@@ -74,11 +74,6 @@ include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-common)
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader)
include_directories(${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader)
# Windows
if (WIN32)
include_directories(../3rdparty/qtwin)
endif (WIN32)
set(SOURCES
core/mainwindow.cpp
core/application.cpp
@@ -107,7 +102,6 @@ set(SOURCES
core/urlhandler.cpp
core/utilities.cpp
core/scangiomodulepath.cpp
core/flowlayout.cpp
core/iconloader.cpp
core/qtsystemtrayicon.cpp
core/standarditemiconloader.cpp
@@ -129,6 +123,10 @@ set(SOURCES
equalizer/equalizer.cpp
equalizer/equalizerslider.cpp
context/contextview.cpp
context/contextalbumsmodel.cpp
context/contextalbumsview.cpp
collection/collection.cpp
collection/collectionmodel.cpp
collection/collectionbackend.cpp
@@ -193,9 +191,15 @@ set(SOURCES
covermanager/currentartloader.cpp
covermanager/coverfromurldialog.cpp
covermanager/musicbrainzcoverprovider.cpp
covermanager/amazoncoverprovider.cpp
covermanager/discogscoverprovider.cpp
lyrics/lyricsproviders.cpp
lyrics/lyricsprovider.cpp
lyrics/lyricsfetcher.cpp
lyrics/lyricsfetchersearch.cpp
lyrics/auddlyricsprovider.cpp
lyrics/apiseedslyricsprovider.cpp
settings/settingsdialog.cpp
settings/settingspage.cpp
settings/behavioursettingspage.cpp
@@ -207,6 +211,7 @@ set(SOURCES
settings/shortcutssettingspage.cpp
settings/appearancesettingspage.cpp
settings/notificationssettingspage.cpp
settings/tidalsettingspage.cpp
dialogs/about.cpp
dialogs/console.cpp
@@ -217,8 +222,6 @@ set(SOURCES
widgets/autoexpandingtreeview.cpp
widgets/busyindicator.cpp
widgets/clickablelabel.cpp
widgets/didyoumean.cpp
widgets/elidedlabel.cpp
widgets/fancytabwidget.cpp
widgets/favoritewidget.cpp
widgets/fileview.cpp
@@ -229,14 +232,9 @@ set(SOURCES
widgets/lineedit.cpp
widgets/linetextedit.cpp
widgets/multiloadingindicator.cpp
widgets/statusview.cpp
widgets/playingwidget.cpp
widgets/osd.cpp
widgets/osdpretty.cpp
widgets/prettyimage.cpp
widgets/prettyimageview.cpp
widgets/progressitemdelegate.cpp
widgets/ratingwidget.cpp
widgets/renametablineedit.cpp
widgets/sliderwidget.cpp
widgets/stickyslider.cpp
@@ -245,7 +243,7 @@ set(SOURCES
widgets/trackslider.cpp
widgets/tracksliderpopup.cpp
widgets/tracksliderslider.cpp
widgets/widgetfadehelper.cpp
widgets/loginstatewidget.cpp
musicbrainz/acoustidclient.cpp
musicbrainz/musicbrainzclient.cpp
@@ -255,16 +253,18 @@ set(SOURCES
globalshortcuts/gnomeglobalshortcutbackend.cpp
globalshortcuts/qxtglobalshortcutbackend.cpp
globalshortcuts/globalshortcutgrabber.cpp
device/connecteddevice.cpp
device/devicedatabasebackend.cpp
device/devicelister.cpp
device/devicemanager.cpp
device/deviceproperties.cpp
device/devicestatefiltermodel.cpp
device/deviceview.cpp
device/deviceviewcontainer.cpp
device/filesystemdevice.cpp
internet/internetmodel.cpp
internet/internetservice.cpp
internet/internetplaylistitem.cpp
tidal/tidalservice.cpp
tidal/tidalsearch.cpp
tidal/tidalsearchview.cpp
tidal/tidalsearchmodel.cpp
tidal/tidalsearchsortmodel.cpp
tidal/tidalsearchitemdelegate.cpp
tidal/tidalurlhandler.cpp
)
@@ -297,6 +297,10 @@ set(HEADERS
equalizer/equalizer.h
equalizer/equalizerslider.h
context/contextview.h
context/contextalbumsmodel.h
context/contextalbumsview.h
collection/collection.h
collection/collectionmodel.h
@@ -353,10 +357,16 @@ set(HEADERS
covermanager/coverexportrunnable.h
covermanager/currentartloader.h
covermanager/coverfromurldialog.h
covermanager/amazoncoverprovider.h
covermanager/musicbrainzcoverprovider.h
covermanager/discogscoverprovider.h
lyrics/lyricsproviders.h
lyrics/lyricsprovider.h
lyrics/lyricsfetcher.h
lyrics/lyricsfetchersearch.h
lyrics/auddlyricsprovider.h
lyrics/apiseedslyricsprovider.h
settings/settingsdialog.h
settings/settingspage.h
settings/behavioursettingspage.h
@@ -368,7 +378,8 @@ set(HEADERS
settings/shortcutssettingspage.h
settings/appearancesettingspage.h
settings/notificationssettingspage.h
settings/tidalsettingspage.h
dialogs/about.h
dialogs/errordialog.h
dialogs/console.h
@@ -378,8 +389,6 @@ set(HEADERS
widgets/autoexpandingtreeview.h
widgets/busyindicator.h
widgets/clickablelabel.h
widgets/didyoumean.h
widgets/elidedlabel.h
widgets/fancytabwidget.h
widgets/favoritewidget.h
widgets/fileview.h
@@ -389,14 +398,9 @@ set(HEADERS
widgets/lineedit.h
widgets/linetextedit.h
widgets/multiloadingindicator.h
widgets/statusview.h
widgets/playingwidget.h
widgets/osd.h
widgets/osdpretty.h
widgets/prettyimage.h
widgets/prettyimageview.h
widgets/progressitemdelegate.h
widgets/ratingwidget.h
widgets/renametablineedit.h
widgets/sliderwidget.h
widgets/stickyslider.h
@@ -404,7 +408,7 @@ set(HEADERS
widgets/trackslider.h
widgets/tracksliderpopup.h
widgets/tracksliderslider.h
widgets/widgetfadehelper.h
widgets/loginstatewidget.h
musicbrainz/acoustidclient.h
musicbrainz/musicbrainzclient.h
@@ -413,16 +417,17 @@ set(HEADERS
globalshortcuts/globalshortcuts.h
globalshortcuts/gnomeglobalshortcutbackend.h
globalshortcuts/globalshortcutgrabber.h
device/connecteddevice.h
device/devicedatabasebackend.h
device/devicelister.h
device/devicemanager.h
device/deviceproperties.h
device/devicestatefiltermodel.h
device/deviceviewcontainer.h
device/deviceview.h
device/filesystemdevice.h
internet/internetmodel.h
internet/internetservice.h
internet/internetmimedata.h
internet/internetsongmimedata.h
tidal/tidalservice.h
tidal/tidalsearch.h
tidal/tidalsearchview.h
tidal/tidalsearchmodel.h
tidal/tidalurlhandler.h
)
@@ -430,6 +435,8 @@ set(UI
core/mainwindow.ui
context/contextviewcontainer.ui
collection/groupbydialog.ui
collection/collectionfilterwidget.ui
collection/collectionviewcontainer.ui
@@ -457,6 +464,7 @@ set(UI
settings/shortcutssettingspage.ui
settings/appearancesettingspage.ui
settings/notificationssettingspage.ui
settings/tidalsettingspage.ui
equalizer/equalizer.ui
equalizer/equalizerslider.ui
@@ -470,12 +478,12 @@ set(UI
widgets/trackslider.ui
widgets/osdpretty.ui
widgets/fileview.ui
device/deviceproperties.ui
device/deviceviewcontainer.ui
widgets/loginstatewidget.ui
globalshortcuts/globalshortcutgrabber.ui
tidal/tidalsearchview.ui
)
set(RESOURCES ../data/data.qrc)
@@ -500,7 +508,7 @@ optional_source(HAVE_GSTREAMER
# Xine
optional_source(HAVE_XINE
SOURCES engine/xineengine.cpp engine/xinescope.c engine/xinefader.cpp
SOURCES engine/xineengine.cpp engine/xinescope.c
HEADERS engine/xineengine.h
)
@@ -648,6 +656,32 @@ optional_source(HAVE_DBUS
core/mpris2.h
)
optional_source(UNIX
SOURCES
device/connecteddevice.cpp
device/devicedatabasebackend.cpp
device/devicelister.cpp
device/devicemanager.cpp
device/devicestatefiltermodel.cpp
device/filesystemdevice.cpp
device/deviceviewcontainer.cpp
device/deviceview.cpp
device/deviceproperties.cpp
HEADERS
device/connecteddevice.h
device/devicedatabasebackend.h
device/devicelister.h
device/devicemanager.h
device/devicestatefiltermodel.h
device/filesystemdevice.h
device/deviceviewcontainer.h
device/deviceview.h
device/deviceproperties.h
UI
device/deviceproperties.ui
device/deviceviewcontainer.ui
)
if(HAVE_DBUS)
optional_source(HAVE_DEVICEKIT
SOURCES device/devicekitlister.cpp
@@ -724,8 +758,6 @@ SOURCES
settings/transcodersettingspage.cpp
dialogs/organisedialog.cpp
dialogs/organiseerrordialog.cpp
musicbrainz/chromaprinter.cpp
musicbrainz/tagfetcher.cpp
transcoder/transcoder.cpp
transcoder/transcodedialog.cpp
transcoder/transcoderoptionsaac.cpp
@@ -741,7 +773,6 @@ HEADERS
settings/transcodersettingspage.h
dialogs/organisedialog.h
dialogs/organiseerrordialog.h
musicbrainz/tagfetcher.h
transcoder/transcoder.h
transcoder/transcodedialog.h
transcoder/transcoderoptionsdialog.h
@@ -764,6 +795,13 @@ UI
# CDIO backend and device
if(HAVE_GSTREAMER)
optional_source(HAVE_CHROMAPRINT
SOURCES
musicbrainz/chromaprinter.cpp
musicbrainz/tagfetcher.cpp
HEADERS
musicbrainz/tagfetcher.h
)
optional_source(HAVE_AUDIOCD
SOURCES
device/cddadevice.cpp
@@ -816,6 +854,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/version.h)
qt5_wrap_cpp(MOC ${HEADERS})
qt5_wrap_ui(UIC ${UI})
qt5_add_resources(QRC ${RESOURCES})
@@ -924,7 +963,6 @@ endif (APPLE)
if (WIN32)
target_link_libraries(strawberry_lib
${ZLIB_LIBRARIES}
qtwin
dsound
${QT_QTGUI_LIBRARY}
)

0
src/analyzer/analyzerbase.cpp Executable file → Normal file
View File

View File

@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "config.h"
@@ -57,14 +57,12 @@ SCollection::SCollection(Application *app, QObject *parent)
backend_->Init(app->database(), kSongsTable, kDirsTable, kSubdirsTable, kFtsTable);
model_ = new CollectionModel(backend_, app_, this);
ReloadSettings();
}
SCollection::~SCollection() {
watcher_->deleteLater();
watcher_thread_->exit();
watcher_thread_->wait(5000 /* five seconds */);

View File

@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef COLLECTION_H

View File

@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "config.h"
@@ -54,7 +54,6 @@ CollectionBackend::CollectionBackend(QObject *parent)
{}
void CollectionBackend::Init(Database *db, const QString &songs_table, const QString &dirs_table, const QString &subdirs_table, const QString &fts_table) {
db_ = db;
songs_table_ = songs_table;
dirs_table_ = dirs_table;
@@ -110,12 +109,14 @@ void CollectionBackend::ChangeDirPath(int id, const QString &old_path, const QSt
ScopedTransaction t(&db);
// Do the dirs table
QSqlQuery q(db);
q.prepare(QString("UPDATE %1 SET path=:path WHERE ROWID=:id").arg(dirs_table_));
q.bindValue(":path", new_path);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
{
QSqlQuery q(db);
q.prepare(QString("UPDATE %1 SET path=:path WHERE ROWID=:id").arg(dirs_table_));
q.bindValue(":path", new_path);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
}
const QByteArray old_url = QUrl::fromLocalFile(old_path).toEncoded();
const QByteArray new_url = QUrl::fromLocalFile(new_path).toEncoded();
@@ -123,20 +124,24 @@ void CollectionBackend::ChangeDirPath(int id, const QString &old_path, const QSt
const int path_len = old_url.length();
// Do the subdirs table
q = QSqlQuery(db);
q.prepare(QString("UPDATE %1 SET path=:path || substr(path, %2) WHERE directory=:id").arg(subdirs_table_).arg(path_len));
q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
{
QSqlQuery q(db);
q.prepare(QString("UPDATE %1 SET path=:path || substr(path, %2) WHERE directory=:id").arg(subdirs_table_).arg(path_len));
q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
}
// Do the songs table
q = QSqlQuery(db);
q.prepare(QString("UPDATE %1 SET filename=:path || substr(filename, %2) WHERE directory=:id").arg(songs_table_).arg(path_len));
q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
{
QSqlQuery q(db);
q.prepare(QString("UPDATE %1 SET filename=:path || substr(filename, %2) WHERE directory=:id").arg(songs_table_).arg(path_len));
q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
}
t.Commit();
@@ -219,8 +224,6 @@ void CollectionBackend::UpdateTotalArtistCount() {
q.exec();
if (db_->CheckErrors(q)) return;
if (!q.next()) return;
//qLog(Debug) << "TotalArtist: " << q.value(0).toInt();
emit TotalArtistCountUpdated(q.value(0).toInt());
@@ -236,8 +239,6 @@ void CollectionBackend::UpdateTotalAlbumCount() {
q.exec();
if (db_->CheckErrors(q)) return;
if (!q.next()) return;
//qLog(Debug) << "TotalAlbum: " << q.value(0).toInt();
emit TotalAlbumCountUpdated(q.value(0).toInt());
@@ -530,7 +531,7 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, bool unavail
}
QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions &opt) {
CollectionQuery query(opt);
query.SetColumnSpec("DISTINCT " + column);
query.AddCompilationRequirement(false);
@@ -547,6 +548,7 @@ QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions
}
QStringList CollectionBackend::GetAllArtists(const QueryOptions &opt) {
return GetAll("artist", opt);
}
@@ -596,8 +598,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString
return GetAlbums(artist, QString(), false, opt);
}
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByAlbumArtist(
const QString &album_artist, const QueryOptions &opt) {
CollectionBackend::AlbumList CollectionBackend::GetAlbumsByAlbumArtist(const QString &album_artist, const QueryOptions &opt) {
return GetAlbums(QString(), album_artist, false, opt);
}
@@ -629,6 +630,7 @@ SongList CollectionBackend::ExecCollectionQuery(CollectionQuery *query) {
ret << song;
}
return ret;
}
Song CollectionBackend::GetSongById(int id) {
@@ -638,7 +640,6 @@ Song CollectionBackend::GetSongById(int id) {
}
SongList CollectionBackend::GetSongsById(const QList<int> &ids) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -658,7 +659,6 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids) {
}
SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QString &table, const QString &column) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@@ -687,7 +687,6 @@ Song CollectionBackend::GetSongById(int id, QSqlDatabase &db) {
}
SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &db) {
QString in = ids.join(",");
QSqlQuery q(db);
@@ -705,7 +704,6 @@ SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &d
}
Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
CollectionQuery query;
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
query.AddWhere("filename", url.toEncoded());
@@ -719,7 +717,6 @@ Song CollectionBackend::GetSongByUrl(const QUrl &url, qint64 beginning) {
}
SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
CollectionQuery query;
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
query.AddWhere("filename", url.toEncoded());
@@ -729,7 +726,6 @@ SongList CollectionBackend::GetSongsByUrl(const QUrl &url) {
while (query.Next()) {
Song song;
song.InitFromQuery(query, true);
songlist << song;
}
}
@@ -757,6 +753,7 @@ SongList CollectionBackend::GetCompilationSongs(const QString &album, const Quer
ret << song;
}
return ret;
}
void CollectionBackend::UpdateCompilations() {
@@ -789,7 +786,7 @@ void CollectionBackend::UpdateCompilations() {
info.artists.insert(artist);
info.directories.insert(filename.left(last_separator));
if (compilation_detected) info.has_compilation_detected = true;
else info.has_not_compilation_detected = true;
else info.has_not_compilation_detected = true;
}
// Now mark the songs that we think are in compilations
@@ -933,7 +930,7 @@ CollectionBackend::Album CollectionBackend::GetAlbumArt(const QString &artist, c
}
void CollectionBackend::UpdateManualAlbumArtAsync(const QString &artist, const QString &albumartist, const QString &album, const QString &art) {
metaObject()->invokeMethod(this, "UpdateManualAlbumArt", Qt::QueuedConnection, Q_ARG(QString, artist), Q_ARG(QString, albumartist), Q_ARG(QString, album), Q_ARG(QString, art));
}

Some files were not shown because too many files have changed in this diff Show More