Skip to content

Commit

Permalink
Parse url query param from Google Alerts feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
jocmp committed Jan 12, 2025
1 parent c1b37ac commit 7e2deb9
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 14 deletions.
2 changes: 1 addition & 1 deletion capy/src/main/java/com/jocmp/capy/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package com.jocmp.capy
import com.jocmp.capy.accounts.AddFeedResult
import com.jocmp.capy.accounts.AutoDelete
import com.jocmp.capy.accounts.FaviconFetcher
import com.jocmp.capy.accounts.LocalAccountDelegate
import com.jocmp.capy.accounts.LocalOkHttpClient
import com.jocmp.capy.accounts.Source
import com.jocmp.capy.accounts.asOPML
import com.jocmp.capy.accounts.feedbin.FeedbinAccountDelegate
import com.jocmp.capy.accounts.feedbin.FeedbinOkHttpClient
import com.jocmp.capy.accounts.local.LocalAccountDelegate
import com.jocmp.capy.accounts.reader.buildReaderDelegate
import com.jocmp.capy.articles.ArticleContent
import com.jocmp.capy.articles.UnreadSortOrder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.jocmp.capy.accounts

import com.jocmp.capy.UserAgentInterceptor
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.brotli.BrotliInterceptor
import java.io.File
import java.net.URI

internal object LocalOkHttpClient {
Expand Down
27 changes: 27 additions & 0 deletions capy/src/main/java/com/jocmp/capy/accounts/local/ArticleURL.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.jocmp.capy.accounts.local

import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import java.net.MalformedURLException
import java.net.URL

internal object ArticleURL {
internal fun parse(url: URL): URL {
return googleAlertURL(url) ?: url
}

private fun googleAlertURL(url: URL): URL? {
if (url.host != GOOGLE_ALERTS_DOMAIN) {
return null
}

val articleURLParam = url.toHttpUrlOrNull()?.queryParameter("url") ?: return null

return try {
URL(articleURLParam)
} catch (e: MalformedURLException) {
null
}
}

private const val GOOGLE_ALERTS_DOMAIN = "www.google.com"
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.jocmp.capy.accounts
package com.jocmp.capy.accounts.local

import com.jocmp.capy.AccountDelegate
import com.jocmp.capy.ArticleFilter
import com.jocmp.capy.Feed
import com.jocmp.capy.accounts.AddFeedResult
import com.jocmp.capy.accounts.FaviconFetcher
import com.jocmp.capy.accounts.FeedOption
import com.jocmp.capy.common.TimeHelpers.nowUTC
import com.jocmp.capy.common.TimeHelpers.published
import com.jocmp.capy.common.transactionWithErrorHandling
Expand All @@ -23,7 +26,7 @@ import java.net.UnknownHostException
import java.time.ZonedDateTime
import com.jocmp.feedfinder.parser.Feed as ParserFeed

class LocalAccountDelegate(
internal class LocalAccountDelegate(
private val database: Database,
private val httpClient: OkHttpClient,
private val faviconFetcher: FaviconFetcher,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jocmp.capy.accounts
package com.jocmp.capy.accounts.local

import com.jocmp.capy.common.escapingHTMLCharacters
import com.jocmp.rssparser.model.RssItem
Expand All @@ -8,7 +8,7 @@ import java.net.URI
import java.net.URL

internal class ParsedItem(private val item: RssItem, private val siteURL: String?) {
val url: String? = cleanedURL(item.link)?.toString()
val url: String? = articleURL()

val id: String? = url ?: item.guid

Expand Down Expand Up @@ -40,6 +40,12 @@ internal class ParsedItem(private val item: RssItem, private val siteURL: String
val imageURL: String?
get() = cleanedURL(item.image)?.toString()

private fun articleURL(): String? {
val link = cleanedURL(item.link) ?: return null

return ArticleURL.parse(link).toString()
}

private fun cleanedURL(inputURL: String?): URL? {
val url = inputURL.orEmpty()

Expand Down
2 changes: 1 addition & 1 deletion capy/src/test/java/com/jocmp/capy/OPMLFileTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.jocmp.capy

import com.jocmp.capy.accounts.FakeFaviconFetcher
import com.jocmp.capy.accounts.LocalAccountDelegate
import com.jocmp.capy.accounts.local.LocalAccountDelegate
import com.jocmp.capy.db.Database
import com.jocmp.capy.fixtures.AccountFixture
import com.jocmp.capy.fixtures.FeedFixture
Expand Down
26 changes: 26 additions & 0 deletions capy/src/test/java/com/jocmp/capy/accounts/local/ArticleURLTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.jocmp.capy.accounts.local

import java.net.URL
import kotlin.test.Test
import kotlin.test.assertEquals

class ArticleURLTest {
@Test
fun `entry URL is the same as article URL`() {
val entryURL = URL("https://www.theverge.com/2025/1/12/24340818/robot-vacuum-innovations-roborock-dreame-ecovacs-ces2025")

val url = ArticleURL.parse(url = entryURL)

assertEquals(expected = entryURL.toString(), actual = url.toString())
}

@Test
fun `with a Google Alert entry URL it returns the url param`() {
val entryURL = URL("https://www.google.com/url?rct=j&sa=t&url=https://www.androidheadlines.com/2025/01/meta-sued-for-allegedly-training-ai-with-content-from-pirated-books.html&ct=ga&cd=CAIyGjQ2MjY4NTIwYjAzMGNkMzc6Y29tOmVuOlVT&usg=AOvVaw2Ez54Yz16bwLLLX_YLfwA2")
val articleURL = URL("https://www.androidheadlines.com/2025/01/meta-sued-for-allegedly-training-ai-with-content-from-pirated-books.html")

val url = ArticleURL.parse(url = entryURL)

assertEquals(expected = articleURL.toString(), actual = url.toString())
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.jocmp.capy.accounts
package com.jocmp.capy.accounts.local

import com.jocmp.capy.AccountDelegate
import com.jocmp.capy.ArticleFilter
import com.jocmp.capy.InMemoryDatabaseProvider
import com.jocmp.capy.accounts.AddFeedResult
import com.jocmp.capy.accounts.FakeFaviconFetcher
import com.jocmp.capy.db.Database
import com.jocmp.capy.fixtures.FeedFixture
import com.jocmp.capy.logging.CapyLog
Expand Down Expand Up @@ -118,7 +120,10 @@ class LocalAccountDelegateTest {

FeedFixture(database).create(feedID = channel.link!!)

delegate.refresh(ArticleFilter.default(), cutoffDate = ZonedDateTime.of(2024, 5, 1, 8, 0, 0, 0, ZoneOffset.UTC))
delegate.refresh(
ArticleFilter.default(),
cutoffDate = ZonedDateTime.of(2024, 5, 1, 8, 0, 0, 0, ZoneOffset.UTC)
)

val articlesCount = database
.articlesQueries
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jocmp.capy.accounts
package com.jocmp.capy.accounts.local

import com.jocmp.rssparser.model.RssItem
import kotlin.test.Test
Expand Down Expand Up @@ -31,7 +31,10 @@ class ParsedItemTest {
val item = RssItem.Builder().title(title).build()
val parsedItem = ParsedItem(item, siteURL = "")

assertEquals(expected = "The `<details>` and `<summary>` elements are getting an upgrade", actual = parsedItem.title)
assertEquals(
expected = "The `<details>` and `<summary>` elements are getting an upgrade",
actual = parsedItem.title
)
}

@Test
Expand Down Expand Up @@ -116,4 +119,15 @@ class ParsedItemTest {

assertEquals(expected = "https://example.com/article", actual = parsedItem.url)
}

@Test
fun url_withGoogleAlertsFeed() {
val articleURL = "https://www.androidcentral.com/apps-software/google-squashes-a-few-pixel-bugs-in-android-15-qpr2-beta-2-1"
val link = "https://www.google.com/url?rct=j&sa=t&url=$articleURL&ct=ga&cd=CAIyGmNmNDdiZGVhOWNiNDUxZTA6Y29tOmVuOlVT&usg=AOvVaw0NIyLHLSRUIwSMg9anVWrG"

val item = RssItem.Builder().link(link).build()
val parsedItem = ParsedItem(item, siteURL = "https://www.google.com/alerts/feeds/12345/12345")

assertEquals(expected = articleURL, actual = parsedItem.url)
}
}
2 changes: 1 addition & 1 deletion capy/src/test/java/com/jocmp/capy/opml/OPMLImporterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.jocmp.capy.Account
import com.jocmp.capy.InMemoryDatabaseProvider
import com.jocmp.capy.MockFeedFinder
import com.jocmp.capy.accounts.FakeFaviconFetcher
import com.jocmp.capy.accounts.LocalAccountDelegate
import com.jocmp.capy.accounts.local.LocalAccountDelegate
import com.jocmp.capy.db.Database
import com.jocmp.capy.fixtures.AccountFixture
import com.jocmp.capy.fixtures.GenericFeed
Expand Down

0 comments on commit 7e2deb9

Please sign in to comment.