-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #570 from lovegaoshi/dev
feat: ACFun and widget
- Loading branch information
Showing
43 changed files
with
877 additions
and
404 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import fetcher from '../../src/utils/mediafetch/acfunvideo'; | ||
|
||
test('acfunvideo', async () => { | ||
const content = await fetcher.regexFetch({ | ||
reExtracted: fetcher.regexSearchMatch.exec( | ||
'https://www.acfun.cn/v/ac46370925' | ||
)!, | ||
}); | ||
expect(content?.songList[0]?.id).not.toBeUndefined(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,112 @@ | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
|
||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> | ||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | ||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> | ||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> | ||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" | ||
android:maxSdkVersion="32"/> | ||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" | ||
android:maxSdkVersion="28" /> | ||
|
||
<!--com.github.yyued:SVGAPlayer-Android:2.6.1 has allowBackup = true; doing tools:replace below. --> | ||
<application | ||
android:usesCleartextTraffic="false" | ||
tools:replace="android:allowBackup" | ||
android:name="com.noxplay.noxplayer.MainApplication" | ||
<uses-permission | ||
android:name="android.permission.READ_EXTERNAL_STORAGE" | ||
android:maxSdkVersion="32" /> | ||
<uses-permission | ||
android:name="android.permission.WRITE_EXTERNAL_STORAGE" | ||
android:maxSdkVersion="28" /> | ||
|
||
<application | ||
android:name=".MainApplication" | ||
android:allowBackup="false" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:largeHeap="true" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@style/AppTheme" | ||
android:supportsRtl="true"> | ||
<profileable android:shell="true" | ||
tools:targetApi="q" /> | ||
|
||
<receiver android:name="androidx.media.session.MediaButtonReceiver" | ||
android:exported="true"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MEDIA_BUTTON" /> | ||
</intent-filter> | ||
android:usesCleartextTraffic="false" | ||
tools:replace="android:allowBackup"> | ||
<receiver | ||
android:name=".APMWidget" | ||
android:exported="false"> | ||
<intent-filter> | ||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> | ||
</intent-filter> | ||
|
||
<meta-data | ||
android:name="android.appwidget.provider" | ||
android:resource="@xml/a_p_m_widget_info" /> | ||
</receiver> | ||
|
||
<profileable | ||
android:shell="true" | ||
tools:targetApi="q" /> | ||
|
||
<receiver | ||
android:name="androidx.media.session.MediaButtonReceiver" | ||
android:exported="true"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MEDIA_BUTTON" /> | ||
</intent-filter> | ||
</receiver> | ||
|
||
<provider | ||
android:name="androidx.core.content.FileProvider" | ||
android:authorities="com.noxplay.noxplayer.provider" | ||
android:exported="false" | ||
android:grantUriPermissions="true"> | ||
<meta-data | ||
android:name="android.support.FILE_PROVIDER_PATHS" | ||
android:resource="@xml/provider_paths" /> | ||
android:name="androidx.core.content.FileProvider" | ||
android:authorities="com.noxplay.noxplayer.provider" | ||
android:exported="false" | ||
android:grantUriPermissions="true"> | ||
<meta-data | ||
android:name="android.support.FILE_PROVIDER_PATHS" | ||
android:resource="@xml/provider_paths" /> | ||
</provider> | ||
|
||
<activity | ||
android:name="com.noxplay.noxplayer.MainActivity" | ||
android:supportsPictureInPicture="true" | ||
android:resizeableActivity="true" | ||
android:name=".MainActivity" | ||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" | ||
android:exported="true" | ||
android:launchMode="singleTask" | ||
android:windowSoftInputMode="adjustResize" | ||
android:networkSecurityConfig="@xml/network_security_config" | ||
android:exported="true"> | ||
<intent-filter> | ||
android:resizeableActivity="true" | ||
android:supportsPictureInPicture="true" | ||
android:windowSoftInputMode="adjustResize"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
|
||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
<intent-filter> | ||
<action android:name="android.intent.action.SEND" /> | ||
|
||
<category android:name="android.intent.category.DEFAULT" /> | ||
|
||
<data android:mimeType="text/plain" /> | ||
</intent-filter> | ||
<intent-filter> | ||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /> | ||
<category android:name="android.intent.category.DEFAULT" /> | ||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /> | ||
|
||
<category android:name="android.intent.category.DEFAULT" /> | ||
</intent-filter> | ||
<meta-data android:name="android.app.shortcuts" | ||
android:resource="@xml/shortcuts" /> | ||
</activity> | ||
|
||
<meta-data | ||
android:name="android.app.shortcuts" | ||
android:resource="@xml/shortcuts" /> | ||
</activity> | ||
<activity | ||
android:name="net.openid.appauth.RedirectUriReceiverActivity" | ||
tools:node="replace" | ||
android:exported="true"> | ||
android:exported="true" | ||
tools:node="replace"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.VIEW"/> | ||
<category android:name="android.intent.category.DEFAULT"/> | ||
<category android:name="android.intent.category.BROWSABLE"/> | ||
<data android:scheme="com.noxplayer"/> | ||
<data android:scheme="com.googleusercontent.apps.369249578889-cvr47cn786i0scicobhlljidu1b32572"/> | ||
<action android:name="android.intent.action.VIEW" /> | ||
|
||
<category android:name="android.intent.category.DEFAULT" /> | ||
<category android:name="android.intent.category.BROWSABLE" /> | ||
|
||
<data android:scheme="com.noxplayer" /> | ||
<data android:scheme="com.googleusercontent.apps.369249578889-cvr47cn786i0scicobhlljidu1b32572" /> | ||
</intent-filter> | ||
</activity> | ||
|
||
<meta-data android:name="com.google.android.gms.car.application" | ||
android:resource="@xml/automotive_app_desc"/> | ||
<meta-data | ||
android:name="com.google.android.gms.car.application" | ||
android:resource="@xml/automotive_app_desc" /> | ||
</application> | ||
|
||
</manifest> |
155 changes: 155 additions & 0 deletions
155
android/app/src/main/java/com/noxplay/noxplayer/APMWidget.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package com.noxplay.noxplayer | ||
|
||
import android.app.PendingIntent | ||
import android.appwidget.AppWidgetManager | ||
import android.appwidget.AppWidgetProvider | ||
import android.content.ComponentName | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.graphics.Bitmap | ||
import android.util.Log | ||
import android.widget.RemoteViews | ||
import com.doublesymmetry.trackplayer.model.Track | ||
import com.doublesymmetry.trackplayer.module.MusicEvents | ||
import com.doublesymmetry.trackplayer.service.MusicService | ||
import com.lovegaoshi.kotlinaudio.models.AudioPlayerState | ||
|
||
/** | ||
* Implementation of App Widget functionality. | ||
*/ | ||
class APMWidget : AppWidgetProvider() { | ||
|
||
private lateinit var binder: MusicService.MusicBinder | ||
private var currentTrack: Track? = null | ||
|
||
private fun bindService (context: Context?): Boolean { | ||
if (!::binder.isInitialized || !binder.isBinderAlive) { | ||
if (context == null) return false | ||
Log.d("APM", "widget attempt to connect to MusicService...") | ||
val mBinder = peekService(context, Intent(context, MusicService::class.java)) ?: return false | ||
Log.d("APM", "widget attempt to cast to MusicService...") | ||
binder = mBinder as MusicService.MusicBinder | ||
if (!binder.isBinderAlive) return false | ||
} | ||
return true | ||
} | ||
|
||
private fun emit(context: Context?, e: String) { | ||
if (!bindService(context)) return | ||
binder.service.emit(e) | ||
} | ||
|
||
private fun initWidget(views: RemoteViews, context: Context): RemoteViews { | ||
views.setOnClickPendingIntent( | ||
R.id.buttonPrev, PendingIntent.getBroadcast( | ||
context, 0, | ||
Intent(context, APMWidget::class.java).setAction(MusicEvents.BUTTON_SKIP_PREVIOUS), | ||
PendingIntent.FLAG_IMMUTABLE)) | ||
views.setOnClickPendingIntent( | ||
R.id.buttonPlay, PendingIntent.getBroadcast( | ||
context, 0, | ||
Intent(context, APMWidget::class.java).setAction(MusicEvents.BUTTON_PLAY_PAUSE), | ||
PendingIntent.FLAG_IMMUTABLE)) | ||
views.setOnClickPendingIntent( | ||
R.id.buttonNext, PendingIntent.getBroadcast( | ||
context, 0, | ||
Intent(context, APMWidget::class.java).setAction(MusicEvents.BUTTON_SKIP_NEXT), | ||
PendingIntent.FLAG_IMMUTABLE)) | ||
views.setOnClickPendingIntent( | ||
R.id.APMWidget, PendingIntent.getBroadcast( | ||
context, 0, | ||
Intent(context, APMWidget::class.java).setAction(WIDGET_CLICK), | ||
PendingIntent.FLAG_IMMUTABLE)) | ||
return views | ||
} | ||
|
||
private fun updateTrack(views: RemoteViews, track: Track?, bitmap: Bitmap?): RemoteViews { | ||
if (track == null) { | ||
views.setTextViewCompoundDrawables( | ||
R.id.buttonPlay, R.drawable.media3_icon_play,0,0,0) | ||
} | ||
views.setTextViewText(R.id.songName, track?.title ?: "") | ||
views.setTextViewText(R.id.artistName, track?.artist ?: "") | ||
views.setImageViewBitmap(R.id.albumArt, bitmap) | ||
return views | ||
} | ||
|
||
private fun updatePlayPause(views: RemoteViews) { | ||
val isPlaying = binder.service.state === AudioPlayerState.PLAYING | ||
views.setTextViewCompoundDrawables( | ||
R.id.buttonPlay, | ||
if (isPlaying) R.drawable.media3_icon_pause else R.drawable.media3_icon_play, | ||
0,0,0) | ||
} | ||
|
||
// HACK: properly abstract all of these | ||
private fun clearWidgetContent(context: Context?) { | ||
if (context == null) return | ||
val widgetManager = AppWidgetManager.getInstance(context) | ||
val ids = widgetManager.getAppWidgetIds(ComponentName(context, APMWidget::class.java)) | ||
val views = RemoteViews(context.packageName, R.layout.a_p_m_widget) | ||
updateTrack(views, null, null) | ||
ids.forEach { id -> widgetManager.updateAppWidget(id, views) } | ||
// onUpdate(context, widgetManager, ids) | ||
} | ||
|
||
override fun onUpdate( | ||
context: Context, | ||
appWidgetManager: AppWidgetManager, | ||
appWidgetIds: IntArray | ||
) { | ||
// Construct the RemoteViews object | ||
val views = RemoteViews(context.packageName, R.layout.a_p_m_widget) | ||
if (!bindService(context)) { | ||
updateTrack(views, null, null) | ||
} else { | ||
initWidget(views, context) | ||
updatePlayPause(views) | ||
val track = binder.service.currentTrack | ||
if (track != currentTrack) { | ||
currentTrack = track | ||
val bitmap = if (binder.service.currentBitmap.size == 1) binder.service.currentBitmap[0] else null | ||
updateTrack(views, currentTrack, bitmap) | ||
} | ||
} | ||
// Instruct the widget manager to update the widget | ||
for (appWidgetId in appWidgetIds) { | ||
appWidgetManager.updateAppWidget(appWidgetId, views) | ||
} | ||
} | ||
|
||
override fun onReceive(context: Context?, intent: Intent?) { | ||
try { | ||
when (intent?.action) { | ||
"clear-widget" -> clearWidgetContent(context) | ||
WIDGET_CLICK -> { | ||
if (!bindService(context)) { | ||
Intent(context, MainActivity::class.java).apply { | ||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | ||
}.also {i -> context?.startActivity(i)} | ||
return | ||
} | ||
} | ||
MusicEvents.BUTTON_SKIP_PREVIOUS -> emit(context, MusicEvents.BUTTON_SKIP_PREVIOUS) | ||
MusicEvents.BUTTON_SKIP_NEXT -> emit(context, MusicEvents.BUTTON_SKIP_NEXT) | ||
MusicEvents.BUTTON_PLAY_PAUSE -> emit(context, MusicEvents.BUTTON_PLAY_PAUSE) | ||
else -> {} | ||
} | ||
} catch (e: Exception) { | ||
Log.w("APM", "widget action ${intent?.action} failed by $e") | ||
|
||
} | ||
super.onReceive(context, intent) | ||
} | ||
|
||
override fun onEnabled(context: Context) { | ||
// Enter relevant functionality for when the first widget is created | ||
} | ||
|
||
override fun onDisabled(context: Context) { | ||
// Enter relevant functionality for when the last widget is disabled | ||
} | ||
} | ||
|
||
const val WIDGET_CLICK = "widget-click" | ||
const val WIDGET_CLEAR = "clear-widget" |
24 changes: 24 additions & 0 deletions
24
android/app/src/main/java/com/noxplay/noxplayer/APMWidgetModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.noxplay.noxplayer | ||
|
||
import android.appwidget.AppWidgetManager | ||
import android.content.ComponentName | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.util.Log | ||
import com.facebook.react.bridge.ReactApplicationContext | ||
import com.facebook.react.bridge.ReactContextBaseJavaModule | ||
import com.facebook.react.bridge.ReactMethod | ||
|
||
class APMWidgetModule (private val reactContext: ReactApplicationContext) : | ||
ReactContextBaseJavaModule(reactContext) { | ||
override fun getName() = "APMWidgetModule" | ||
|
||
@ReactMethod fun updateWidget() { | ||
val intent = Intent(reactContext, APMWidget::class.java) | ||
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE") | ||
val widgetManager = AppWidgetManager.getInstance(reactContext) | ||
val ids = widgetManager.getAppWidgetIds(ComponentName(reactContext, APMWidget::class.java)) | ||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids) | ||
reactContext.sendBroadcast(intent) | ||
} | ||
} |
Oops, something went wrong.