diff --git a/src/es/tumanhwas/AndroidManifest.xml b/src/es/tumanhwas/AndroidManifest.xml
new file mode 100644
index 000000000..e3140cec2
--- /dev/null
+++ b/src/es/tumanhwas/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <application>
+        <activity
+            android:name=".es.tumanhwas.TuManhwasUrlActivity"
+            android:excludeFromRecents="true"
+            android:exported="true"
+            android:theme="@android:style/Theme.NoDisplay">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+
+                <data
+                    android:host="tumanhwas.com"
+                    android:pathPattern="/manga/..*"
+                    android:scheme="https" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/src/es/tumanhwas/build.gradle b/src/es/tumanhwas/build.gradle
new file mode 100644
index 000000000..b6f7bfbe7
--- /dev/null
+++ b/src/es/tumanhwas/build.gradle
@@ -0,0 +1,8 @@
+ext {
+    extName = 'TuManhwas'
+    extClass = '.TuManhwas'
+    extVersionCode = 1
+    isNsfw = true
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/es/tumanhwas/res/mipmap-hdpi/ic_launcher.png b/src/es/tumanhwas/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..bd4a86355
Binary files /dev/null and b/src/es/tumanhwas/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/es/tumanhwas/res/mipmap-mdpi/ic_launcher.png b/src/es/tumanhwas/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..2a87030f0
Binary files /dev/null and b/src/es/tumanhwas/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/es/tumanhwas/res/mipmap-xhdpi/ic_launcher.png b/src/es/tumanhwas/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..a1d9d63c3
Binary files /dev/null and b/src/es/tumanhwas/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/es/tumanhwas/res/mipmap-xxhdpi/ic_launcher.png b/src/es/tumanhwas/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..2d1204269
Binary files /dev/null and b/src/es/tumanhwas/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/es/tumanhwas/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/tumanhwas/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..3a853b7c2
Binary files /dev/null and b/src/es/tumanhwas/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwas.kt b/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwas.kt
new file mode 100644
index 000000000..c2a4bca32
--- /dev/null
+++ b/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwas.kt
@@ -0,0 +1,136 @@
+package eu.kanade.tachiyomi.extension.es.tumanhwas
+
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.interceptor.rateLimit
+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 okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.Request
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+import rx.Observable
+import java.util.Calendar
+
+class TuManhwas : ParsedHttpSource() {
+    override val name: String = "TuManhwas"
+
+    override val baseUrl: String = "https://tumanhwas.com"
+
+    override val lang: String = "es"
+
+    override val supportsLatest: Boolean = true
+
+    override val client = network.cloudflareClient.newBuilder()
+        .rateLimit(3)
+        .build()
+
+    override fun popularMangaFromElement(element: Element) = SManga.create().apply {
+        title = element.selectFirst(".tt")!!.text()
+        thumbnail_url = element.selectFirst("img")?.imgAttr()
+        setUrlWithoutDomain(element.absUrl("href"))
+    }
+
+    override fun popularMangaNextPageSelector() = ".page-link[rel='next']"
+
+    override fun popularMangaRequest(page: Int): Request {
+        val url = "$baseUrl/biblioteca".toHttpUrl().newBuilder()
+            .addQueryParameter("page", "$page")
+            .build()
+        return GET(url, headers)
+    }
+
+    override fun popularMangaSelector() = "div.bs div.bsx a"
+
+    override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
+        if (query.startsWith(URL_SEARCH_PREFIX).not()) {
+            return super.fetchSearchManga(page, query, filters)
+        }
+
+        val manga = SManga.create().apply {
+            url = "/manga/${query.substringAfter(URL_SEARCH_PREFIX)}"
+        }
+
+        return fetchMangaDetails(manga)
+            .asObservable().map {
+                MangasPage(listOf(it), false)
+            }
+    }
+
+    override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
+
+    override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
+
+    override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+        val url = "$baseUrl/biblioteca".toHttpUrl().newBuilder()
+            .addQueryParameter("search", query)
+            .addQueryParameter("page", "$page")
+            .build()
+        return GET(url, headers)
+    }
+
+    override fun searchMangaSelector() = popularMangaSelector()
+
+    override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element).apply {
+        url = url.replace("news", "manga")
+            .substringBeforeLast("-")
+    }
+
+    override fun latestUpdatesNextPageSelector() = null
+
+    override fun latestUpdatesRequest(page: Int) = GET(baseUrl, headers)
+
+    override fun latestUpdatesSelector() = ".bixbox.seriesearch:has(h1) a"
+
+    override fun mangaDetailsParse(document: Document) = SManga.create().apply {
+        document.selectFirst(".main-info")!!.let {
+            title = it.selectFirst("h1")!!.text()
+            thumbnail_url = it.selectFirst("img")?.imgAttr()
+            description = it.selectFirst(".summary p")?.text()
+            genre = it.select(".genres-container a")
+                .joinToString { it.text() }
+            setUrlWithoutDomain(document.location())
+        }
+    }
+
+    override fun chapterFromElement(element: Element) = SChapter.create().apply {
+        name = element.selectFirst(".chapternum")!!.text()
+        date_upload = parseRelativeDate(element.selectFirst(".chapterdate")?.text() ?: "")
+        setUrlWithoutDomain(element.attr("href"))
+    }
+
+    override fun chapterListSelector() = "#chapterlist a"
+
+    override fun pageListParse(document: Document): List<Page> {
+        return document.select("#chapter_imgs img").mapIndexed { index, element ->
+            Page(index, document.location(), imageUrl = element.imgAttr())
+        }
+    }
+
+    override fun imageUrlParse(document: Document) = ""
+
+    private fun Element.imgAttr(): String {
+        return when {
+            hasAttr("data-src") -> absUrl("data-src")
+            else -> absUrl("src")
+        }
+    }
+
+    private fun parseRelativeDate(date: String): Long {
+        val number = RELATIVE_DATE_REGEX.find(date)?.value?.toIntOrNull() ?: return 0
+        val cal = Calendar.getInstance()
+        return when {
+            date.contains("mes", ignoreCase = true) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
+            date.contains("año", ignoreCase = true) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
+            else -> 0
+        }
+    }
+
+    companion object {
+        const val URL_SEARCH_PREFIX = "slug:"
+        val RELATIVE_DATE_REGEX = """(\d+)""".toRegex()
+    }
+}
diff --git a/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwasUrlActivity.kt b/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwasUrlActivity.kt
new file mode 100644
index 000000000..7f252810d
--- /dev/null
+++ b/src/es/tumanhwas/src/eu/kanade/tachiyomi/extension/es/tumanhwas/TuManhwasUrlActivity.kt
@@ -0,0 +1,37 @@
+package eu.kanade.tachiyomi.extension.es.tumanhwas
+
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import kotlin.system.exitProcess
+
+class TuManhwasUrlActivity : Activity() {
+
+    private val tag = javaClass.simpleName
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val pathSegments = intent?.data?.pathSegments
+        if (pathSegments != null && pathSegments.size > 1) {
+            val item = pathSegments[1]
+            val mainIntent = Intent().apply {
+                action = "eu.kanade.tachiyomi.SEARCH"
+                putExtra("query", "${TuManhwas.URL_SEARCH_PREFIX}$item")
+                putExtra("filter", packageName)
+            }
+
+            try {
+                startActivity(mainIntent)
+            } catch (e: ActivityNotFoundException) {
+                Log.e(tag, e.toString())
+            }
+        } else {
+            Log.e(tag, "could not parse uri from intent $intent")
+        }
+
+        finish()
+        exitProcess(0)
+    }
+}