Merge branch 'master' into afh-fix-typos

This commit is contained in:
Alexis Hildebrandt 2022-07-22 19:37:04 +02:00
commit 5d2cc8151d
15 changed files with 78 additions and 85 deletions

View File

@ -1,4 +1,11 @@
0.98 0.98.1
* fixed album art extraction for xiph comments.
* fixed PulseAudio compile issue
--------------------------------------------------------------------------------
0.98.0
* added the ability to click the browse and tracklist headers to change filter * added the ability to click the browse and tracklist headers to change filter
options options

View File

@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.0)
project(musikcube) project(musikcube)
set (musikcube_VERSION_MAJOR 0) set (musikcube_VERSION_MAJOR 0)
set (musikcube_VERSION_MINOR 98) set (musikcube_VERSION_MINOR 98)
set (musikcube_VERSION_PATCH 0) set (musikcube_VERSION_PATCH 1)
set (musikcube_VERSION "${musikcube_VERSION_MAJOR}.${musikcube_VERSION_MINOR}.${musikcube_VERSION_PATCH}") set (musikcube_VERSION "${musikcube_VERSION_MAJOR}.${musikcube_VERSION_MINOR}.${musikcube_VERSION_PATCH}")
set (LIBRARY_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin/plugins) set (LIBRARY_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin/plugins)
set (EXECUTABLE_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin) set (EXECUTABLE_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin)

View File

@ -1,6 +1,6 @@
%define name musikcube %define name musikcube
%define build_timestamp %{lua: print(os.date("%Y%m%d"))} %define build_timestamp %{lua: print(os.date("%Y%m%d"))}
%define version 0.98.0 %define version 0.98.1
Name: %{name} Name: %{name}
Version: %{version} Version: %{version}
Release: %{dist} Release: %{dist}

2
src/3rdparty/bin vendored

@ -1 +1 @@
Subproject commit d0c091be64b2c124b2791c7e51916876ef0e1a76 Subproject commit 8b6a9f577c49864fbfe3c01e6151099bd25c4c4d

View File

@ -38,9 +38,9 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 98 #define VERSION_MINOR 98
#define VERSION_PATCH 0 #define VERSION_PATCH 1
#define VERSION_COMMIT_HASH "#6a440c69" #define VERSION_COMMIT_HASH "#f311ad4d"
#define VERSION "0.98.0" #define VERSION "0.98.1"
namespace musik { namespace musik {
namespace cube { namespace cube {

View File

@ -783,8 +783,9 @@ void TransportWindow::Update(TimeMode timeMode) {
const std::string replayGain = replayGainEnabled ? "rg" : ""; const std::string replayGain = replayGainEnabled ? "rg" : "";
int const escapedPercentSignWidth = (muted ? 0 : 1); /* 1 for escaped percent sign when not muted */
int const bottomRowControlsWidth = int const bottomRowControlsWidth =
displayCache.Columns(volume) - (muted ? 0 : 1) + /* -1 for escaped percent sign when not muted */ displayCache.Columns(volume) - escapedPercentSignWidth +
(replayGainEnabled ? (narrow_cast<int>(u8cols(replayGain)) + 4) : 0) + /* [] brackets */ (replayGainEnabled ? (narrow_cast<int>(u8cols(replayGain)) + 4) : 0) + /* [] brackets */
narrow_cast<int>(u8cols(currentTime)) + 1 + /* +1 for space padding */ narrow_cast<int>(u8cols(currentTime)) + 1 + /* +1 for space padding */
/* timer track with thumb */ /* timer track with thumb */
@ -793,7 +794,8 @@ void TransportWindow::Update(TimeMode timeMode) {
int const timerTrackWidth = int const timerTrackWidth =
this->GetContentWidth() - this->GetContentWidth() -
bottomRowControlsWidth - 1; /* this `- 1` is a hack i don't know why we need it please send help */ bottomRowControlsWidth -
escapedPercentSignWidth;
thumbOffset = 0; thumbOffset = 0;

Binary file not shown.

View File

@ -12,14 +12,14 @@ apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
android { android {
compileSdkVersion 31 compileSdkVersion 33
defaultConfig { defaultConfig {
applicationId "io.casey.musikcube.remote" applicationId "io.casey.musikcube.remote"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 31 targetSdkVersion 33
versionCode 111 versionCode 111
versionName "0.96.10" versionName "0.98.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -60,22 +60,22 @@ dependencies {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
implementation 'com.google.firebase:firebase-analytics:20.1.0' implementation 'com.google.firebase:firebase-analytics:21.1.0'
implementation 'com.google.firebase:firebase-core:20.1.0' implementation 'com.google.firebase:firebase-core:21.1.0'
implementation 'com.google.firebase:firebase-crashlytics:18.2.9' implementation 'com.google.firebase:firebase-crashlytics:18.2.11'
implementation 'org.slf4j:slf4j-android:1.7.21' implementation 'org.slf4j:slf4j-android:1.7.21'
implementation "androidx.room:room-runtime:2.4.2" implementation "androidx.room:room-runtime:2.4.2"
kapt "androidx.room:room-compiler:2.4.2" kapt "androidx.room:room-compiler:2.4.2"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.4.1" implementation "androidx.lifecycle:lifecycle-common-java8:2.5.0"
compileOnly 'org.glassfish:javax.annotation:10.0-b28' compileOnly 'org.glassfish:javax.annotation:10.0-b28'
implementation 'com.google.dagger:dagger:2.38.1' implementation 'com.google.dagger:dagger:2.42'
kapt 'com.google.dagger:dagger-compiler:2.38.1' kapt 'com.google.dagger:dagger-compiler:2.42'
implementation 'com.neovisionaries:nv-websocket-client:1.31' implementation 'com.neovisionaries:nv-websocket-client:1.31'
implementation 'com.squareup.okhttp3:okhttp:4.9.2' implementation 'com.squareup.okhttp3:okhttp:4.9.2'
@ -85,15 +85,15 @@ dependencies {
implementation 'io.reactivex.rxjava2:rxjava:2.2.16' implementation 'io.reactivex.rxjava2:rxjava:2.2.16'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
implementation 'com.google.android.exoplayer:exoplayer:2.17.1' implementation 'com.google.android.exoplayer:exoplayer:2.18.0'
implementation 'com.google.android.exoplayer:extension-okhttp:2.17.1' implementation 'com.google.android.exoplayer:extension-okhttp:2.18.0'
implementation 'com.simplecityapps:recyclerview-fastscroll:2.0.0' implementation 'com.simplecityapps:recyclerview-fastscroll:2.0.0'
implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1' implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1'
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.material:material:1.6.0-alpha03' implementation 'com.google.android.material:material:1.7.0-alpha03'
implementation 'androidx.media:media:1.5.0' implementation 'androidx.media:media:1.6.0'
testImplementation 'junit:junit:4.13.1' testImplementation 'junit:junit:4.13.1'
} }

View File

@ -9,10 +9,7 @@ import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.source.TrackGroupArray import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.google.android.exoplayer2.upstream.DataSource import com.google.android.exoplayer2.upstream.*
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.util.Util import com.google.android.exoplayer2.util.Util
import io.casey.musikcube.remote.Application import io.casey.musikcube.remote.Application
import io.casey.musikcube.remote.service.playback.PlayerWrapper import io.casey.musikcube.remote.service.playback.PlayerWrapper
@ -37,16 +34,13 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
init { init {
val userAgent = Util.getUserAgent(context, "musikdroid") val userAgent = Util.getUserAgent(context, "musikdroid")
val httpFactory: DataSource.Factory = DefaultHttpDataSource.Factory().apply { val httpFactory: DataSource.Factory = DefaultHttpDataSource.Factory().apply {
setUserAgent(userAgent) setUserAgent(userAgent)
setConnectTimeoutMs(TIMEOUT) setConnectTimeoutMs(TIMEOUT)
setReadTimeoutMs(TIMEOUT) setReadTimeoutMs(TIMEOUT)
setAllowCrossProtocolRedirects(true) setAllowCrossProtocolRedirects(true)
} }
this.sourceFactory = DefaultDataSource.Factory(context, httpFactory)
this.sourceFactory = DefaultDataSourceFactory(context, null, httpFactory)
this.transcoding = prefs.getInt(Prefs.Key.TRANSCODER_BITRATE_INDEX, 0) != 0 this.transcoding = prefs.getInt(Prefs.Key.TRANSCODER_BITRATE_INDEX, 0) != 0
} }
@ -144,7 +138,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
this.lastPosition = -1 this.lastPosition = -1
if (gaplessPlayer?.playbackState != Player.STATE_IDLE) { if (gaplessPlayer?.playbackState != Player.STATE_IDLE) {
if (gaplessPlayer?.isCurrentWindowSeekable == true) { if (gaplessPlayer?.isCurrentMediaItemSeekable == true) {
var offset = millis.toLong() var offset = millis.toLong()
val isInitialSeek = initialOffsetMs > 0 && (millis == initialOffsetMs) val isInitialSeek = initialOffsetMs > 0 && (millis == initialOffsetMs)
@ -228,19 +222,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
} }
private var eventListener = object : Player.Listener { private var eventListener = object : Player.Listener {
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) { override fun onPlaybackStateChanged(playbackState: Int) {
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onSeekProcessed() {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
Preconditions.throwIfNotOnMainThread() Preconditions.throwIfNotOnMainThread()
if (playbackState == Player.STATE_BUFFERING) { if (playbackState == Player.STATE_BUFFERING) {
@ -293,11 +275,13 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
} }
} }
override fun onPositionDiscontinuity(type: Int) { override fun onPositionDiscontinuity(
oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo,type: Int)
{
/* window index corresponds to the position of the current song in /* window index corresponds to the position of the current song in
the queue. the current song should always be 0! if it's not, then the queue. the current song should always be 0! if it's not, then
that means we advanced to the next one... */ that means we advanced to the next one... */
if (gaplessPlayer?.currentWindowIndex ?: 0 != 0) { if ((gaplessPlayer?.currentMediaItemIndex ?: 0) != 0) {
promoteNext() promoteNext()
state = State.Finished state = State.Finished
} }
@ -316,7 +300,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
private val context: Context by lazy { Application.instance } private val context: Context by lazy { Application.instance }
private var all = mutableListOf<GaplessExoPlayerWrapper>() private var all = mutableListOf<GaplessExoPlayerWrapper>()
private lateinit var dcms: ConcatenatingMediaSource private lateinit var dcms: ConcatenatingMediaSource
private var gaplessPlayer: SimpleExoPlayer? = null private var gaplessPlayer: ExoPlayer? = null
private fun promoteNext() { private fun promoteNext() {
if (all.size > 0) { if (all.size > 0) {
@ -337,7 +321,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
all.clear() all.clear()
gaplessPlayer?.stop() gaplessPlayer?.stop()
gaplessPlayer?.release() gaplessPlayer?.release()
gaplessPlayer = SimpleExoPlayer.Builder(context) gaplessPlayer = ExoPlayer.Builder(context)
.setBandwidthMeter(DefaultBandwidthMeter.Builder(context).build()) .setBandwidthMeter(DefaultBandwidthMeter.Builder(context).build())
.build() .build()
dcms = ConcatenatingMediaSource() dcms = ConcatenatingMediaSource()

View File

@ -1,5 +1,6 @@
package io.casey.musikcube.remote.ui.settings.activity package io.casey.musikcube.remote.ui.settings.activity
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -80,10 +81,8 @@ class RemoteSettingsActivity: BaseActivity() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu): Boolean {
menu?.findItem(R.id.action_save)?.isEnabled = menu.findItem(R.id.action_save)?.isEnabled = viewModel.state == ViewModelState.Ready
viewModel.state == ViewModelState.Ready
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
@ -139,6 +138,7 @@ class RemoteSettingsActivity: BaseActivity() {
viewModel.save(replayGainMode, preampGain, transport, driverName, deviceId) viewModel.save(replayGainMode, preampGain, transport, driverName, deviceId)
} }
@SuppressLint("CheckResult")
private fun initListeners() { private fun initListeners() {
/* metadata */ /* metadata */
reindexButton.setOnClickListener { reindexButton.setOnClickListener {

View File

@ -32,8 +32,7 @@ class Connection : Parcelable {
return name.isNotBlank() && hostname.isNotEmpty() && httpPort > 0 && wssPort > 0 return name.isNotBlank() && hostname.isNotEmpty() && httpPort > 0 && wssPort > 0
} }
override fun writeToParcel(parcel: Parcel?, flags: Int) { override fun writeToParcel(parcel: Parcel, flags: Int) {
if (parcel != null) {
parcel.writeString(name) parcel.writeString(name)
parcel.writeString(hostname) parcel.writeString(hostname)
parcel.writeString(password) parcel.writeString(password)
@ -42,7 +41,6 @@ class Connection : Parcelable {
parcel.writeInt(if (ssl) 1 else 0) parcel.writeInt(if (ssl) 1 else 0)
parcel.writeInt(if (noValidate) 1 else 0) parcel.writeInt(if (noValidate) 1 else 0)
} }
}
override fun describeContents(): Int { override fun describeContents(): Int {
return 0 return 0

View File

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.6.10' ext.kotlin_version = '1.7.10'
repositories { repositories {
google() google()
@ -7,10 +7,10 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.android.tools.build:gradle:7.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.gms:google-services:4.3.13'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
} }
} }

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip

View File

@ -37,5 +37,3 @@
#include <musikcore/config.h> #include <musikcore/config.h>
#include <iostream> #include <iostream>
#include <alsa/asoundlib.h>

View File

@ -225,6 +225,18 @@ static inline bool replayGainValid(ReplayGain& rg) {
rg.trackGain != 1.0 || rg.trackPeak != 1.0; rg.trackGain != 1.0 || rg.trackPeak != 1.0;
} }
static inline void processAlbumArt(TagLib::List<TagLib::FLAC::Picture*> pictures, ITagStore* target) {
for (auto picture : pictures) {
if (picture->type() == TagLib::FLAC::Picture::FrontCover) {
auto byteVector = picture->data();
if (byteVector.size()) {
target->SetThumbnail(byteVector.data(), byteVector.size());
}
break;
}
}
}
TaglibMetadataReader::TaglibMetadataReader() { TaglibMetadataReader::TaglibMetadataReader() {
} }
@ -337,6 +349,7 @@ bool TaglibMetadataReader::ReadGeneric(
field list. if we're dealing with a straight-up Xiph tag, process it now */ field list. if we're dealing with a straight-up Xiph tag, process it now */
const auto xiphTag = dynamic_cast<TagLib::Ogg::XiphComment*>(tag); const auto xiphTag = dynamic_cast<TagLib::Ogg::XiphComment*>(tag);
if (xiphTag) { if (xiphTag) {
processAlbumArt(xiphTag->pictureList(), target);
this->ReadFromMap(xiphTag->fieldListMap(), target); this->ReadFromMap(xiphTag->fieldListMap(), target);
this->ExtractReplayGain(xiphTag->fieldListMap(), target); this->ExtractReplayGain(xiphTag->fieldListMap(), target);
} }
@ -350,22 +363,13 @@ bool TaglibMetadataReader::ReadGeneric(
see if there's a xiph comment buried deep. */ see if there's a xiph comment buried deep. */
auto flacFile = dynamic_cast<TagLib::FLAC::File*>(file.file()); auto flacFile = dynamic_cast<TagLib::FLAC::File*>(file.file());
if (flacFile) { if (flacFile) {
auto pictures = flacFile->pictureList(); processAlbumArt(flacFile->pictureList(), target);
for (auto picture : pictures) { if (flacFile->hasXiphComment()) {
if (picture->type() == TagLib::FLAC::Picture::FrontCover) {
auto byteVector = picture->data();
if (byteVector.size()) {
target->SetThumbnail(byteVector.data(), byteVector.size());
}
break;
}
}
}
if (flacFile && flacFile->hasXiphComment()) {
this->ReadFromMap(flacFile->xiphComment()->fieldListMap(), target); this->ReadFromMap(flacFile->xiphComment()->fieldListMap(), target);
this->ExtractReplayGain(flacFile->xiphComment()->fieldListMap(), target); this->ExtractReplayGain(flacFile->xiphComment()->fieldListMap(), target);
handled = true; handled = true;
} }
}
/* similarly, mp4 buries disc number and album artist. however, taglib does /* similarly, mp4 buries disc number and album artist. however, taglib does
NOT exposed a map with normalized keys, so we have to do special property NOT exposed a map with normalized keys, so we have to do special property