aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2018-04-13 00:13:28 -0400
committerGitHub <noreply@github.com>2018-04-13 00:13:28 -0400
commitc5e769deabeb80d7257b85c5c3d802cf46e6b191 (patch)
treeb3ac48678e893495b932c6500025db73a83e3d2b /app/src/main/kotlin/com
parentd9e2562267e549ee407e683262406581f2c4888e (diff)
downloadfrost-c5e769deabeb80d7257b85c5c3d802cf46e6b191.tar.gz
frost-c5e769deabeb80d7257b85c5c3d802cf46e6b191.tar.bz2
frost-c5e769deabeb80d7257b85c5c3d802cf46e6b191.zip
Fix view full image (#882)v2.0.1
* Test including full photo viewer * Test cookie in glide * Fix parser and add redirects to view full image * Update changelog
Diffstat (limited to 'app/src/main/kotlin/com')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt21
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt17
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt21
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt20
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt13
10 files changed, 102 insertions, 27 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
index e9426beb..399e86b0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -24,9 +24,11 @@ import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.facebook.requests.call
+import com.pitchedapps.frost.facebook.requests.getFullSizedImageUrl
+import com.pitchedapps.frost.facebook.requests.requestBuilder
import com.pitchedapps.frost.utils.*
import com.sothree.slidinguppanel.SlidingUpPanelLayout
-import okhttp3.Request
+import okhttp3.Response
import org.jetbrains.anko.activityUiThreadWithContext
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
@@ -86,8 +88,18 @@ class ImageActivity : KauBaseActivity() {
private val L = KauLoggerExtension("Image", com.pitchedapps.frost.utils.L)
}
+ private val cookie: String? by lazy { intent.getStringExtra(ARG_COOKIE) }
+
val imageUrl: String by lazy { intent.getStringExtra(ARG_IMAGE_URL).trim('"') }
+ private val trueImageUrl: String by lazy {
+ val result = if (!imageUrl.isIndirectImageUrl) imageUrl
+ else cookie?.getFullSizedImageUrl(imageUrl)?.blockingGet() ?: imageUrl
+ if (result != imageUrl)
+ L.v { "Launching with true url $result" }
+ result
+ }
+
private val imageText: String? by lazy { intent.getStringExtra(ARG_TEXT) }
// a unique image identifier based on the id (if it exists), and its hash
@@ -205,12 +217,13 @@ class ImageActivity : KauBaseActivity() {
return File.createTempFile(imageFileName, IMG_EXTENSION, frostDir)
}
- private fun getImageResponse() = Request.Builder()
- .url(imageUrl)
+ private fun getImageResponse(): Response = cookie.requestBuilder()
+ .url(trueImageUrl)
.get()
.call()
.execute()
+
@Throws(IOException::class)
private fun downloadImageTo(file: File) {
val body = getImageResponse().body()
@@ -263,7 +276,7 @@ class ImageActivity : KauBaseActivity() {
override fun onDestroy() {
tempFile = null
val purge = System.currentTimeMillis() - PURGE_TIME
- tempDir.listFiles(FileFilter { it.isFile && it.lastModified() < purge }).forEach {
+ tempDir.listFiles(FileFilter { it.isFile && it.lastModified() < purge })?.forEach {
it.delete()
}
super.onDestroy()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
index e5f0b8fe..38de6150 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
@@ -20,6 +20,10 @@ import io.reactivex.subjects.SingleSubject
*/
object FbCookie {
+ /**
+ * Retrieves the facebook cookie if it exists
+ * Note that this is a synchronized call
+ */
inline val webCookie: String?
get() = CookieManager.getInstance().getCookie(FB_URL_BASE)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt
index 4ba3c80d..cfa2796c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt
@@ -26,6 +26,7 @@ val FB_MESSAGE_NOTIF_ID_MATCHER: Regex by lazy { Regex("[thread|user]_fbid_([0-9
val FB_CSS_URL_MATCHER: Regex by lazy { Regex("url\\([\"|']?(.*?)[\"|']?\\)") }
val FB_JSON_URL_MATCHER: Regex by lazy { Regex("\"(http.*?)\"") }
val FB_IMAGE_ID_MATCHER: Regex by lazy { Regex("fbcdn.*?/[0-9]+_([0-9]+)_") }
+val FB_REDIRECT_URL_MATCHER: Regex by lazy { Regex("url=(.*?fbcdn.*?)\"") }
operator fun MatchResult?.get(groupIndex: Int) = this?.groupValues?.get(groupIndex)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
index f21c03e9..add35154 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
@@ -43,6 +43,7 @@ class FbUrlFormatter(url: String) {
L.e(e) { "Failed url formatting" }
return url
}
+ cleanedUrl = cleanedUrl.replace("&amp;", "&")
if (changed && !cleanedUrl.contains("?")) //ensure we aren't missing '?'
cleanedUrl = cleanedUrl.replaceFirst("&", "?")
val qm = cleanedUrl.indexOf("?")
@@ -54,8 +55,6 @@ class FbUrlFormatter(url: String) {
cleanedUrl = cleanedUrl.substring(0, qm)
}
discardableQueries.forEach { queries.remove(it) }
- //final cleanup
- misc.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) }
if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1)
cleanedUrl = cleanedUrl.replaceFirst(".facebook.com//", ".facebook.com/") //sometimes we are given a bad url
L.v { "Formatted url from $url to $cleanedUrl" }
@@ -101,8 +100,6 @@ class FbUrlFormatter(url: String) {
VIDEO_REDIRECT
)
- val misc = arrayOf("&amp;" to "&")
-
val discardableQueries = arrayOf("ref", "refid", "acontext", "SharedWith")
val converter = listOf(
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt
index b5c2e4e9..692312a1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt
@@ -6,7 +6,10 @@ import com.pitchedapps.frost.rx.RxFlyweight
import com.pitchedapps.frost.utils.L
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
-import okhttp3.*
+import okhttp3.Call
+import okhttp3.FormBody
+import okhttp3.OkHttpClient
+import okhttp3.Request
import okhttp3.logging.HttpLoggingInterceptor
import org.apache.commons.text.StringEscapeUtils
@@ -92,12 +95,16 @@ internal fun List<Pair<String, Any?>>.withEmptyData(vararg key: String): List<Pa
return newList
}
-private fun String.requestBuilder() = Request.Builder()
- .header("Cookie", this)
- .header("User-Agent", USER_AGENT_BASIC)
- .cacheControl(CacheControl.FORCE_NETWORK)
+internal fun String?.requestBuilder(): Request.Builder {
+ val builder = Request.Builder()
+ .header("User-Agent", USER_AGENT_BASIC)
+ if (this != null)
+ builder.header("Cookie", this)
+// .cacheControl(CacheControl.FORCE_NETWORK)
+ return builder
+}
-fun Request.Builder.call() = httpClient.newCall(build())!!
+fun Request.Builder.call(): Call = httpClient.newCall(build())
fun String.getAuth(): RequestAuth {
L.v { "Getting auth for ${hashCode()}" }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt
index 453400d3..8eeef08d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt
@@ -11,9 +11,8 @@ import com.bumptech.glide.load.model.MultiModelLoaderFactory
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.signature.ObjectKey
-import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER
-import com.pitchedapps.frost.facebook.FB_URL_BASE
-import com.pitchedapps.frost.facebook.get
+import com.pitchedapps.frost.facebook.*
+import io.reactivex.Maybe
import okhttp3.Call
import okhttp3.Request
import java.io.IOException
@@ -27,6 +26,18 @@ fun RequestAuth.getFullSizedImage(fbid: Long) = frostRequest(::getJsonUrl) {
get()
}
+val test: () -> InputStream? = { null }
+
+/**
+ * Attempts to get the fbcdn url of the supplied image redirect url
+ */
+fun String.getFullSizedImageUrl(url: String): Maybe<String?> = Maybe.fromCallable {
+ val redirect = requestBuilder().url(url).get().call()
+ .execute().body()?.string() ?: return@fromCallable null
+ return@fromCallable FB_REDIRECT_URL_MATCHER.find(redirect)[1]?.formattedFbUrl
+ ?: return@fromCallable null
+}.onErrorComplete()
+
/**
* Request loader for a potentially hd version of a url
* In this case, each url may potentially return an id,
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt
index 651e57d8..50d4d7b4 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt
@@ -10,6 +10,11 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
+import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.utils.L
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.Response
/**
* Created by Allan Wang on 28/12/17.
@@ -35,6 +40,22 @@ fun <T> RequestBuilder<T>.transform(vararg transformation: BitmapTransformation)
class FrostGlideModule : AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
+// registry.replace(GlideUrl::class.java,
+// InputStream::class.java,
+// OkHttpUrlLoader.Factory(getFrostHttpClient()))
// registry.prepend(HdImageMaybe::class.java, InputStream::class.java, HdImageLoadingFactory())
}
+}
+
+private fun getFrostHttpClient(): OkHttpClient =
+ OkHttpClient.Builder().addInterceptor(FrostCookieInterceptor()).build()
+
+class FrostCookieInterceptor : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val origRequest = chain.request()
+ val cookie = FbCookie.webCookie ?: return chain.proceed(origRequest)
+ L.v { "Add cookie to req $cookie" }
+ val request = origRequest.newBuilder().addHeader("Cookie", cookie).build()
+ return chain.proceed(request)
+ }
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
index b1b129fb..b4b78bf2 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -44,6 +44,7 @@ const val ARG_URL = "arg_url"
const val ARG_USER_ID = "arg_user_id"
const val ARG_IMAGE_URL = "arg_image_url"
const val ARG_TEXT = "arg_text"
+const val ARG_COOKIE = "arg_cookie"
inline fun <reified T : Activity> Context.launchNewTask(cookieList: ArrayList<CookieModel> = arrayListOf(), clearStack: Boolean = false) {
startActivity<T>(clearStack, intentBuilder = {
@@ -83,11 +84,12 @@ fun Context.launchWebOverlayBasic(url: String) = launchWebOverlayImpl<WebOverlay
private fun Context.fadeBundle() = ActivityOptions.makeCustomAnimation(this,
android.R.anim.fade_in, android.R.anim.fade_out).toBundle()
-fun Context.launchImageActivity(imageUrl: String, text: String?) {
+fun Context.launchImageActivity(imageUrl: String, text: String? = null, cookie: String? = null) {
startActivity<ImageActivity>(intentBuilder = {
putExtras(fadeBundle())
putExtra(ARG_IMAGE_URL, imageUrl)
putExtra(ARG_TEXT, text)
+ putExtra(ARG_COOKIE, cookie)
})
}
@@ -241,10 +243,20 @@ inline val String.isVideoUrl
(startsWith("https://video-") && contains(FBCDN_NET))
/**
- * [true] if url is or redirects to an explicit facebook image
+ * [true] if url directly leads to a usable image
*/
-inline val String.isImageUrl
- get() = contains(FBCDN_NET) && (contains(".png") || contains(".jpg"))
+inline val String.isImageUrl: Boolean
+ get() {
+ return contains(FBCDN_NET) && (contains(".png") || contains(".jpg"))
+ }
+
+/**
+ * [true] if url can be retrieved to get a direct image url
+ */
+inline val String.isIndirectImageUrl: Boolean
+ get() {
+ return contains("/photo/view_full_size/") && contains("fbid=")
+ }
/**
* [true] if url can be displayed in a different webview
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
index 7e5f1632..b58f1a16 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
@@ -4,6 +4,7 @@ import com.pitchedapps.frost.activities.WebOverlayActivity
import com.pitchedapps.frost.activities.WebOverlayActivityBase
import com.pitchedapps.frost.activities.WebOverlayBasicActivity
import com.pitchedapps.frost.contracts.VideoViewHolder
+import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
import com.pitchedapps.frost.facebook.formattedFbUrl
@@ -37,7 +38,12 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean {
}
if (url.isImageUrl) {
L.d { "Found fb image" }
- context.launchImageActivity(url.formattedFbUrl, null)
+ context.launchImageActivity(url.formattedFbUrl)
+ return true
+ }
+ if (url.isIndirectImageUrl) {
+ L.d { "Found indirect fb image" }
+ context.launchImageActivity(url.formattedFbUrl, cookie = FbCookie.webCookie)
return true
}
if (!url.isIndependent) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
index f1d03f35..a1fd594f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -7,7 +7,9 @@ import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import com.pitchedapps.frost.facebook.FB_URL_BASE
+import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.injectors.*
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.views.FrostWebView
@@ -57,7 +59,6 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
)
}
-
override fun onPageCommitVisible(view: WebView, url: String?) {
super.onPageCommitVisible(view, url)
injectBackgroundColor()
@@ -91,7 +92,7 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
onPageFinishedActions(url)
}
- open internal fun onPageFinishedActions(url: String) {
+ internal open fun onPageFinishedActions(url: String) {
if (url.startsWith("${FbItem.MESSAGES.url}/read/") && Prefs.messageScrollToBottom)
web.pageDown(true)
injectAndFinish()
@@ -125,9 +126,9 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
return web.requestWebOverlay(request.url.toString())
}
- private fun launchImage(url: String, text: String? = null): Boolean {
+ private fun launchImage(url: String, text: String? = null, cookie: String? = null): Boolean {
v { "Launching image: $url" }
- web.context.launchImageActivity(url, text)
+ web.context.launchImageActivity(url, text, cookie)
if (web.canGoBack()) web.goBack()
return true
}
@@ -143,7 +144,9 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() {
}
if (path.startsWith("/composer/")) return launchRequest(request)
if (url.isImageUrl)
- return launchImage(url)
+ return launchImage(url.formattedFbUrl)
+ if (url.isIndirectImageUrl)
+ return launchImage(url.formattedFbUrl, cookie = FbCookie.webCookie)
if (Prefs.linksInDefaultApp && view.context.resolveActivityForUri(request.url)) return true
return super.shouldOverrideUrlLoading(view, request)
}