diff --git a/src/all/manga18me/build.gradle b/src/all/manga18me/build.gradle
new file mode 100644
index 000000000..59b8f4fff
--- /dev/null
+++ b/src/all/manga18me/build.gradle
@@ -0,0 +1,9 @@
+ext {
+    extName = 'Manga18Me'
+    extClass = '.M18MFactory'
+    extVersionCode = 1
+    isNsfw = true
+}
+
+apply from: "$rootDir/common.gradle"
+
diff --git a/src/all/manga18me/res/mipmap-hdpi/ic_launcher.png b/src/all/manga18me/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..566ee3d55
Binary files /dev/null and b/src/all/manga18me/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/all/manga18me/res/mipmap-mdpi/ic_launcher.png b/src/all/manga18me/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..fd08ca6a7
Binary files /dev/null and b/src/all/manga18me/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/all/manga18me/res/mipmap-xhdpi/ic_launcher.png b/src/all/manga18me/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..c3206829f
Binary files /dev/null and b/src/all/manga18me/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/all/manga18me/res/mipmap-xxhdpi/ic_launcher.png b/src/all/manga18me/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..7e28fedf7
Binary files /dev/null and b/src/all/manga18me/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/all/manga18me/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/manga18me/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..2980765d5
Binary files /dev/null and b/src/all/manga18me/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Filters.kt b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Filters.kt
new file mode 100644
index 000000000..56887ac01
--- /dev/null
+++ b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Filters.kt
@@ -0,0 +1,84 @@
+package eu.kanade.tachiyomi.extension.all.manga18me
+
+import eu.kanade.tachiyomi.source.model.Filter
+import eu.kanade.tachiyomi.source.model.FilterList
+
+fun getFilters(): FilterList {
+    return FilterList(
+        Filter.Header(name = "The filter is ignored when using text search."),
+        GenreFilter("Genre", getGenresList),
+        SortFilter("Sort", getSortsList),
+        RawFilter("Raw"),
+        CompletedFilter("Completed"),
+    )
+}
+
+/** Filters **/
+
+internal class GenreFilter(name: String, genreList: List<Pair<String, String>>, state: Int = 0) :
+    SelectFilter(name, genreList, state)
+
+internal class SortFilter(name: String, sortList: List<Pair<String, String>>, state: Int = 0) :
+    SelectFilter(name, sortList, state)
+
+internal class CompletedFilter(name: String) : CheckBoxFilter(name)
+
+internal class RawFilter(name: String) : CheckBoxFilter(name)
+
+internal open class CheckBoxFilter(name: String, val value: String = "") : Filter.CheckBox(name)
+
+internal open class SelectFilter(name: String, private val vals: List<Pair<String, String>>, state: Int = 0) :
+    Filter.Select<String>(name, vals.map { it.first }.toTypedArray(), state) {
+    fun getValue() = vals[state].second
+}
+
+/** Filters Data **/
+private val getGenresList: List<Pair<String, String>> = listOf(
+    Pair("Manga", "manga"),
+    Pair("Drama", "drama"),
+    Pair("Mature", "mature"),
+    Pair("Romance", "romance"),
+    Pair("Adult", "adult"),
+    Pair("Hentai", "hentai"),
+    Pair("Comedy", "comedy"),
+    Pair("Ecchi", "ecchi"),
+    Pair("School Life", "school-life"),
+    Pair("Shounen", "shounen"),
+    Pair("Slice of Life", "slice-of-life"),
+    Pair("Seinen", "seinen"),
+    Pair("Yuri", "yuri"),
+    Pair("Action", "action"),
+    Pair("Fantasy", "fantasy"),
+    Pair("Harem", "harem"),
+    Pair("Supernatural", "supernatural"),
+    Pair("Sci-Fi", "sci-fi"),
+    Pair("Isekai", "isekai"),
+    Pair("Shoujo", "shoujo"),
+    Pair("Horror", "horror"),
+    Pair("Psychological", "psychological"),
+    Pair("Smut", "smut"),
+    Pair("Tragedy", "tragedy"),
+    Pair("Raw", "raw"),
+    Pair("Historical", "historical"),
+    Pair("Adventure", "adventure"),
+    Pair("Martial Arts", "martial-arts"),
+    Pair("Manhwa", "manhwa"),
+    Pair("Manhua", "manhua"),
+    Pair("Mystery", "mystery"),
+    Pair("BL", "bl"),
+    Pair("Yaoi", "yaoi"),
+    Pair("Gender Bender", "gender-bender"),
+    Pair("Thriller", "thriller"),
+    Pair("Josei", "josei"),
+    Pair("Sports", "sports"),
+    Pair("GL", "gl"),
+    Pair("Family", "family"),
+    Pair("Magic", "magic"),
+)
+
+private val getSortsList: List<Pair<String, String>> = listOf(
+    Pair("Latest", "latest"),
+    Pair("A-Z", "alphabet"),
+    Pair("Rating", "rating"),
+    Pair("Trending", "trending"),
+)
diff --git a/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/M18MFactory.kt b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/M18MFactory.kt
new file mode 100644
index 000000000..a2c0e2d53
--- /dev/null
+++ b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/M18MFactory.kt
@@ -0,0 +1,12 @@
+package eu.kanade.tachiyomi.extension.all.manga18me
+
+import eu.kanade.tachiyomi.source.Source
+import eu.kanade.tachiyomi.source.SourceFactory
+
+class M18MFactory : SourceFactory {
+    override fun createSources(): List<Source> =
+        listOf(
+            Manga18Me("all"),
+            Manga18Me("en"),
+        )
+}
diff --git a/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Manga18Me.kt b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Manga18Me.kt
new file mode 100644
index 000000000..bef68bcfc
--- /dev/null
+++ b/src/all/manga18me/src/eu/kanade/tachiyomi/extension/all/manga18me/Manga18Me.kt
@@ -0,0 +1,194 @@
+package eu.kanade.tachiyomi.extension.all.manga18me
+
+import eu.kanade.tachiyomi.network.GET
+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.ParsedHttpSource
+import eu.kanade.tachiyomi.util.asJsoup
+import okhttp3.Headers
+import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.Request
+import okhttp3.Response
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+import java.lang.Exception
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+open class Manga18Me(override val lang: String) : ParsedHttpSource() {
+
+    override val name = "Manga18.me"
+
+    override val baseUrl = "https://manga18.me"
+
+    override val supportsLatest = true
+
+    override val client = network.cloudflareClient
+
+    override fun headersBuilder() = Headers.Builder().apply {
+        add("Referer", "$baseUrl/")
+    }
+
+    override fun popularMangaRequest(page: Int): Request {
+        return GET("$baseUrl/manga/$page?orderby=trending", headers)
+    }
+
+    override fun popularMangaParse(response: Response): MangasPage {
+        val document = response.asJsoup()
+
+        val entries = document.select(popularMangaSelector())
+        val hasNextPage = document.selectFirst(popularMangaNextPageSelector()) != null
+
+        if (lang == "en") {
+            val searchText = document.selectFirst("div.section-heading h1")?.text() ?: ""
+            val raw = document.selectFirst("div.canonical")?.attr("href") ?: ""
+            return MangasPage(
+                entries
+                    .filter { it ->
+                        val title = it.selectFirst("div.item-thumb.wleft a")?.attr("href") ?: ""
+
+                        searchText.lowercase().contains("raw") ||
+                            raw.contains("raw") ||
+                            !title.contains("raw")
+                    }
+                    .map(::popularMangaFromElement),
+                hasNextPage,
+            )
+        }
+
+        return MangasPage(entries.map(::popularMangaFromElement), hasNextPage)
+    }
+
+    override fun popularMangaSelector() = "div.page-item-detail"
+    override fun popularMangaNextPageSelector() = ".next"
+
+    override fun popularMangaFromElement(element: Element) = SManga.create().apply {
+        setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
+        title = element.selectFirst("div.item-thumb.wleft a")!!.attr("title")
+        thumbnail_url = element.selectFirst("img")?.absUrl("src")
+    }
+
+    override fun latestUpdatesRequest(page: Int): Request {
+        return GET("$baseUrl/manga/$page?orderby=latest", headers)
+    }
+
+    override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
+    override fun latestUpdatesSelector() = popularMangaSelector()
+    override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
+    override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
+
+    override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+        val url = baseUrl.toHttpUrl().newBuilder().apply {
+            if (query.isEmpty()) {
+                var completed = false
+                var raw = false
+                var genre = ""
+                filters.forEach {
+                    when (it) {
+                        is GenreFilter -> {
+                            genre = it.getValue()
+                        }
+
+                        is CompletedFilter -> {
+                            completed = it.state
+                        }
+
+                        is RawFilter -> {
+                            raw = it.state
+                        }
+
+                        is SortFilter -> {
+                            addQueryParameter("orderby", it.getValue())
+                        }
+
+                        else -> {}
+                    }
+                }
+                if (raw) {
+                    addPathSegment("raw")
+                } else if (completed) {
+                    addPathSegment("completed")
+                } else {
+                    if (genre != "manga") addPathSegment("genre")
+                    addPathSegment(genre)
+                }
+                addPathSegment(page.toString())
+            } else {
+                addPathSegment("search")
+                addQueryParameter("q", query)
+                addQueryParameter("page", page.toString())
+            }
+        }.build()
+
+        return GET(url, headers)
+    }
+
+    override fun searchMangaParse(response: Response) = popularMangaParse(response)
+    override fun searchMangaSelector() = popularMangaSelector()
+    override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
+    override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
+
+    override fun getFilterList() = getFilters()
+
+    override fun mangaDetailsParse(document: Document) = SManga.create().apply {
+        val info = document.selectFirst("div.post_content")!!
+
+        title = document.select("div.post-title.wleft > h1").text()
+        description = buildString {
+            document.select("div.ss-manga > p")
+                .eachText().onEach {
+                    append(it.trim())
+                    append("\n\n")
+                }
+
+            info.selectFirst("div.post-content_item.wleft:contains(Alternative) div.summary-content")
+                ?.text()
+                ?.takeIf { it != "Updating" && it.isNotEmpty() }
+                ?.let {
+                    append("Alternative Names:\n")
+                    append(it.trim())
+                }
+        }
+        status = when (info.select("div.post-content_item.wleft:contains(Status) div.summary-content").text()) {
+            "Ongoing" -> SManga.ONGOING
+            "Completed" -> SManga.COMPLETED
+            else -> SManga.UNKNOWN
+        }
+        author = info.selectFirst("div.href-content.artist-content > a")?.text()?.takeIf { it != "Updating" }
+        artist = info.selectFirst("div.href-content.artist-content > a")?.text()?.takeIf { it != "Updating" }
+        genre = info.select("div.href-content.genres-content > a[href*=/manga-list/]").eachText().joinToString()
+        thumbnail_url = document.selectFirst("div.summary_image > img")?.absUrl("src")
+    }
+
+    override fun chapterListSelector() = "ul.row-content-chapter.wleft .a-h.wleft"
+
+    private val dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH)
+
+    override fun chapterFromElement(element: Element) = SChapter.create().apply {
+        element.selectFirst("a")!!.run {
+            setUrlWithoutDomain(absUrl("href"))
+            name = text()
+        }
+        date_upload = try {
+            dateFormat.parse(element.selectFirst("span")!!.text())!!.time
+        } catch (_: Exception) {
+            0L
+        }
+    }
+
+    override fun pageListParse(document: Document): List<Page> {
+        val contents = document.select("div.read-content.wleft img")
+        if (contents.isEmpty()) {
+            throw Exception("Unable to find script with image data")
+        }
+
+        return contents.mapIndexed { idx, image ->
+            val imageUrl = image.attr("src")
+            Page(idx, imageUrl = imageUrl)
+        }
+    }
+    override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
+}