diff --git a/src/en/brewingscans/AndroidManifest.xml b/src/en/brewingscans/AndroidManifest.xml
new file mode 100644
index 000000000..30deb7f79
--- /dev/null
+++ b/src/en/brewingscans/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/en/brewingscans/build.gradle b/src/en/brewingscans/build.gradle
new file mode 100644
index 000000000..c9fd1d7e6
--- /dev/null
+++ b/src/en/brewingscans/build.gradle
@@ -0,0 +1,14 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlinx-serialization'
+
+ext {
+ extName = 'Brewing Scans'
+ pkgNameSuffix = 'en.brewingscans'
+ extClass = '.BrewingScans'
+ extVersionCode = 1
+ libVersion = '1.2'
+ containsNsfw = true
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/en/brewingscans/res/mipmap-hdpi/ic_launcher.png b/src/en/brewingscans/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..6f484fa6d
Binary files /dev/null and b/src/en/brewingscans/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/en/brewingscans/res/mipmap-mdpi/ic_launcher.png b/src/en/brewingscans/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..8c921e48e
Binary files /dev/null and b/src/en/brewingscans/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/en/brewingscans/res/mipmap-xhdpi/ic_launcher.png b/src/en/brewingscans/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..cd489c562
Binary files /dev/null and b/src/en/brewingscans/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/en/brewingscans/res/mipmap-xxhdpi/ic_launcher.png b/src/en/brewingscans/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..25e1bc7eb
Binary files /dev/null and b/src/en/brewingscans/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/en/brewingscans/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/brewingscans/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..623bc5994
Binary files /dev/null and b/src/en/brewingscans/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/en/brewingscans/res/web_hi_res_512.png b/src/en/brewingscans/res/web_hi_res_512.png
new file mode 100644
index 000000000..d78b6769f
Binary files /dev/null and b/src/en/brewingscans/res/web_hi_res_512.png differ
diff --git a/src/en/brewingscans/src/eu/kanade/tachiyomi/extension/en/brewingscans/BrewingScans.kt b/src/en/brewingscans/src/eu/kanade/tachiyomi/extension/en/brewingscans/BrewingScans.kt
new file mode 100644
index 000000000..30582e5e5
--- /dev/null
+++ b/src/en/brewingscans/src/eu/kanade/tachiyomi/extension/en/brewingscans/BrewingScans.kt
@@ -0,0 +1,107 @@
+package eu.kanade.tachiyomi.extension.en.brewingscans
+
+import eu.kanade.tachiyomi.annotations.Nsfw
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.asObservableSuccess
+import eu.kanade.tachiyomi.source.model.FilterList
+import eu.kanade.tachiyomi.source.model.MangasPage
+import eu.kanade.tachiyomi.source.model.Page
+import eu.kanade.tachiyomi.source.model.SChapter
+import eu.kanade.tachiyomi.source.model.SManga
+import eu.kanade.tachiyomi.source.online.HttpSource
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
+import okhttp3.Response
+import uy.kohesive.injekt.injectLazy
+
+@Nsfw class BrewingScans : HttpSource() {
+ override val lang = "en"
+
+ override val name = "Brewing Scans"
+
+ override val baseUrl = "https://www.brewingscans.com"
+
+ override val supportsLatest = false
+
+ private val json by injectLazy()
+
+ override fun popularMangaRequest(page: Int) =
+ GET("$baseUrl/api/series", headers)
+
+ // Request the frontend URL for the webview
+ override fun mangaDetailsRequest(manga: SManga) =
+ GET("$baseUrl/menu/${manga.url}", headers)
+
+ override fun chapterListRequest(manga: SManga) =
+ GET("$baseUrl/api/series/${manga.url}", headers)
+
+ override fun pageListRequest(chapter: SChapter) =
+ GET("$baseUrl/api/series/${chapter.url}", headers)
+
+ override fun popularMangaParse(response: Response) =
+ response.toMangasPage { sortedByDescending { it.view_count } }
+
+ override fun pageListParse(response: Response) =
+ json.decodeFromString>(response.body!!.string())
+ .mapIndexed { idx, url -> Page(idx, "", url) }
+
+ override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
+ client.newCall(popularMangaRequest(page)).asObservableSuccess().map { res ->
+ res.toMangasPage { filter { it.title.contains(query, true) } }
+ }!!
+
+ override fun fetchMangaDetails(manga: SManga) =
+ client.newCall(chapterListRequest(manga)).asObservableSuccess().map { res ->
+ val series = json.decodeFromString(res.body!!.string())
+ manga.description = series.description
+ manga.author = series.author
+ manga.artist = series.artist
+ manga.genre = series.genres?.joinToString()
+ manga.status = SManga.UNKNOWN
+ manga.initialized = true
+ return@map manga
+ }!!
+
+ override fun fetchChapterList(manga: SManga) =
+ client.newCall(chapterListRequest(manga)).asObservableSuccess().map { res ->
+ json.decodeFromString(res.body!!.string()).chapters.map {
+ SChapter.create().apply {
+ url = "${manga.url}/chapter/${it.key}"
+ chapter_number = it.key.toFloat()
+ name = it.value
+ }
+ }
+ }!!
+
+ private inline fun Response.toMangasPage(
+ crossinline func: Collection.() -> List) =
+ json.decodeFromString