feat: parse flac and ogg audio file

从这个版本开始,播放 flac 和 ogg 格式的音频文件将会从原文件中读取歌曲封面,而不是仅仅通过 Apple Music 搜索获取封面,解决了匹配错误和库中无相关歌曲时无法加载封面的问题。

Beginning with this update, playing audio files in the flac and ogg formats will read the song cover directly from the original file rather than just looking for it on Apple Music. This will fix the issue where the cover won't load when there is a match error and no pertinent song in the library.
This commit is contained in:
xtaodada 2022-09-27 23:17:46 +08:00
parent 6de14140ae
commit c7fec5ea79
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
3 changed files with 92 additions and 1 deletions

View File

@ -344,6 +344,7 @@ dependencies {
implementation "cn.hutool:hutool-crypto:5.7.13"
implementation 'cn.hutool:hutool-http:5.7.5'
implementation "com.jakewharton:process-phoenix:2.1.2"
implementation 'org:jaudiotagger:2.0.3'
compileOnly 'org.yaml:snakeyaml:1.29'
fullImplementation 'org.yaml:snakeyaml:1.29'

View File

@ -26,6 +26,8 @@ import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import xyz.nextalone.nagram.helper.audio.GenAudioInfo;
public abstract class AudioInfo {
protected String brand; // brand, e.g. "M4A", "ID3", ...
protected String version; // version, e.g. "0", "2.3.0", ...
@ -145,7 +147,11 @@ public abstract class AudioInfo {
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p') {
return new M4AInfo(input);
} else if (file.getAbsolutePath().endsWith("mp3")) {
return new MP3Info(input, file.length());
return new MP3Info(input, file.length());
} else if (file.getAbsolutePath().endsWith("flac")) {
return new GenAudioInfo(file, "FLAC");
} else if (file.getAbsolutePath().endsWith("ogg")) {
return new GenAudioInfo(file, "OGG");
} else {
return null;
}

View File

@ -0,0 +1,84 @@
package xyz.nextalone.nagram.helper.audio
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey
import org.jaudiotagger.tag.Tag
import org.telegram.messenger.audioinfo.AudioInfo
import java.io.ByteArrayInputStream
import java.io.File
import java.util.logging.Level
import java.util.logging.Logger
import kotlin.math.max
class GenAudioInfo @JvmOverloads constructor(file: File?, format: String? = "FLAC", debugLevel: Level? = Level.FINEST) :
AudioInfo() {
init {
brand = format
version = "0"
val f = AudioFileIO.read(file)
val info = f.tag as Tag
val header = f.audioHeader
album = info.getFirst(FieldKey.ALBUM)
albumArtist = info.getFirst(FieldKey.ALBUM_ARTIST)
artist = info.getFirst(FieldKey.ARTIST)
comment = info.getFirst(FieldKey.COMMENT)
val image = info.artworkList[0]
cover = if (image != null) {
BitmapFactory.decodeStream(ByteArrayInputStream(image.binaryData))
} else {
null
}
if (cover != null) {
val scale = max(cover.width, cover.height) / 120.0f
smallCover = if (scale > 0) {
Bitmap.createScaledBitmap(
cover,
(cover.width / scale).toInt(),
(cover.height / scale).toInt(),
true
)
} else {
cover
}
if (smallCover == null) {
smallCover = cover
}
}
compilation = info.getFirst(FieldKey.IS_COMPILATION).toBoolean()
composer = info.getFirst(FieldKey.COMPOSER)
copyright = ""
try {
disc = info.getFirst(FieldKey.DISC_NO).toShort()
discs = info.getFirst(FieldKey.DISC_TOTAL).toShort()
} catch (ignored: NumberFormatException) {}
duration = header.trackLength.toLong()
genre = info.getFirst(FieldKey.GENRE)
grouping = info.getFirst(FieldKey.GROUPING)
lyrics = info.getFirst(FieldKey.LYRICS)
title = info.getFirst(FieldKey.TITLE)
try {
track = info.getFirst(FieldKey.TRACK).toShort()
tracks = info.getFirst(FieldKey.TRACK_TOTAL).toShort()
} catch (ignored: NumberFormatException) {}
try {
year = info.getFirst(FieldKey.YEAR).toShort()
} catch (ignored: NumberFormatException) {}
if (duration <= 0 || duration >= 3600000L) {
if (debugLevel?.let { LOGGER.isLoggable(it) } == true) {
LOGGER.log(debugLevel, "Maybe false $format duration.")
}
}
}
companion object {
val LOGGER: Logger = Logger.getLogger(GenAudioInfo::class.java.name)
}
}