Skip to content

Commit

Permalink
Merge branch 'feature/local-playback' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mikooomich committed May 22, 2024
2 parents 3d42526 + ca320c9 commit 180bb85
Show file tree
Hide file tree
Showing 64 changed files with 4,953 additions and 527 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ lint/tmp/

.DS_Store
/app/release/
app/src/main/java/com/dd3boh/outertune/utils/scanners/jni/ffmpeg-android-maker
app/src/main/java/com/dd3boh/outertune/utils/scanners/jni/src/
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ A Material 3 YouTube Music client for Android
- Library management
- Cache and download songs for offline playback
- Personalized quick picks
- Synchronized lyrics
- Local media playback
- Multi artist support (non MediaStore tag extractor)
- Synchronized lyrics (LRC format, also includes multi-line support)
- Audio normalization, tempo/pitch adjustment, and various other audio effects
- Dynamic Material theme & localization
- New integrated library screen design
Expand Down Expand Up @@ -60,6 +62,23 @@ recommend [Pano Scrobbler](https://play.google.com/store/apps/details?id=com.arn
Follow the [instructions](https://developer.android.com/guide/topics/resources/localization) and
create a pull request. If possible, please build the app beforehand and make sure there is no error
before you create a pull request.
./app/src/main/java/com/dd3boh/outertune/utils/scanners/jni/ffmpeg-android-maker
## Building with FFmpeg (non-kit)

By default, we shit a prebuilt library (`/app/prebuilt/ffMetadataEx.arr`), and you *do not* need to care about this.
However, should you choose to opt for self built libraries and/or work on the extractor itself, keep reading:

1. First you will need to setup the [Android NDK](https://developer.android.com/studio/projects/install-ndk)

2. We use FFMpeg to extract metadata from local files. The FFMpeg (non-kit) implementation must be resolved in one of two ways:

- a) Build libraries. Clone [ffmpeg-android-maker](https://github.com/Javernaut/ffmpeg-android-maker) into `/ffMetadataEx/src/main/cpp/ffmpeg-android-maker`, run the build script. Note: It may be helpful to modify the FFmpeg build script disable uneeded FFmpeg fetaures to reduce app size, see [here](https://github.com/mikooomich/ffmpeg-android-maker/blob/master/scripts/ffmpeg/build.sh) for an example.

- b) Use prebuilt FFmpeg libraries. Clone [prebuilt ffmpeg-android-maker](https://github.com/mikooomich/ffmpeg-android-maker) into `/ffMetadataEx/src/main/cpp/ffmpeg-android-maker`.

3. Modify `app/build.gradle.kts` and `settings.gradle.kts` to switch to the self built version, with the instructions being in both of the files

Then start the build are you normally would.

## Donate

Expand Down
Empty file removed app/CMakeLists.txt
Empty file.
12 changes: 11 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ android {

defaultConfig {
applicationId = "com.dd3boh.outertune"
minSdk = 21
minSdk = 24
targetSdk = 34
versionCode = 19
versionName = "0.5.3"
Expand Down Expand Up @@ -120,4 +120,14 @@ dependencies {
coreLibraryDesugaring(libs.desugaring)

implementation(libs.timber)

/**
* Custom FFmpeg metadata extractor
*
* My boss has requested prebuilt libraries by default. Shall you choose
* to work on the scanner itself, switch the implementation below AND
* include the project (uncomment the include line) in /settings.gradle.kts
*/
implementation(files("prebuilt/ffMetadataEx-release.aar")) // prebuilt
// implementation(project(":ffMetadataEx")) // self built
}
Binary file added app/prebuilt/ffMetadataEx-release.aar
Binary file not shown.
46 changes: 40 additions & 6 deletions app/schemas/com.dd3boh.outertune.db.InternalDatabase/1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "ffcb09ea8afcb091239f073ebc021c7e",
"identityHash": "8be7f629fa3d0170044e19ffbe1669a9",
"entities": [
{
"tableName": "song",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `duration` INTEGER NOT NULL, `thumbnailUrl` TEXT, `albumId` TEXT, `albumName` TEXT, `liked` INTEGER NOT NULL, `likedDate` INTEGER, `totalPlayTime` INTEGER NOT NULL, `inLibrary` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `duration` INTEGER NOT NULL, `thumbnailUrl` TEXT, `albumId` TEXT, `albumName` TEXT, `liked` INTEGER NOT NULL, `likedDate` INTEGER, `totalPlayTime` INTEGER NOT NULL, `inLibrary` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, `localPath` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -67,6 +67,19 @@
"columnName": "inLibrary",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "localPath",
"columnName": "localPath",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
Expand All @@ -90,7 +103,7 @@
},
{
"tableName": "artist",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT, `channelId` TEXT, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT, `channelId` TEXT, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -127,6 +140,13 @@
"columnName": "bookmarkedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand All @@ -140,7 +160,7 @@
},
{
"tableName": "album",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlistId` TEXT, `title` TEXT NOT NULL, `year` INTEGER, `thumbnailUrl` TEXT, `themeColor` INTEGER, `songCount` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlistId` TEXT, `title` TEXT NOT NULL, `year` INTEGER, `thumbnailUrl` TEXT, `themeColor` INTEGER, `songCount` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -201,6 +221,13 @@
"columnName": "bookmarkedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand All @@ -214,7 +241,7 @@
},
{
"tableName": "playlist",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `browseId` TEXT, `isEditable` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `thumbnailUrl` TEXT, `remoteSongCount` INTEGER, `playEndpointParams` TEXT, `shuffleEndpointParams` TEXT, `radioEndpointParams` TEXT, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `browseId` TEXT, `isEditable` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `thumbnailUrl` TEXT, `remoteSongCount` INTEGER, `playEndpointParams` TEXT, `shuffleEndpointParams` TEXT, `radioEndpointParams` TEXT, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -275,6 +302,13 @@
"columnName": "radioEndpointParams",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand Down Expand Up @@ -878,7 +912,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ffcb09ea8afcb091239f073ebc021c7e')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8be7f629fa3d0170044e19ffbe1669a9')"
]
}
}
46 changes: 37 additions & 9 deletions app/schemas/com.dd3boh.outertune.db.InternalDatabase/13.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 13,
"identityHash": "322eee64a08c3369d4dec5dbd7c2efee",
"identityHash": "3158aac19867a81982b62ce3e0528ff4",
"entities": [
{
"tableName": "song",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `duration` INTEGER NOT NULL, `thumbnailUrl` TEXT, `albumId` TEXT, `albumName` TEXT, `liked` INTEGER NOT NULL, `likedDate` INTEGER, `totalPlayTime` INTEGER NOT NULL, `inLibrary` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `duration` INTEGER NOT NULL, `thumbnailUrl` TEXT, `albumId` TEXT, `albumName` TEXT, `liked` INTEGER NOT NULL, `likedDate` INTEGER, `totalPlayTime` INTEGER NOT NULL, `inLibrary` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, `localPath` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -67,6 +67,19 @@
"columnName": "inLibrary",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "localPath",
"columnName": "localPath",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
Expand All @@ -90,7 +103,7 @@
},
{
"tableName": "artist",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT, `channelId` TEXT, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT, `channelId` TEXT, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -127,6 +140,13 @@
"columnName": "bookmarkedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand All @@ -140,7 +160,7 @@
},
{
"tableName": "album",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlistId` TEXT, `title` TEXT NOT NULL, `year` INTEGER, `thumbnailUrl` TEXT, `themeColor` INTEGER, `songCount` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlistId` TEXT, `title` TEXT NOT NULL, `year` INTEGER, `thumbnailUrl` TEXT, `themeColor` INTEGER, `songCount` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `lastUpdateTime` INTEGER NOT NULL, `bookmarkedAt` INTEGER, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -201,6 +221,13 @@
"columnName": "bookmarkedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand All @@ -214,7 +241,7 @@
},
{
"tableName": "playlist",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `browseId` TEXT, `isEditable` INTEGER, `bookmarkedAt` INTEGER, `thumbnailUrl` TEXT, `remoteSongCount` INTEGER, `playEndpointParams` TEXT, `shuffleEndpointParams` TEXT, `radioEndpointParams` TEXT, `test` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `browseId` TEXT, `isEditable` INTEGER, `bookmarkedAt` INTEGER, `thumbnailUrl` TEXT, `remoteSongCount` INTEGER, `playEndpointParams` TEXT, `shuffleEndpointParams` TEXT, `radioEndpointParams` TEXT, `isLocal` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -277,10 +304,11 @@
"notNull": false
},
{
"fieldPath": "test",
"columnName": "test",
"fieldPath": "isLocal",
"columnName": "isLocal",
"affinity": "INTEGER",
"notNull": true
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
Expand Down Expand Up @@ -884,7 +912,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '322eee64a08c3369d4dec5dbd7c2efee')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3158aac19867a81982b62ce3e0528ff4')"
]
}
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />

<queries>
<intent>
Expand Down
Loading

0 comments on commit 180bb85

Please sign in to comment.