mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-16 15:52:26 +02:00
Update axios requests to nativeHttp, add openid connect auth button
This commit is contained in:
parent
00bed39733
commit
46f558d6e0
14 changed files with 128 additions and 14 deletions
|
@ -36,6 +36,9 @@ android {
|
||||||
versionCode 97
|
versionCode 97
|
||||||
versionName "0.9.66-beta"
|
versionName "0.9.66-beta"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
manifestPlaceholders = [
|
||||||
|
"appAuthRedirectScheme": "com.audiobookshelf.app"
|
||||||
|
]
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(':byteowls-capacitor-oauth2')
|
||||||
implementation project(':capacitor-app')
|
implementation project(':capacitor-app')
|
||||||
implementation project(':capacitor-clipboard')
|
implementation project(':capacitor-clipboard')
|
||||||
implementation project(':capacitor-dialog')
|
implementation project(':capacitor-dialog')
|
||||||
|
|
14
android/app/src/debug/res/values/strings.xml
Normal file
14
android/app/src/debug/res/values/strings.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">audiobookshelf</string>
|
||||||
|
<string name="title_activity_main">audiobookshelf</string>
|
||||||
|
<string name="package_name">com.audiobookshelf.app</string>
|
||||||
|
<string name="custom_url_scheme">com.audiobookshelf.app.debug</string>
|
||||||
|
<string name="add_widget">Add widget</string>
|
||||||
|
<string name="app_widget_description">Simple widget for audiobookshelf playback</string>
|
||||||
|
<string name="action_jump_forward">Jump Forward</string>
|
||||||
|
<string name="action_jump_backward">Jump Backward</string>
|
||||||
|
<string name="action_skip_forward">Skip Forward</string>
|
||||||
|
<string name="action_skip_backward">Skip Backward</string>
|
||||||
|
<string name="action_change_speed">Change Playback Speed</string>
|
||||||
|
</resources>
|
|
@ -1,4 +1,8 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"pkg": "@byteowls/capacitor-oauth2",
|
||||||
|
"classpath": "com.byteowls.capacitor.oauth2.OAuth2ClientPlugin"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pkg": "@capacitor/app",
|
"pkg": "@capacitor/app",
|
||||||
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
include ':capacitor-android'
|
include ':capacitor-android'
|
||||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||||
|
|
||||||
|
include ':byteowls-capacitor-oauth2'
|
||||||
|
project(':byteowls-capacitor-oauth2').projectDir = new File('../node_modules/@byteowls/capacitor-oauth2/android')
|
||||||
|
|
||||||
include ':capacitor-app'
|
include ':capacitor-app'
|
||||||
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
|
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<span v-if="!serverConfig.id" class="material-icons" style="font-size: 1.1rem" @click="editServerAddress">edit</span>
|
<span v-if="!serverConfig.id" class="material-icons" style="font-size: 1.1rem" @click="editServerAddress">edit</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
|
||||||
<form @submit.prevent="submitAuth" class="pt-3">
|
<form v-if="isLocalAuthEnabled" @submit.prevent="submitAuth" class="pt-3">
|
||||||
<ui-text-input v-model="serverConfig.username" :disabled="processing" placeholder="username" class="w-full mb-2 text-lg" />
|
<ui-text-input v-model="serverConfig.username" :disabled="processing" placeholder="username" class="w-full mb-2 text-lg" />
|
||||||
<ui-text-input v-model="password" type="password" :disabled="processing" placeholder="password" class="w-full mb-2 text-lg" />
|
<ui-text-input v-model="password" type="password" :disabled="processing" placeholder="password" class="w-full mb-2 text-lg" />
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@
|
||||||
<ui-btn :disabled="processing || !networkConnected" type="submit" class="mt-1 h-10">{{ networkConnected ? 'Submit' : 'No Internet' }}</ui-btn>
|
<ui-btn :disabled="processing || !networkConnected" type="submit" class="mt-1 h-10">{{ networkConnected ? 'Submit' : 'No Internet' }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<div v-if="isLocalAuthEnabled && isOpenIDAuthEnabled" class="w-full h-px bg-white bg-opacity-10 my-2" />
|
||||||
|
<ui-btn v-if="isOpenIDAuthEnabled" :disabled="processing" class="mt-1 h-10" @click="clickLoginWithOpenId">Login with OpenId</ui-btn>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -78,6 +80,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { Dialog } from '@capacitor/dialog'
|
import { Dialog } from '@capacitor/dialog'
|
||||||
import { CapacitorHttp } from '@capacitor/core'
|
import { CapacitorHttp } from '@capacitor/core'
|
||||||
|
import { OAuth2Client } from '@byteowls/capacitor-oauth2'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
@ -93,7 +96,8 @@ export default {
|
||||||
password: null,
|
password: null,
|
||||||
error: null,
|
error: null,
|
||||||
showForm: false,
|
showForm: false,
|
||||||
showAddCustomHeaders: false
|
showAddCustomHeaders: false,
|
||||||
|
authMethods: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -116,9 +120,51 @@ export default {
|
||||||
numCustomHeaders() {
|
numCustomHeaders() {
|
||||||
if (!this.serverConfig.customHeaders) return 0
|
if (!this.serverConfig.customHeaders) return 0
|
||||||
return Object.keys(this.serverConfig.customHeaders).length
|
return Object.keys(this.serverConfig.customHeaders).length
|
||||||
|
},
|
||||||
|
isLocalAuthEnabled() {
|
||||||
|
return this.authMethods.includes('local') || !this.authMethods.length
|
||||||
|
},
|
||||||
|
isOpenIDAuthEnabled() {
|
||||||
|
return this.authMethods.includes('openid')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async clickLoginWithOpenId() {
|
||||||
|
this.error = ''
|
||||||
|
const options = {
|
||||||
|
authorizationBaseUrl: `${this.serverConfig.address}/auth/openid`,
|
||||||
|
logsEnabled: true,
|
||||||
|
web: {
|
||||||
|
appId: 'com.audiobookshelf.web',
|
||||||
|
responseType: 'token',
|
||||||
|
redirectUrl: location.origin
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
appId: 'com.audiobookshelf.app',
|
||||||
|
responseType: 'code',
|
||||||
|
redirectUrl: 'com.audiobookshelf.app:/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OAuth2Client.authenticate(options)
|
||||||
|
.then(async (response) => {
|
||||||
|
const token = response.authorization_response?.additional_parameters?.setToken || response.authorization_response?.setToken
|
||||||
|
if (token) {
|
||||||
|
this.serverConfig.token = token
|
||||||
|
const payload = await this.authenticateToken()
|
||||||
|
if (payload) {
|
||||||
|
this.setUserAndConnection(payload)
|
||||||
|
} else {
|
||||||
|
this.showAuth = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.error = 'Invalid response: No token'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('OAuth rejected', error)
|
||||||
|
this.error = error.toString?.() || error.message
|
||||||
|
})
|
||||||
|
},
|
||||||
addCustomHeaders() {
|
addCustomHeaders() {
|
||||||
this.showAddCustomHeaders = true
|
this.showAddCustomHeaders = true
|
||||||
},
|
},
|
||||||
|
@ -251,6 +297,23 @@ export default {
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Get request to server /status api endpoint
|
||||||
|
*
|
||||||
|
* @param {string} address
|
||||||
|
* @returns {Promise<{isInit:boolean, language:string, authMethods:string[]}>}
|
||||||
|
*/
|
||||||
|
getServerAddressStatus(address) {
|
||||||
|
return this.getRequest(`${address}/status`).catch((error) => {
|
||||||
|
console.error('Failed to get server status', error)
|
||||||
|
const errorMsg = error.message || error
|
||||||
|
this.error = 'Failed to ping server'
|
||||||
|
if (typeof errorMsg === 'string') {
|
||||||
|
this.error += ` (${errorMsg})`
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
},
|
||||||
pingServerAddress(address, customHeaders) {
|
pingServerAddress(address, customHeaders) {
|
||||||
return this.getRequest(`${address}/ping`, customHeaders)
|
return this.getRequest(`${address}/ping`, customHeaders)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
@ -302,10 +365,18 @@ export default {
|
||||||
this.serverConfig.address = validServerAddress
|
this.serverConfig.address = validServerAddress
|
||||||
this.processing = true
|
this.processing = true
|
||||||
this.error = null
|
this.error = null
|
||||||
|
this.authMethods = []
|
||||||
|
|
||||||
var success = await this.pingServerAddress(this.serverConfig.address, this.serverConfig.customHeaders)
|
const statusData = await this.getServerAddressStatus(this.serverConfig.address)
|
||||||
this.processing = false
|
this.processing = false
|
||||||
if (success) this.showAuth = true
|
if (statusData) {
|
||||||
|
if (!statusData.isInit) {
|
||||||
|
this.error = 'Server is not initialized'
|
||||||
|
} else {
|
||||||
|
this.showAuth = true
|
||||||
|
this.authMethods = statusData.authMethods || []
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async submitAuth() {
|
async submitAuth() {
|
||||||
if (!this.networkConnected) return
|
if (!this.networkConnected) return
|
||||||
|
@ -346,6 +417,7 @@ export default {
|
||||||
|
|
||||||
this.serverConfig.userId = user.id
|
this.serverConfig.userId = user.id
|
||||||
this.serverConfig.token = user.token
|
this.serverConfig.token = user.token
|
||||||
|
this.serverConfig.username = user.username
|
||||||
|
|
||||||
var serverConnectionConfig = await this.$db.setServerConnectionConfig(this.serverConfig)
|
var serverConnectionConfig = await this.$db.setServerConnectionConfig(this.serverConfig)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ install! 'cocoapods', :disable_input_output_paths => true
|
||||||
def capacitor_pods
|
def capacitor_pods
|
||||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||||
|
pod 'ByteowlsCapacitorOauth2', :path => '../../node_modules/@byteowls/capacitor-oauth2'
|
||||||
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
|
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
|
||||||
pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard'
|
pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard'
|
||||||
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'
|
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'
|
||||||
|
|
19
package-lock.json
generated
19
package-lock.json
generated
|
@ -6,8 +6,9 @@
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf-app",
|
"name": "audiobookshelf-app",
|
||||||
"version": "0.9.65-beta",
|
"version": "0.9.66-beta",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@byteowls/capacitor-oauth2": "^5.0.0",
|
||||||
"@capacitor/android": "^5.0.0",
|
"@capacitor/android": "^5.0.0",
|
||||||
"@capacitor/app": "^5.0.0",
|
"@capacitor/app": "^5.0.0",
|
||||||
"@capacitor/clipboard": "^5.0.0",
|
"@capacitor/clipboard": "^5.0.0",
|
||||||
|
@ -1938,6 +1939,14 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@byteowls/capacitor-oauth2": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@byteowls/capacitor-oauth2/-/capacitor-oauth2-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-yW50GypmyPJcH/95NwR2jJcgT78vBN3FYKL2w6A3vrT04bRLQyw2K0fLqfj8Zws6DJy43Ck1wPs0Bcdvbsub7A==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@capacitor/core": ">=5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@capacitor/android": {
|
"node_modules/@capacitor/android": {
|
||||||
"version": "5.4.0",
|
"version": "5.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",
|
||||||
|
@ -21069,6 +21078,12 @@
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@byteowls/capacitor-oauth2": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@byteowls/capacitor-oauth2/-/capacitor-oauth2-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-yW50GypmyPJcH/95NwR2jJcgT78vBN3FYKL2w6A3vrT04bRLQyw2K0fLqfj8Zws6DJy43Ck1wPs0Bcdvbsub7A==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@capacitor/android": {
|
"@capacitor/android": {
|
||||||
"version": "5.4.0",
|
"version": "5.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",
|
||||||
|
@ -34068,4 +34083,4 @@
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"ionic:serve": "npm run start"
|
"ionic:serve": "npm run start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@byteowls/capacitor-oauth2": "^5.0.0",
|
||||||
"@capacitor/android": "^5.0.0",
|
"@capacitor/android": "^5.0.0",
|
||||||
"@capacitor/app": "^5.0.0",
|
"@capacitor/app": "^5.0.0",
|
||||||
"@capacitor/clipboard": "^5.0.0",
|
"@capacitor/clipboard": "^5.0.0",
|
||||||
|
@ -46,4 +47,4 @@
|
||||||
"postcss": "^8.3.5",
|
"postcss": "^8.3.5",
|
||||||
"tailwindcss": "^3.3.2"
|
"tailwindcss": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
async asyncData({ params, app, store, redirect }) {
|
async asyncData({ params, app, store, redirect }) {
|
||||||
var series = await app.$axios.$get(`/api/series/${params.id}`).catch((error) => {
|
var series = await app.$nativeHttp.get(`/api/series/${params.id}`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default {
|
||||||
return redirect(`/connect?redirect=${route.path}`)
|
return redirect(`/connect?redirect=${route.path}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
var collection = await app.$axios.$get(`/api/collections/${params.id}`).catch((error) => {
|
var collection = await app.$nativeHttp.get(`/api/collections/${params.id}`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default {
|
||||||
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
|
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
|
||||||
console.log('Got lli', libraryItemId)
|
console.log('Got lli', libraryItemId)
|
||||||
} else if (store.state.user.serverConnectionConfig) {
|
} else if (store.state.user.serverConnectionConfig) {
|
||||||
libraryItem = await app.$axios.$get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
|
libraryItem = await app.$nativeHttp.get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -150,7 +150,7 @@ export default {
|
||||||
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
|
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
|
||||||
console.log('Got lli', libraryItemId)
|
console.log('Got lli', libraryItemId)
|
||||||
} else if (store.state.user.serverConnectionConfig) {
|
} else if (store.state.user.serverConnectionConfig) {
|
||||||
libraryItem = await app.$axios.$get(`/api/items/${libraryItemId}?expanded=1&include=rssfeed`).catch((error) => {
|
libraryItem = await app.$nativeHttp.get(`/api/items/${libraryItemId}?expanded=1&include=rssfeed`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default {
|
||||||
return redirect(`/connect?redirect=${route.path}`)
|
return redirect(`/connect?redirect=${route.path}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const playlist = await app.$axios.$get(`/api/playlists/${params.id}`).catch((error) => {
|
const playlist = await app.$nativeHttp.get(`/api/playlists/${params.id}`).catch((error) => {
|
||||||
console.error('Failed', error)
|
console.error('Failed', error)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue