summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Pösel <robyer@seznam.cz>2016-07-17 19:42:55 +0000
committerRobert Pösel <robyer@seznam.cz>2016-07-17 19:42:55 +0000
commit144d4abae7e3bbdd5c7e6afb9098f84ab443f475 (patch)
treee9eaed82fac22d3ab3d565c3018b91e53c7edc65
parenta992047f2696936927f9b220592ee0edd030bc42 (diff)
Facebook: Greatly improve format of wall post's text
git-svn-id: http://svn.miranda-ng.org/main/trunk@17105 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
-rw-r--r--protocols/FacebookRM/src/communication.cpp6
-rw-r--r--protocols/FacebookRM/src/constants.h5
-rw-r--r--protocols/FacebookRM/src/json.cpp4
-rw-r--r--protocols/FacebookRM/src/process.cpp121
-rw-r--r--protocols/FacebookRM/src/proto.cpp7
5 files changed, 87 insertions, 56 deletions
diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp
index d0c62cae5f..128613ed06 100644
--- a/protocols/FacebookRM/src/communication.cpp
+++ b/protocols/FacebookRM/src/communication.cpp
@@ -768,10 +768,12 @@ void facebook_client::erase_reader(MCONTACT hContact)
}
void loginError(FacebookProto *proto, std::string error_str) {
+ utils::text::replace_all(&error_str, "<br \\/>", "\n");
+ utils::text::replace_all(&error_str, "\n\n\n", "\n\n");
+
error_str = utils::text::trim(
utils::text::html_entities_decode(
- utils::text::remove_html(
- utils::text::edit_html(error_str))));
+ utils::text::remove_html(error_str)));
proto->debugLogA("!!! Login error: %s", !error_str.empty() ? error_str.c_str() : "Unknown error");
diff --git a/protocols/FacebookRM/src/constants.h b/protocols/FacebookRM/src/constants.h
index 8868d6a99a..389f4eec65 100644
--- a/protocols/FacebookRM/src/constants.h
+++ b/protocols/FacebookRM/src/constants.h
@@ -70,6 +70,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MAX_NEWSFEED_LEN 500
#define MAX_LINK_DESCRIPTION_LEN 200
+#define TEXT_ELLIPSIS "\xE2\x80\xA6" // unicode ellipsis
+#define TEXT_EMOJI_LINK "\xF0\x9F\x94\x97" // emoji :link:
+#define TEXT_EMOJI_CLOCK "\xF0\x9F\x95\x92" // emoji :clock3:
+#define TEXT_EMOJI_PAGE "\xF0\x9F\x93\x84" // emoji :page_facing_up:
+
// Defaults
#define FACEBOOK_MINIMAL_POLL_RATE 10
#define FACEBOOK_DEFAULT_POLL_RATE 24 // in seconds
diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp
index 4786213919..4cfa53c3fe 100644
--- a/protocols/FacebookRM/src/json.cpp
+++ b/protocols/FacebookRM/src/json.cpp
@@ -238,7 +238,7 @@ void parseAttachments(FacebookProto *proto, std::string *message_text, const JSO
// shorten long descriptions
if (description.length() > MAX_LINK_DESCRIPTION_LEN)
- description = description.substr(0, MAX_LINK_DESCRIPTION_LEN) + "...";
+ description = description.substr(0, MAX_LINK_DESCRIPTION_LEN) + TEXT_ELLIPSIS;
if (link.find("l." FACEBOOK_SERVER_DOMAIN) != std::string::npos) {
// de-facebook this link
@@ -447,6 +447,8 @@ int facebook_json_parser::parse_messages(std::string *pData, std::vector<faceboo
continue;
}
else {
+ // DeliveryReceipt, MarkRead, ThreadDelete
+
proto->debugLogA("json::parse_messages - Unknown class '%s'", cls.c_str());
}
}
diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp
index aba751c8b9..c76b0c6800 100644
--- a/protocols/FacebookRM/src/process.cpp
+++ b/protocols/FacebookRM/src/process.cpp
@@ -515,6 +515,18 @@ void FacebookProto::SyncThreads(void*)
facy.handle_success("SyncThreads");
}
+std::string truncateUtf8(std::string &text, size_t maxLength) {
+ // To not split some unicode character we need to transform it to TCHAR first, then split it, and then convert it back, because we want std::string as result
+ // TODO: Probably there is much simpler and nicer way
+ std::tstring ttext = ptrT(mir_utf8decodeT(text.c_str()));
+ if (ttext.length() > maxLength) {
+ ttext = ttext.substr(0, maxLength) + _T("\x2026"); // unicode ellipsis
+ return std::string(_T2A(ttext.c_str(), CP_UTF8));
+ }
+ // It's not longer, return given string
+ return text;
+}
+
void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news, DWORD &last_post_time, bool filterAds = true) {
std::string::size_type pos = 0;
UINT limit = 0;
@@ -523,19 +535,12 @@ void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news,
while ((pos = text.find("<div class=\"userContentWrapper", pos)) != std::string::npos && limit <= 25)
{
- /*std::string::size_type pos2 = text.find("<div class=\"userContentWrapper", pos+5);
- if (pos2 == std::string::npos)
- pos2 = text.length();
-
- std::string post = text.substr(pos, pos2 - pos);*/
std::string post = text.substr(pos, text.find("</form>", pos) - pos);
pos += 5;
std::string post_header = utils::text::source_get_value(&post, 3, "<h5", ">", "</h5>");
std::string post_message = utils::text::source_get_value(&post, 3, " userContent\"", ">", "<form");
std::string post_link = utils::text::source_get_value(&post, 4, "</h5>", "<a", "href=\"", "\"");
- //std::string post_attach = utils::text::source_get_value(&post, 4, "<div class=", "uiStreamAttachments", ">", "<form");
-
std::string post_time = utils::text::source_get_value(&post, 3, "</h5>", "<abbr", "</a>");
std::string time = utils::text::source_get_value(&post_time, 2, "data-utime=\"", "\"");
@@ -564,33 +569,23 @@ void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news,
//debugLogA(" - Newsfeed time: %d (normal)", ttime);
}
+ std::string timeandloc = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(time_text)));
std::string post_place = utils::text::source_get_value(&post, 4, "</abbr>", "<a", ">", "</a>");
-
- std::string premsg = "\n" + time_text;
-
- post_place = utils::text::trim(
- utils::text::remove_html(post_place));
+ post_place = utils::text::trim(utils::text::remove_html(post_place));
if (!post_place.empty()) {
- premsg += " - " + post_place;
+ timeandloc += " · " + post_place;
}
- premsg += "\n";
// in title keep only name, end of events like "X shared link" put into message
- std::string::size_type pos2 = post_header.find("?");
-
- if (pos2 != std::string::npos) {
- utils::text::replace_first(&post_header, "?", " � ");
- }
- else {
- pos2 = post_header.find("</a></");
- if (pos2 != std::string::npos) {
- pos2 += 4;
- std::string a = utils::text::trim(utils::text::remove_html(post_header.substr(pos2, post_header.length() - pos2)));
- if (a.length() > 2)
- premsg += a;
- post_header = post_header.substr(0, pos2);
- }
- }
+ std::string::size_type pos2 = post_header.find("</a>");
+ std::string header_author = utils::text::trim(
+ utils::text::html_entities_decode(
+ utils::text::remove_html(
+ post_header.substr(0, pos2))));
+ std::string header_rest = utils::text::trim(
+ utils::text::html_entities_decode(
+ utils::text::remove_html(
+ post_header.substr(pos2, post_header.length() - pos2))));
// Strip "Translate" link
pos2 = post_message.find("role=\"button\">");
@@ -598,16 +593,50 @@ void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news,
post_message = post_message.substr(0, pos2 + 14);
}
- post_message = premsg + post_message;
+ // Process attachment (if present)
+ std::string post_attachment = "";
+ pos2 = post_message.find("class=\"mtm\">");
+ if (pos2 != std::string::npos) {
+ pos2 += 12;
+ post_attachment = post_message.substr(pos2, post_message.length() - pos2);
+ post_message = post_message.substr(0, pos2);
- // append attachement to message (if any)
- //post_message += utils::text::trim(post_attach);
+ // Add new lines between some elements to improve formatting
+ utils::text::replace_all(&post_attachment, "</a>", "</a>\n");
+ utils::text::replace_all(&post_attachment, "ellipsis\">", "ellipsis\">\n");
- facebook_newsfeed* nf = new facebook_newsfeed;
+ post_attachment = utils::text::trim(
+ utils::text::html_entities_decode(
+ utils::text::remove_html(post_attachment)));
+
+ post_attachment = truncateUtf8(post_attachment, MAX_LINK_DESCRIPTION_LEN);
+
+ if (post_attachment.empty()) {
+ // This is some textless attachment, so mention it
+ post_attachment = Translate("<attachment without text>");
+ }
+ }
- nf->title = utils::text::trim(
+ post_message = utils::text::trim(
utils::text::html_entities_decode(
- utils::text::remove_html(post_header)));
+ utils::text::remove_html(post_message)));
+
+ // Truncate text of newsfeed when it's too long
+ post_message = truncateUtf8(post_message, MAX_NEWSFEED_LEN);
+
+ std::string content = "";
+ if (header_rest.length() > 2)
+ content += TEXT_ELLIPSIS + header_rest + "\n";
+ if (!post_message.empty())
+ content += post_message + "\n";
+ if (!post_attachment.empty())
+ content += TEXT_EMOJI_LINK" " + post_attachment + "\n";
+ if (!timeandloc.empty())
+ content += TEXT_EMOJI_CLOCK" " + timeandloc;
+
+ facebook_newsfeed* nf = new facebook_newsfeed;
+
+ nf->title = header_author;
nf->user_id = utils::text::source_get_value(&post_header, 2, "user.php?id=", "&amp;");
@@ -618,10 +647,7 @@ void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news,
|| post.find("class=\"uiStreamSponsoredLink\"") != std::string::npos
|| post.find("href=\"/about/ads\"") != std::string::npos);
- nf->text = utils::text::trim(
- utils::text::html_entities_decode(
- utils::text::remove_html(
- utils::text::edit_html(post_message))));
+ nf->text = utils::text::trim(content);
if (filtered || nf->title.empty() || nf->text.empty()) {
//debugLogA(" \\ Newsfeed (time: %d) is filtered: %s", ttime, filtered ? "advertisement" : (nf->title.empty() ? "title empty" : "text empty"));
@@ -677,13 +703,8 @@ void FacebookProto::ProcessOnThisDay(void*)
for (std::vector<facebook_newsfeed*>::size_type i = 0; i < news.size(); i++)
{
- // Truncate text of newsfeed when it's too long
- std::tstring text = ptrT(mir_utf8decodeT(news[i]->text.c_str()));
- if (text.length() > MAX_NEWSFEED_LEN)
- text = text.substr(0, MAX_NEWSFEED_LEN) + _T("...");
-
ptrT tszTitle(mir_utf8decodeT(news[i]->title.c_str()));
- ptrT tszText(mir_tstrdup(text.c_str()));
+ ptrT tszText(mir_utf8decodeT(news[i]->text.c_str()));
NotifyEvent(TranslateT("On this day"), tszText, NULL, FACEBOOK_EVENT_ON_THIS_DAY, &news[i]->link);
delete news[i];
@@ -1103,15 +1124,11 @@ void FacebookProto::ProcessFeeds(void*)
for (std::vector<facebook_newsfeed*>::size_type i = 0; i < news.size(); i++)
{
- // Truncate text of newsfeed when it's too long
- std::tstring text = ptrT(mir_utf8decodeT(news[i]->text.c_str()));
- if (text.length() > MAX_NEWSFEED_LEN)
- text = text.substr(0, MAX_NEWSFEED_LEN) + _T("...");
-
ptrT tszTitle(mir_utf8decodeT(news[i]->title.c_str()));
- ptrT tszText(mir_tstrdup(text.c_str()));
+ ptrT tszText(mir_utf8decodeT(news[i]->text.c_str()));
+ MCONTACT hContact = ContactIDToHContact(news[i]->user_id);
- NotifyEvent(tszTitle, tszText, this->ContactIDToHContact(news[i]->user_id), FACEBOOK_EVENT_NEWSFEED, &news[i]->link);
+ NotifyEvent(tszTitle, tszText, hContact, FACEBOOK_EVENT_NEWSFEED, &news[i]->link);
delete news[i];
}
news.clear();
diff --git a/protocols/FacebookRM/src/proto.cpp b/protocols/FacebookRM/src/proto.cpp
index ed2125bed5..c5dbb60c2c 100644
--- a/protocols/FacebookRM/src/proto.cpp
+++ b/protocols/FacebookRM/src/proto.cpp
@@ -49,7 +49,7 @@ FacebookProto::FacebookProto(const char* proto_name, const TCHAR* username) :
// Load custom page prefix, if set
ptrT pagePrefix(getTStringA(FACEBOOK_KEY_PAGE_PREFIX));
- m_pagePrefix = (pagePrefix != NULL) ? _T2A(pagePrefix, CP_UTF8) : "\xF0\x9F\x93\x84"; // emoji :page_facing_up:
+ m_pagePrefix = (pagePrefix != NULL) ? _T2A(pagePrefix, CP_UTF8) : TEXT_EMOJI_PAGE;
if (m_tszDefaultGroup == NULL)
m_tszDefaultGroup = mir_tstrdup(_T("Facebook"));
@@ -638,6 +638,11 @@ int FacebookProto::OnPreCreateEvent(WPARAM, LPARAM lParam)
INT_PTR FacebookProto::CheckNewsfeeds(WPARAM, LPARAM)
{
if (!isOffline()) {
+ // If holding control, load all newsfeeds (not only newer since last check)
+ bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ if (ctrlPressed) {
+ facy.last_feeds_update_ = 0;
+ }
NotifyEvent(m_tszUserName, TranslateT("Loading wall posts..."), NULL, FACEBOOK_EVENT_OTHER);
ForkThread(&FacebookProto::ProcessFeeds, NULL);
}