diff --git a/3rdparty/qtsingleapplication/qtlocalpeer.cpp b/3rdparty/qtsingleapplication/qtlocalpeer.cpp
index ee335d98e..3f391853f 100644
--- a/3rdparty/qtsingleapplication/qtlocalpeer.cpp
+++ b/3rdparty/qtsingleapplication/qtlocalpeer.cpp
@@ -209,3 +209,8 @@ void QtLocalPeer::receiveConnection()
emit messageReceived(uMsg); //### (might take a long time to return)
emit messageReceived(QString::fromUtf8(uMsg));
}
+
+QtLocalPeer::~QtLocalPeer ()
+{
+ lockFile.remove();
+}
diff --git a/3rdparty/qtsingleapplication/qtlocalpeer.h b/3rdparty/qtsingleapplication/qtlocalpeer.h
index dc3ca2253..4ef492e94 100644
--- a/3rdparty/qtsingleapplication/qtlocalpeer.h
+++ b/3rdparty/qtsingleapplication/qtlocalpeer.h
@@ -57,6 +57,7 @@ class QtLocalPeer : public QObject
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
+ ~QtLocalPeer ();
bool isClient();
bool sendMessage(const QString &message, int timeout);
bool sendMessage(const QByteArray &message, int timeout);
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
index ef6748c5c..bd78c06c2 100644
--- a/cmake/Version.cmake
+++ b/cmake/Version.cmake
@@ -3,7 +3,7 @@
# Version numbers.
set(CLEMENTINE_VERSION_MAJOR 1)
set(CLEMENTINE_VERSION_MINOR 2)
-set(CLEMENTINE_VERSION_PATCH 2)
+set(CLEMENTINE_VERSION_PATCH 3)
# set(CLEMENTINE_VERSION_PRERELEASE rc4)
# This should be set to OFF in a release branch
diff --git a/data/grooveshark-valicert-ca.pem b/data/grooveshark-valicert-ca.pem
index 0c3389594..1cb1d7126 100644
--- a/data/grooveshark-valicert-ca.pem
+++ b/data/grooveshark-valicert-ca.pem
@@ -17,3 +17,27 @@ IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
diff --git a/dist/windows/clementine.nsi.in b/dist/windows/clementine.nsi.in
index 98c979dc9..babdcea65 100644
--- a/dist/windows/clementine.nsi.in
+++ b/dist/windows/clementine.nsi.in
@@ -219,6 +219,7 @@ Section "Clementine" Clementine
File "libgio-2.0-0.dll"
File "libglib-2.0-0.dll"
File "libgmodule-2.0-0.dll"
+ File "libgmp-10.dll"
File "libgnutls-28.dll"
File "libgobject-2.0-0.dll"
File "libgpg-error-0.dll"
@@ -1035,6 +1036,7 @@ Section "Uninstall"
Delete "$INSTDIR\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll"
+ Delete "$INSTDIR\libgmp-10.dll"
Delete "$INSTDIR\libgnutls-26.dll"
Delete "$INSTDIR\libgobject-2.0-0.dll"
Delete "$INSTDIR\libgpg-error-0.dll"
diff --git a/ext/libclementine-remote/remotecontrolmessages.proto b/ext/libclementine-remote/remotecontrolmessages.proto
index 2d0ee7433..01dd57942 100644
--- a/ext/libclementine-remote/remotecontrolmessages.proto
+++ b/ext/libclementine-remote/remotecontrolmessages.proto
@@ -52,6 +52,7 @@ enum MsgType {
SONG_FILE_CHUNK = 50;
DOWNLOAD_QUEUE_EMPTY = 51;
LIBRARY_CHUNK = 52;
+ DOWNLOAD_TOTAL_SIZE = 53;
}
// Valid Engine states
@@ -243,10 +244,12 @@ enum DownloadItem {
CurrentItem = 1;
ItemAlbum = 2;
APlaylist = 3;
+ Urls = 4;
}
message RequestDownloadSongs {
optional DownloadItem download_item = 1;
optional int32 playlist_id = 2;
+ repeated string urls = 3;
}
message ResponseSongFileChunk {
@@ -276,9 +279,14 @@ message RequestRateSong {
optional float rating = 1; // 0 to 1
}
+message ResponseDownloadTotalSize {
+ optional int32 total_size = 1;
+ optional int32 file_count = 2;
+}
+
// The message itself
message Message {
- optional int32 version = 1 [default=14];
+ optional int32 version = 1 [default=16];
optional MsgType type = 2 [default=UNKNOWN]; // What data is in the message?
optional RequestConnect request_connect = 21;
@@ -309,4 +317,5 @@ message Message {
optional ResponseSongFileChunk response_song_file_chunk = 32;
optional ResponseSongOffer response_song_offer = 33;
optional ResponseLibraryChunk response_library_chunk = 34;
+ optional ResponseDownloadTotalSize response_download_total_size = 36;
}
diff --git a/src/analyzers/analyzerbase.cpp b/src/analyzers/analyzerbase.cpp
old mode 100644
new mode 100755
index f0ca647b1..00c2e57ee
--- a/src/analyzers/analyzerbase.cpp
+++ b/src/analyzers/analyzerbase.cpp
@@ -52,6 +52,7 @@ Analyzer::Base::Base(QWidget* parent, uint scopeSize)
m_fht(new FHT(scopeSize)),
m_engine(nullptr),
m_lastScope(512),
+ current_chunk_(0),
new_frame_(false),
is_playing_(false) {}
@@ -85,10 +86,10 @@ void Analyzer::Base::paintEvent(QPaintEvent* e) {
switch (m_engine->state()) {
case Engine::Playing: {
- const Engine::Scope& thescope = m_engine->scope();
+ const Engine::Scope& thescope = m_engine->scope(m_timeout);
int i = 0;
- // convert to mono here - our built in analyzers need mono, but we the
+ // convert to mono here - our built in analyzers need mono, but the
// engines provide interleaved pcm
for (uint x = 0; (int)x < m_fht->size(); ++x) {
m_lastScope[x] =
diff --git a/src/analyzers/analyzerbase.h b/src/analyzers/analyzerbase.h
old mode 100644
new mode 100755
index f6c7eebfd..189b178d7
--- a/src/analyzers/analyzerbase.h
+++ b/src/analyzers/analyzerbase.h
@@ -50,6 +50,8 @@ class Base : public QWidget {
}
}
+ virtual void framerateChanged() {}
+
protected:
Base(QWidget*, uint scopeSize = 7);
@@ -73,6 +75,7 @@ class Base : public QWidget {
FHT* m_fht;
EngineBase* m_engine;
Scope m_lastScope;
+ int current_chunk_;
bool new_frame_;
bool is_playing_;
@@ -83,6 +86,4 @@ void initSin(Scope&, const uint = 6000);
} // END namespace Analyzer
-using Analyzer::Scope;
-
#endif
diff --git a/src/analyzers/analyzercontainer.cpp b/src/analyzers/analyzercontainer.cpp
index e6bd00ec1..c7da4c9e9 100644
--- a/src/analyzers/analyzercontainer.cpp
+++ b/src/analyzers/analyzercontainer.cpp
@@ -165,6 +165,9 @@ void AnalyzerContainer::ChangeFramerate(int new_framerate) {
// Even if it is not supposed to happen, I don't want to get a dbz error
new_framerate = new_framerate == 0 ? kMediumFramerate : new_framerate;
current_analyzer_->changeTimeout(1000 / new_framerate);
+
+ // notify the current analyzer that the framerate has changed
+ current_analyzer_->framerateChanged();
}
SaveFramerate(new_framerate);
}
diff --git a/src/analyzers/baranalyzer.cpp b/src/analyzers/baranalyzer.cpp
index a6549ed8a..dfb35f7e4 100644
--- a/src/analyzers/baranalyzer.cpp
+++ b/src/analyzers/baranalyzer.cpp
@@ -16,11 +16,12 @@
#include
#include
+using Analyzer::Scope;
+
const char* BarAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Bar analyzer");
-BarAnalyzer::BarAnalyzer(QWidget* parent)
- : Analyzer::Base(parent, 8) {
+BarAnalyzer::BarAnalyzer(QWidget* parent) : Analyzer::Base(parent, 8) {
// roof pixmaps don't depend on size() so we do in the ctor
m_bg = parent->palette().color(QPalette::Background);
diff --git a/src/analyzers/baranalyzer.h b/src/analyzers/baranalyzer.h
index ffe9e27a4..3118bb9f4 100644
--- a/src/analyzers/baranalyzer.h
+++ b/src/analyzers/baranalyzer.h
@@ -16,7 +16,7 @@ class BarAnalyzer : public Analyzer::Base {
Q_INVOKABLE BarAnalyzer(QWidget*);
void init();
- virtual void analyze(QPainter& p, const Scope&, bool new_frame);
+ virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
// virtual void transform( Scope& );
/**
@@ -53,7 +53,7 @@ class BarAnalyzer : public Analyzer::Base {
QPixmap m_pixBarGradient;
QPixmap m_pixCompose;
QPixmap canvas_;
- Scope m_scope; // so we don't create a vector every frame
+ Analyzer::Scope m_scope; // so we don't create a vector every frame
QColor m_bg;
};
diff --git a/src/analyzers/blockanalyzer.cpp b/src/analyzers/blockanalyzer.cpp
index 6b4d630f4..eb4cc2e77 100644
--- a/src/analyzers/blockanalyzer.cpp
+++ b/src/analyzers/blockanalyzer.cpp
@@ -100,10 +100,16 @@ void BlockAnalyzer::determineStep() {
// boxes/blocks of pixels)
// I calculated the value 30 based on some trial and error
- const double fallTime = 30 * m_rows;
+ // the fall time of 30 is too slow on framerates above 50fps
+ const double fallTime = timeout() < 20 ? 20 * m_rows : 30 * m_rows;
+
m_step = double(m_rows * timeout()) / fallTime;
}
+void BlockAnalyzer::framerateChanged() { // virtual
+ determineStep();
+}
+
void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual
{
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
diff --git a/src/analyzers/blockanalyzer.h b/src/analyzers/blockanalyzer.h
index d6c6d4ac9..86c4c63b0 100644
--- a/src/analyzers/blockanalyzer.h
+++ b/src/analyzers/blockanalyzer.h
@@ -32,10 +32,11 @@ class BlockAnalyzer : public Analyzer::Base {
static const char* kName;
protected:
- virtual void transform(Scope&);
- virtual void analyze(QPainter& p, const Scope&, bool new_frame);
+ virtual void transform(Analyzer::Scope&);
+ virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
virtual void resizeEvent(QResizeEvent*);
virtual void paletteChange(const QPalette&);
+ virtual void framerateChanged();
void drawBackground();
void determineStep();
@@ -49,7 +50,7 @@ class BlockAnalyzer : public Analyzer::Base {
QPixmap m_topBarPixmap;
QPixmap m_background;
QPixmap canvas_;
- Scope m_scope; // so we don't create a vector every frame
+ Analyzer::Scope m_scope; // so we don't create a vector every frame
std::vector m_store; // current bar heights
std::vector m_yscale;
diff --git a/src/analyzers/boomanalyzer.cpp b/src/analyzers/boomanalyzer.cpp
index ef5b4092e..3713064fa 100644
--- a/src/analyzers/boomanalyzer.cpp
+++ b/src/analyzers/boomanalyzer.cpp
@@ -5,6 +5,8 @@
#include
#include
+using Analyzer::Scope;
+
const char* BoomAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer");
diff --git a/src/analyzers/boomanalyzer.h b/src/analyzers/boomanalyzer.h
index bb9532735..8d7f3394c 100644
--- a/src/analyzers/boomanalyzer.h
+++ b/src/analyzers/boomanalyzer.h
@@ -19,8 +19,8 @@ class BoomAnalyzer : public Analyzer::Base {
static const char* kName;
virtual void init();
- virtual void transform(Scope& s);
- virtual void analyze(QPainter& p, const Scope&, bool new_frame);
+ virtual void transform(Analyzer::Scope& s);
+ virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
public slots:
void changeK_barHeight(int);
diff --git a/src/analyzers/nyancatanalyzer.cpp b/src/analyzers/nyancatanalyzer.cpp
index 4de3f8b3f..4a2ba57cc 100644
--- a/src/analyzers/nyancatanalyzer.cpp
+++ b/src/analyzers/nyancatanalyzer.cpp
@@ -25,6 +25,8 @@
#include "core/arraysize.h"
#include "core/logging.h"
+using Analyzer::Scope;
+
const char* NyanCatAnalyzer::kName = "Nyanalyzer cat";
const float NyanCatAnalyzer::kPixelScale = 0.02f;
diff --git a/src/analyzers/nyancatanalyzer.h b/src/analyzers/nyancatanalyzer.h
index 8b16527b8..5004cfa2f 100644
--- a/src/analyzers/nyancatanalyzer.h
+++ b/src/analyzers/nyancatanalyzer.h
@@ -31,7 +31,7 @@ class NyanCatAnalyzer : public Analyzer::Base {
static const char* kName;
protected:
- void transform(Scope&);
+ void transform(Analyzer::Scope&);
void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
void timerEvent(QTimerEvent* e);
diff --git a/src/analyzers/sonogram.cpp b/src/analyzers/sonogram.cpp
index b7e290714..552701ce0 100644
--- a/src/analyzers/sonogram.cpp
+++ b/src/analyzers/sonogram.cpp
@@ -15,6 +15,8 @@
#include
+using Analyzer::Scope;
+
const char* Sonogram::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Sonogram");
diff --git a/src/analyzers/sonogram.h b/src/analyzers/sonogram.h
index 35ce753cc..967d97ac2 100644
--- a/src/analyzers/sonogram.h
+++ b/src/analyzers/sonogram.h
@@ -29,8 +29,8 @@ class Sonogram : public Analyzer::Base {
static const char* kName;
protected:
- void analyze(QPainter& p, const Scope&, bool new_frame);
- void transform(Scope&);
+ void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
+ void transform(Analyzer::Scope&);
void demo(QPainter& p);
void resizeEvent(QResizeEvent*);
diff --git a/src/analyzers/turbine.cpp b/src/analyzers/turbine.cpp
index 5b00cae94..6aeecceb5 100644
--- a/src/analyzers/turbine.cpp
+++ b/src/analyzers/turbine.cpp
@@ -12,6 +12,8 @@
#include "turbine.h"
+using Analyzer::Scope;
+
const char* TurbineAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Turbine");
diff --git a/src/analyzers/turbine.h b/src/analyzers/turbine.h
index 1175bff1f..984bcd6c9 100644
--- a/src/analyzers/turbine.h
+++ b/src/analyzers/turbine.h
@@ -16,7 +16,7 @@ class TurbineAnalyzer : public BoomAnalyzer {
public:
Q_INVOKABLE TurbineAnalyzer(QWidget* parent) : BoomAnalyzer(parent) {}
- void analyze(QPainter& p, const Scope&, bool new_frame);
+ void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
static const char* kName;
};
diff --git a/src/core/organiseformat.cpp b/src/core/organiseformat.cpp
index b0e650c10..06f9a4ecc 100644
--- a/src/core/organiseformat.cpp
+++ b/src/core/organiseformat.cpp
@@ -22,6 +22,7 @@
#include
#include
+#include "core/arraysize.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
@@ -47,9 +48,13 @@ const QStringList OrganiseFormat::kKnownTags = QStringList() << "title"
<< "grouping";
// From http://en.wikipedia.org/wiki/8.3_filename#Directory_table
-const char* OrganiseFormat::kInvalidFatCharacters = "\"*/\\:<>?|";
+const char OrganiseFormat::kInvalidFatCharacters[] = "\"*/\\:<>?|";
const int OrganiseFormat::kInvalidFatCharactersCount =
- strlen(OrganiseFormat::kInvalidFatCharacters);
+ arraysize(OrganiseFormat::kInvalidFatCharacters) - 1;
+
+const char OrganiseFormat::kInvalidPrefixCharacters[] = ".";
+const int OrganiseFormat::kInvalidPrefixCharactersCount =
+ arraysize(OrganiseFormat::kInvalidPrefixCharacters) - 1;
const QRgb OrganiseFormat::SyntaxHighlighter::kValidTagColorLight =
qRgb(64, 64, 255);
@@ -116,7 +121,19 @@ QString OrganiseFormat::GetFilenameForSong(const Song& song) const {
filename = stripped;
}
- return filename;
+ // Fix any parts of the path that start with dots.
+ QStringList parts = filename.split("/");
+ for (int i = 0; i < parts.count(); ++i) {
+ QString* part = &parts[i];
+ for (int j = 0; j < kInvalidPrefixCharactersCount; ++j) {
+ if (part->startsWith(kInvalidPrefixCharacters[j])) {
+ part->replace(0, 1, '_');
+ break;
+ }
+ }
+ }
+
+ return parts.join("/");
}
QString OrganiseFormat::ParseBlock(QString block, const Song& song,
diff --git a/src/core/organiseformat.h b/src/core/organiseformat.h
index 04c3b8f35..e11a24006 100644
--- a/src/core/organiseformat.h
+++ b/src/core/organiseformat.h
@@ -30,8 +30,10 @@ class OrganiseFormat {
static const char* kTagPattern;
static const char* kBlockPattern;
static const QStringList kKnownTags;
- static const char* kInvalidFatCharacters;
+ static const char kInvalidFatCharacters[];
static const int kInvalidFatCharactersCount;
+ static const char kInvalidPrefixCharacters[];
+ static const int kInvalidPrefixCharactersCount;
QString format() const { return format_; }
bool replace_non_ascii() const { return replace_non_ascii_; }
diff --git a/src/core/song.cpp b/src/core/song.cpp
index 693bbe735..fba36f8c5 100644
--- a/src/core/song.cpp
+++ b/src/core/song.cpp
@@ -885,7 +885,7 @@ void Song::BindToQuery(QSqlQuery* query) const {
if (Application::kIsPortable &&
Utilities::UrlOnSameDriveAsClementine(d->url_)) {
query->bindValue(":filename",
- Utilities::GetRelativePathToClementineBin(d->url_));
+ Utilities::GetRelativePathToClementineBin(d->url_).toEncoded());
} else {
query->bindValue(":filename", d->url_.toEncoded());
}
diff --git a/src/covers/currentartloader.cpp b/src/covers/currentartloader.cpp
index 0567e6357..4210c2137 100644
--- a/src/covers/currentartloader.cpp
+++ b/src/covers/currentartloader.cpp
@@ -57,6 +57,7 @@ void CurrentArtLoader::TempArtLoaded(quint64 id, const QImage& image) {
if (!image.isNull()) {
temp_art_.reset(new QTemporaryFile(temp_file_pattern_));
+ temp_art_->setAutoRemove(true);
temp_art_->open();
image.save(temp_art_->fileName(), "JPEG");
@@ -64,6 +65,7 @@ void CurrentArtLoader::TempArtLoaded(quint64 id, const QImage& image) {
// since it's the GUI thread, but the alternative is hard.
temp_art_thumbnail_.reset(new QTemporaryFile(temp_file_pattern_));
temp_art_thumbnail_->open();
+ temp_art_thumbnail_->setAutoRemove(true);
thumbnail = image.scaledToHeight(120, Qt::SmoothTransformation);
thumbnail.save(temp_art_thumbnail_->fileName(), "JPEG");
diff --git a/src/engines/enginebase.h b/src/engines/enginebase.h
old mode 100644
new mode 100755
index 7dc3c6b06..e6c30d2c3
--- a/src/engines/enginebase.h
+++ b/src/engines/enginebase.h
@@ -85,7 +85,7 @@ class Base : public QObject {
// Simple accessors
inline uint volume() const { return volume_; }
- virtual const Scope& scope() { return scope_; }
+ virtual const Scope& scope(int chunk_length) { return scope_; }
bool is_fadeout_enabled() const { return fadeout_enabled_; }
bool is_crossfade_enabled() const { return crossfade_enabled_; }
bool is_autocrossfade_enabled() const { return autocrossfade_enabled_; }
diff --git a/src/engines/gstengine.cpp b/src/engines/gstengine.cpp
old mode 100644
new mode 100755
index 105092f4d..20e1682f4
--- a/src/engines/gstengine.cpp
+++ b/src/engines/gstengine.cpp
@@ -22,6 +22,7 @@
#include "gstengine.h"
#include
+#include
#include
#include
@@ -44,6 +45,7 @@
#include "gstenginepipeline.h"
#include "core/logging.h"
#include "core/taskmanager.h"
+#include "core/timeconstants.h"
#include "core/utilities.h"
#ifdef HAVE_MOODBAR
@@ -96,7 +98,9 @@ GstEngine::GstEngine(TaskManager* task_manager)
timer_id_(-1),
next_element_id_(0),
is_fading_out_to_pause_(false),
- has_faded_out_(false) {
+ has_faded_out_(false),
+ scope_chunk_(0),
+ have_new_buffer_(false) {
seek_timer_->setSingleShot(true);
seek_timer_->setInterval(kSeekDelayNanosec / kNsecPerMsec);
connect(seek_timer_, SIGNAL(timeout()), SLOT(SeekNow()));
@@ -235,20 +239,40 @@ void GstEngine::AddBufferToScope(GstBuffer* buf, int pipeline_id) {
if (latest_buffer_ != nullptr) {
gst_buffer_unref(latest_buffer_);
}
+
latest_buffer_ = buf;
+ have_new_buffer_ = true;
}
-const Engine::Scope& GstEngine::scope() {
- if (latest_buffer_ != nullptr) {
- UpdateScope();
+const Engine::Scope& GstEngine::scope(int chunk_length) {
+ // the new buffer could have a different size
+ if (have_new_buffer_) {
+ if (latest_buffer_ != nullptr) {
+ scope_chunks_ = ceil(((double)GST_BUFFER_DURATION(latest_buffer_) /
+ (double)(chunk_length * kNsecPerMsec)));
+ }
+
+ // if the buffer is shorter than the chunk length
+ if (scope_chunks_ <= 0) {
+ scope_chunks_ = 1;
+ }
+
+ scope_chunk_ = 0;
+ have_new_buffer_ = false;
}
+ UpdateScope(chunk_length);
return scope_;
}
-void GstEngine::UpdateScope() {
+void GstEngine::UpdateScope(int chunk_length) {
typedef Engine::Scope::value_type sample_type;
+ // determine where to split the buffer
+ int chunk_density = GST_BUFFER_SIZE(latest_buffer_) /
+ (GST_BUFFER_DURATION(latest_buffer_) / kNsecPerMsec);
+ int chunk_size = chunk_length * chunk_density;
+
// determine the number of channels
GstStructure* structure =
gst_caps_get_structure(GST_BUFFER_CAPS(latest_buffer_), 0);
@@ -258,17 +282,34 @@ void GstEngine::UpdateScope() {
// scope does not support >2 channels
if (channels > 2) return;
+ // in case a buffer doesn't arrive in time
+ if (scope_chunk_ >= scope_chunks_) {
+ scope_chunk_ = 0;
+ return;
+ }
+
+ // set the starting point in the buffer to take data from
const sample_type* source =
reinterpret_cast(GST_BUFFER_DATA(latest_buffer_));
+ source += (chunk_size / sizeof(sample_type)) * scope_chunk_;
sample_type* dest = scope_.data();
- const int bytes = qMin(
- static_cast(GST_BUFFER_SIZE(latest_buffer_)),
- scope_.size() * sizeof(sample_type));
+
+ int bytes = 0;
+
+ // make sure we don't go beyond the end of the buffer
+ if (scope_chunk_ == scope_chunks_ - 1) {
+ bytes =
+ qMin(static_cast(
+ GST_BUFFER_SIZE(latest_buffer_) - (chunk_size * scope_chunk_)),
+ scope_.size() * sizeof(sample_type));
+ } else {
+ bytes = qMin(static_cast(chunk_size),
+ scope_.size() * sizeof(sample_type));
+ }
+
+ scope_chunk_++;
memcpy(dest, source, bytes);
-
- gst_buffer_unref(latest_buffer_);
- latest_buffer_ = nullptr;
}
void GstEngine::StartPreloading(const QUrl& url, bool force_stop_at_end,
diff --git a/src/engines/gstengine.h b/src/engines/gstengine.h
old mode 100644
new mode 100755
index bd2ceb73d..053f8f128
--- a/src/engines/gstengine.h
+++ b/src/engines/gstengine.h
@@ -80,7 +80,7 @@ class GstEngine : public Engine::Base, public BufferConsumer {
qint64 position_nanosec() const;
qint64 length_nanosec() const;
Engine::State state() const;
- const Engine::Scope& scope();
+ const Engine::Scope& scope(int chunk_length);
OutputDetailsList GetOutputsList() const;
@@ -161,7 +161,7 @@ class GstEngine : public Engine::Base, public BufferConsumer {
std::shared_ptr CreatePipeline(const QUrl& url,
qint64 end_nanosec);
- void UpdateScope();
+ void UpdateScope(int chunk_length);
int AddBackgroundStream(std::shared_ptr pipeline);
@@ -224,6 +224,10 @@ class GstEngine : public Engine::Base, public BufferConsumer {
bool is_fading_out_to_pause_;
bool has_faded_out_;
+ int scope_chunk_;
+ bool have_new_buffer_;
+ int scope_chunks_;
+
QList device_finders_;
};
diff --git a/src/internet/soundcloudsettingspage.ui b/src/internet/soundcloudsettingspage.ui
index 0581c4002..e4b2d1c08 100644
--- a/src/internet/soundcloudsettingspage.ui
+++ b/src/internet/soundcloudsettingspage.ui
@@ -20,15 +20,14 @@
-
-
- You don't need to be logged in to search and to listen to music on SoundCloud.
+
+ true
-
-
- -
-
- However, you need to login to access your playlists and your stream.
+ You don't need to be logged in to search and to listen to music on SoundCloud. However, you need to login to access your playlists and your stream.
+
+
+ true
diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp
index 9b7d2517d..0758476bb 100644
--- a/src/networkremote/outgoingdatacreator.cpp
+++ b/src/networkremote/outgoingdatacreator.cpp
@@ -588,14 +588,41 @@ void OutgoingDataCreator::SendSongs(
case pb::remote::APlaylist:
SendPlaylist(client, request.playlist_id());
break;
+ case pb::remote::Urls:
+ SendUrls(client, request);
+ break;
default:
break;
}
+ // Send total file size & file count
+ SendTotalFileSize(client);
+
// Send first file
OfferNextSong(client);
}
+void OutgoingDataCreator::SendTotalFileSize(RemoteClient *client) {
+ if (!download_queue_.contains(client)) return;
+
+ pb::remote::Message msg;
+ msg.set_type(pb::remote::DOWNLOAD_TOTAL_SIZE);
+
+ pb::remote::ResponseDownloadTotalSize* response =
+ msg.mutable_response_download_total_size();
+
+ response->set_file_count(download_queue_[client].size());
+
+ int total = 0;
+ for (DownloadItem item : download_queue_[client]) {
+ total += item.song_.filesize();
+ }
+
+ response->set_total_size(total);
+
+ client->SendData(&msg);
+}
+
void OutgoingDataCreator::OfferNextSong(RemoteClient* client) {
if (!download_queue_.contains(client)) return;
@@ -737,6 +764,29 @@ void OutgoingDataCreator::SendPlaylist(RemoteClient* client, int playlist_id) {
}
}
+void OutgoingDataCreator::SendUrls(RemoteClient *client,
+ const pb::remote::RequestDownloadSongs &request) {
+ SongList song_list;
+
+ // First gather all valid songs
+ for (auto it = request.urls().begin(); it != request.urls().end(); ++it) {
+ std::string s = *it;
+ QUrl url = QUrl(QStringFromStdString(s));
+
+ Song song = app_->library_backend()->GetSongByUrl(url);
+
+ if (song.is_valid() && song.url().scheme() == "file") {
+ song_list.append(song);
+ }
+ }
+
+ // Then send them to Clementine Remote
+ for (Song s : song_list) {
+ DownloadItem item(s, song_list.indexOf(s) + 1, song_list.count());
+ download_queue_[client].append(item);
+ }
+}
+
void OutgoingDataCreator::SendLibrary(RemoteClient* client) {
// Get a temporary file name
QString temp_file_name = Utilities::GetTemporaryFileName();
diff --git a/src/networkremote/outgoingdatacreator.h b/src/networkremote/outgoingdatacreator.h
index 5a2083727..05f89b292 100644
--- a/src/networkremote/outgoingdatacreator.h
+++ b/src/networkremote/outgoingdatacreator.h
@@ -107,7 +107,9 @@ class OutgoingDataCreator : public QObject {
int song_count);
void SendAlbum(RemoteClient* client, const Song& song);
void SendPlaylist(RemoteClient* client, int playlist_id);
+ void SendUrls(RemoteClient* client, const pb::remote::RequestDownloadSongs& request);
void OfferNextSong(RemoteClient* client);
+ void SendTotalFileSize(RemoteClient* client);
};
#endif // OUTGOINGDATACREATOR_H
diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp
index a97c3b1ab..855c4b0e6 100644
--- a/src/playlist/playlistview.cpp
+++ b/src/playlist/playlistview.cpp
@@ -476,7 +476,6 @@ void PlaylistView::drawRow(QPainter* painter,
QPalette::HighlightedText));
opt.palette.setColor(QPalette::Highlight, Qt::transparent);
opt.palette.setColor(QPalette::AlternateBase, Qt::transparent);
- opt.font.setItalic(true);
opt.decorationSize = QSize(20, 20);
// Draw the actual row data on top. We cache this, because it's fairly
diff --git a/src/playlist/songloaderinserter.cpp b/src/playlist/songloaderinserter.cpp
index c513810cd..b11114d4e 100644
--- a/src/playlist/songloaderinserter.cpp
+++ b/src/playlist/songloaderinserter.cpp
@@ -119,15 +119,21 @@ void SongLoaderInserter::InsertSongs() {
}
void SongLoaderInserter::AsyncLoad() {
-
// First, quick load raw songs.
int async_progress = 0;
int async_load_id = task_manager_->StartTask(tr("Loading tracks"));
task_manager_->SetTaskProgress(async_load_id, async_progress,
pending_.count());
- for (SongLoader* loader : pending_) {
+ for (int i = 0; i < pending_.count(); ++i) {
+ SongLoader* loader = pending_[i];
loader->LoadFilenamesBlocking();
task_manager_->SetTaskProgress(async_load_id, ++async_progress);
+ if (i == 0) {
+ // Load everything from the first song. It'll start playing as soon as
+ // we emit PreloadFinished, so it needs to have the duration set to show
+ // properly in the UI.
+ loader->LoadMetadataBlocking();
+ }
songs_ << loader->songs();
}
task_manager_->SetTaskFinished(async_load_id);
@@ -138,8 +144,12 @@ void SongLoaderInserter::AsyncLoad() {
async_load_id = task_manager_->StartTask(tr("Loading tracks info"));
task_manager_->SetTaskProgress(async_load_id, async_progress, songs_.count());
SongList songs;
- for (SongLoader* loader : pending_) {
- loader->LoadMetadataBlocking();
+ for (int i = 0; i < pending_.count(); ++i) {
+ SongLoader* loader = pending_[i];
+ if (i != 0) {
+ // We already did this earlier for the first song.
+ loader->LoadMetadataBlocking();
+ }
songs << loader->songs();
task_manager_->SetTaskProgress(async_load_id, songs.count());
}
diff --git a/src/transcoder/transcoderoptionsflac.ui b/src/transcoder/transcoderoptionsflac.ui
index 9eaae5cc7..8375ff62f 100644
--- a/src/transcoder/transcoderoptionsflac.ui
+++ b/src/transcoder/transcoderoptionsflac.ui
@@ -17,7 +17,7 @@
-
- Quality
+ Quality
diff --git a/src/transcoder/transcoderoptionsmp3.ui b/src/transcoder/transcoderoptionsmp3.ui
index 0933a54fc..a6eb09b5b 100644
--- a/src/transcoder/transcoderoptionsmp3.ui
+++ b/src/transcoder/transcoderoptionsmp3.ui
@@ -45,7 +45,7 @@
-
- Quality
+ Quality
diff --git a/src/transcoder/transcoderoptionsspeex.ui b/src/transcoder/transcoderoptionsspeex.ui
index f66d89ed6..7aedd6134 100644
--- a/src/transcoder/transcoderoptionsspeex.ui
+++ b/src/transcoder/transcoderoptionsspeex.ui
@@ -17,7 +17,7 @@
-
- Quality
+ Quality
diff --git a/src/transcoder/transcoderoptionsvorbis.ui b/src/transcoder/transcoderoptionsvorbis.ui
index 809a959e2..65f390acc 100644
--- a/src/transcoder/transcoderoptionsvorbis.ui
+++ b/src/transcoder/transcoderoptionsvorbis.ui
@@ -17,7 +17,7 @@
-
- Quality
+ Quality
diff --git a/src/translations/af.po b/src/translations/af.po
index e44e0d4d7..82d3afa3d 100644
--- a/src/translations/af.po
+++ b/src/translations/af.po
@@ -9,7 +9,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Clementine Music Player\n"
-"PO-Revision-Date: 2014-04-14 07:10+0000\n"
+"PO-Revision-Date: 2014-05-11 07:38+0000\n"
"Last-Translator: Clementine Buildbot \n"
"Language-Team: Afrikaans (http://www.transifex.com/projects/p/clementine/language/af/)\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -687,7 +687,7 @@ msgstr "Alle albums"
msgid "All artists"
msgstr "Alle kunstenaars"
-#: ui/albumcoverchoicecontroller.cpp:47
+#: ui/albumcoverchoicecontroller.cpp:48
msgid "All files (*)"
msgstr "Alle lêers (*)"
@@ -756,7 +756,7 @@ msgstr "'n Onbekende fout het voorgekom"
msgid "And:"
msgstr "En:"
-#: moodbar/moodbarrenderer.cpp:169
+#: moodbar/moodbarrenderer.cpp:171
msgid "Angry"
msgstr "Kwaai"
@@ -979,7 +979,7 @@ msgstr "Gaan soek..."
msgid "Buffer duration"
msgstr ""
-#: engines/gstengine.cpp:821
+#: engines/gstengine.cpp:862
msgid "Buffering"
msgstr "Buffering"
@@ -1072,7 +1072,7 @@ msgstr ""
msgid "Choose a name for your smart playlist"
msgstr "Kies 'n naam vir jou slimspeellys"
-#: engines/gstengine.cpp:842
+#: engines/gstengine.cpp:883
msgid "Choose automatically"
msgstr "Kies outomaties"
@@ -1202,7 +1202,7 @@ msgstr ""
msgid "Click to toggle between remaining time and total time"
msgstr "Kliek hier om te wissel tussen oorblywende en totale tyd"
-#: ../bin/src/ui_soundcloudsettingspage.h:112
+#: ../bin/src/ui_soundcloudsettingspage.h:107
#: ../bin/src/ui_dropboxsettingspage.h:106
#: ../bin/src/ui_skydrivesettingspage.h:106
#: ../bin/src/ui_boxsettingspage.h:106
@@ -1596,7 +1596,7 @@ msgstr "Verlaag die volume"
msgid "Default background image"
msgstr "Standaars agtergrond prentjie"
-#: engines/gstengine.cpp:867
+#: engines/gstengine.cpp:908
#, qt-format
msgid "Default device on %1"
msgstr ""
@@ -2375,7 +2375,7 @@ msgstr "Beeldduur"
msgid "Frames per buffer"
msgstr "Beelde per buffer"
-#: moodbar/moodbarrenderer.cpp:171
+#: moodbar/moodbarrenderer.cpp:173
msgid "Frozen"
msgstr "Bevrore"
@@ -2526,7 +2526,7 @@ msgstr ""
msgid "HTTP proxy"
msgstr "HTTP instaanbediener"
-#: moodbar/moodbarrenderer.cpp:173
+#: moodbar/moodbarrenderer.cpp:175
msgid "Happy"
msgstr "Gelukkig"
@@ -2560,10 +2560,6 @@ msgstr ""
msgid "Hours"
msgstr "Ure"
-#: ../bin/src/ui_soundcloudsettingspage.h:110
-msgid "However, you need to login to access your playlists and your stream."
-msgstr ""
-
#: core/backgroundstreams.cpp:27
msgid "Hypnotoad"
msgstr "Hypnopadda"
@@ -2598,11 +2594,11 @@ msgstr "As jy die URL van 'n potgooi ken, tik dit hier onder in en druk dan op G
msgid "Ignore \"The\" in artist names"
msgstr "Ignoreer \"The\" in kunstenaars se name"
-#: ui/albumcoverchoicecontroller.cpp:43
+#: ui/albumcoverchoicecontroller.cpp:44
msgid "Images (*.png *.jpg *.jpeg *.bmp *.gif *.xpm *.pbm *.pgm *.ppm *.xbm)"
msgstr "Beelde (*.png *.jpg *.jpeg *.bmp *.gif *.xpm *.pbm *.pgm *.ppm *.xbm)"
-#: ui/albumcoverchoicecontroller.cpp:45
+#: ui/albumcoverchoicecontroller.cpp:46
msgid "Images (*.png *.jpg *.jpeg *.bmp *.xpm *.pbm *.ppm *.xbm)"
msgstr "Beelde (*.png *.jpg *.jpeg *.bmp *.xpm *.pbm *.ppm *.xbm)"
@@ -2887,15 +2883,15 @@ msgstr "Laai"
msgid "Load cover from URL"
msgstr "Verkry omslag van URL"
-#: ui/albumcoverchoicecontroller.cpp:63
+#: ui/albumcoverchoicecontroller.cpp:64
msgid "Load cover from URL..."
msgstr "Verkry omslag van URL..."
-#: ui/albumcoverchoicecontroller.cpp:103
+#: ui/albumcoverchoicecontroller.cpp:104
msgid "Load cover from disk"
msgstr "Laai omslag vanaf skyf"
-#: ui/albumcoverchoicecontroller.cpp:59
+#: ui/albumcoverchoicecontroller.cpp:60
msgid "Load cover from disk..."
msgstr "Verkry omslag van skyf..."
@@ -2928,11 +2924,11 @@ msgstr "Liedjies word gelaai"
msgid "Loading stream"
msgstr "Stroom word gelaai"
-#: playlist/songloaderinserter.cpp:125 ui/edittagdialog.cpp:242
+#: playlist/songloaderinserter.cpp:124 ui/edittagdialog.cpp:242
msgid "Loading tracks"
msgstr "Snitte word gelaai"
-#: playlist/songloaderinserter.cpp:138
+#: playlist/songloaderinserter.cpp:144
msgid "Loading tracks info"
msgstr "Snitinligting word gelaai"
@@ -2952,7 +2948,7 @@ msgstr "Laai lêers/URLs en vervang huidige afspeellys"
#: ../bin/src/ui_digitallyimportedsettingspage.h:163
#: ../bin/src/ui_groovesharksettingspage.h:144
#: ../bin/src/ui_magnatunesettingspage.h:164
-#: ../bin/src/ui_soundcloudsettingspage.h:111
+#: ../bin/src/ui_soundcloudsettingspage.h:106
#: ../bin/src/ui_spotifysettingspage.h:211
#: ../bin/src/ui_subsonicsettingspage.h:130
#: ../bin/src/ui_dropboxsettingspage.h:105
@@ -3317,7 +3313,7 @@ msgstr "Geen"
msgid "None of the selected songs were suitable for copying to a device"
msgstr "Geen van die gekose liedjies is geskik om na die toestel te kopiëer nie."
-#: moodbar/moodbarrenderer.cpp:167
+#: moodbar/moodbarrenderer.cpp:169
msgid "Normal"
msgstr "Normaal"
@@ -3797,9 +3793,14 @@ msgstr "Skommel die liedjies"
#: ../bin/src/ui_transcoderoptionsmp3.h:192
#: ../bin/src/ui_transcoderoptionsspeex.h:217
#: ../bin/src/ui_transcoderoptionsvorbis.h:202
-#: visualisations/visualisationcontainer.cpp:118
+msgctxt "Sound quality"
msgid "Quality"
-msgstr "Kwaliteit"
+msgstr ""
+
+#: visualisations/visualisationcontainer.cpp:118
+msgctxt "Visualisation quality"
+msgid "Quality"
+msgstr ""
#: ../bin/src/ui_deviceproperties.h:383
msgid "Querying device..."
@@ -4115,11 +4116,11 @@ msgstr "Monstertempo"
msgid "Save .mood files in your music library"
msgstr "Stoor .mood-lêers in jou musiekversameling"
-#: ui/albumcoverchoicecontroller.cpp:126
+#: ui/albumcoverchoicecontroller.cpp:127
msgid "Save album cover"
msgstr "Stoor albumomslag"
-#: ui/albumcoverchoicecontroller.cpp:61
+#: ui/albumcoverchoicecontroller.cpp:62
msgid "Save cover to disk..."
msgstr "Stoor omslag op skyf"
@@ -4208,11 +4209,11 @@ msgstr "Soek deur Magnatune"
msgid "Search Subsonic"
msgstr "Soek deur Subsonic"
-#: ui/albumcoverchoicecontroller.cpp:72
+#: ui/albumcoverchoicecontroller.cpp:73
msgid "Search automatically"
msgstr ""
-#: ui/albumcoverchoicecontroller.cpp:65
+#: ui/albumcoverchoicecontroller.cpp:66
msgid "Search for album covers..."
msgstr "Soek vir album omslae..."
@@ -4410,7 +4411,7 @@ msgstr "Wys omslae in die versameling"
msgid "Show dividers"
msgstr "Wys verdelers"
-#: ui/albumcoverchoicecontroller.cpp:69 widgets/prettyimage.cpp:182
+#: ui/albumcoverchoicecontroller.cpp:70 widgets/prettyimage.cpp:182
msgid "Show fullsize..."
msgstr "Wys volgrootte..."
@@ -4599,7 +4600,7 @@ msgstr "Sorteer liedjies volgens"
msgid "Sorting"
msgstr "Sortering"
-#: ../bin/src/ui_soundcloudsettingspage.h:108
+#: ../bin/src/ui_soundcloudsettingspage.h:104
msgid "SoundCloud"
msgstr ""
@@ -4775,7 +4776,7 @@ msgstr "Spotify afspeellys word gesinkroniseer"
msgid "Syncing Spotify starred tracks"
msgstr "Gegradeerde Spotify snitte word gesinkroniseer"
-#: moodbar/moodbarrenderer.cpp:175
+#: moodbar/moodbarrenderer.cpp:177
msgid "System colors"
msgstr "Standaard kleure"
@@ -5072,7 +5073,7 @@ msgstr "Kan nie %1 aflaai nie (%2)"
#: core/song.cpp:408 library/librarymodel.cpp:336 library/librarymodel.cpp:340
#: library/librarymodel.cpp:344 library/librarymodel.cpp:1018
#: playlist/playlistdelegates.cpp:306 playlist/playlistmanager.cpp:473
-#: playlist/playlistmanager.cpp:474 ui/albumcoverchoicecontroller.cpp:123
+#: playlist/playlistmanager.cpp:474 ui/albumcoverchoicecontroller.cpp:124
#: ui/edittagdialog.cpp:439 ui/edittagdialog.cpp:483
msgid "Unknown"
msgstr "Onbekend"
@@ -5085,7 +5086,7 @@ msgstr "Onbekende inhoudtipe"
msgid "Unknown error"
msgstr "Onbekende fout"
-#: ui/albumcoverchoicecontroller.cpp:67
+#: ui/albumcoverchoicecontroller.cpp:68
msgid "Unset cover"
msgstr "Verwyder omslag"
@@ -5504,10 +5505,11 @@ msgstr "Jy het nie Spotify Premium lidmaatskap nie."
msgid "You do not have an active subscription"
msgstr "Jy het nie 'n aktiewe lidmaatskap nie"
-#: ../bin/src/ui_soundcloudsettingspage.h:109
+#: ../bin/src/ui_soundcloudsettingspage.h:105
msgid ""
"You don't need to be logged in to search and to listen to music on "
-"SoundCloud."
+"SoundCloud. However, you need to login to access your playlists and your "
+"stream."
msgstr ""
#: internet/spotifyservice.cpp:175
diff --git a/src/translations/ar.po b/src/translations/ar.po
index dcaaba6cc..bf5bbc8e9 100644
--- a/src/translations/ar.po
+++ b/src/translations/ar.po
@@ -5,6 +5,7 @@
# Translators:
# ahameed , 2012
# FIRST AUTHOR , 2010
+# mankind , 2014
# khire aldin kajjan , 2012
# Storm Al Ghussein , 2013
# simohamed , 2013-2014
@@ -13,7 +14,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Clementine Music Player\n"
-"PO-Revision-Date: 2014-04-14 07:10+0000\n"
+"PO-Revision-Date: 2014-05-11 07:38+0000\n"
"Last-Translator: Clementine Buildbot \n"
"Language-Team: Arabic (http://www.transifex.com/projects/p/clementine/language/ar/)\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -44,13 +45,13 @@ msgstr "الأيام"
#: ../bin/src/ui_transcoderoptionsvorbis.h:211
#: ../bin/src/ui_transcoderoptionswma.h:80
msgid " kbps"
-msgstr "kbps"
+msgstr "كب\\ث"
#: ../bin/src/ui_playbacksettingspage.h:318
#: ../bin/src/ui_playbacksettingspage.h:321
#: ../bin/src/ui_playbacksettingspage.h:335
msgid " ms"
-msgstr " ms"
+msgstr "مث"
#: ../bin/src/ui_songinfosettingspage.h:157
msgid " pt"
@@ -59,7 +60,7 @@ msgstr " pt"
#: ../bin/src/ui_notificationssettingspage.h:439
#: ../bin/src/ui_visualisationselector.h:116
msgid " seconds"
-msgstr "ثواني"
+msgstr "ثانية"
#: ../bin/src/ui_querysortpage.h:144
msgid " songs"
@@ -68,7 +69,7 @@ msgstr "المقاطع"
#: internet/vkservice.cpp:145
#, qt-format
msgid "%1 (%2 songs)"
-msgstr ""
+msgstr "1% (2% أغنية)"
#: widgets/osd.cpp:190
#, qt-format
@@ -118,7 +119,7 @@ msgstr "%1 العثور على مقاطع"
#: smartplaylists/searchpreview.cpp:128
#, qt-format
msgid "%1 songs found (showing %2)"
-msgstr "%1 songs found (showing %2)"
+msgstr "عثر على 1% أغنية (يعرض منها 2%)"
#: playlist/playlistmanager.cpp:387
#, qt-format
@@ -134,7 +135,7 @@ msgstr "%1 منقولة"
#: widgets/osd.cpp:255 widgets/osd.cpp:261 widgets/osd.cpp:268
#, qt-format
msgid "%1: Wiimotedev module"
-msgstr "%1: Wiimotedev module"
+msgstr "1%: أداة Wiimotedev"
#: songinfo/lastfmtrackinfoprovider.cpp:95
#, qt-format
@@ -301,7 +302,7 @@ msgid ""
"artists that contain the word Bode.
Available fields: %1.