Skip to content
This repository has been archived by the owner on Aug 23, 2024. It is now read-only.

Commit

Permalink
新增 Bilibili 源(感谢大佬)
Browse files Browse the repository at this point in the history
  • Loading branch information
Moriafly committed Jun 13, 2022
1 parent 0ddd5cb commit f204da5
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ app/src/main/res/drawable-v24/

app/src/main/cpp/cry.c
"app/release/\346\265\201\345\205\211\346\233\262.apk"
/app/release
5 changes: 5 additions & 0 deletions UPDATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
TODO 插件支持

3.14.0 2022年6月13日
新增 Bilibili 源(感谢大佬)
尝试修复 vpn 导致的连接白屏
添加「精细调节」的按钮,即是否通过音量键精准修改音乐声音大小

3.13.0 2022年5月31日
优化本地歌曲界面、我的页面
修复【我的】无法获取用户信息,换成了自定义 API
Expand Down
87 changes: 87 additions & 0 deletions app/src/main/java/com/dirror/music/music/bilibili/BilibiliUrl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.dirror.music.music.bilibili

import android.util.Log
import com.dirror.music.util.HttpUtils
import com.dirror.music.util.getStr
import org.json.JSONObject
import java.util.regex.Matcher
import java.util.regex.Pattern


object BilibiliUrl {
const val bilibiliAPI = "https://api.bilibili.com/x/player/playurl?"
const val bilibiliBangumiAPI = "https://api.bilibili.com/pgc/player/web/playurl?"
const val bilibiliTokenAPI = "https://api.bilibili.com/x/player/playurl/token?"
const val referer = "https://www.bilibili.com"
val headers = HashMap<String, String>()

suspend fun getPlayUrl(aid: String): String {
try {
headers["referer"] = referer
headers["origin"] = referer
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"
val videoUrl = "https://www.bilibili.com/video/av$aid";
val html = HttpUtils.get(videoUrl, String::class.java, headers = headers) ?: return ""

val pageData = getMultiPageData(html)
val page = pageData.getJSONObject("videoData").getJSONArray("pages").getJSONObject(0)
val api = genAPI(
pageData.getInt("aid"),
page.getInt("cid"),
127,
pageData.getStr("bvid")
)

val jsonString = HttpUtils.get(api, String::class.java, headers = headers) ?: return ""
Log.i("API_RESPONSE", jsonString)
val data = JSONObject(jsonString)
val description = data.getJSONObject("data").getJSONArray("accept_description")
val dashData: JSONObject
if (description.length() == 0) {
dashData = data.getJSONObject("result");
} else {
dashData = data.getJSONObject("data");
}
val audioList = dashData.getJSONObject("dash").getJSONArray("audio")
var max = 0
var url = ""
(0 until audioList.length()).forEach {
val stream = audioList.getJSONObject(it)
Log.i("AUDIO_URL", stream.getString("baseUrl"))
val bandwidth = stream.getInt("bandwidth")
if (bandwidth > max) {
max = bandwidth
url = stream.getString("baseUrl")
}
}
return url
} catch (e: Exception) {
Log.e("FYERROR", "error", e)
}
return ""
}

private fun genAPI(
aid: Int,
cid: Int,
quality: Int,
bvid: String
): String {

val params = String.format(
"avid=%d&cid=%d&bvid=%s&qn=%d&type=&otype=json&fourk=1&fnver=0&fnval=2000",
aid, cid, bvid, quality
)
return bilibiliAPI + params
}

private fun getMultiPageData(html: String): JSONObject {
val p: Pattern = Pattern.compile("window.__INITIAL_STATE__=(.+?);\\(function")
val matcher: Matcher = p.matcher(html)
if (!matcher.find()) {
throw RuntimeException("not find page info")
}
val json: String = matcher.group(1)
return JSONObject(json)
}
}
76 changes: 76 additions & 0 deletions app/src/main/java/com/dirror/music/music/bilibili/SearchSong.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.dirror.music.music.bilibili

import android.net.Uri
import com.dirror.music.music.standard.data.SOURCE_BILIBILI
import com.dirror.music.music.standard.data.StandardSongData
import com.dirror.music.util.MagicHttp
import com.dirror.music.util.getStr
import com.dirror.music.util.toast
import org.json.JSONArray
import org.json.JSONObject

object SearchSong {
const val referer = "https://www.bilibili.com"
fun search(keywords: String, success: (ArrayList<StandardSongData>) -> Unit) {
val kw = Uri.encode(keywords)
val url =
"https://api.bilibili.com/x/web-interface/search/all/v2?__refresh__=true&_extra=&context=&page=1&page_size=42&order=&duration=&from_source=&from_spmid=333.337&platform=pc&highlight=1&single_column=0&keyword=$kw&preload=true&com2co=true"
MagicHttp.OkHttpManager().getWithHeader(url, mapOf(
"Referer" to referer,
"csrf" to "EUOH79P2LLK",
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"
), {
try {
val resp = JSONObject(it)
val resultList = resp
.getJSONObject("data")
.getJSONArray("result")
val standardSongDataList = ArrayList<StandardSongData>()
(0 until resultList.length()).forEach {
val obj = resultList.getJSONObject(it)
if ("video" == obj.getString("result_type")) {
val videoList = obj.getJSONArray("data")
transform(videoList, standardSongDataList)
}
}
success.invoke(standardSongDataList)
} catch (e: Exception) {
e.printStackTrace()
toast("网络异常,或者解析错误")
}
}, {

})
val standardSongDataList = ArrayList<StandardSongData>()
success(standardSongDataList)
}

fun transform(videoList: JSONArray, standardSongDataList: ArrayList<StandardSongData>) {
(0 until videoList.length()).forEach {
val item = videoList.getJSONObject(it)
handlerVideoItem(item)
val artists = ArrayList<StandardSongData.StandardArtistData>()
artists.add(StandardSongData.StandardArtistData(0, item.getStr("author")))
standardSongDataList.add(
StandardSongData(
SOURCE_BILIBILI,
item.getStr("aid"),
item.getStr("title"),
"https:" + item.getStr("pic"),
artists,
null,
null,
null
)
)
}
}

private fun handlerVideoItem(video: JSONObject) {
var title: String = video.getStr("title")
title = title
.replace("</\\w+>".toRegex(), "")
.replace("<\\w+( \\w+=\"\\w+\")*>".toRegex(), "")
video.put("title", title)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const val SOURCE_QQ = 3
const val SOURCE_DIRROR = 4
const val SOURCE_KUWO = 5
const val SOURCE_NETEASE_CLOUD = 6
const val SOURCE_BILIBILI = 6

val EMPTY_STANDARD_SONG = StandardSongData(
SOURCE_LOCAL,
Expand Down
13 changes: 10 additions & 3 deletions app/src/main/java/com/dirror/music/plugin/PluginSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.function.Function;

import dalvik.system.DexClassLoader;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;

public class PluginSupport {
Expand Down Expand Up @@ -68,11 +69,17 @@ public Object apply(Object s) {
});


pluginContext.put(PluginConstants.METHOD_GET_URL_PROXY, new Function<Function1, Object>() {
pluginContext.put(PluginConstants.METHOD_GET_URL_PROXY, new Function<Function, Object>() {
@Override
public Object apply(Function1 success) {
public Object apply(Function success) {
StandardSongData songData = (StandardSongData) pluginContext.get(PluginConstants.FIELD_SONG);
ServiceSongUrl.INSTANCE.getUrlProxy(songData, success);
ServiceSongUrl.INSTANCE.getUrlProxy(songData, new Function1<Object, Unit>() {
@Override
public Unit invoke(Object o) {
success.apply(o);
return Unit.INSTANCE;
}
});
return null;
}
});
Expand Down
12 changes: 11 additions & 1 deletion app/src/main/java/com/dirror/music/service/MusicService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.dirror.music.App
import com.dirror.music.App.Companion.context
import com.dirror.music.App.Companion.mmkv
import com.dirror.music.R
import com.dirror.music.music.bilibili.BilibiliUrl
import com.dirror.music.music.local.PlayHistory
import com.dirror.music.music.netease.PersonalFM
import com.dirror.music.music.standard.data.*
Expand All @@ -56,6 +57,7 @@ import com.dirror.music.ui.main.MainActivity
import com.dirror.music.ui.player.PlayerActivity
import com.dirror.music.util.*
import com.dso.ext.*
import com.google.gson.Gson
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.*
Expand Down Expand Up @@ -409,8 +411,16 @@ class MusicService : BaseMediaService() {
return@runOnMainThread
} else {
try {
setDataSource(it)
if(it.contains("bilivideo")){
val uri = Uri.parse(it)
Log.i("SETURL"," BILIBILIURL " + it + " " + Gson().toJson(BilibiliUrl.headers))
setDataSource(applicationContext, uri, BilibiliUrl.headers)
}else {
Log.i("SETURL"," NORMALURL " + it)
setDataSource(it)
}
} catch (e: Exception) {
Log.e("FYERROR", "error", e)
onError(mediaPlayer, -1, 0)
return@runOnMainThread
}
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/dirror/music/service/ServiceSongUrl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.ContentUris
import android.net.Uri
import com.dirror.music.App
import com.dirror.music.data.LyricViewData
import com.dirror.music.music.bilibili.BilibiliUrl
import com.dirror.music.music.kuwo.SearchSong
import com.dirror.music.music.netease.SongUrl
import com.dirror.music.music.qq.PlayUrl
Expand Down Expand Up @@ -86,6 +87,11 @@ object ServiceSongUrl {
success.invoke(url)
}
}
SOURCE_BILIBILI -> {
GlobalScope.launch {
success.invoke(BilibiliUrl.getPlayUrl(song.id ?: ""))
}
}
SOURCE_NETEASE_CLOUD -> {
SongUrl.getSongUrlCookie(song.id ?: "") {
success.invoke(it)
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/dirror/music/service/SongPicture.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ object SongPicture {
}
}
}
SOURCE_BILIBILI -> {
songData.imageUrl?.let { url ->
CoilUtil.load(context, url) {
success.invoke(it)
}
}
}
SOURCE_LOCAL -> {
songData.imageUrl?.let {
val bitmap = LocalMusic.getBitmapFromUir(context, it.toUri())
Expand Down
36 changes: 28 additions & 8 deletions app/src/main/java/com/dirror/music/ui/activity/SearchActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ class SearchActivity : BaseActivity() {
// toast("酷我音源暂只支持精确搜索,需要填入完整歌曲名")
}

clBilibili.setOnClickListener {
changeSearchEngine(SearchViewModel.ENGINE_BILIBILI)
}

itemOpenSource.setOnClickListener {
openUrlByBrowser(this@SearchActivity, "https://github.com/Moriafly/DsoMusic")
}
Expand Down Expand Up @@ -175,26 +179,37 @@ class SearchActivity : BaseActivity() {
}

override fun initObserver() {
searchViewModel.searchEngine.observe(this, {
searchViewModel.searchEngine.observe(this) {
binding.apply {
clNetease.background = R.drawable.background_transparency.asDrawable(this@SearchActivity)
clNetease.background =
R.drawable.background_transparency.asDrawable(this@SearchActivity)
clQQ.background = R.drawable.background_transparency.asDrawable(this@SearchActivity)
clKuwo.background = R.drawable.background_transparency.asDrawable(this@SearchActivity)
clKuwo.background =
R.drawable.background_transparency.asDrawable(this@SearchActivity)
clBilibili.background =
R.drawable.background_transparency.asDrawable(this@SearchActivity)
}
val vis = if(it == SearchViewModel.ENGINE_NETEASE) View.VISIBLE else View.GONE
val vis = if (it == SearchViewModel.ENGINE_NETEASE) View.VISIBLE else View.GONE
binding.searchTypeView.visibility = vis
when (it) {
SearchViewModel.ENGINE_NETEASE -> {
binding.clNetease.background = ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
binding.clNetease.background =
ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
}
SearchViewModel.ENGINE_QQ -> {
binding.clQQ.background = ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
binding.clQQ.background =
ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
}
SearchViewModel.ENGINE_KUWO -> {
binding.clKuwo.background = ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
binding.clKuwo.background =
ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
}
SearchViewModel.ENGINE_BILIBILI -> {
binding.clBilibili.background =
ContextCompat.getDrawable(this@SearchActivity, R.drawable.bg_edit_text)
}
}
})
}
}

/**
Expand Down Expand Up @@ -243,6 +258,11 @@ class SearchActivity : BaseActivity() {
initRecycleView(it)
}
}
SearchViewModel.ENGINE_BILIBILI -> {
com.dirror.music.music.bilibili.SearchSong.search(keywords) {
initRecycleView(it)
}
}
}
binding.clPanel.visibility = View.GONE
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class SongInfoDialog(
SOURCE_KUWO -> {
binding.valueViewSource.setValue("酷我音乐")
}
SOURCE_BILIBILI -> {
binding.valueViewSource.setValue("B站")
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class SearchViewModel: ViewModel() {
const val ENGINE_NETEASE = 1
const val ENGINE_QQ = 2
const val ENGINE_KUWO = 3
const val ENGINE_BILIBILI = 4
}

/* 搜索引擎 */
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_bilibili_music_engine.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FF000000"
android:pathData="M306,117.6L444.3,256h135.3l138.4,-138.3a42.7,42.7 0,0 1,60.4 60.4L700.3,256L789.3,256A149.3,149.3 0,0 1,938.7 405.3v341.3a149.3,149.3 0,0 1,-149.3 149.3h-554.7A149.3,149.3 0,0 1,85.3 746.7v-341.3A149.3,149.3 0,0 1,234.7 256h89L245.6,178a42.7,42.7 0,0 1,60.4 -60.4zM789.3,341.3h-554.7a64,64 0,0 0,-63.7 57.9L170.7,405.3v341.3a64,64 0,0 0,57.9 63.7L234.7,810.7h554.7a64,64 0,0 0,63.7 -57.9L853.3,746.7v-341.3A64,64 0,0 0,789.3 341.3zM341.3,469.3a42.7,42.7 0,0 1,42.7 42.7v85.3a42.7,42.7 0,0 1,-85.3 0v-85.3a42.7,42.7 0,0 1,42.7 -42.7zM682.7,469.3a42.7,42.7 0,0 1,42.7 42.7v85.3a42.7,42.7 0,0 1,-85.3 0v-85.3a42.7,42.7 0,0 1,42.7 -42.7z" />
</vector>
Loading

0 comments on commit f204da5

Please sign in to comment.