├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── README_ENG.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── hwinzniej
│ │ └── musichelper
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── QQMusic
│ │ ├── cloudmusic.db
│ │ ├── kugou_music_phone_v7.db
│ │ ├── kwplayer.db
│ │ ├── licenses.html
│ │ └── licenses_dark.html
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── hwinzniej
│ │ │ └── musichelper
│ │ │ ├── MainActivity.kt
│ │ │ ├── activity
│ │ │ ├── ConvertPage.kt
│ │ │ ├── PermissionResultHandler.kt
│ │ │ ├── ProcessPage.kt
│ │ │ ├── ScanPage.kt
│ │ │ ├── SettingsPage.kt
│ │ │ ├── TagPage.kt
│ │ │ └── UnlockPage.kt
│ │ │ ├── data
│ │ │ ├── DataStoreConstants.kt
│ │ │ ├── SourceApp.kt
│ │ │ ├── dao
│ │ │ │ └── MusicDao.kt
│ │ │ ├── database
│ │ │ │ └── MusicDatabase.kt
│ │ │ └── model
│ │ │ │ ├── Music.kt
│ │ │ │ └── MusicInfo.kt
│ │ │ ├── ui
│ │ │ ├── AboutPageUi.kt
│ │ │ ├── ConvertPageUi.kt
│ │ │ ├── MySaltUi.kt
│ │ │ ├── ProcessPageUi.kt
│ │ │ ├── ScanPageUi.kt
│ │ │ ├── SettingsPageUi.kt
│ │ │ ├── TagPageUi.kt
│ │ │ ├── UnlockPageUi.kt
│ │ │ └── theme
│ │ │ │ ├── Color.kt
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Type.kt
│ │ │ └── utils
│ │ │ ├── DoubanMusicApi.kt
│ │ │ ├── MyDataStore.kt
│ │ │ ├── MyVibrationEffect.kt
│ │ │ └── Tools.kt
│ └── res
│ │ ├── drawable
│ │ ├── about.xml
│ │ ├── agreement.xml
│ │ ├── alipay.jpg
│ │ ├── all.xml
│ │ ├── android.xml
│ │ ├── aplayer.xml
│ │ ├── app_theme.xml
│ │ ├── auto_check_update.xml
│ │ ├── bilibili.xml
│ │ ├── caution.xml
│ │ ├── check.xml
│ │ ├── check_update.xml
│ │ ├── chinese.xml
│ │ ├── cloudmusic.xml
│ │ ├── coffee.xml
│ │ ├── color.xml
│ │ ├── complete.xml
│ │ ├── computer.xml
│ │ ├── convert.xml
│ │ ├── cookie.xml
│ │ ├── coolapk.xml
│ │ ├── csv_file.xml
│ │ ├── dark_color.xml
│ │ ├── database.xml
│ │ ├── developer.xml
│ │ ├── english.xml
│ │ ├── gitee.xml
│ │ ├── github.xml
│ │ ├── gitlab.xml
│ │ ├── haptic.xml
│ │ ├── home_screen.xml
│ │ ├── ic_arrow_back.xml
│ │ ├── ic_arrow_drop_down.xml
│ │ ├── ic_check.xml
│ │ ├── ic_chevron_right.xml
│ │ ├── ic_clear.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_launcher_border_foreground.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_tips.xml
│ │ ├── ic_uncheck.xml
│ │ ├── json_file.xml
│ │ ├── korean.xml
│ │ ├── kugou.xml
│ │ ├── kuwo.xml
│ │ ├── language.xml
│ │ ├── license.xml
│ │ ├── light_color.xml
│ │ ├── luna_music.xml
│ │ ├── manual.xml
│ │ ├── microsoft_zune.xml
│ │ ├── network.xml
│ │ ├── no_items.xml
│ │ ├── overall.xml
│ │ ├── plus.xml
│ │ ├── plus_no_circle.xml
│ │ ├── poweramp.xml
│ │ ├── proxy.xml
│ │ ├── qinalt.xml
│ │ ├── qq_group.xml
│ │ ├── qqmusic.xml
│ │ ├── refresh.xml
│ │ ├── result.xml
│ │ ├── root_access.xml
│ │ ├── saltplayer.xml
│ │ ├── scan.xml
│ │ ├── search.xml
│ │ ├── server.xml
│ │ ├── settings.xml
│ │ ├── sort.xml
│ │ ├── split.xml
│ │ ├── spotify.xml
│ │ ├── success.xml
│ │ ├── tag.xml
│ │ ├── text.xml
│ │ ├── tune_my_music.xml
│ │ ├── um.xml
│ │ ├── user.xml
│ │ ├── web_page.xml
│ │ ├── wechat.png
│ │ └── wechat_app.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-ko
│ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── hwinzniej
│ └── musichelper
│ └── ExampleUnitTest.kt
├── build.gradle.kts
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── markdownResources
├── Alipay WeChatPay.jpg
├── Questionnaire QR Code.png
├── Sponsorship.png
├── ic_launcher.png
├── img1.png
├── img2.png
└── img3.png
└── settings.gradle.kts
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.html linguist-language=Kotlin
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,kotlin
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,kotlin
3 |
4 | ### Android ###
5 | # Gradle files
6 | .gradle/
7 | build/
8 |
9 | # Local configuration file (sdk path, etc)
10 | local.properties
11 |
12 | # Log/OS Files
13 | *.log
14 |
15 | # Android Studio generated files and folders
16 | captures/
17 | .externalNativeBuild/
18 | .cxx/
19 | *.apk
20 | output.json
21 |
22 | # IntelliJ
23 | *.iml
24 | .idea/
25 | misc.xml
26 | deploymentTargetDropDown.xml
27 | render.experimental.xml
28 |
29 | # Keystore files
30 | *.jks
31 | *.keystore
32 |
33 | # Google Services (e.g. APIs or Firebase)
34 | google-services.json
35 |
36 | # Android Profiling
37 | *.hprof
38 |
39 | ### Android Patch ###
40 | gen-external-apklibs
41 |
42 | # Replacement of .externalNativeBuild directories introduced
43 | # with Android Studio 3.5.
44 |
45 | ### Kotlin ###
46 | # Compiled class file
47 | *.class
48 |
49 | # Log file
50 |
51 | # BlueJ files
52 | *.ctxt
53 |
54 | # Mobile Tools for Java (J2ME)
55 | .mtj.tmp/
56 |
57 | # Package Files #
58 | *.jar
59 | *.war
60 | *.nar
61 | *.ear
62 | *.zip
63 | *.tar.gz
64 | *.rar
65 |
66 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
67 | hs_err_pid*
68 | replay_pid*
69 |
70 | ### AndroidStudio ###
71 | # Covers files to be ignored for android development using Android Studio.
72 |
73 | # Built application files
74 | *.ap_
75 | *.aab
76 |
77 | # Files for the ART/Dalvik VM
78 | *.dex
79 |
80 | # Java class files
81 |
82 | # Generated files
83 | bin/
84 | gen/
85 | out/
86 |
87 | # Gradle files
88 | .gradle
89 |
90 | # Signing files
91 | .signing/
92 |
93 | # Local configuration file (sdk path, etc)
94 |
95 | # Proguard folder generated by Eclipse
96 | proguard/
97 |
98 | # Log Files
99 |
100 | # Android Studio
101 | /*/build/
102 | /*/local.properties
103 | /*/out
104 | /*/*/build
105 | /*/*/production
106 | .navigation/
107 | *.ipr
108 | *~
109 | *.swp
110 |
111 | # Keystore files
112 |
113 | # Google Services (e.g. APIs or Firebase)
114 | # google-services.json
115 |
116 | # Android Patch
117 |
118 | # External native build folder generated in Android Studio 2.2 and later
119 | .externalNativeBuild
120 |
121 | # NDK
122 | obj/
123 |
124 | # IntelliJ IDEA
125 | *.iws
126 | /out/
127 |
128 | # User-specific configurations
129 | .idea/caches/
130 | .idea/libraries/
131 | .idea/shelf/
132 | .idea/workspace.xml
133 | .idea/tasks.xml
134 | .idea/.name
135 | .idea/compiler.xml
136 | .idea/copyright/profiles_settings.xml
137 | .idea/encodings.xml
138 | .idea/misc.xml
139 | .idea/modules.xml
140 | .idea/scopes/scope_settings.xml
141 | .idea/dictionaries
142 | .idea/vcs.xml
143 | .idea/jsLibraryMappings.xml
144 | .idea/datasources.xml
145 | .idea/dataSources.ids
146 | .idea/sqlDataSources.xml
147 | .idea/dynamic.xml
148 | .idea/uiDesigner.xml
149 | .idea/assetWizardSettings.xml
150 | .idea/gradle.xml
151 | .idea/jarRepositories.xml
152 | .idea/navEditor.xml
153 |
154 | # Legacy Eclipse project files
155 | .classpath
156 | .project
157 | .cproject
158 | .settings/
159 |
160 | # Mobile Tools for Java (J2ME)
161 |
162 | # Package Files #
163 |
164 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
165 |
166 | ## Plugin-specific files:
167 |
168 | # mpeltonen/sbt-idea plugin
169 | .idea_modules/
170 |
171 | # JIRA plugin
172 | atlassian-ide-plugin.xml
173 |
174 | # Mongo Explorer plugin
175 | .idea/mongoSettings.xml
176 |
177 | # Crashlytics plugin (for Android Studio and IntelliJ)
178 | com_crashlytics_export_strings.xml
179 | crashlytics.properties
180 | crashlytics-build.properties
181 | fabric.properties
182 |
183 | ### AndroidStudio Patch ###
184 |
185 | !/gradle/wrapper/gradle-wrapper.jar
186 |
187 | # End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,kotlin
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 HWinZnieJ
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README_ENG.md:
--------------------------------------------------------------------------------
1 | # 施工中……
2 |
3 | # Under Construction……
4 |
5 | # 🛠️🛠️🛠️
6 |
7 | ## 🛠️🛠️
8 |
9 | ### 🛠️
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | id("org.jetbrains.kotlin.android")
4 | id("com.google.devtools.ksp")
5 | id("org.jetbrains.compose") version "1.7.3"
6 | id("org.jetbrains.kotlin.plugin.compose")
7 | }
8 |
9 | android {
10 | namespace = "com.hwinzniej.musichelper"
11 | compileSdk = 35
12 | // useLibrary("org.apache.http.legacy")
13 |
14 | defaultConfig {
15 | applicationId = "com.hwinzniej.musichelper"
16 | minSdk = 26
17 | // targetSdk = 28
18 | targetSdk = 35
19 | versionCode = 78
20 | versionName = "1.6.8"
21 |
22 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
23 | vectorDrawables {
24 | useSupportLibrary = true
25 | }
26 | }
27 | packaging {
28 | resources.excludes.add("META-INF/*")
29 | }
30 |
31 | buildTypes {
32 | release {
33 | isMinifyEnabled = false
34 | proguardFiles(
35 | getDefaultProguardFile("proguard-android-optimize.txt"),
36 | "proguard-rules.pro"
37 | )
38 | }
39 | }
40 | compileOptions {
41 | sourceCompatibility = JavaVersion.VERSION_21
42 | targetCompatibility = JavaVersion.VERSION_21
43 | }
44 | kotlinOptions {
45 | jvmTarget = "21"
46 | }
47 | buildFeatures {
48 | compose = true
49 | }
50 | packaging {
51 | resources {
52 | excludes += "/META-INF/{AL2.0,LGPL2.1}"
53 | }
54 | }
55 | }
56 |
57 | dependencies {
58 |
59 | implementation("androidx.core:core-ktx:1.15.0")
60 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
61 | implementation("androidx.activity:activity-compose:1.10.0")
62 | implementation(platform("androidx.compose:compose-bom:2025.01.01"))
63 | implementation("androidx.compose.ui:ui")
64 | implementation("androidx.compose.ui:ui-graphics")
65 | implementation("androidx.compose.material:material")
66 | implementation("androidx.compose.material3:material3")
67 | implementation("androidx.annotation:annotation:1.9.1")
68 | implementation("androidx.documentfile:documentfile:1.0.1")
69 | testImplementation("junit:junit:4.13.2")
70 | androidTestImplementation("androidx.test.ext:junit:1.2.1")
71 | androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
72 | androidTestImplementation(platform("androidx.compose:compose-bom:2025.01.01"))
73 |
74 | // Android Studio Preview support
75 | implementation("androidx.compose.ui:ui-tooling-preview")
76 | debugImplementation("androidx.compose.ui:ui-tooling")
77 |
78 | // UI Tests
79 | androidTestImplementation("androidx.compose.ui:ui-test-junit4")
80 | debugImplementation("androidx.compose.ui:ui-test-manifest")
81 |
82 | //SaltUI
83 | implementation("io.github.moriafly:salt-ui:2.3.1")
84 |
85 | //JAudioTagger
86 | // implementation("org.bitbucket.ijabz:jaudiotagger:7b004a1")
87 | implementation("com.github.maxbruecken:jaudiotagger-android:master")
88 |
89 | //Kotlin协程
90 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
91 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
92 | implementation("androidx.activity:activity-ktx:1.10.0")
93 | implementation("androidx.fragment:fragment-ktx:1.8.5")
94 |
95 | //Room数据库
96 | val roomVersion = "2.6.1"
97 | implementation("androidx.room:room-runtime:$roomVersion")
98 | annotationProcessor("androidx.room:room-compiler:$roomVersion")
99 | ksp("androidx.room:room-compiler:$roomVersion")
100 |
101 | //FastJson
102 | implementation("com.alibaba.fastjson2:fastjson2-kotlin:2.0.54")
103 |
104 | //Navigation
105 | implementation("androidx.navigation:navigation-compose:2.8.6")
106 |
107 | //DataStore
108 | implementation("androidx.datastore:datastore-preferences:1.1.2")
109 |
110 | //OkHttp3
111 | implementation("com.squareup.okhttp3:okhttp:4.12.0")
112 |
113 | //Markdown渲染器
114 | implementation("com.github.jeziellago:compose-markdown:0.5.6")
115 |
116 | //Google ZXing二维码生成
117 | implementation("com.google.zxing:core:3.5.3")
118 |
119 | //Splashscreen
120 | implementation("androidx.core:core-splashscreen:1.1.0-rc01")
121 |
122 | //Apache Common Csv
123 | implementation("org.apache.commons:commons-csv:1.12.0")
124 |
125 | //拖拽排序-可注释
126 | // implementation("org.burnoutcrew.composereorderable:reorderable:0.9.6")
127 |
128 | //Jsoup-可注释
129 | // implementation("org.jsoup:jsoup:1.17.2")
130 |
131 | //Ksoup-不可注释,可用于跨平台
132 | implementation("com.fleeksoft.ksoup:ksoup:0.2.1")
133 |
134 | //HtmlUnit-可注释
135 | // implementation("org.htmlunit:htmlunit3-android:3.7.0")
136 |
137 | //XmlAPI-可注释
138 | // implementation("xml-apis:xml-apis:2.0.2")
139 |
140 |
141 | // Optional - Included automatically by material, only add when you need
142 | // the icons but not the material library (e.g. when using Material3 or a
143 | // custom design system based on Foundation)
144 | //implementation("androidx.compose.material:material-icons-core")
145 | // Optional - Add full set of material icons
146 | //implementation("androidx.compose.material:material-icons-extended")
147 | // Optional - Add window size utils
148 | //implementation("androidx.compose.material3:material3-window-size-class")
149 |
150 | // Optional - Integration with activities
151 | //implementation("androidx.activity:activity-compose:1.6.1")
152 | // Optional - Integration with ViewModels
153 | //implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1")
154 | // Optional - Integration with LiveData
155 | //implementation("androidx.compose.runtime:runtime-livedata")
156 | // Optional - Integration with RxJava
157 | //implementation("androidx.compose.runtime:runtime-rxjava2")
158 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/hwinzniej/musichelper/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.hwinzniej.musichelper", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
24 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/assets/QQMusic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/assets/QQMusic
--------------------------------------------------------------------------------
/app/src/main/assets/cloudmusic.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/assets/cloudmusic.db
--------------------------------------------------------------------------------
/app/src/main/assets/kugou_music_phone_v7.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/assets/kugou_music_phone_v7.db
--------------------------------------------------------------------------------
/app/src/main/assets/kwplayer.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/assets/kwplayer.db
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/activity/PermissionResultHandler.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.activity
2 |
3 | interface PermissionResultHandler {
4 | fun onPermissionResult(
5 | requestCode: Int, permissions: Array, grantResults: IntArray
6 | )
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/activity/ProcessPage.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.activity
2 | //
3 | //import android.content.Context
4 | //import android.widget.Toast
5 | //import androidx.compose.runtime.mutableStateOf
6 | //import androidx.lifecycle.LifecycleOwner
7 | //import androidx.lifecycle.lifecycleScope
8 | //import com.hwinzniej.musichelper.data.database.MusicDatabase
9 | //import com.hwinzniej.musichelper.data.model.MusicInfo
10 | //import com.hwinzniej.musichelper.utils.DoubanMusicApi
11 | //import kotlinx.coroutines.Dispatchers
12 | //import kotlinx.coroutines.launch
13 | //
14 | //class ProcessPage(
15 | // val context: Context,
16 | // val lifecycleOwner: LifecycleOwner,
17 | // val db: MusicDatabase
18 | //) {
19 | // var processAllScannedMusic = mutableStateOf(true)
20 | // var overwriteOriginalTag = mutableStateOf(true)
21 | // var showSelectTagTypeDialog = mutableStateOf(false)
22 | // var enableAlbumArtist = mutableStateOf(true)
23 | // var enableReleaseYear = mutableStateOf(true)
24 | // var enableGenre = mutableStateOf(true)
25 | // var enableTrackNumber = mutableStateOf(true)
26 | // var showProgressBar = mutableStateOf(false)
27 | // var showSelectSourceDialog = mutableStateOf(false)
28 | // val useDoubanMusicSource = mutableStateOf(true)
29 | // val useMusicBrainzSource = mutableStateOf(true)
30 | // val useBaiduBaikeSource = mutableStateOf(true)
31 | //
32 | // lateinit var musicInfoList: List
33 | //
34 | // fun getMusicList() {
35 | //// showProgressBar.value = true
36 | // lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
37 | // if (processAllScannedMusic.value) {
38 | // musicInfoList = db.musicDao().getMusic3Info() //应为getMusicInfo
39 | // startProcess()
40 | // } else {
41 | //// db.musicDao().getMusicByPath("")
42 | // }
43 | // }
44 | //
45 | // }
46 | //
47 | // fun startProcess() {
48 | // if (musicInfoList.isEmpty()) {
49 | // lifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
50 | // Toast.makeText(context, "数据库为空,请先扫描本地歌曲", Toast.LENGTH_SHORT).show()
51 | // }
52 | // return
53 | // }
54 | // if (useDoubanMusicSource.value) {
55 | // getDoubanMusicInfo()
56 | // }
57 | // if (useMusicBrainzSource.value) {
58 | // //TODO
59 | // }
60 | // if (useBaiduBaikeSource.value) {
61 | // //TODO
62 | // }
63 | // }
64 | //
65 | // fun getDoubanMusicInfo() {
66 | // lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
67 | // musicInfoList.forEach {
68 | // val musicInfo = it
69 | // val musicName = it.song
70 | // val artistName = it.artist
71 | // val albumName = it.album
72 | // val musicInfoFromDouban =
73 | // DoubanMusicApi.getMusicInfo(musicName, artistName, albumName)
74 | // return@launch
75 | //// if (musicInfoFromDouban != null) {
76 | //// musicInfo.releaseYear = musicInfoFromDouban.releaseYear
77 | //// musicInfo.trackNumber = musicInfoFromDouban.trackNumber
78 | //// musicInfo.albumArtist = musicInfoFromDouban.albumArtist
79 | //// musicInfo.genre = musicInfoFromDouban.genre
80 | ////// db.musicDao().updateMusicInfo(musicInfo)
81 | //// }
82 | // }
83 | // }
84 | // }
85 | //}
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/activity/SettingsPage.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.activity
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.widget.Toast
6 | import androidx.activity.result.ActivityResultLauncher
7 | import androidx.compose.runtime.mutableIntStateOf
8 | import androidx.compose.runtime.mutableStateMapOf
9 | import androidx.compose.runtime.mutableStateOf
10 | import androidx.datastore.core.DataStore
11 | import androidx.datastore.preferences.core.Preferences
12 | import androidx.datastore.preferences.core.edit
13 | import androidx.lifecycle.LifecycleOwner
14 | import androidx.lifecycle.lifecycleScope
15 | import com.hwinzniej.musichelper.R
16 | import com.hwinzniej.musichelper.data.DataStoreConstants
17 | import com.hwinzniej.musichelper.utils.Tools
18 | import kotlinx.coroutines.Dispatchers
19 | import kotlinx.coroutines.async
20 | import kotlinx.coroutines.delay
21 | import kotlinx.coroutines.launch
22 | import kotlinx.coroutines.withContext
23 | import java.io.File
24 |
25 | class SettingsPage(
26 | val context: Context,
27 | private val lifecycleOwner: LifecycleOwner,
28 | val openUmExecutableFileLauncher: ActivityResultLauncher>,
29 | val dataStore: DataStore,
30 | ) {
31 | val enableAutoCheckUpdate = mutableStateOf(true)
32 | val encryptServer = mutableStateOf("")
33 | val serverPing = mutableStateMapOf(
34 | 0 to context.getString(R.string.pinging),
35 | 1 to context.getString(R.string.pinging),
36 | 2 to context.getString(R.string.pinging)
37 | )
38 | val showDialogProgressBar = mutableStateOf(false)
39 | val initialPage = mutableIntStateOf(0)
40 | val githubProxy = mutableIntStateOf(2)
41 |
42 | fun checkServerPing() {
43 | lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
44 | showDialogProgressBar.value = true
45 | val regex = "\\d+\\.\\d+".toRegex()
46 | val t1 = async {
47 | val text = Tools().execShellCmd("ping -c 1 -q -W 3 'plnb-cf.hwinzniej.top'", true)
48 | delay(300L)
49 | if (text.contains("1 received"))
50 | serverPing[0] = "${regex.findAll(text).toList()[3].value} ms"
51 | else
52 | serverPing[0] = context.getString(R.string.timeout)
53 | }
54 | val t2 = async {
55 | val text = Tools().execShellCmd("ping -c 1 -q -W 3 'plnb1.hwinzniej.top'", true)
56 | delay(300L)
57 | if (text.contains("1 received"))
58 | serverPing[1] = "${regex.findAll(text).toList()[3].value} ms"
59 | else
60 | serverPing[1] = context.getString(R.string.timeout)
61 | }
62 | val t3 = async {
63 | val text = Tools().execShellCmd("ping -c 1 -q -W 3 'plnb2.hwinzniej.top'", true)
64 | delay(300L)
65 | if (text.contains("1 received"))
66 | serverPing[2] = "${regex.findAll(text).toList()[3].value} ms"
67 | else
68 | serverPing[2] = context.getString(R.string.timeout)
69 | }
70 | t1.await()
71 | t2.await()
72 | t3.await()
73 | showDialogProgressBar.value = false
74 | }
75 | }
76 |
77 | fun selectUmFile() {
78 | try {
79 | openUmExecutableFileLauncher.launch(arrayOf("*/*"))
80 | } catch (_: Exception) {
81 | Toast.makeText(
82 | context,
83 | context.getString(R.string.unable_start_documentsui),
84 | Toast.LENGTH_SHORT
85 | ).show()
86 | }
87 | }
88 |
89 | var umFileLegal = mutableStateOf(false)
90 | var umSupportOverWrite = mutableStateOf(false)
91 |
92 | fun checkUmFile(uri: Uri?) {
93 | if (uri == null)
94 | return
95 | lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
96 | val inputStream = context.contentResolver.openInputStream(uri)
97 |
98 | val internalFile = File(context.filesDir, "um_executable")
99 | if (internalFile.exists())
100 | internalFile.delete()
101 |
102 | val outputStream = internalFile.outputStream()
103 |
104 | inputStream?.copyTo(outputStream)
105 | inputStream?.close()
106 | outputStream.close()
107 |
108 | try {
109 | Tools().execShellCmd(
110 | cmd = "chmod 700 ${internalFile.absolutePath}",
111 | withoutRoot = true
112 | )
113 | } catch (e: Exception) {
114 | e.printStackTrace()
115 | }
116 |
117 | try {
118 | val result = Tools().execShellCmd(
119 | cmd = "${internalFile.absolutePath} -v",
120 | withoutRoot = true
121 | )
122 | if (result.contains("Unlock Music CLI version", true)) {
123 | dataStore.edit { settings ->
124 | settings[DataStoreConstants.UM_FILE_LEGAL] = true
125 | }
126 | umFileLegal.value = true
127 | withContext(Dispatchers.Main) {
128 | Toast.makeText(
129 | context,
130 | context.getString(R.string.valid_um_file),
131 | Toast.LENGTH_SHORT
132 | ).show()
133 | }
134 | val supportOverwrite = Tools().execShellCmd(
135 | cmd = "${internalFile.absolutePath} -h",
136 | withoutRoot = true
137 | )
138 | if (supportOverwrite.contains("--overwrite", true)) {
139 | dataStore.edit { settings ->
140 | settings[DataStoreConstants.UM_SUPPORT_OVERWRITE] = true
141 | }
142 | umSupportOverWrite.value = true
143 | } else {
144 | dataStore.edit { settings ->
145 | settings[DataStoreConstants.UM_SUPPORT_OVERWRITE] = false
146 | }
147 | umSupportOverWrite.value = false
148 | }
149 | } else {
150 | dataStore.edit { settings ->
151 | settings[DataStoreConstants.UM_FILE_LEGAL] = false
152 | }
153 | umFileLegal.value = false
154 | internalFile.delete()
155 | withContext(Dispatchers.Main) {
156 | Toast.makeText(
157 | context,
158 | context.getString(R.string.invalid_um_file),
159 | Toast.LENGTH_SHORT
160 | ).show()
161 | }
162 | }
163 | } catch (_: Exception) {
164 | }
165 | }
166 | }
167 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/DataStoreConstants.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data
2 |
3 | import androidx.datastore.preferences.core.booleanPreferencesKey
4 | import androidx.datastore.preferences.core.intPreferencesKey
5 | import androidx.datastore.preferences.core.longPreferencesKey
6 | import androidx.datastore.preferences.core.stringPreferencesKey
7 |
8 | object DataStoreConstants {
9 | const val SETTINGS_PREFERENCES = "settings"
10 | val KEY_LANGUAGE = stringPreferencesKey("language")
11 | val KEY_THEME_MODE = intPreferencesKey("theme_mode")
12 | val KEY_ENABLE_DYNAMIC_COLOR = booleanPreferencesKey("enable_dynamic_color")
13 | val KEY_ENABLE_AUTO_CHECK_UPDATE = booleanPreferencesKey("enable_auto_check_update")
14 | val KEY_USE_ROOT_ACCESS = booleanPreferencesKey("use_root_access")
15 | val KEY_ENABLE_HAPTIC = booleanPreferencesKey("enable_haptic")
16 | val KEY_ENCRYPT_SERVER = stringPreferencesKey("encrypt_server")
17 | val LAST_LOGIN_TIMESTAMP = longPreferencesKey("last_login_timestamp")
18 | val NETEASE_USER_ID = stringPreferencesKey("netease_user_id")
19 | val PLAYLIST_SOURCE_PLATFORM = intPreferencesKey("playlist_source_platform")
20 | val GET_PLAYLIST_METHOD = intPreferencesKey("get_playlist_method")
21 | val KUGOU_TOKEN = stringPreferencesKey("kugou_token")
22 | val KUGOU_USER_ID = stringPreferencesKey("kugou_user_id")
23 | val UM_FILE_LEGAL = booleanPreferencesKey("um_file_legal")
24 | val UM_SUPPORT_OVERWRITE = booleanPreferencesKey("um_support_overwrite")
25 | val HAPTIC_STRENGTH = intPreferencesKey("haptic_strength")
26 | val TAG_OVERWRITE = booleanPreferencesKey("tag_overwrite")
27 | val TAG_LYRICIST = booleanPreferencesKey("tag_lyricist")
28 | val TAG_COMPOSER = booleanPreferencesKey("tag_composer")
29 | val TAG_ARRANGER = booleanPreferencesKey("tag_arranger")
30 | val SORT_METHOD = intPreferencesKey("sort_method")
31 | val SLOW_MODE = booleanPreferencesKey("slow_mode")
32 | val LUNA_DEVICE_ID = stringPreferencesKey("luna_device_id")
33 | val LUNA_INSTALL_ID = stringPreferencesKey("luna_install_id")
34 | val LUNA_COOKIE = stringPreferencesKey("luna_cookie")
35 | val CONVERT_MODE = intPreferencesKey("convert_mode")
36 | val SELECTED_TARGET_APP = intPreferencesKey("selected_target_app")
37 | val SELECTED_SOURCE_APP = intPreferencesKey("selected_source_app")
38 | val INITIAL_PAGE = intPreferencesKey("initial_page")
39 | val SPOTIFY_USER_ID = stringPreferencesKey("spotify_user_id")
40 | val AGREE_USER_AGREEMENT = booleanPreferencesKey("agree_user_agreement")
41 | val WIN_PATH = stringPreferencesKey("win_path")
42 | val MUSIC_DIRNAME = stringPreferencesKey("music_dirName")
43 | val SHOW_ADVANCED_OPTIONS = booleanPreferencesKey("show_advanced_options")
44 | val GITHUB_PROXY = intPreferencesKey("github_proxy")
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/SourceApp.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data
2 |
3 | class SourceApp {
4 | lateinit var sourceEng: String
5 | lateinit var sourceChn: String
6 | lateinit var databaseName: String
7 | lateinit var songListTableName: String
8 | lateinit var songListId: String
9 | lateinit var songListName: String
10 | lateinit var songListSongInfoTableName: String
11 | lateinit var songListSongInfoPlaylistId: String
12 | lateinit var songListSongInfoSongId: String
13 | lateinit var songInfoTableName: String
14 | lateinit var sortField: String
15 | lateinit var songInfoSongId: String
16 | lateinit var songInfoSongName: String
17 | lateinit var songInfoSongArtist: String
18 | lateinit var songInfoSongAlbum: String
19 | lateinit var pakageName: String
20 | lateinit var musicNum: String
21 |
22 | fun init(sourceApp: String) {
23 | when (sourceApp) {
24 | "QQMusic" -> {
25 | sourceEng = "QQMusic"
26 | sourceChn = "QQ音乐"
27 | databaseName = "QQMusic"
28 | songListTableName = "User_Folder_table"
29 | songListId = "folderid"
30 | songListName = "foldername"
31 | musicNum = "count"
32 | songListSongInfoTableName = "User_Folder_Song_table"
33 | songListSongInfoPlaylistId = "folderid"
34 | songListSongInfoSongId = "id"
35 | songInfoTableName = "Song_table"
36 | sortField = "position"
37 | songInfoSongId = "id"
38 | songInfoSongName = "name"
39 | songInfoSongArtist = "singername"
40 | songInfoSongAlbum = "albumname"
41 | pakageName = "com.tencent.qqmusic"
42 | }
43 |
44 | "CloudMusic" -> {
45 | sourceEng = "CloudMusic"
46 | sourceChn = "网易云音乐"
47 | databaseName = "cloudmusic.db"
48 | songListTableName = "playlist"
49 | songListId = "_id"
50 | songListName = "name"
51 | musicNum = "track_count"
52 | songListSongInfoTableName = "playlist_track"
53 | songListSongInfoPlaylistId = "playlist_id"
54 | songListSongInfoSongId = "track_id"
55 | songInfoTableName = "track"
56 | sortField = "track_order"
57 | songInfoSongId = "id"
58 | songInfoSongName = "name"
59 | songInfoSongArtist = "artists"
60 | songInfoSongAlbum = "album_name"
61 | pakageName =
62 | "com.netease.cloudmusic|com.hihonor.cloudmusic"
63 | }
64 |
65 | "KugouMusic" -> {
66 | sourceEng = "KuGouMusic"
67 | sourceChn = "酷狗音乐"
68 | databaseName = "kugou_music_phone_v7.db"
69 | songListTableName = "kugou_playlists"
70 | songListId = "_id"
71 | songListName = "name"
72 | musicNum = "num_of_songs"
73 | songListSongInfoTableName = "playlistsong"
74 | songListSongInfoPlaylistId = "plistid"
75 | songListSongInfoSongId = "songid"
76 | songInfoTableName = "kugou_songs"
77 | sortField = "cloudfileorderweight"
78 | songInfoSongId = "_id"
79 | songInfoSongName = "trackName"
80 | songInfoSongArtist = "artistName"
81 | songInfoSongAlbum = "albumName"
82 | pakageName = "com.kugou.android"
83 | }
84 |
85 | "KuwoMusic" -> {
86 | sourceEng = "KuWoMusic"
87 | sourceChn = "酷我音乐"
88 | databaseName = "kwplayer.db"
89 | songListTableName = "v3_list"
90 | songListId = "id"
91 | songListName = "showname"
92 | musicNum = "musicNum"
93 | songListSongInfoTableName = "v3_music"
94 | songListSongInfoPlaylistId = "listid"
95 | songListSongInfoSongId = "rid"
96 | songInfoTableName = "v3_music"
97 | sortField = "id"
98 | songInfoSongId = "rid"
99 | songInfoSongName = "name"
100 | songInfoSongArtist = "artist"
101 | songInfoSongAlbum = "album"
102 | pakageName = "cn.kuwo.player"
103 | }
104 |
105 | "LunaMusic" -> {
106 | sourceEng = "LunaMusic"
107 | sourceChn = "汽水音乐"
108 | databaseName = "QQMusic"
109 | songListTableName = "User_Folder_table"
110 | songListId = "folderid"
111 | songListName = "foldername"
112 | musicNum = "count"
113 | songListSongInfoTableName = "User_Folder_Song_table"
114 | songListSongInfoPlaylistId = "folderid"
115 | songListSongInfoSongId = "id"
116 | songInfoTableName = "Song_table"
117 | sortField = "position"
118 | songInfoSongId = "id"
119 | songInfoSongName = "name"
120 | songInfoSongArtist = "singername"
121 | songInfoSongAlbum = "albumname"
122 | pakageName = "com.luna.music"
123 | }
124 |
125 | "Spotify" -> {
126 | sourceEng = "Spotify"
127 | sourceChn = "Spotify"
128 | databaseName = "QQMusic"
129 | songListTableName = "User_Folder_table"
130 | songListId = "folderid"
131 | songListName = "foldername"
132 | musicNum = "count"
133 | songListSongInfoTableName = "User_Folder_Song_table"
134 | songListSongInfoPlaylistId = "folderid"
135 | songListSongInfoSongId = "id"
136 | songInfoTableName = "Song_table"
137 | sortField = "position"
138 | songInfoSongId = "id"
139 | songInfoSongName = "name"
140 | songInfoSongArtist = "singername"
141 | songInfoSongAlbum = "albumname"
142 | pakageName = "com.spotify.music"
143 | }
144 |
145 | "TuneMyMusic" -> {
146 | sourceEng = "TuneMyMusic"
147 | sourceChn = "TuneMyMusic"
148 | databaseName = "QQMusic"
149 | songListTableName = "User_Folder_table"
150 | songListId = "folderid"
151 | songListName = "foldername"
152 | musicNum = "count"
153 | songListSongInfoTableName = "User_Folder_Song_table"
154 | songListSongInfoPlaylistId = "folderid"
155 | songListSongInfoSongId = "id"
156 | songInfoTableName = "Song_table"
157 | sortField = "position"
158 | songInfoSongId = "id"
159 | songInfoSongName = "name"
160 | songInfoSongArtist = "singername"
161 | songInfoSongAlbum = "albumname"
162 | pakageName = "com.tunemymusic.hwinzniej.idontknow"
163 | }
164 | }
165 | }
166 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/dao/MusicDao.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.Query
6 | import com.hwinzniej.musichelper.data.model.Music
7 | import com.hwinzniej.musichelper.data.model.MusicInfo
8 |
9 | @Dao
10 | interface MusicDao {
11 | @Query("SELECT id, song, artist, album, absolutePath FROM music ORDER BY modifyTime ASC")
12 | fun getAll(): List
13 |
14 | @Query("SELECT id, song, artist, album, absolutePath FROM music WHERE id IN (:selection) ORDER BY modifyTime ASC")
15 | fun getSelectedMusic(selection: List): List
16 |
17 | @Insert
18 | fun insertAll(vararg music: Music)
19 |
20 | @Insert
21 | fun insert(music: Music)
22 |
23 | @Query("DELETE FROM music")
24 | fun deleteAll()
25 |
26 | // @Query("SELECT song, artist, album, releaseYear, trackNumber, albumArtist, genre FROM music")
27 | // fun getMusicInfo(): List
28 |
29 | @Query("SELECT song, artist, album, absolutePath, id, modifyTime, albumArtist FROM music")
30 | fun getMusic3Info(): List
31 |
32 | @Query("SELECT COUNT(*) FROM music")
33 | fun getMusicCount(): Int
34 |
35 | @Query("SELECT song, artist, album, absolutePath, id FROM music WHERE song LIKE :keyword OR artist LIKE :keyword OR album LIKE :keyword LIMIT 3")
36 | fun searchMusic(keyword: String): List
37 |
38 | @Query("SELECT song, artist, album, absolutePath, id FROM music WHERE song LIKE :keyword OR artist LIKE :keyword OR album LIKE :keyword OR absolutePath LIKE :keyword")
39 | fun searchMusicAll(keyword: String): List
40 |
41 | @Query("SELECT song, artist, album, absolutePath, id FROM music WHERE id = :id")
42 | fun getMusicById(id: Int): MusicInfo
43 |
44 | @Query("SELECT song, artist, album, absolutePath, id, albumArtist, genre, trackNumber, releaseYear FROM music WHERE id = :id")
45 | fun getMusicAllInfo(id: Int): MusicInfo
46 |
47 | @Query("UPDATE music SET song = :song, artist = :artist, album = :album, albumArtist = :albumArtist, genre = :genre, trackNumber = :trackNumber, releaseYear = :releaseYear, lyricist = :lyricist, composer = :composer, arranger = :arranger, modifyTime = :modifyTime WHERE id = :id")
48 | fun updateMusicInfo(
49 | id: Int,
50 | song: String,
51 | artist: String,
52 | album: String,
53 | albumArtist: String?,
54 | genre: String?,
55 | trackNumber: String?,
56 | releaseYear: String?,
57 | lyricist: String?,
58 | composer: String?,
59 | arranger: String?,
60 | modifyTime: Long,
61 | )
62 |
63 | @Query(
64 | """
65 | SELECT *
66 | FROM music
67 | WHERE album IN (
68 | SELECT album
69 | FROM music
70 | GROUP BY album
71 | HAVING COUNT(*) >= 2
72 | )
73 | """
74 | )
75 | fun searchDuplicateAlbum(): List
76 |
77 | // @Query(
78 | // """
79 | // SELECT *
80 | // FROM music
81 | // WHERE album IN (
82 | // SELECT album
83 | // FROM music
84 | // WHERE albumArtist IS NULL OR albumArtist = ''
85 | // GROUP BY album
86 | // HAVING COUNT(*) >= 2
87 | // ) AND (albumArtist IS NULL OR albumArtist = '')
88 | // """
89 | // )
90 | @Query("SELECT id, song, artist, album, absolutePath FROM music WHERE albumArtist IS NULL OR albumArtist = '' ORDER BY modifyTime ASC")
91 | fun searchDuplicateAlbumNoOverwrite(): List
92 |
93 | @Query("SELECT id, song, artist, album, absolutePath FROM music WHERE id IN (:selection) AND (albumArtist IS NULL OR albumArtist = '') ORDER BY modifyTime ASC")
94 | fun searchSelectedDuplicateAlbumNoOverwrite(selection: List): List
95 |
96 | @Query("SELECT DISTINCT artist FROM music WHERE album = :album")
97 | fun getDuplicateAlbumArtistList(album: String): List
98 |
99 | @Query("UPDATE music SET albumArtist = :albumArtist, modifyTime = :modifyTime WHERE id = :id")
100 | fun updateAlbumArtist(
101 | id: Int,
102 | albumArtist: String?,
103 | modifyTime: Long
104 | )
105 |
106 | @Query("SELECT COUNT(*) FROM music WHERE albumArtist IS NULL OR albumArtist = ''")
107 | fun countNullAlbumArtist(): Int
108 |
109 | @Query("SELECT COUNT(*) FROM music WHERE id IN (:selection) AND (albumArtist IS NULL OR albumArtist = '')")
110 | fun countSelectedNullAlbumArtist(selection: List): Int
111 |
112 | @Query("SELECT COUNT(*) FROM music WHERE lyricist IS NULL OR lyricist = ''")
113 | fun countNullLyricist(): Int
114 |
115 | @Query("SELECT COUNT(*) FROM music WHERE composer IS NULL OR composer = ''")
116 | fun countNullComposer(): Int
117 |
118 | @Query("SELECT COUNT(*) FROM music WHERE arranger IS NULL OR arranger = ''")
119 | fun countNullArranger(): Int
120 |
121 | @Query("SELECT COUNT(*) FROM music WHERE id IN (:selection) AND (lyricist IS NULL OR lyricist = '')")
122 | fun countSelectedNullLyricist(selection: List): Int
123 |
124 | @Query("SELECT COUNT(*) FROM music WHERE id IN (:selection) AND (composer IS NULL OR composer = '')")
125 | fun countSelectedNullComposer(selection: List): Int
126 |
127 | @Query("SELECT COUNT(*) FROM music WHERE id IN (:selection) AND (arranger IS NULL OR arranger = '')")
128 | fun countSelectedNullArranger(selection: List): Int
129 |
130 | @Query("UPDATE music SET lyricist = :lyricist, composer = :composer, arranger = :arranger, modifyTime = :modifyTime WHERE id = :id")
131 | fun updateLyricistComposerArranger(
132 | id: Int,
133 | lyricist: String?,
134 | composer: String?,
135 | arranger: String?,
136 | modifyTime: Long
137 | )
138 |
139 | // @Insert
140 | // fun updateMusicInfo(musicInfo: MusicInfo)
141 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/database/MusicDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data.database
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import com.hwinzniej.musichelper.data.dao.MusicDao
6 | import com.hwinzniej.musichelper.data.model.Music
7 |
8 | @Database(entities = [Music::class], version = 3, exportSchema = false)
9 | abstract class MusicDatabase : RoomDatabase() {
10 | abstract fun musicDao(): MusicDao
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/model/Music.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity
8 | data class Music(
9 | @PrimaryKey val id: Int,
10 | @ColumnInfo(name = "song") val song: String, //歌名
11 | @ColumnInfo(name = "artist") val artist: String, //歌手
12 | @ColumnInfo(name = "album") val album: String, //专辑
13 | @ColumnInfo(name = "absolutePath") val absolutePath: String, //绝对路径
14 | @ColumnInfo(name = "releaseYear") val releaseYear: String, //发行年份
15 | @ColumnInfo(name = "trackNumber") val trackNumber: String, //音轨号
16 | @ColumnInfo(name = "albumArtist") val albumArtist: String, //专辑艺术家
17 | @ColumnInfo(name = "genre") val genre: String, //风格(流派)
18 | @ColumnInfo(name = "lyricist") val lyricist: String, //作词
19 | @ColumnInfo(name = "composer") val composer: String, //作曲
20 | @ColumnInfo(name = "arranger") val arranger: String, //编曲
21 | @ColumnInfo(name = "modifyTime") val modifyTime: Long //修改时间
22 | )
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/data/model/MusicInfo.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.data.model
2 |
3 | class MusicInfo(
4 | val id: Int,
5 | var song: String,
6 | var artist: String,
7 | var album: String,
8 | var releaseYear: String?,
9 | var trackNumber: String?,
10 | var albumArtist: String?,
11 | var genre: String?,
12 | var absolutePath: String,
13 | var lyricist: String?,
14 | var composer: String?,
15 | var arranger: String?,
16 | var modifyTime: Long?
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/ui/UnlockPageUi.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.ui
2 |
3 | import android.widget.Toast
4 | import androidx.activity.compose.BackHandler
5 | import androidx.compose.animation.AnimatedContent
6 | import androidx.compose.animation.AnimatedVisibility
7 | import androidx.compose.animation.fadeIn
8 | import androidx.compose.animation.fadeOut
9 | import androidx.compose.animation.togetherWith
10 | import androidx.compose.foundation.background
11 | import androidx.compose.foundation.layout.Box
12 | import androidx.compose.foundation.layout.Column
13 | import androidx.compose.foundation.layout.fillMaxSize
14 | import androidx.compose.foundation.layout.fillMaxWidth
15 | import androidx.compose.foundation.layout.heightIn
16 | import androidx.compose.foundation.layout.padding
17 | import androidx.compose.foundation.lazy.LazyColumn
18 | import androidx.compose.foundation.rememberScrollState
19 | import androidx.compose.foundation.shape.RoundedCornerShape
20 | import androidx.compose.foundation.verticalScroll
21 | import androidx.compose.material3.LinearProgressIndicator
22 | import androidx.compose.runtime.Composable
23 | import androidx.compose.runtime.LaunchedEffect
24 | import androidx.compose.runtime.MutableIntState
25 | import androidx.compose.runtime.MutableState
26 | import androidx.compose.runtime.getValue
27 | import androidx.compose.runtime.mutableStateOf
28 | import androidx.compose.runtime.remember
29 | import androidx.compose.runtime.setValue
30 | import androidx.compose.ui.Modifier
31 | import androidx.compose.ui.draw.clip
32 | import androidx.compose.ui.graphics.StrokeCap
33 | import androidx.compose.ui.platform.LocalConfiguration
34 | import androidx.compose.ui.platform.LocalContext
35 | import androidx.compose.ui.res.colorResource
36 | import androidx.compose.ui.res.stringResource
37 | import androidx.compose.ui.unit.dp
38 | import androidx.compose.ui.unit.sp
39 | import androidx.compose.ui.zIndex
40 | import com.hwinzniej.musichelper.R
41 | import com.hwinzniej.musichelper.activity.SettingsPage
42 | import com.hwinzniej.musichelper.activity.UnlockPage
43 | import com.moriafly.salt.ui.ItemContainer
44 | import com.moriafly.salt.ui.RoundedColumn
45 | import com.moriafly.salt.ui.SaltTheme
46 | import com.moriafly.salt.ui.Text
47 |
48 | @Composable
49 | fun UnlockPageUi(
50 | unlockPage: UnlockPage,
51 | enableHaptic: MutableState,
52 | settingsPage: SettingsPage,
53 | hapticStrength: MutableIntState
54 | ) {
55 | val context = LocalContext.current
56 | var inputPath by remember { mutableStateOf("") }
57 | var outputPath by remember { mutableStateOf("") }
58 | var deleteEncryptedFile by remember { mutableStateOf(false) }
59 | var overwriteOutputFile by remember { mutableStateOf(true) }
60 | var umSupportOverWrite by remember { mutableStateOf(false) }
61 | var showInputOutputPathNotSameDialog by remember { mutableStateOf(false) }
62 |
63 | BackHandler(enabled = unlockPage.showLoadingProgressBar.value) {
64 | Toast.makeText(
65 | context,
66 | context.getString(R.string.wait_operate_end),
67 | Toast.LENGTH_SHORT
68 | ).show()
69 | }
70 |
71 | LaunchedEffect(key1 = settingsPage.umSupportOverWrite.value) {
72 | umSupportOverWrite = settingsPage.umSupportOverWrite.value
73 | }
74 |
75 | LaunchedEffect(key1 = unlockPage.selectedInputPath.value) {
76 | inputPath = unlockPage.selectedInputPath.value
77 | }
78 |
79 | LaunchedEffect(key1 = unlockPage.selectedOutputPath.value) {
80 | outputPath = unlockPage.selectedOutputPath.value
81 | }
82 |
83 | if (unlockPage.showUmStdoutDialog.value) {
84 | YesDialog(
85 | onDismissRequest = { unlockPage.showUmStdoutDialog.value = false },
86 | title = stringResource(id = R.string.um_stdout),
87 | content = null,
88 | enableHaptic = enableHaptic.value,
89 | hapticStrength = hapticStrength.intValue
90 | ) {
91 | ItemContainer {
92 | LazyColumn(
93 | modifier = Modifier
94 | .fillMaxWidth()
95 | .heightIn(
96 | min = 25.dp,
97 | max = (LocalConfiguration.current.screenHeightDp / 2.55).dp
98 | )
99 | .clip(RoundedCornerShape(12.dp))
100 | .background(color = SaltTheme.colors.subBackground)
101 | ) {
102 | items(unlockPage.operateResult.size) { index ->
103 | Text(
104 | modifier = Modifier.padding(
105 | horizontal = 16.dp,
106 | vertical = 4.dp
107 | ),
108 | text = unlockPage.operateResult[index].keys.first(),
109 | fontSize = 14.sp,
110 | color = if (unlockPage.operateResult[index].values.first())
111 | SaltTheme.colors.subText
112 | else
113 | colorResource(id = R.color.unmatched),
114 | )
115 | }
116 | }
117 | }
118 | }
119 | }
120 |
121 | if (showInputOutputPathNotSameDialog) {
122 | YesDialog(
123 | onDismissRequest = {
124 | showInputOutputPathNotSameDialog = false
125 | },
126 | title = stringResource(id = R.string.error),
127 | content = if (inputPath.isBlank() || outputPath.isBlank())
128 | stringResource(id = R.string.input_and_output_path_cant_null)
129 | else
130 | stringResource(id = R.string.input_output_path_cant_same),
131 | fontSize = 14.sp,
132 | enableHaptic = enableHaptic.value,
133 | hapticStrength = hapticStrength.intValue
134 | )
135 | }
136 |
137 | Column(
138 | modifier = Modifier
139 | .fillMaxSize()
140 | .background(color = SaltTheme.colors.background)
141 | ) {
142 | TitleBar(
143 | onBack = {},
144 | text = stringResource(id = R.string.unlock_function_name) + if (settingsPage.umFileLegal.value)
145 | ""
146 | else
147 | stringResource(id = R.string.unavailable),
148 | showBackBtn = false
149 | )
150 | Box {
151 | if (unlockPage.showLoadingProgressBar.value) {
152 | LinearProgressIndicator(
153 | modifier = Modifier
154 | .fillMaxWidth()
155 | .zIndex(1f),
156 | color = SaltTheme.colors.highlight,
157 | trackColor = SaltTheme.colors.background,
158 | strokeCap = StrokeCap.Square
159 | )
160 | }
161 | Column(
162 | modifier = Modifier
163 | .fillMaxSize()
164 | .background(color = SaltTheme.colors.background)
165 | .verticalScroll(rememberScrollState())
166 | ) {
167 | RoundedColumn {
168 | ItemTitle(text = stringResource(id = R.string.input_options))
169 | Item(
170 | enabled = settingsPage.umFileLegal.value,
171 | text = stringResource(id = R.string.select_the_directory_for_input_files),
172 | onClick = {
173 | unlockPage.selectInputDir()
174 | }
175 | )
176 | AnimatedVisibility(
177 | visible = inputPath != ""
178 | ) {
179 | ItemValue(
180 | text = stringResource(R.string.you_have_selected),
181 | rightSub = inputPath
182 | )
183 | }
184 | ItemSwitcher(
185 | enabled = settingsPage.umFileLegal.value,
186 | state = deleteEncryptedFile,
187 | onChange = {
188 | deleteEncryptedFile = it
189 | unlockPage.deleteOriginalFile.value = it
190 | },
191 | text = stringResource(id = R.string.delete_input_file),
192 | sub = stringResource(id = R.string.delete_input_file_sub),
193 | enableHaptic = enableHaptic.value,
194 | hapticStrength = hapticStrength.intValue
195 | )
196 | }
197 | RoundedColumn {
198 | ItemTitle(text = stringResource(id = R.string.output_options))
199 | Item(
200 | enabled = settingsPage.umFileLegal.value,
201 | text = stringResource(id = R.string.select_the_directory_for_output_files),
202 | onClick = {
203 | unlockPage.selectOutputDir()
204 | }
205 | )
206 | AnimatedVisibility(
207 | visible = outputPath != ""
208 | ) {
209 | ItemValue(
210 | text = stringResource(R.string.you_have_selected),
211 | rightSub = outputPath
212 | )
213 | }
214 | ItemSwitcher(
215 | enabled = umSupportOverWrite && settingsPage.umFileLegal.value,
216 | state = overwriteOutputFile && umSupportOverWrite && settingsPage.umFileLegal.value,
217 | onChange = {
218 | overwriteOutputFile = it
219 | unlockPage.overwriteOutputFile.value = it
220 | },
221 | text = stringResource(id = R.string.overwrite_output_file),
222 | sub = if (umSupportOverWrite) stringResource(id = R.string.overwrite_output_file_sub)
223 | else if (settingsPage.umFileLegal.value) stringResource(id = R.string.current_um_not_support_this_fun) else "" + "\n" +
224 | stringResource(id = R.string.overwrite_output_file_sub),
225 | enableHaptic = enableHaptic.value,
226 | hapticStrength = hapticStrength.intValue
227 | )
228 | }
229 | AnimatedContent(
230 | targetState = unlockPage.showLoadingProgressBar.value,
231 | label = "",
232 | transitionSpec = {
233 | fadeIn() togetherWith fadeOut()
234 | }) {
235 | ItemContainer {
236 | TextButton(
237 | onClick = {
238 | if ((inputPath == outputPath) || (inputPath.isBlank() || outputPath.isBlank())) {
239 | showInputOutputPathNotSameDialog = true
240 | } else {
241 | unlockPage.requestPermission()
242 | }
243 | }, text = stringResource(R.string.start_text),
244 | enabled = !it && settingsPage.umFileLegal.value,
245 | enableHaptic = enableHaptic.value,
246 | hapticStrength = hapticStrength.intValue
247 | )
248 | }
249 | }
250 | }
251 | }
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.ui.theme
2 |
3 | import android.app.Activity
4 | import android.os.Build
5 | import androidx.compose.foundation.isSystemInDarkTheme
6 | import androidx.compose.material3.MaterialTheme
7 | import androidx.compose.material3.darkColorScheme
8 | import androidx.compose.material3.dynamicDarkColorScheme
9 | import androidx.compose.material3.dynamicLightColorScheme
10 | import androidx.compose.material3.lightColorScheme
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.SideEffect
13 | import androidx.compose.ui.graphics.toArgb
14 | import androidx.compose.ui.platform.LocalContext
15 | import androidx.compose.ui.platform.LocalView
16 | import androidx.core.view.WindowCompat
17 |
18 | private val DarkColorScheme = darkColorScheme(
19 | primary = Purple80,
20 | secondary = PurpleGrey80,
21 | tertiary = Pink80
22 | )
23 |
24 | private val LightColorScheme = lightColorScheme(
25 | primary = Purple40,
26 | secondary = PurpleGrey40,
27 | tertiary = Pink40
28 |
29 | /* Other default colors to override
30 | background = Color(0xFFFFFBFE),
31 | surface = Color(0xFFFFFBFE),
32 | onPrimary = Color.White,
33 | onSecondary = Color.White,
34 | onTertiary = Color.White,
35 | onBackground = Color(0xFF1C1B1F),
36 | onSurface = Color(0xFF1C1B1F),
37 | */
38 | )
39 |
40 | @Composable
41 | fun MusicHelperTheme(
42 | darkTheme: Boolean = isSystemInDarkTheme(),
43 | // Dynamic color is available on Android 12+
44 | dynamicColor: Boolean = true,
45 | content: @Composable () -> Unit
46 | ) {
47 | val colorScheme = when {
48 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
49 | val context = LocalContext.current
50 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
51 | }
52 |
53 | darkTheme -> DarkColorScheme
54 | else -> LightColorScheme
55 | }
56 | val view = LocalView.current
57 | if (!view.isInEditMode) {
58 | SideEffect {
59 | val window = (view.context as Activity).window
60 | window.statusBarColor = colorScheme.primary.toArgb()
61 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
62 | }
63 | }
64 |
65 | MaterialTheme(
66 | colorScheme = colorScheme,
67 | typography = Typography,
68 | content = content
69 | )
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | )
18 | /* Other default text styles to override
19 | titleLarge = TextStyle(
20 | fontFamily = FontFamily.Default,
21 | fontWeight = FontWeight.Normal,
22 | fontSize = 22.sp,
23 | lineHeight = 28.sp,
24 | letterSpacing = 0.sp
25 | ),
26 | labelSmall = TextStyle(
27 | fontFamily = FontFamily.Default,
28 | fontWeight = FontWeight.Medium,
29 | fontSize = 11.sp,
30 | lineHeight = 16.sp,
31 | letterSpacing = 0.5.sp
32 | )
33 | */
34 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/utils/DoubanMusicApi.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.utils
2 | //
3 | //import com.hwinzniej.musichelper.data.model.MusicInfo
4 | //import okhttp3.OkHttpClient
5 | //import okio.IOException
6 | //import org.htmlunit.WebClient
7 | //import org.htmlunit.html.HtmlPage
8 | //import org.jsoup.Jsoup
9 | //
10 | //class DoubanMusicApi {
11 | // companion object {
12 | // fun getMusicInfo(musicName: String, artistName: String, albumName: String): MusicInfo? {
13 | //
14 | // val url = "https://search.douban.com/music/subject_search?search_text=Moon halo"
15 | //// val url =
16 | //// "https://music.douban.com/subject_search?search_text=要嫁就嫁灰太狼 周艳泓"
17 | //
18 | // val webClient = WebClient().apply {
19 | // options.isCssEnabled = false
20 | // options.isJavaScriptEnabled = true
21 | // options.isThrowExceptionOnScriptError = false
22 | // options.isThrowExceptionOnFailingStatusCode = false
23 | // }
24 | //
25 | // webClient.waitForBackgroundJavaScript(500) // 等待JavaScript执行完成
26 | // val htmlPage: HtmlPage = webClient.getPage(url)
27 | //
28 | // val musicInfoPage =
29 | // "https://music.douban.com/subject/[0-9]*/".toRegex().find(htmlPage.asXml())?.value
30 | //
31 | // val client = OkHttpClient()
32 | // val request = okhttp3.Request.Builder()
33 | // .url(musicInfoPage.toString())
34 | // .build()
35 | //
36 | // client.newCall(request).execute().use { response ->
37 | // if (!response.isSuccessful) throw IOException("Unexpected code $response")
38 | //
39 | // val doc = Jsoup.parse(response.body?.string())
40 | // val title = doc.title()
41 | //
42 | // println("Title: $title")
43 | // }
44 | //
45 | // return null
46 | // }
47 | // }
48 | //}
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/utils/MyDataStore.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.utils
2 |
3 | import android.app.Application
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.Preferences
6 | import androidx.datastore.preferences.preferencesDataStore
7 | import com.hwinzniej.musichelper.data.DataStoreConstants
8 |
9 | class MyDataStore : Application() {
10 | val dataStore: DataStore by preferencesDataStore(name = DataStoreConstants.SETTINGS_PREFERENCES)
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hwinzniej/musichelper/utils/MyVibrationEffect.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper.utils
2 |
3 | import android.content.Context
4 | import android.os.VibrationEffect
5 | import android.os.Vibrator
6 |
7 | class MyVibrationEffect(
8 | context: Context,
9 | private val enable: Boolean,
10 | private val strength: Int
11 | ) {
12 | private val vibrator: Vibrator = context.getSystemService(Vibrator::class.java)
13 |
14 | fun dialog() {
15 | if (enable) {
16 | val vibrationEffect =
17 | VibrationEffect.createWaveform(
18 | longArrayOf(
19 | (18 + (strength - 3) * 3).toLong(),
20 | 100,
21 | (13 + (strength - 3) * 3).toLong()
22 | ),
23 | intArrayOf(200 + (strength - 3) * 15, 0, 120 + (strength - 3) * 15),
24 | -1
25 | )
26 | vibrator.vibrate(vibrationEffect)
27 | }
28 | }
29 |
30 | fun click() {
31 | if (enable) {
32 | val vibrationEffect =
33 | VibrationEffect.createOneShot(
34 | (12 + (strength - 3) * 3).toLong(),
35 | 180 + (strength - 3) * 15
36 | )
37 | vibrator.vibrate(vibrationEffect)
38 | }
39 | }
40 |
41 | fun turnOn() {
42 | if (enable) {
43 | val vibrationEffect =
44 | VibrationEffect.createWaveform(
45 | longArrayOf(
46 | (12 + (strength - 3) * 3).toLong(),
47 | 130,
48 | (18 + (strength - 3) * 3).toLong()
49 | ),
50 | intArrayOf(110 + (strength - 3) * 15, 0, 180 + (strength - 3) * 15),
51 | -1
52 | )
53 | vibrator.vibrate(vibrationEffect)
54 | }
55 | }
56 |
57 | fun turnOff() {
58 | if (enable) {
59 | val vibrationEffect =
60 | VibrationEffect.createWaveform(
61 | longArrayOf(
62 | (18 + (strength - 3) * 3).toLong(),
63 | 130,
64 | (12 + (strength - 3) * 3).toLong()
65 | ),
66 | intArrayOf(180 + (strength - 3) * 15, 0, 110 + (strength - 3) * 15),
67 | -1
68 | )
69 | vibrator.vibrate(vibrationEffect)
70 | }
71 | }
72 |
73 | fun done() {
74 | if (enable) {
75 | val vibrationEffect =
76 | VibrationEffect.createOneShot(
77 | (20 + (strength - 3) * 3).toLong(),
78 | 225 + (strength - 3) * 15
79 | )
80 | vibrator.vibrate(vibrationEffect)
81 | }
82 | }
83 |
84 | fun dragMove() {
85 | if (enable) {
86 | val vibrationEffect =
87 | VibrationEffect.createOneShot(
88 | (10 + (strength - 3) * 3).toLong(),
89 | 220 + (strength - 3) * 15
90 | )
91 | vibrator.vibrate(vibrationEffect)
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/about.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/agreement.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
20 |
26 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/alipay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/drawable/alipay.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/all.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/android.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/aplayer.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/auto_check_update.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bilibili.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/caution.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/check_update.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chinese.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cloudmusic.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/coffee.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/color.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
16 |
20 |
24 |
28 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/complete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/computer.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/convert.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cookie.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/coolapk.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/csv_file.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dark_color.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/database.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/developer.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/english.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gitee.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/github.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gitlab.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/haptic.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/home_screen.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_drop_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_right.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_clear.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_border_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
19 |
27 |
33 |
41 |
49 |
57 |
64 |
72 |
80 |
88 |
96 |
104 |
112 |
120 |
124 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
16 |
20 |
24 |
28 |
31 |
32 |
39 |
42 |
45 |
48 |
49 |
50 |
51 |
59 |
67 |
73 |
81 |
89 |
97 |
104 |
112 |
120 |
128 |
136 |
144 |
152 |
160 |
164 |
168 |
172 |
176 |
180 |
184 |
188 |
196 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_tips.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_uncheck.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/json_file.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/korean.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/kugou.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/kuwo.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
16 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/language.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/license.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/light_color.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/luna_music.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/manual.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/microsoft_zune.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/network.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/no_items.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/overall.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/plus.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/plus_no_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/poweramp.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/proxy.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/qinalt.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
13 |
17 |
21 |
25 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/qq_group.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/qqmusic.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/refresh.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/result.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/root_access.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/saltplayer.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
17 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/scan.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/server.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sort.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/split.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/spotify.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/success.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tag.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tune_my_music.xml:
--------------------------------------------------------------------------------
1 |
6 |
14 |
22 |
30 |
34 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/um.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/user.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/web_page.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/drawable/wechat.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/wechat_app.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #599E5E
11 | #C94F4F
12 | #3D76A7
13 | #E1A800
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/hwinzniej/musichelper/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.hwinzniej.musichelper
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id("com.android.application") version "8.8.0" apply false
4 | id("com.android.library") version "8.8.0" apply false
5 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false
6 | id("org.jetbrains.kotlin.plugin.compose") version "2.1.0" apply false
7 | id("com.google.devtools.ksp") version "2.1.0-1.0.29" apply false
8 | id("com.cookpad.android.plugin.license-tools") version "1.2.8" // 需要把生成的yml文件放到项目根目录,才能生成license.html
9 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 11 19:31:47 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.10.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/markdownResources/Alipay WeChatPay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/Alipay WeChatPay.jpg
--------------------------------------------------------------------------------
/markdownResources/Questionnaire QR Code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/Questionnaire QR Code.png
--------------------------------------------------------------------------------
/markdownResources/Sponsorship.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/Sponsorship.png
--------------------------------------------------------------------------------
/markdownResources/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/ic_launcher.png
--------------------------------------------------------------------------------
/markdownResources/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/img1.png
--------------------------------------------------------------------------------
/markdownResources/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/img2.png
--------------------------------------------------------------------------------
/markdownResources/img3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Winnie0408/LocalMusicHelper/cf00054963590ee3d10cdef4ea7edc7539923bdb/markdownResources/img3.png
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | // maven { url = uri("https://maven.aliyun.com/repository/central") }
4 | // maven { url = uri("https://maven.aliyun.com/repository/public") }
5 | // maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
6 | // maven { url = uri("https://maven.aliyun.com/repository/apache-snapshots") }
7 | maven { url = uri("https://plugins.gradle.org/m2/") }
8 | maven { url = uri("https://jitpack.io") }
9 | google()
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | // maven { url = uri("https://maven.aliyun.com/repository/central") }
18 | // maven { url = uri("https://maven.aliyun.com/repository/public") }
19 | // maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
20 | // maven { url = uri("https://maven.aliyun.com/repository/apache-snapshots") }
21 | maven { url = uri("https://plugins.gradle.org/m2/") }
22 | maven { url = uri("https://jitpack.io") }
23 | google()
24 | mavenCentral()
25 | }
26 | }
27 |
28 | rootProject.name = "MusicHelper"
29 | include(":app")
30 |
--------------------------------------------------------------------------------