mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-21 21:40:48 +00:00
Merge branch 'master' into afh-fix-typos
This commit is contained in:
commit
5d2cc8151d
@ -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
|
||||
options
|
||||
|
@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.0)
|
||||
project(musikcube)
|
||||
set (musikcube_VERSION_MAJOR 0)
|
||||
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 (LIBRARY_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin/plugins)
|
||||
set (EXECUTABLE_OUTPUT_PATH ${musikcube_SOURCE_DIR}/bin)
|
||||
|
@ -1,6 +1,6 @@
|
||||
%define name musikcube
|
||||
%define build_timestamp %{lua: print(os.date("%Y%m%d"))}
|
||||
%define version 0.98.0
|
||||
%define version 0.98.1
|
||||
Name: %{name}
|
||||
Version: %{version}
|
||||
Release: %{dist}
|
||||
|
2
src/3rdparty/bin
vendored
2
src/3rdparty/bin
vendored
@ -1 +1 @@
|
||||
Subproject commit d0c091be64b2c124b2791c7e51916876ef0e1a76
|
||||
Subproject commit 8b6a9f577c49864fbfe3c01e6151099bd25c4c4d
|
@ -38,9 +38,9 @@
|
||||
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 98
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_COMMIT_HASH "#6a440c69"
|
||||
#define VERSION "0.98.0"
|
||||
#define VERSION_PATCH 1
|
||||
#define VERSION_COMMIT_HASH "#f311ad4d"
|
||||
#define VERSION "0.98.1"
|
||||
|
||||
namespace musik {
|
||||
namespace cube {
|
||||
|
@ -783,8 +783,9 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
|
||||
const std::string replayGain = replayGainEnabled ? "rg" : "";
|
||||
|
||||
int const escapedPercentSignWidth = (muted ? 0 : 1); /* 1 for escaped percent sign when not muted */
|
||||
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 */
|
||||
narrow_cast<int>(u8cols(currentTime)) + 1 + /* +1 for space padding */
|
||||
/* timer track with thumb */
|
||||
@ -793,7 +794,8 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
|
||||
int const timerTrackWidth =
|
||||
this->GetContentWidth() -
|
||||
bottomRowControlsWidth - 1; /* this `- 1` is a hack i don't know why we need it please send help */
|
||||
bottomRowControlsWidth -
|
||||
escapedPercentSignWidth;
|
||||
|
||||
thumbOffset = 0;
|
||||
|
||||
|
Binary file not shown.
@ -12,14 +12,14 @@ apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
compileSdkVersion 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.casey.musikcube.remote"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
targetSdkVersion 33
|
||||
versionCode 111
|
||||
versionName "0.96.10"
|
||||
versionName "0.98.1"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@ -60,22 +60,22 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
|
||||
implementation 'com.google.firebase:firebase-analytics:20.1.0'
|
||||
implementation 'com.google.firebase:firebase-core:20.1.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:18.2.9'
|
||||
implementation 'com.google.firebase:firebase-analytics:21.1.0'
|
||||
implementation 'com.google.firebase:firebase-core:21.1.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:18.2.11'
|
||||
|
||||
implementation 'org.slf4j:slf4j-android:1.7.21'
|
||||
|
||||
implementation "androidx.room:room-runtime: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-common-java8:2.4.1"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:2.5.0"
|
||||
|
||||
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
|
||||
implementation 'com.google.dagger:dagger:2.38.1'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.38.1'
|
||||
implementation 'com.google.dagger:dagger:2.42'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.42'
|
||||
|
||||
implementation 'com.neovisionaries:nv-websocket-client:1.31'
|
||||
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:rxandroid:2.1.1'
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.17.1'
|
||||
implementation 'com.google.android.exoplayer:extension-okhttp:2.17.1'
|
||||
implementation 'com.google.android.exoplayer:exoplayer:2.18.0'
|
||||
implementation 'com.google.android.exoplayer:extension-okhttp:2.18.0'
|
||||
implementation 'com.simplecityapps:recyclerview-fastscroll:2.0.0'
|
||||
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 'com.google.android.material:material:1.6.0-alpha03'
|
||||
implementation 'androidx.media:media:1.5.0'
|
||||
implementation 'com.google.android.material:material:1.7.0-alpha03'
|
||||
implementation 'androidx.media:media:1.6.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
}
|
||||
|
@ -9,10 +9,7 @@ import com.google.android.exoplayer2.source.MediaSource
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
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.upstream.*
|
||||
import com.google.android.exoplayer2.util.Util
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.service.playback.PlayerWrapper
|
||||
@ -37,16 +34,13 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
init {
|
||||
val userAgent = Util.getUserAgent(context, "musikdroid")
|
||||
|
||||
val httpFactory: DataSource.Factory = DefaultHttpDataSource.Factory().apply {
|
||||
setUserAgent(userAgent)
|
||||
setConnectTimeoutMs(TIMEOUT)
|
||||
setReadTimeoutMs(TIMEOUT)
|
||||
setAllowCrossProtocolRedirects(true)
|
||||
}
|
||||
|
||||
this.sourceFactory = DefaultDataSourceFactory(context, null, httpFactory)
|
||||
|
||||
this.sourceFactory = DefaultDataSource.Factory(context, httpFactory)
|
||||
this.transcoding = prefs.getInt(Prefs.Key.TRANSCODER_BITRATE_INDEX, 0) != 0
|
||||
}
|
||||
|
||||
@ -144,7 +138,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
this.lastPosition = -1
|
||||
if (gaplessPlayer?.playbackState != Player.STATE_IDLE) {
|
||||
if (gaplessPlayer?.isCurrentWindowSeekable == true) {
|
||||
if (gaplessPlayer?.isCurrentMediaItemSeekable == true) {
|
||||
var offset = millis.toLong()
|
||||
val isInitialSeek = initialOffsetMs > 0 && (millis == initialOffsetMs)
|
||||
|
||||
@ -228,19 +222,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
}
|
||||
|
||||
private var eventListener = object : Player.Listener {
|
||||
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) {
|
||||
}
|
||||
|
||||
override fun onLoadingChanged(isLoading: Boolean) {
|
||||
}
|
||||
|
||||
override fun onSeekProcessed() {
|
||||
}
|
||||
|
||||
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
|
||||
}
|
||||
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
Preconditions.throwIfNotOnMainThread()
|
||||
|
||||
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
|
||||
the queue. the current song should always be 0! if it's not, then
|
||||
that means we advanced to the next one... */
|
||||
if (gaplessPlayer?.currentWindowIndex ?: 0 != 0) {
|
||||
if ((gaplessPlayer?.currentMediaItemIndex ?: 0) != 0) {
|
||||
promoteNext()
|
||||
state = State.Finished
|
||||
}
|
||||
@ -316,7 +300,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
private val context: Context by lazy { Application.instance }
|
||||
private var all = mutableListOf<GaplessExoPlayerWrapper>()
|
||||
private lateinit var dcms: ConcatenatingMediaSource
|
||||
private var gaplessPlayer: SimpleExoPlayer? = null
|
||||
private var gaplessPlayer: ExoPlayer? = null
|
||||
|
||||
private fun promoteNext() {
|
||||
if (all.size > 0) {
|
||||
@ -337,7 +321,7 @@ class GaplessExoPlayerWrapper : PlayerWrapper() {
|
||||
all.clear()
|
||||
gaplessPlayer?.stop()
|
||||
gaplessPlayer?.release()
|
||||
gaplessPlayer = SimpleExoPlayer.Builder(context)
|
||||
gaplessPlayer = ExoPlayer.Builder(context)
|
||||
.setBandwidthMeter(DefaultBandwidthMeter.Builder(context).build())
|
||||
.build()
|
||||
dcms = ConcatenatingMediaSource()
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.casey.musikcube.remote.ui.settings.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
@ -80,10 +81,8 @@ class RemoteSettingsActivity: BaseActivity() {
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||
menu?.findItem(R.id.action_save)?.isEnabled =
|
||||
viewModel.state == ViewModelState.Ready
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
menu.findItem(R.id.action_save)?.isEnabled = viewModel.state == ViewModelState.Ready
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
@ -139,6 +138,7 @@ class RemoteSettingsActivity: BaseActivity() {
|
||||
viewModel.save(replayGainMode, preampGain, transport, driverName, deviceId)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun initListeners() {
|
||||
/* metadata */
|
||||
reindexButton.setOnClickListener {
|
||||
|
@ -32,16 +32,14 @@ class Connection : Parcelable {
|
||||
return name.isNotBlank() && hostname.isNotEmpty() && httpPort > 0 && wssPort > 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel?, flags: Int) {
|
||||
if (parcel != null) {
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(hostname)
|
||||
parcel.writeString(password)
|
||||
parcel.writeInt(httpPort)
|
||||
parcel.writeInt(wssPort)
|
||||
parcel.writeInt(if (ssl) 1 else 0)
|
||||
parcel.writeInt(if (noValidate) 1 else 0)
|
||||
}
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(hostname)
|
||||
parcel.writeString(password)
|
||||
parcel.writeInt(httpPort)
|
||||
parcel.writeInt(wssPort)
|
||||
parcel.writeInt(if (ssl) 1 else 0)
|
||||
parcel.writeInt(if (noValidate) 1 else 0)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
@ -7,10 +7,10 @@ buildscript {
|
||||
}
|
||||
|
||||
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 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
classpath 'com.google.gms:google-services:4.3.13'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
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
|
||||
|
@ -37,5 +37,3 @@
|
||||
|
||||
#include <musikcore/config.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
@ -225,6 +225,18 @@ static inline bool replayGainValid(ReplayGain& rg) {
|
||||
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() {
|
||||
}
|
||||
|
||||
@ -337,6 +349,7 @@ bool TaglibMetadataReader::ReadGeneric(
|
||||
field list. if we're dealing with a straight-up Xiph tag, process it now */
|
||||
const auto xiphTag = dynamic_cast<TagLib::Ogg::XiphComment*>(tag);
|
||||
if (xiphTag) {
|
||||
processAlbumArt(xiphTag->pictureList(), target);
|
||||
this->ReadFromMap(xiphTag->fieldListMap(), target);
|
||||
this->ExtractReplayGain(xiphTag->fieldListMap(), target);
|
||||
}
|
||||
@ -350,22 +363,13 @@ bool TaglibMetadataReader::ReadGeneric(
|
||||
see if there's a xiph comment buried deep. */
|
||||
auto flacFile = dynamic_cast<TagLib::FLAC::File*>(file.file());
|
||||
if (flacFile) {
|
||||
auto pictures = flacFile->pictureList();
|
||||
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;
|
||||
}
|
||||
processAlbumArt(flacFile->pictureList(), target);
|
||||
if (flacFile->hasXiphComment()) {
|
||||
this->ReadFromMap(flacFile->xiphComment()->fieldListMap(), target);
|
||||
this->ExtractReplayGain(flacFile->xiphComment()->fieldListMap(), target);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
if (flacFile && flacFile->hasXiphComment()) {
|
||||
this->ReadFromMap(flacFile->xiphComment()->fieldListMap(), target);
|
||||
this->ExtractReplayGain(flacFile->xiphComment()->fieldListMap(), target);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user