mirror of
https://gitlab.com/mangadex-pub/mangadex_at_home.git
synced 2024-01-19 02:48:37 +00:00
Remove webui
This commit is contained in:
parent
821cc85776
commit
76cf90e31d
|
@ -41,6 +41,14 @@ dependencies {
|
|||
|
||||
implementation "info.picocli:picocli:4.5.0"
|
||||
kapt "info.picocli:picocli-codegen:4.5.0"
|
||||
|
||||
testImplementation "io.kotest:kotest-runner-junit5:$kotest_version"
|
||||
testImplementation "io.kotest:kotest-assertions-core:$kotest_version"
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
kapt {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
http_4k_version=3.284.0
|
||||
exposed_version=0.26.2
|
||||
exposed_version=0.26.2
|
||||
kotest_version=4.4.0.RC1
|
|
@ -28,9 +28,7 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
|||
import mdnet.base.Main.dieWithError
|
||||
import mdnet.base.cache.ImageStorage
|
||||
import mdnet.base.logging.*
|
||||
import mdnet.base.server.getUiServer
|
||||
import mdnet.base.settings.*
|
||||
import org.http4k.server.Http4kServer
|
||||
import org.ktorm.database.Database
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
|
@ -57,7 +55,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
|
||||
// state that must only be accessed from the thread on the executor
|
||||
private var imageServer: ServerManager? = null
|
||||
private var webUi: Http4kServer? = null
|
||||
// end protected state
|
||||
|
||||
init {
|
||||
|
@ -99,23 +96,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
)
|
||||
|
||||
startImageServer()
|
||||
startWebUi()
|
||||
}
|
||||
|
||||
// Precondition: settings must be filled with up-to-date settings and `imageServer` must not be null
|
||||
private fun startWebUi() {
|
||||
settings.webSettings?.let { webSettings ->
|
||||
val imageServer = requireNotNull(imageServer)
|
||||
|
||||
if (webUi != null) {
|
||||
throw AssertionError()
|
||||
}
|
||||
LOGGER.info { "WebUI starting" }
|
||||
webUi = getUiServer(webSettings, imageServer.statistics, imageServer.statsMap).also {
|
||||
it.start()
|
||||
}
|
||||
LOGGER.info { "WebUI started" }
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition: settings must be filled with up-to-date settings
|
||||
|
@ -137,13 +117,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
LOGGER.info { "Server manager stopped" }
|
||||
}
|
||||
|
||||
private fun stopWebUi() {
|
||||
LOGGER.info { "WebUI stopping" }
|
||||
requireNotNull(webUi).stop()
|
||||
webUi = null
|
||||
LOGGER.info { "WebUI stopped" }
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
LOGGER.info { "Mangadex@Home Client shutting down" }
|
||||
val latch = CountDownLatch(1)
|
||||
|
@ -152,15 +125,11 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
|
||||
executor.schedule(
|
||||
{
|
||||
if (webUi != null) {
|
||||
stopWebUi()
|
||||
}
|
||||
if (imageServer != null) {
|
||||
stopImageServer()
|
||||
}
|
||||
|
||||
storage.close()
|
||||
|
||||
latch.countDown()
|
||||
},
|
||||
0, TimeUnit.SECONDS
|
||||
|
@ -193,25 +162,11 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
val restartServer = newSettings.serverSettings != settings.serverSettings ||
|
||||
newSettings.devSettings != settings.devSettings
|
||||
|
||||
val stopWebUi = restartServer || newSettings.webSettings != settings.webSettings
|
||||
val startWebUi = stopWebUi && newSettings.webSettings != null
|
||||
|
||||
if (stopWebUi) {
|
||||
LOGGER.info { "Stopping WebUI to reload ClientSettings" }
|
||||
if (webUi != null) {
|
||||
stopWebUi()
|
||||
}
|
||||
}
|
||||
|
||||
if (restartServer) {
|
||||
stopImageServer()
|
||||
startImageServer()
|
||||
}
|
||||
|
||||
if (startWebUi) {
|
||||
startWebUi()
|
||||
}
|
||||
|
||||
settings = newSettings
|
||||
} catch (e: UnrecognizedPropertyException) {
|
||||
LOGGER.warn { "Settings file is invalid: '$e.propertyName' is not a valid setting" }
|
||||
|
@ -256,11 +211,6 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
|||
throw ClientSettingsException("Config Error: Graceful shutdown wait must be >= 15")
|
||||
}
|
||||
}
|
||||
settings.webSettings?.let {
|
||||
if (it.port == 0) {
|
||||
throw ClientSettingsException("Config Error: Invalid UI port number")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun readClientSettings(): ClientSettings {
|
||||
|
|
|
@ -132,10 +132,7 @@ class ServerHandler(
|
|||
}
|
||||
|
||||
private fun getServerAddress(): String {
|
||||
return if (!devSettings.isDev)
|
||||
SERVER_ADDRESS
|
||||
else
|
||||
SERVER_ADDRESS_DEV
|
||||
return devSettings.devUrl ?: SERVER_ADDRESS
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -143,6 +140,5 @@ class ServerHandler(
|
|||
private val STRING_ANY_MAP_LENS = Body.auto<Map<String, Any>>().toLens()
|
||||
private val SERVER_SETTINGS_LENS = Body.auto<RemoteSettings>().toLens()
|
||||
private const val SERVER_ADDRESS = "https://api.mangadex.network/"
|
||||
private const val SERVER_ADDRESS_DEV = "https://mangadex-test.net/"
|
||||
}
|
||||
}
|
||||
|
|
66
src/main/kotlin/mdnet/base/cache/ImageStorage.kt
vendored
66
src/main/kotlin/mdnet/base/cache/ImageStorage.kt
vendored
|
@ -49,7 +49,7 @@ data class Image(val data: ImageMetadata, val stream: InputStream)
|
|||
*
|
||||
* @constructor Creates an `ImageStorage`, creating necessary tables in the database.
|
||||
*/
|
||||
class ImageStorage(var maxSize: Long, private val cacheDirectory: Path, private val database: Database) {
|
||||
class ImageStorage(var maxSize: Long, private val cacheDirectory: Path, private val database: Database, autoPrune: Boolean = true) {
|
||||
private val evictor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
|
||||
private val queue = LinkedBlockingQueue<String>()
|
||||
/**
|
||||
|
@ -71,7 +71,6 @@ class ImageStorage(var maxSize: Long, private val cacheDirectory: Path, private
|
|||
|
||||
// clear any files that have been writing or reading
|
||||
// and are still in the database for some reason
|
||||
// FIXME: also run this regularly based on access times
|
||||
val iter = database.from(DbImage)
|
||||
.select(DbImage.id)
|
||||
.where { DbImage.lock notEq DbImageLock.UNLOCKED }
|
||||
|
@ -109,40 +108,51 @@ class ImageStorage(var maxSize: Long, private val cacheDirectory: Path, private
|
|||
1, 1, TimeUnit.MINUTES
|
||||
)
|
||||
|
||||
evictor.scheduleWithFixedDelay(
|
||||
{
|
||||
size = calculateSize()
|
||||
if (autoPrune) {
|
||||
evictor.scheduleWithFixedDelay(
|
||||
{
|
||||
pruneImages()
|
||||
},
|
||||
0, 3, TimeUnit.MINUTES
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info { "Cache at $size out of $maxSize bytes" }
|
||||
// we need to prune the cache now
|
||||
if (size > maxSize * 0.95) {
|
||||
val toClear = size - (maxSize * 0.9).toLong()
|
||||
LOGGER.info { "Evicting at least $toClear bytes from cache" }
|
||||
/**
|
||||
* Prunes excess images from the cache in order to meet
|
||||
* the [maxSize] property and not waste disk space.
|
||||
*/
|
||||
fun pruneImages() {
|
||||
val size = calculateSize()
|
||||
this.size = size
|
||||
|
||||
val list = database.useConnection { conn ->
|
||||
conn.prepareStatement(IMAGES_TO_PRUNE).apply {
|
||||
setLong(1, toClear)
|
||||
}.use { stmt ->
|
||||
stmt.executeQuery().let {
|
||||
val ret = ArrayList<String>()
|
||||
LOGGER.info { "Cache at $size out of $maxSize bytes" }
|
||||
// we need to prune the cache now
|
||||
if (size > maxSize * 0.95) {
|
||||
val toClear = size - (maxSize * 0.9).toLong()
|
||||
LOGGER.info { "Evicting at least $toClear bytes from cache" }
|
||||
|
||||
while (it.next()) {
|
||||
ret.add(it.getString(1))
|
||||
}
|
||||
val list = database.useConnection { conn ->
|
||||
conn.prepareStatement(IMAGES_TO_PRUNE).apply {
|
||||
setLong(1, toClear)
|
||||
}.use { stmt ->
|
||||
stmt.executeQuery().let {
|
||||
val ret = ArrayList<String>()
|
||||
|
||||
ret
|
||||
}
|
||||
while (it.next()) {
|
||||
ret.add(it.getString(1))
|
||||
}
|
||||
}
|
||||
|
||||
for (id in list) {
|
||||
LOGGER.info { "Evicting images $id from cache" }
|
||||
deleteImage(id)
|
||||
ret
|
||||
}
|
||||
}
|
||||
},
|
||||
0, 3, TimeUnit.MINUTES
|
||||
)
|
||||
}
|
||||
|
||||
for (id in list) {
|
||||
LOGGER.info { "Evicting images $id from cache" }
|
||||
deleteImage(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -116,9 +116,8 @@ class Netty(private val tls: TlsCert, private val serverSettings: ServerSettings
|
|||
LOGGER.info { "User (downloader) abruptly closed the connection" }
|
||||
LOGGER.trace(cause) { "Exception in pipeline" }
|
||||
} else if (cause !is ReadTimeoutException && cause !is WriteTimeoutException) {
|
||||
// ctx.fireExceptionCaught(cause)
|
||||
ctx.fireExceptionCaught(cause)
|
||||
}
|
||||
ctx.fireExceptionCaught(cause)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -83,11 +83,6 @@ class ImageServer(
|
|||
"/data"
|
||||
} + "/$chapterHash/$fileName"
|
||||
|
||||
if (!request.referrerMatches(ALLOWED_REFERER_DOMAINS)) {
|
||||
LOGGER.info { "Request for $sanitizedUri rejected due to non-allowed referrer ${request.header("Referer")}" }
|
||||
return@then Response(Status.FORBIDDEN)
|
||||
}
|
||||
|
||||
if (remoteSettings.forceTokens && !isTestImage(chapterHash)) {
|
||||
val tokenArr = try {
|
||||
val toDecode = try {
|
||||
|
@ -152,21 +147,6 @@ class ImageServer(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters referrers based on passed (sub)domains. Ignores `scheme` (protocol) in URL
|
||||
*/
|
||||
private fun Request.referrerMatches(allowedDomains: List<String>, permitBlank: Boolean = true): Boolean {
|
||||
val referer = this.header("Referer") ?: return permitBlank // Referrer was misspelled as "Referer" and now we're stuck with it -_-
|
||||
if (referer == "") return permitBlank
|
||||
|
||||
return allowedDomains.any {
|
||||
referer.substringAfter("//") // Ignore scheme
|
||||
.substringBefore("/") // Ignore path
|
||||
.substringBefore(":")
|
||||
.endsWith(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Request.handleCacheHit(sanitizedUri: String, image: Image): Response {
|
||||
// our files never change, so it's safe to use the browser cache
|
||||
return if (this.header("If-Modified-Since") != null) {
|
||||
|
@ -283,7 +263,6 @@ class ImageServer(
|
|||
private val JACKSON: ObjectMapper = jacksonObjectMapper()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
.registerModule(JavaTimeModule())
|
||||
private val ALLOWED_REFERER_DOMAINS = listOf("mangadex.org", "mangadex.network") // TODO: Factor out hardcoded domains?
|
||||
|
||||
private fun baseHandler(): Filter =
|
||||
CachingFilters.Response.MaxAge(Clock.systemUTC(), Constants.MAX_AGE_CACHE)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
Mangadex@Home
|
||||
Copyright (c) 2020, MangaDex Network
|
||||
This file is part of MangaDex@Home.
|
||||
|
||||
MangaDex@Home is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
MangaDex@Home is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this MangaDex@Home. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* ktlint-disable no-wildcard-imports */
|
||||
package mdnet.base.server
|
||||
|
||||
import mdnet.base.data.Statistics
|
||||
import mdnet.base.netty.WebUiNetty
|
||||
import mdnet.base.settings.WebSettings
|
||||
import org.http4k.core.Body
|
||||
import org.http4k.core.Method
|
||||
import org.http4k.core.Response
|
||||
import org.http4k.core.Status
|
||||
import org.http4k.core.then
|
||||
import org.http4k.filter.ServerFilters
|
||||
import org.http4k.format.Jackson.auto
|
||||
import org.http4k.routing.ResourceLoader
|
||||
import org.http4k.routing.bind
|
||||
import org.http4k.routing.routes
|
||||
import org.http4k.routing.singlePageApp
|
||||
import org.http4k.server.Http4kServer
|
||||
import org.http4k.server.asServer
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
fun getUiServer(
|
||||
webSettings: WebSettings,
|
||||
statistics: AtomicReference<Statistics>,
|
||||
statsMap: Map<Instant, Statistics>
|
||||
): Http4kServer {
|
||||
val statsMapLens = Body.auto<Map<Instant, Statistics>>().toLens()
|
||||
|
||||
return catchAllHideDetails()
|
||||
.then(ServerFilters.CatchLensFailure)
|
||||
.then(addCommonHeaders())
|
||||
.then(
|
||||
routes(
|
||||
"/api/stats" bind Method.GET to {
|
||||
statsMapLens(mapOf(Instant.now() to statistics.get()), Response(Status.OK))
|
||||
},
|
||||
"/api/pastStats" bind Method.GET to {
|
||||
synchronized(statsMap) {
|
||||
statsMapLens(statsMap, Response(Status.OK))
|
||||
}
|
||||
},
|
||||
singlePageApp(ResourceLoader.Classpath("/webui"))
|
||||
)
|
||||
)
|
||||
.asServer(WebUiNetty(webSettings.hostname, webSettings.port))
|
||||
}
|
|
@ -25,9 +25,8 @@ import dev.afanasev.sekret.Secret
|
|||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
data class ClientSettings(
|
||||
val maxCacheSizeInMebibytes: Long = 20480,
|
||||
val devSettings: DevSettings = DevSettings(isDev = false),
|
||||
val devSettings: DevSettings = DevSettings(),
|
||||
val serverSettings: ServerSettings = ServerSettings(),
|
||||
val webSettings: WebSettings? = null,
|
||||
)
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
|
@ -42,13 +41,7 @@ data class ServerSettings(
|
|||
val threads: Int = 4,
|
||||
)
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
data class WebSettings(
|
||||
val hostname: String = "127.0.0.1",
|
||||
val port: Int = 8080
|
||||
)
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
|
||||
data class DevSettings(
|
||||
val isDev: Boolean = false
|
||||
val devUrl: String? = null
|
||||
)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<configuration>
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
|
||||
<!-- <level>${file-level:-WARN}</level>-->
|
||||
<!-- </filter>-->
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>${file-level:-WARN}</level>
|
||||
</filter>
|
||||
|
||||
<file>log/latest.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
|
@ -32,7 +32,6 @@
|
|||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
|
||||
<logger name="org." level="ERROR"/>
|
||||
<logger name="io.netty" level="INFO"/>
|
||||
<logger name="org.apache" level="WARN"/>
|
||||
<logger name="org.apache.hc.client5" level="ERROR"/>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.vue-resizable-handle{background-image:none!important}.xterm{font-feature-settings:"liga" 0;position:relative;-moz-user-select:none;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm{cursor:text}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:.5}.xterm-underline{text-decoration:underline}.xterm ::-webkit-scrollbar{width:7px}.xterm ::-webkit-scrollbar-track{background-color:transparent}.xterm ::-webkit-scrollbar-thumb{background-color:#fff}
|
|
@ -1 +0,0 @@
|
|||
.echarts{width:600px;height:400px}
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +0,0 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 215 B |
|
@ -1 +0,0 @@
|
|||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="favicon.ico"><![endif]--><title>MD@H Client</title><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css><script src=https://cdn.jsdelivr.net/npm/echarts@4.1.0/dist/echarts.js></script><script src=https://cdn.jsdelivr.net/npm/vue-echarts@4.0.2></script><script src=https://unpkg.com/xterm@4.0.0/lib/xterm.js></script><link rel=text/css href=node_modules/xterm/css/xterm.css><link href=css/chunk-7577183e.6dc57fe0.css rel=prefetch><link href=js/chunk-7577183e.d6d29bcc.js rel=prefetch><link href=css/app.14a6e628.css rel=preload as=style><link href=css/chunk-vendors.b02cf67a.css rel=preload as=style><link href=js/app.ede7edb7.js rel=preload as=script><link href=js/chunk-vendors.1256013f.js rel=preload as=script><link href=css/chunk-vendors.b02cf67a.css rel=stylesheet><link href=css/app.14a6e628.css rel=stylesheet><link rel=icon type=image/png sizes=32x32 href=img/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=img/icons/favicon-16x16.png><link rel=manifest href=manifest.json><meta name=theme-color content=#f79421><meta name=apple-mobile-web-app-capable content=yes><meta name=apple-mobile-web-app-status-bar-style content=black><meta name=apple-mobile-web-app-title content="MD@H Client Interface"><link rel=apple-touch-icon href=img/icons/apple-touch-icon-152x152.png><link rel=mask-icon href=img/icons/safari-pinned-tab.svg color=#f79421><meta name=msapplication-TileImage content=img/icons/msapplication-icon-144x144.png><meta name=msapplication-TileColor content=#000000></head><body style="overflow: hidden"><noscript><div style="background-color: #0980e8; position: absolute; top: 0; left: 0; width: 100%; height: 100%; user-select: none"><div style="position: absolute; top: 15%; left: 20%; width: 60%; font-family: Segoe UI; color: white;"><p style="font-size: 180px; margin: 0">:(</p><p style="font-size: 30px; margin-top: 50px">It appears that you don't have javascript enabled.<br>This isn't a big deal, but it just means that you've killed my wonderful web UI.<br>How evil of you...</p><p style="font-size: 10px; margin-top: 10px">Really though ;-;<br>I put in a lot of work and I'm very sad that you choose to disable the one thing that I needed :/</p></div></div></noscript><div id=app></div><script src=js/chunk-vendors.1256013f.js></script><script src=js/app.ede7edb7.js></script></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
{"name":"MD@H Client Interface","short_name":"MD@H","theme_color":"#f79421","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":"","display":"standalone","background_color":"#000000"}
|
|
@ -1,38 +0,0 @@
|
|||
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
||||
{
|
||||
"revision": "bb309837f2cf709edac5",
|
||||
"url": "css/app.14a6e628.css"
|
||||
},
|
||||
{
|
||||
"revision": "f9df31735412a9a525ef",
|
||||
"url": "css/chunk-7577183e.6dc57fe0.css"
|
||||
},
|
||||
{
|
||||
"revision": "027724770bde7ff56e58",
|
||||
"url": "css/chunk-vendors.b02cf67a.css"
|
||||
},
|
||||
{
|
||||
"revision": "7968686572fffa22fa9bdf28cc308706",
|
||||
"url": "index.html"
|
||||
},
|
||||
{
|
||||
"revision": "bb309837f2cf709edac5",
|
||||
"url": "js/app.ede7edb7.js"
|
||||
},
|
||||
{
|
||||
"revision": "f9df31735412a9a525ef",
|
||||
"url": "js/chunk-7577183e.d6d29bcc.js"
|
||||
},
|
||||
{
|
||||
"revision": "027724770bde7ff56e58",
|
||||
"url": "js/chunk-vendors.1256013f.js"
|
||||
},
|
||||
{
|
||||
"revision": "134416f208a045e960280cbf5c867e5c",
|
||||
"url": "manifest.json"
|
||||
},
|
||||
{
|
||||
"revision": "b6216d61c03e6ce0c9aea6ca7808f7ca",
|
||||
"url": "robots.txt"
|
||||
}
|
||||
]);
|
|
@ -1,2 +0,0 @@
|
|||
User-agent: *
|
||||
Disallow:
|
|
@ -1,3 +0,0 @@
|
|||
importScripts("precache-manifest.9917f0a006705c9b6b6c1abfab436c1f.js", "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
|
||||
|
||||
|
Loading…
Reference in a new issue