Skip to content

Commit

Permalink
Add another trending stocks api
Browse files Browse the repository at this point in the history
  • Loading branch information
premnirmal committed Oct 12, 2022
1 parent 04b5d63 commit ce47c73
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 15 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
implementation "com.squareup.retrofit2:converter-gson:$RETROFIT_VERSION"
implementation "com.squareup.retrofit2:converter-simplexml:$RETROFIT_VERSION"
implementation "org.jsoup:jsoup:1.10.2"

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$COROUTINES_VERSION"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import retrofit2.http.GET

interface ApeWisdom {

@GET("filter/all-stocks")
@GET("filter/stocks")
suspend fun getTrendingStocks(): TrendingResult
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.github.premnirmal.ticker.network

import okhttp3.ResponseBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.parser.Parser
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
import java.nio.charset.Charset

class JsoupConverterFactory : Converter.Factory() {

override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
return when (type) {
Document::class.java -> JsoupConverter(retrofit.baseUrl().toString())
else -> null
}
}

private class JsoupConverter(val baseUri: String) : Converter<ResponseBody, Document?> {

override fun convert(value: ResponseBody): Document? {
val charset = value.contentType()?.charset() ?: Charset.forName("UTF-8")
val parser = when (value.contentType().toString()) {
"application/xml", "text/xml" -> Parser.xmlParser()
else -> Parser.htmlParser()
}
return Jsoup.parse(value.byteStream(), charset.name(), baseUri, parser)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ class NetworkModule {
return apewisdom
}

@Provides @Singleton internal fun provideYahooFinanceMostActive(
@ApplicationContext context: Context,
okHttpClient: OkHttpClient,
): YahooFinanceMostActive {
val retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(context.getString(R.string.yahoo_finance_endpoint))
.addConverterFactory(JsoupConverterFactory())
.build()
return retrofit.create(YahooFinanceMostActive::class.java)
}

@Provides @Singleton internal fun provideGoogleNewsApi(
@ApplicationContext context: Context,
okHttpClient: OkHttpClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.premnirmal.ticker.network

import com.github.premnirmal.ticker.network.data.NewsRssFeed
import org.jsoup.nodes.Document
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query

Expand All @@ -22,4 +24,9 @@ interface GoogleNewsApi {
interface YahooFinanceNewsApi {
@GET("rssindex")
suspend fun getNewsFeed(): NewsRssFeed
}

interface YahooFinanceMostActive {
@GET("most-active")
suspend fun getMostActive(): Response<Document>
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class NewsProvider @Inject constructor(
private val googleNewsApi: GoogleNewsApi,
private val yahooNewsApi: YahooFinanceNewsApi,
private val apeWisdom: ApeWisdom,
private val yahooFinanceMostActive: YahooFinanceMostActive,
private val stocksApi: StocksApi
) {

Expand Down Expand Up @@ -72,6 +73,34 @@ class NewsProvider @Inject constructor(
if (useCache && cachedTrendingStocks.isNotEmpty()) {
return@withContext FetchResult.success(cachedTrendingStocks)
}

// adding this extra try/catch because html format can change and parsing will fail
try {
val mostActiveHtml = yahooFinanceMostActive.getMostActive()
if (mostActiveHtml.isSuccessful) {
val doc = mostActiveHtml.body()!!
val elements = doc.select("fin-streamer")
val symbols = ArrayList<String>()
for (element in elements) {
if (element.hasAttr("data-symbol") && element.attr("class").equals("fw(600)", ignoreCase = true)) {
val symbol = element.attr("data-symbol")
if (!symbols.contains(symbol)) symbols.add(symbol)
}
}
if (symbols.isNotEmpty()) {
Timber.d("symbols: ${symbols.joinToString(",")}")
val mostActiveStocks = stocksApi.getStocks(symbols.toList())
if (mostActiveStocks.wasSuccessful) {
cachedTrendingStocks = mostActiveStocks.data
}
return@withContext mostActiveStocks
}
}
} catch (e: Exception) {
Timber.w(e)
}

// fallback to apewisdom api
val result = apeWisdom.getTrendingStocks().results
val data = result.map { it.ticker }
val trendingResult = stocksApi.getStocks(data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.github.premnirmal.ticker.analytics.ClickEvent
import com.github.premnirmal.ticker.base.BaseFragment
import com.github.premnirmal.ticker.components.InAppMessage
import com.github.premnirmal.ticker.dismissKeyboard
import com.github.premnirmal.ticker.home.ChildFragment
import com.github.premnirmal.ticker.isNetworkOnline
import com.github.premnirmal.ticker.network.data.Suggestion
import com.github.premnirmal.ticker.news.QuoteDetailActivity
import com.github.premnirmal.ticker.portfolio.search.SuggestionsAdapter.SuggestionClickListener
import com.github.premnirmal.ticker.showDialog
import com.github.premnirmal.ticker.showKeyboard
import com.github.premnirmal.ticker.ui.SpacingDecoration
import com.github.premnirmal.ticker.viewBinding
import com.github.premnirmal.ticker.widget.WidgetDataProvider
Expand Down Expand Up @@ -135,16 +133,6 @@ class SearchFragment : BaseFragment<FragmentSearchBinding>(), ChildFragment, Sug
}
}

override fun onResume() {
super.onResume()
binding.searchView.showKeyboard()
}

override fun onPause() {
super.onPause()
dismissKeyboard()
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(ARG_WIDGET_ID, selectedWidgetId)
super.onSaveInstanceState(outState)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<string name="widget_label" translatable="false">Stocks Tracker Widget</string>
<string name="google_news_endpoint" translatable="false">https://news.google.com/</string>
<string name="yahoo_news_endpoint" translatable="false">https://finance.yahoo.com/news/</string>
<string name="yahoo_finance_endpoint" translatable="false">https://finance.yahoo.com/</string>
<string name="suggestions_endpoint" translatable="false">https://query2.finance.yahoo.com/v1/finance/</string>
<string name="yahoo_endpoint" translatable="false">https://query1.finance.yahoo.com/v7/finance/</string>
<string name="historical_data_endpoint" translatable="false">https://query1.finance.yahoo.com/v8/finance/</string>
Expand Down
4 changes: 2 additions & 2 deletions app/version.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# this file is purely for f-droid because it cannot infer the version name/code from the git tag
versionName=3.9.811
versionCode=300900011
versionName=3.9.812
versionCode=300900012

0 comments on commit ce47c73

Please sign in to comment.