/*
* Copyright 2018 Allan Wang
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.pitchedapps.frost.facebook.requests
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.utils.L
import okhttp3.Call
import org.apache.commons.text.StringEscapeUtils
import org.jsoup.Jsoup
import java.io.IOException
/**
* Created by Allan Wang on 29/12/17.
*/
fun RequestAuth.getMenuData(): FrostRequest {
val body = listOf(
"fb_dtsg" to fb_dtsg,
"__user" to userId
).withEmptyData("m_sess", "__dyn", "__req", "__ajax__")
return frostRequest(::parseMenu) {
url("${FB_URL_BASE}bookmarks/flyout/body/?id=u_0_2")
post(body.toForm())
}
}
fun parseMenu(call: Call): MenuData? {
val fullString = call.execute().body()?.string() ?: return null
var jsonString = fullString.substringAfter("bookmarkGroups", "")
.substringAfter("[", "")
if (jsonString.isBlank()) return null
jsonString = "{ \"data\" : [${StringEscapeUtils.unescapeEcmaScript(jsonString)}"
val mapper = ObjectMapper()
.disable(MapperFeature.AUTO_DETECT_SETTERS)
return try {
val data = mapper.readValue(jsonString, MenuData::class.java)
// parse footer content
val footer = fullString.substringAfter("footerMarkup", "")
.substringAfter("{", "")
.substringBefore("}", "")
val doc = Jsoup.parseBodyFragment(
StringEscapeUtils.unescapeEcmaScript(
StringEscapeUtils.unescapeEcmaScript(footer)
)
)
val footerData = mutableListOf()
val footerSmallData = mutableListOf()
doc.select("a[href]").forEach {
val text = it.text()
it.parent()
if (text.isEmpty()) return@forEach
val href = it.attr("href").formattedFbUrl
val item = MenuFooterItem(name = text, url = href)
if (it.parent().tag().name == "span")
footerSmallData.add(item)
else
footerData.add(item)
}
return data.copy(footer = MenuFooter(footerData, footerSmallData))
} catch (e: IOException) {
L.e(e) { "Menu parse fail" }
null
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
data class MenuData(
val data: List = emptyList(),
val footer: MenuFooter = MenuFooter()
) {
@JsonCreator
constructor(
@JsonProperty("data") data: List?
) : this(data ?: emptyList(), MenuFooter())
fun flatMapValid(): List {
val items = mutableListOf()
data.forEach {
if (it.isValid) items.add(it)
items.addAll(it.visible.filter(MenuItem::isValid))
}
items.addAll(footer.data.filter(MenuFooterItem::isValid))
items.addAll(footer.smallData.filter(MenuFooterItem::isValid))
return items
}
}
interface MenuItemData {
val isValid: Boolean
}
@JsonIgnoreProperties(ignoreUnknown = true)
data class MenuHeader(
val id: String? = null,
val header: String? = null,
val visible: List