fix: stabilize seek slider and clean backend lint issues
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
//! qobuz-backend: C-ABI library consumed by the Qt frontend.
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
mod api;
|
||||
mod player;
|
||||
|
||||
@@ -157,7 +157,7 @@ impl MediaSource for SegmentStreamSource {
|
||||
|
||||
fn http_client() -> &'static reqwest::blocking::Client {
|
||||
static CLIENT: OnceLock<reqwest::blocking::Client> = OnceLock::new();
|
||||
CLIENT.get_or_init(|| reqwest::blocking::Client::new())
|
||||
CLIENT.get_or_init(reqwest::blocking::Client::new)
|
||||
}
|
||||
|
||||
fn fetch_segment(url: &str, cancel: &Arc<AtomicBool>) -> Option<Vec<u8>> {
|
||||
@@ -260,8 +260,10 @@ fn decrypt_and_extract_frames(data: &mut [u8], key: Option<&[u8; 16]>) -> Vec<u8
|
||||
break;
|
||||
}
|
||||
|
||||
if &data[pos + 4..pos + 8] == b"uuid" && box_size >= 36 {
|
||||
if &data[pos + 8..pos + 24] == QBZ1_UUID {
|
||||
if data[pos + 4..pos + 8] == *b"uuid"
|
||||
&& box_size >= 36
|
||||
&& data[pos + 8..pos + 24] == QBZ1_UUID
|
||||
{
|
||||
let body = pos + 24;
|
||||
if body + 12 > data.len() {
|
||||
pos += box_size;
|
||||
@@ -284,18 +286,19 @@ fn decrypt_and_extract_frames(data: &mut [u8], key: Option<&[u8; 16]>) -> Vec<u8
|
||||
|
||||
let end = offset + size;
|
||||
if end <= data.len() {
|
||||
if enc && key.is_some() {
|
||||
if enc {
|
||||
if let Some(k) = key {
|
||||
let mut iv = [0u8; 16];
|
||||
iv[..8].copy_from_slice(&data[e + 8..e + 16]);
|
||||
Ctr128BE::<Aes128>::new(key.unwrap().into(), (&iv).into())
|
||||
Ctr128BE::<Aes128>::new(k.into(), (&iv).into())
|
||||
.apply_keystream(&mut data[offset..end]);
|
||||
}
|
||||
}
|
||||
frames.extend_from_slice(&data[offset..end]);
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
pos += box_size;
|
||||
}
|
||||
frames
|
||||
@@ -845,7 +848,7 @@ impl Seek for HttpStreamSource {
|
||||
.send()
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e.to_string())),
|
||||
Err(e) => return Err(io::Error::other(e.to_string())),
|
||||
};
|
||||
|
||||
if resp.status() == reqwest::StatusCode::PARTIAL_CONTENT {
|
||||
@@ -881,10 +884,7 @@ impl Seek for HttpStreamSource {
|
||||
self.pos = self.reader_pos;
|
||||
Ok(self.pos)
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("HTTP Error {}", resp.status()),
|
||||
))
|
||||
Err(io::Error::other(format!("HTTP Error {}", resp.status())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ impl AudioOutput {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn flush(&self) {
|
||||
// Wait until the ring buffer is fully emptied by cpal
|
||||
while !self._ring.is_empty() {
|
||||
|
||||
@@ -297,7 +297,7 @@ void QobuzBackend::onEvent(int eventType, const QString &json)
|
||||
case EV_SEARCH_OK:
|
||||
emit searchResult(obj);
|
||||
break;
|
||||
case 26: // EV_MOST_POPULAR_OK
|
||||
case EV_MOST_POPULAR_OK:
|
||||
emit mostPopularResult(obj);
|
||||
break;
|
||||
case EV_SEARCH_ERR:
|
||||
@@ -312,7 +312,7 @@ void QobuzBackend::onEvent(int eventType, const QString &json)
|
||||
case EV_ARTIST_OK:
|
||||
emit artistLoaded(obj);
|
||||
break;
|
||||
case 24: // EV_ARTIST_RELEASES_OK
|
||||
case EV_ARTIST_RELEASES_OK:
|
||||
emit artistReleasesLoaded(
|
||||
obj["release_type"].toString(),
|
||||
obj["items"].toArray(),
|
||||
@@ -320,25 +320,25 @@ void QobuzBackend::onEvent(int eventType, const QString &json)
|
||||
obj["offset"].toInt()
|
||||
);
|
||||
break;
|
||||
case 25: // EV_DEEP_SHUFFLE_OK
|
||||
case EV_DEEP_SHUFFLE_OK:
|
||||
emit deepShuffleTracksLoaded(obj["tracks"].toArray());
|
||||
break;
|
||||
case 29: // EV_DYNAMIC_SUGGEST_OK
|
||||
case EV_DYNAMIC_SUGGEST_OK:
|
||||
emit dynamicSuggestionsLoaded(obj);
|
||||
break;
|
||||
case 27: // EV_GENRES_OK
|
||||
case EV_GENRES_OK:
|
||||
emit genresLoaded(obj);
|
||||
break;
|
||||
case 28: // EV_FEATURED_ALBUMS_OK
|
||||
case EV_FEATURED_ALBUMS_OK:
|
||||
emit featuredAlbumsLoaded(obj);
|
||||
break;
|
||||
case 30: // EV_FEATURED_PLAYLISTS_OK
|
||||
case EV_FEATURED_PLAYLISTS_OK:
|
||||
emit featuredPlaylistsLoaded(obj);
|
||||
break;
|
||||
case 31: // EV_DISCOVER_PLAYLISTS_OK
|
||||
case EV_DISCOVER_PLAYLISTS_OK:
|
||||
emit discoverPlaylistsLoaded(obj);
|
||||
break;
|
||||
case 32: // EV_PLAYLIST_SEARCH_OK
|
||||
case EV_PLAYLIST_SEARCH_OK:
|
||||
emit playlistSearchLoaded(obj);
|
||||
break;
|
||||
case EV_ARTIST_ERR:
|
||||
@@ -368,19 +368,19 @@ void QobuzBackend::onEvent(int eventType, const QString &json)
|
||||
case EV_STATE_CHANGED:
|
||||
emit stateChanged(obj["state"].toString());
|
||||
break;
|
||||
case 20: // EV_PLAYLIST_CREATED
|
||||
case EV_PLAYLIST_CREATED:
|
||||
emit playlistCreated(obj);
|
||||
break;
|
||||
case 21: // EV_PLAYLIST_DELETED
|
||||
case EV_PLAYLIST_DELETED:
|
||||
emit playlistDeleted(obj);
|
||||
break;
|
||||
case 22: // EV_PLAYLIST_TRACK_ADDED
|
||||
case EV_PLAYLIST_TRACK_ADDED:
|
||||
emit playlistTrackAdded(static_cast<qint64>(obj["playlist_id"].toDouble()));
|
||||
break;
|
||||
case 33: // EV_PLAYLIST_SUBSCRIBED
|
||||
case EV_PLAYLIST_SUBSCRIBED:
|
||||
emit playlistSubscribed(static_cast<qint64>(obj["playlist_id"].toDouble()));
|
||||
break;
|
||||
case 34: // EV_PLAYLIST_UNSUBSCRIBED
|
||||
case EV_PLAYLIST_UNSUBSCRIBED:
|
||||
emit playlistUnsubscribed(static_cast<qint64>(obj["playlist_id"].toDouble()));
|
||||
break;
|
||||
case EV_USER_OK:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <QNetworkRequest>
|
||||
#include <QResizeEvent>
|
||||
#include <QMenu>
|
||||
#include <QDateTime>
|
||||
|
||||
MainToolBar::MainToolBar(QobuzBackend *backend, PlayQueue *queue, QWidget *parent)
|
||||
: QToolBar(parent)
|
||||
@@ -221,6 +222,10 @@ void MainToolBar::onProgressReleased()
|
||||
const quint64 dur = m_backend->duration();
|
||||
if (dur > 0) {
|
||||
const quint64 target = dur * static_cast<quint64>(m_progress->value()) / 1000;
|
||||
m_seekPending = true;
|
||||
m_pendingSeekTarget = target;
|
||||
m_pendingSeekStartedMs = QDateTime::currentMSecsSinceEpoch();
|
||||
updateProgress(target, dur);
|
||||
m_backend->seek(target);
|
||||
}
|
||||
}
|
||||
@@ -238,6 +243,8 @@ void MainToolBar::onBackendStateChanged(const QString &state)
|
||||
|
||||
void MainToolBar::onTrackChanged(const QJsonObject &track)
|
||||
{
|
||||
m_seekPending = false;
|
||||
m_seeking = false;
|
||||
setCurrentTrack(track);
|
||||
|
||||
const qint64 trackId = static_cast<qint64>(track["id"].toDouble());
|
||||
@@ -258,6 +265,18 @@ void MainToolBar::onTrackChanged(const QJsonObject &track)
|
||||
|
||||
void MainToolBar::onPositionChanged(quint64 position, quint64 duration)
|
||||
{
|
||||
if (m_seekPending) {
|
||||
const qint64 nowMs = QDateTime::currentMSecsSinceEpoch();
|
||||
const quint64 delta = (position > m_pendingSeekTarget)
|
||||
? (position - m_pendingSeekTarget)
|
||||
: (m_pendingSeekTarget - position);
|
||||
|
||||
if (delta > 2 && (nowMs - m_pendingSeekStartedMs) < 1500)
|
||||
return;
|
||||
|
||||
m_seekPending = false;
|
||||
}
|
||||
|
||||
updateProgress(position, duration);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,9 @@ private:
|
||||
QVector<RecentTrackSeed> m_recentTracks;
|
||||
bool m_playing = false;
|
||||
bool m_seeking = false;
|
||||
bool m_seekPending = false;
|
||||
quint64 m_pendingSeekTarget = 0;
|
||||
qint64 m_pendingSeekStartedMs = 0;
|
||||
bool m_fetchingAutoplay = false;
|
||||
|
||||
void requestAutoplaySuggestions();
|
||||
|
||||
Reference in New Issue
Block a user