uninstalling extensions implemented

This commit is contained in:
Aria Moradi 2021-01-29 15:23:29 +03:30
parent 99316f4bd5
commit 832c224ed4
4 changed files with 84 additions and 40 deletions

View File

@ -17,6 +17,7 @@ import ir.armor.tachidesk.util.getSource
import ir.armor.tachidesk.util.getSourceList import ir.armor.tachidesk.util.getSourceList
import ir.armor.tachidesk.util.getThumbnail import ir.armor.tachidesk.util.getThumbnail
import ir.armor.tachidesk.util.installAPK import ir.armor.tachidesk.util.installAPK
import ir.armor.tachidesk.util.removeExtension
import ir.armor.tachidesk.util.sourceFilters import ir.armor.tachidesk.util.sourceFilters
import ir.armor.tachidesk.util.sourceGlobalSearch import ir.armor.tachidesk.util.sourceGlobalSearch
import ir.armor.tachidesk.util.sourceSearch import ir.armor.tachidesk.util.sourceSearch
@ -79,11 +80,20 @@ class Main {
app.get("/api/v1/extension/install/:apkName") { ctx -> app.get("/api/v1/extension/install/:apkName") { ctx ->
val apkName = ctx.pathParam("apkName") val apkName = ctx.pathParam("apkName")
println(apkName) println("installing $apkName")
ctx.status( ctx.status(
installAPK(apkName) installAPK(apkName)
) )
} }
app.get("/api/v1/extension/uninstall/:apkName") { ctx ->
val apkName = ctx.pathParam("apkName")
println("uninstalling $apkName")
removeExtension(apkName)
ctx.status(200)
}
app.get("/api/v1/source/list") { ctx -> app.get("/api/v1/source/list") { ctx ->
ctx.json(getSourceList()) ctx.json(getSourceList())
} }

View File

@ -66,28 +66,28 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
println("${mangaEntry[MangaTable.title]} is initialized") println("${mangaEntry[MangaTable.title]} is initialized")
println("${mangaEntry[MangaTable.thumbnail_url]}") println("${mangaEntry[MangaTable.thumbnail_url]}")
MangaDataClass( MangaDataClass(
mangaId, mangaId,
mangaEntry[MangaTable.sourceReference].value, mangaEntry[MangaTable.sourceReference].value,
mangaEntry[MangaTable.url], mangaEntry[MangaTable.url],
mangaEntry[MangaTable.title], mangaEntry[MangaTable.title],
if (proxyThumbnail) proxyThumbnailUrl(mangaId) else mangaEntry[MangaTable.thumbnail_url], if (proxyThumbnail) proxyThumbnailUrl(mangaId) else mangaEntry[MangaTable.thumbnail_url],
true, true,
mangaEntry[MangaTable.artist], mangaEntry[MangaTable.artist],
mangaEntry[MangaTable.author], mangaEntry[MangaTable.author],
mangaEntry[MangaTable.description], mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre], mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name, MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
) )
} else { // initialize manga } else { // initialize manga
val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value) val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value)
val fetchedManga = source.fetchMangaDetails( val fetchedManga = source.fetchMangaDetails(
SManga.create().apply { SManga.create().apply {
url = mangaEntry[MangaTable.url] url = mangaEntry[MangaTable.url]
title = mangaEntry[MangaTable.title] title = mangaEntry[MangaTable.title]
} }
).toBlocking().first() ).toBlocking().first()
// update database // update database
@ -97,25 +97,25 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
// mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! // mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!!
val newThumbnail = val newThumbnail =
if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty()) { if (fetchedManga.thumbnail_url != null && fetchedManga.thumbnail_url!!.isNotEmpty()) {
fetchedManga.thumbnail_url fetchedManga.thumbnail_url
} else mangaEntry[MangaTable.thumbnail_url] } else mangaEntry[MangaTable.thumbnail_url]
MangaDataClass( MangaDataClass(
mangaId, mangaId,
mangaEntry[MangaTable.sourceReference].value, mangaEntry[MangaTable.sourceReference].value,
mangaEntry[MangaTable.url], mangaEntry[MangaTable.url],
mangaEntry[MangaTable.title], mangaEntry[MangaTable.title],
if (proxyThumbnail) proxyThumbnailUrl(mangaId) else newThumbnail, if (proxyThumbnail) proxyThumbnailUrl(mangaId) else newThumbnail,
true, true,
fetchedManga.artist, fetchedManga.artist,
fetchedManga.author, fetchedManga.author,
fetchedManga.description, fetchedManga.description,
fetchedManga.genre, fetchedManga.genre,
MangaStatus.valueOf(fetchedManga.status).name, MangaStatus.valueOf(fetchedManga.status).name,
) )
} }
} }
@ -135,8 +135,8 @@ fun getThumbnail(mangaId: Int): Pair<InputStream, String> {
if (potentialCache != null) { if (potentialCache != null) {
println("using cached thumbnail file") println("using cached thumbnail file")
return@transaction Pair( return@transaction Pair(
pathToInputStream(potentialCache), pathToInputStream(potentialCache),
"image/${potentialCache.substringAfter("$mangaId.")}" "image/${potentialCache.substringAfter("$mangaId.")}"
) )
} }
@ -149,7 +149,7 @@ fun getThumbnail(mangaId: Int): Pair<InputStream, String> {
} }
println(thumbnailUrl) println(thumbnailUrl)
val response = source.client.newCall( val response = source.client.newCall(
GET(thumbnailUrl, source.headers) GET(thumbnailUrl, source.headers)
).execute() ).execute()
println(response.code) println(response.code)
@ -161,8 +161,8 @@ fun getThumbnail(mangaId: Int): Pair<InputStream, String> {
writeStream(response.body!!.byteStream(), filePath) writeStream(response.body!!.byteStream(), filePath)
return@transaction Pair( return@transaction Pair(
pathToInputStream(filePath), pathToInputStream(filePath),
contentType contentType
) )
} else { } else {
throw Exception("request error! ${response.code}") throw Exception("request error! ${response.code}")

View File

@ -17,6 +17,7 @@ import kotlinx.coroutines.runBlocking
import okhttp3.Request import okhttp3.Request
import okio.buffer import okio.buffer
import okio.sink import okio.sink
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
@ -32,8 +33,8 @@ fun installAPK(apkName: String): Int {
val dirPathWithoutType = "${Config.extensionsRoot}/$fileNameWithoutType" val dirPathWithoutType = "${Config.extensionsRoot}/$fileNameWithoutType"
// check if we don't have the dex file already downloaded // check if we don't have the dex file already downloaded
val dexPath = "${Config.extensionsRoot}/$fileNameWithoutType.jar" val jarPath = "${Config.extensionsRoot}/$fileNameWithoutType.jar"
if (!File(dexPath).exists()) { if (!File(jarPath).exists()) {
runBlocking { runBlocking {
val api = ExtensionGithubApi() val api = ExtensionGithubApi()
val apkToDownload = api.getApkUrl(extensionRecord) val apkToDownload = api.getApkUrl(extensionRecord)
@ -130,3 +131,21 @@ private fun downloadAPKFile(url: String, apkPath: String) {
sink.writeAll(response.body!!.source()) sink.writeAll(response.body!!.source())
sink.close() sink.close()
} }
fun removeExtension(pkgName: String) {
val extensionRecord = getExtensionList(true).first { it.apkName == pkgName }
val fileNameWithoutType = pkgName.substringBefore(".apk")
val jarPath = "${Config.extensionsRoot}/$fileNameWithoutType.jar"
transaction {
val extensionId = ExtensionsTable.select { ExtensionsTable.name eq extensionRecord.name }.first()[ExtensionsTable.id]
SourceTable.deleteWhere { SourceTable.extension eq extensionId }
ExtensionsTable.update({ ExtensionsTable.name eq extensionRecord.name }) {
it[ExtensionsTable.installed] = false
}
}
if (File(jarPath).exists()) {
File(jarPath).delete()
}
}

View File

@ -46,7 +46,7 @@ export default function ExtensionCard(props: IProps) {
name, lang, versionName, iconUrl, installed, apkName, name, lang, versionName, iconUrl, installed, apkName,
}, },
} = props; } = props;
const [installedState, setInstalledState] = useState<string>((installed ? 'installed' : 'install')); const [installedState, setInstalledState] = useState<string>((installed ? 'uninstall' : 'install'));
const classes = useStyles(); const classes = useStyles();
const langPress = lang === 'all' ? 'All' : lang.toUpperCase(); const langPress = lang === 'all' ? 'All' : lang.toUpperCase();
@ -54,10 +54,25 @@ export default function ExtensionCard(props: IProps) {
function install() { function install() {
setInstalledState('installing'); setInstalledState('installing');
fetch(`http://127.0.0.1:4567/api/v1/extension/install/${apkName}`).then(() => { fetch(`http://127.0.0.1:4567/api/v1/extension/install/${apkName}`).then(() => {
setInstalledState('installed'); setInstalledState('uninstall');
}); });
} }
function uninstall() {
setInstalledState('uninstalling');
fetch(`http://127.0.0.1:4567/api/v1/extension/uninstall/${apkName}`).then(() => {
setInstalledState('install');
});
}
function handleButtonClick() {
if (installedState === 'install') {
install();
} else {
uninstall();
}
}
return ( return (
<Card> <Card>
<CardContent className={classes.root}> <CardContent className={classes.root}>
@ -80,7 +95,7 @@ export default function ExtensionCard(props: IProps) {
</div> </div>
</div> </div>
<Button variant="outlined" onClick={() => install()}>{installedState}</Button> <Button variant="outlined" onClick={() => handleButtonClick()}>{installedState}</Button>
</CardContent> </CardContent>
</Card> </Card>
); );