Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.7.1 #12

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ detekt {
config = files("$projectDir/detekt.yml")
parallel = true
setSource(files(projectDir))
reports {
xml.required.set(true)
html.required.set(true)
txt.required.set(false)
sarif.required.set(true)
}
// DEPRECATED
// reports {
// xml.required.set(true)
// html.required.set(true)
// txt.required.set(false)
// sarif.required.set(true)
// }
}

dependencies {
Expand Down
16 changes: 8 additions & 8 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ android.enableJetifier=false
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Declare versions
agp_version=7.0.2
kotlin_version=1.6.10
compilesdk_version=31
buildtools_version=30.0.2
minsdk_version=14
targetsdk_version=31
project_version=0.6.0
project_version_code=600
agp_version=7.3.1
kotlin_version=1.8.10
compilesdk_version=33
buildtools_version=31.0.0
minsdk_version=26
targetsdk_version=33
project_version=0.7.5
project_version_code=705
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Wed Sep 21 10:44:36 CEST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal object ParseRSSKeyword {
const val TITLE = "title"
const val DESCRIPTION = "description"
const val IMAGE = "image"
const val PUBLISH_DATE = "pubdate"
const val PUBLISH_DATE = "pubDate"
const val GUID = "guid"
const val LINK = "link"
const val URL = "url"
Expand All @@ -22,7 +22,7 @@ internal object ParseRSSKeyword {
const val AUTHOR = "author"
const val COPYRIGHT = "copyright"
const val RIGHTS = "rights"
const val LAST_BUILD_DATE = "lastbuilddate"
const val LAST_BUILD_DATE = "lastBuildDate"
const val GROUP = "group"
const val CONTENT = "content"
const val CREDIT = "credit"
Expand All @@ -48,6 +48,11 @@ internal object ParseRSSKeyword {
const val ATTR_URI = "uri"
const val ATTR_HREF = "href"
const val ATTR_REL = "rel"

const val ENCLOSURE = "enclosure"
const val ENCLOSURE_URL = "url"
const val DC_NS_DATE = "date"
const val DC_NS_TYPE = "type"
}

enum class RSSVersion(val elementName: String, val xmlns: String) {
Expand Down
180 changes: 122 additions & 58 deletions parserss/src/main/java/com/github/muhrifqii/parserss/ParserExecutor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import com.github.muhrifqii.parserss.utils.getRSSAttributeElement
import com.github.muhrifqii.parserss.utils.getRSSElement
import com.github.muhrifqii.parserss.utils.nextTextTrimmed
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
import java.io.Reader

class ParserExecutor<T>(
factory: XmlPullParserFactory,
private val input: Reader,
strictMode: Boolean,
feedSupplier: () -> T
feedSupplier: () -> T,
) where T : RSSFeed {

private val parser: XmlPullParser
Expand Down Expand Up @@ -52,7 +53,9 @@ class ParserExecutor<T>(
if (element.name != RSSVersion.RSS_V1.elementName &&
element.name != RSSVersion.RSS_V2.elementName &&
element.name != RSSVersion.RSS_ATOM.elementName
) return element
) {
return element
}
val attrCount = parser.attributeCount
for (i in 0 until attrCount) {
val attribute = parser.getRSSAttributeElement(i, pullParserNSAware)
Expand Down Expand Up @@ -93,74 +96,134 @@ class ParserExecutor<T>(
}

private fun parseNSDefault(element: ParseRSSElement) {
when (element.name) {
ParseRSSKeyword.TITLE -> mode[TitleEnabledObject::class.java] = {
it?.title = parser.nextTextTrimmed()
}
ParseRSSKeyword.DESCRIPTION -> mode[DescriptionEnabledObject::class.java] = {
it?.description = parser.nextTextTrimmed()
}
ParseRSSKeyword.LINK -> mode[LinkEnabledObject::class.java] = {
it?.link = parser.nextTextTrimmed()
}
ParseRSSKeyword.PUBLISH_DATE -> mode[PublishDateEnabledObject::class.java] = {
it?.publishDate = parser.nextTextTrimmed()
}
ParseRSSKeyword.LAST_BUILD_DATE -> mode[LastUpdatedEnabledObject::class.java] = {
it?.lastUpdated = parser.nextTextTrimmed()
}
ParseRSSKeyword.URL -> mode[UrlEnabledObject::class.java] = {
it?.url = parser.nextTextTrimmed()
}
ParseRSSKeyword.LANG -> mode[LangEnabledObject::class.java] = {
it?.language = parser.nextTextTrimmed()
}
ParseRSSKeyword.GUID -> mode[GUIdEnabledObject::class.java] = {
val isPerma =
(parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_PERMALINK) ?: "true")
.toBoolean()
it?.guId = GUId(parser.nextTextTrimmed(), isPerma)
}
ParseRSSKeyword.AUTHOR -> mode[AuthorEnabledObject::class.java] = {
it?.author = RSSPersonAwareObject(parser.nextTextTrimmed())
}
ParseRSSKeyword.CATEGORY -> mode[CategoryEnabledObject::class.java] = {
val domain = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_DOMAIN)
it?.category?.add(
RSSCategoryObject(domain, parser.nextTextTrimmed())
)
}
ParseRSSKeyword.COPYRIGHT -> mode[CopyrightsEnabledObject::class.java] = {
it?.copyright = parser.nextTextTrimmed()
}
ParseRSSKeyword.COMMENTS -> mode[CommentEnabledObject::class.java] = {
it?.comments = parser.nextTextTrimmed()
try {
when (element.name) {
ParseRSSKeyword.TITLE -> mode[TitleEnabledObject::class.java] = {
it?.title = parser.nextTextTrimmed()
}
ParseRSSKeyword.DESCRIPTION -> mode[DescriptionEnabledObject::class.java] = {
it?.description = parser.nextTextTrimmed()
}
ParseRSSKeyword.LINK -> mode[LinkEnabledObject::class.java] = {
it?.link = parser.nextTextTrimmed()
}
ParseRSSKeyword.PUBLISH_DATE -> mode[PublishDateEnabledObject::class.java] = {
val date = parser.nextTextTrimmed()
if (date.isNotEmpty()) {
it?.publishDate = date
}
}
ParseRSSKeyword.LAST_BUILD_DATE -> mode[LastUpdatedEnabledObject::class.java] = {
it?.lastUpdated = parser.nextTextTrimmed()
}
ParseRSSKeyword.URL -> mode[UrlEnabledObject::class.java] = {
it?.url = parser.nextTextTrimmed()
}
ParseRSSKeyword.LANG -> mode[LangEnabledObject::class.java] = {
it?.language = parser.nextTextTrimmed()
}
ParseRSSKeyword.GUID -> mode[GUIdEnabledObject::class.java] = {
val isPermanent = (
parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_PERMALINK,
) ?: "true"
).toBoolean()
it?.guId = GUId(parser.nextTextTrimmed(), isPermanent)
}
ParseRSSKeyword.AUTHOR -> mode[AuthorEnabledObject::class.java] = {
val parsed = parser.nextTextTrimmed()
it?.author = RSSPersonAwareObject(parsed)
}
ParseRSSKeyword.CATEGORY -> mode[CategoryEnabledObject::class.java] = {
val domain = parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_DOMAIN,
)
it?.categories?.add(RSSCategoryObject(domain, parser.nextTextTrimmed()))
}
ParseRSSKeyword.COPYRIGHT -> mode[CopyrightsEnabledObject::class.java] = {
it?.copyright = parser.nextTextTrimmed()
}
ParseRSSKeyword.COMMENTS -> mode[CommentEnabledObject::class.java] = {
it?.comments = parser.nextTextTrimmed()
}
ParseRSSKeyword.ENCLOSURE -> mode[ImageUrlEnabledObject::class.java] = {
val imageUrl = parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ENCLOSURE_URL,
)
it?.imageUrls?.add(imageUrl.trim())
}
ParseRSSKeyword.DC_NS_DATE -> mode[PublishDateEnabledObject::class.java] = {
val date = parser.nextTextTrimmed()
if (date.isNotEmpty()) {
it?.publishDate = date
}
}
ParseRSSKeyword.DC_NS_TYPE -> mode[CategoryEnabledObject::class.java] = {
val domain = parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_DOMAIN,
)
it?.categories?.add(RSSCategoryObject(domain, parser.nextTextTrimmed()))
}
}
} catch (ignored: XmlPullParserException) {
// Note: added try/catch to handle RSS with broken and not valid structures, so we
// can continue the parsing instead of return a brutal exception
if (BuildConfig.DEBUG) { println("[ParseRSS] Ignored XmlPullParserException on parseNSDefault: $ignored") }
} catch (ignored: Exception) {
// Note: added try/catch to handle RSS with broken and not valid structures, so we
// can continue the parsing instead of return a brutal exception
if (BuildConfig.DEBUG) { println("[ParseRSS] Ignored Exception on parseNSDefault: $ignored") }
}
}

private fun parseNSMedia(element: ParseRSSElement) {
when (element.name) {
ParseRSSKeyword.CONTENT -> mode[MediaEnabledObject::class.java] = {
val media = RSSMediaObject()
media.url = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_URL)
media.medium = MediaType.from(
parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_MEDIUM)
)
media.width =
parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_WIDTH).toInt()
media.height =
parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_HEIGHT).toInt()
it?.media?.add(media)
try {
val media = RSSMediaObject()
media.url = parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_URL,
)
media.medium = MediaType.from(
parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_MEDIUM,
),
)
media.width =
parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_WIDTH,
).toInt()
media.height =
parser.getAttributeValue(
XmlPullParser.NO_NAMESPACE,
ParseRSSKeyword.ATTR_HEIGHT,
).toInt()
it?.medias?.add(media)
} catch (ignored: NumberFormatException) {
if (BuildConfig.DEBUG) {
println("[ParseRSS] Ignored NumberFormatException error: ${ignored.localizedMessage}")
}
} catch (ignored: Exception) {
// Note: added try/catch to handle RSS with broken and not valid structures, so we
// can continue the parsing instead of return a brutal exception
if (BuildConfig.DEBUG) { println("[ParseRSS] Ignored Exception on parseNSMedia: $ignored") }
}
}
ParseRSSKeyword.DESCRIPTION -> mode[MediaEnabledObject::class.java] = {
it?.apply {
media.lastOrNull()?.description = parser.nextTextTrimmed()
medias.lastOrNull()?.description = parser.nextTextTrimmed()
}
}
ParseRSSKeyword.CREDIT -> mode[MediaEnabledObject::class.java] = {
it?.apply {
media.lastOrNull()?.credit = parser.nextTextTrimmed()
medias.lastOrNull()?.credit = parser.nextTextTrimmed()
}
}
}
Expand All @@ -186,10 +249,11 @@ class ParserExecutor<T>(
ParseRSSKeyword.LINK -> mode[LinkEnabledObject::class.java] = {
val rel = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_REL) ?: ""
val href = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ParseRSSKeyword.ATTR_HREF)
if (rel == "self" && it is RSSFeed)
if (rel == "self" && it is RSSFeed) {
it.link = href
else if (rel == "alternate" && it is RSSItem)
} else if (rel == "alternate" && it is RSSItem) {
it.link = href
}
}
ParseRSSKeyword.RIGHTS -> mode[CopyrightsEnabledObject::class.java] = {
it?.copyright = parser.nextTextTrimmed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,19 @@ sealed class ParsingMode(val nameToken: String) : ParsingModeOperation {
is Read -> return
is MediaNS.Group -> {
val item = modes.lastValue()
if (item !is Item) throw ParseRSSException(
"Error ${other.nameToken} should be under the item element",
)
if (item !is Item) {
throw ParseRSSException(
"Error ${other.nameToken} should be under the item element",
)
}
other.rssObject = item.rssObject
}
is Author -> {
val authorHolder = modes.lastValue()
val channel = (authorHolder as? Channel)?.rssObject
val item = (authorHolder as? Item)?.rssObject
other.rssObject = item ?: channel ?: throw ParseRSSException(
"Error ${other.nameToken} should be under item/atom:entry or atom:feed"
"Error ${other.nameToken} should be under item/atom:entry or atom:feed",
)
}
is Channel -> {
Expand Down Expand Up @@ -166,10 +168,16 @@ sealed class ParsingMode(val nameToken: String) : ParsingModeOperation {
else -> return
}
} catch (err: ClassCastException) {
throw ParseRSSException(
"Error on casting ${mode.nameToken} element to ${clazz.name}",
err
)
if (mode.nameToken == ParseRSSKeyword.IMAGE) {
if (BuildConfig.DEBUG) {
println("[ParseRSS] Ignored error on casting ${mode.nameToken} element to ${clazz.name} with err ${err.localizedMessage}")
}
} else {
throw ParseRSSException(
"Error on casting ${mode.nameToken} element to ${clazz.name}",
err,
)
}
}
}

Expand All @@ -188,7 +196,7 @@ sealed class ParsingMode(val nameToken: String) : ParsingModeOperation {
} catch (err: ClassCastException) {
throw ParseRSSException(
"Error on casting rss object to ${clazz.name}",
err
err,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ data class RSSItemObject(
override var link: String? = null,
override var publishDate: String? = null,
override var guId: GUId? = null,
override var media: MutableList<RSSMedia> = mutableListOf(),
override var medias: MutableList<RSSMedia> = mutableListOf(),
override var author: RSSPersonAware? = null,
override var category: MutableList<RSSCategory> = mutableListOf(),
override var categories: MutableList<RSSCategory> = mutableListOf(),
override var comments: String? = null,
override var lastUpdated: String? = null,
override var summary: String? = null
override var summary: String? = null,
override var imageUrls: MutableList<String?> = mutableListOf()
) : RSSItem

data class RSSImageObject(
override var url: String = "",
override var url: String? = "",
override var link: String? = null,
override var title: String? = null
) : RSSImage
Expand Down
Loading