From 5130d3f9926219dc4ab845dbe082a13aad6f1ca8 Mon Sep 17 00:00:00 2001 From: shts Date: Tue, 4 Aug 2015 01:53:20 +0900 Subject: [PATCH] add getting BlogFeed from HTML source --- .../nogifeed/activities/MainActivity.java | 22 +- .../nogifeed/api/AsyncBlogFeedClient.java | 199 ++++++++++++++++++ .../android/nogifeed/models/BlogEntries.java | 37 ++++ .../jp/android/nogifeed/models/BlogEntry.java | 73 +++++++ 4 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/shts/jp/android/nogifeed/api/AsyncBlogFeedClient.java create mode 100644 app/src/main/java/shts/jp/android/nogifeed/models/BlogEntries.java create mode 100644 app/src/main/java/shts/jp/android/nogifeed/models/BlogEntry.java diff --git a/app/src/main/java/shts/jp/android/nogifeed/activities/MainActivity.java b/app/src/main/java/shts/jp/android/nogifeed/activities/MainActivity.java index 812ecdc..61615ba 100644 --- a/app/src/main/java/shts/jp/android/nogifeed/activities/MainActivity.java +++ b/app/src/main/java/shts/jp/android/nogifeed/activities/MainActivity.java @@ -14,10 +14,15 @@ import android.view.MenuInflater; import android.view.MenuItem; +import java.util.ArrayList; + +import shts.jp.android.nogifeed.BuildConfig; import shts.jp.android.nogifeed.R; +import shts.jp.android.nogifeed.api.AsyncBlogFeedClient; +import shts.jp.android.nogifeed.common.Logger; import shts.jp.android.nogifeed.fragments.AllFeedListFragment; import shts.jp.android.nogifeed.fragments.FavoriteMemberFeedListFragment; -import shts.jp.android.nogifeed.fragments.NewsFeedListFragment; +import shts.jp.android.nogifeed.models.BlogEntry; import shts.jp.android.nogifeed.views.PagerSlidingTabStrip; /** @@ -116,6 +121,21 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { + if (BuildConfig.DEBUG) { + final AsyncBlogFeedClient.Target target = new AsyncBlogFeedClient.Target(1, 8); + AsyncBlogFeedClient.getBlogEntry(this, target, + new AsyncBlogFeedClient.Callbacks() { + @Override + public void onFinish(ArrayList blogEntries) { + Logger.v(TAG, "blogEntries size(" + blogEntries.size() + ")"); + for (BlogEntry e : blogEntries) { + Logger.v(TAG, "--------------"); + Logger.v(TAG, "blogEntry(" + e.toString() + ")"); + } + } + }); + return super.onOptionsItemSelected(item); + } // TODO: go to settings Intent i = new Intent(this, AboutActivity.class); // MemberListActivity diff --git a/app/src/main/java/shts/jp/android/nogifeed/api/AsyncBlogFeedClient.java b/app/src/main/java/shts/jp/android/nogifeed/api/AsyncBlogFeedClient.java new file mode 100644 index 0000000..a145442 --- /dev/null +++ b/app/src/main/java/shts/jp/android/nogifeed/api/AsyncBlogFeedClient.java @@ -0,0 +1,199 @@ +package shts.jp.android.nogifeed.api; + +import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; + +import shts.jp.android.nogifeed.common.Logger; +import shts.jp.android.nogifeed.models.BlogEntry; +import shts.jp.android.nogifeed.utils.NetworkUtils; + +// TODO: implement pagination +public class AsyncBlogFeedClient { + + private static final String TAG = AsyncBlogFeedClient.class.getSimpleName(); + private static final String URL = "http://blog.nogizaka46.com/"; + private static final String USER_AGENT + = "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52"; + + private static final HandlerThread WORKER_THREAD = new HandlerThread("AsyncBlogFeedClient"); + private static Handler HANDLER; + static { + WORKER_THREAD.start(); + HANDLER = new Handler(WORKER_THREAD.getLooper()); + } + + public interface Callbacks { + public void onFinish(ArrayList blogEntries); + } + + public static class Target { + public int year; + public int month; + public Page page; + public Target(int from, int to) { + Calendar calendar = Calendar.getInstance(); + this.year = calendar.get(Calendar.YEAR); + this.month = calendar.get(Calendar.MONTH) + 1; + this.page = new Page(from, to); + } + public Target(int year, int month, int from, int to) { + this.year = year; + this.month = month; + this.page = new Page(from, to); + } + static class Page { + public int from; + public int to; + Page(int from, int to) { + this.from = from; + this.to = to; + } + } + + public void nextPage() { + Logger.v(TAG, "next before(" + toString() + ")"); +// page.from += 8; +// page.to += 8; + Logger.v(TAG, "next after(" + toString() + ")"); + } + + void nextMonth() { + Logger.v(TAG, "next before(" + toString() + ")"); + if (month == 1) { + month = 12; + year--; + } else { + month--; + } + page.from = 1; + page.to = 8; + Logger.v(TAG, "next after(" + toString() + ")"); + } + + String getDateParameter() { + return String.valueOf(year) + (month < 10 ? String.valueOf("0") + month : month); + } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("year(").append(year).append(") "); + sb.append("month(").append(month).append(") "); + sb.append("from(").append(page.from).append(") "); + sb.append("to(").append(page.to).append(") "); + return sb.toString(); + } + } + + public static boolean getBlogEntry(final Context context, + final Target target, + final Callbacks callbacks) { + if (callbacks == null) { + Logger.w(TAG, "cannot connection because of callback is null."); + return false; + } + + if (target == null) { + Logger.w(TAG, "cannot connection because of entryTarget is null."); + return false; + } + + if (!NetworkUtils.enableNetwork(context)) { + Logger.w(TAG, "cannot connection because of network disconnected."); + return false; + } + + HANDLER.post(new Runnable() { + @Override + public void run() { + try { + final ArrayList blogEntries + = getBlogEntry(target); + + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callbacks.onFinish(blogEntries); + } + }); + + } catch (IOException e) { + Logger.e(TAG, "failed to parse blog feed", e); + } + } + }); + + return true; + } + + private static ArrayList getBlogEntry( + final Target target) throws IOException { + + final ArrayList blogEntries = new ArrayList(); + + // decriment read page to max page size + final int maxSize = getPaginate(target.getDateParameter()); + Logger.v(TAG, "getBlogEntry(Target) in : maxSize(" + maxSize + + ") to(" + target.page.to + ")"); + final boolean needToNextMonth = (maxSize < (target.page.to + 1)); + while (maxSize < (target.page.to + 1)) { + target.page.to--; + } + Logger.v(TAG, "getBlogEntry(Target) in : target(" + target.toString() + ")"); + + for (int i = target.page.from; i < (target.page.to + 1); i++) { + + String pageUrl = URL + "?p=" + i + "&d=" + target.getDateParameter(); + Logger.d(TAG, "getBlogEntry() : pageUrl(" + pageUrl + ")"); + + Document document = Jsoup.connect(pageUrl).userAgent(USER_AGENT).get(); + + Element body = document.body(); + Element sheet = body.getElementById("sheet"); + Elements clearfix = sheet.getElementsByClass("clearfix"); + + final int size = clearfix.size(); + for (int j = 0; j < size; j++) { + Element e = clearfix.get(j); + + String yearmonth = e.getElementsByClass("yearmonth").get(0).text(); + String dd1 = e.getElementsByClass("dd1").get(0).text(); + String dd2 = e.getElementsByClass("dd2").get(0).text(); + String date = yearmonth + "/" + dd1 + " " + dd2; + + String title = e.getElementsByClass("entrytitle").get(0).text(); + String author = e.getElementsByClass("author").get(0).text(); + String url = e.getElementsByTag("a").get(0).attr("href"); + + String comment = body.getElementsByClass("entrybottom") + .get(j).getElementsByTag("a").get(1) + .text().replace("コメント(", "").replace(")", ""); + + blogEntries.add(new BlogEntry(date, title, url, author, comment)); + } + } + + if (needToNextMonth) { + target.nextMonth(); + } + + return blogEntries; + } + + private static int getPaginate(String param) throws IOException { + Document document = Jsoup.connect(URL + "?d=" + param).userAgent(USER_AGENT).get(); + Element paginate = document.body() + .getElementsByClass("paginate").get(0); + return paginate.getElementsByTag("a").size(); + } +} diff --git a/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntries.java b/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntries.java new file mode 100644 index 0000000..4f33874 --- /dev/null +++ b/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntries.java @@ -0,0 +1,37 @@ +package shts.jp.android.nogifeed.models; + +import android.text.TextUtils; + +import java.util.ArrayList; + +/** + * Created by saitoushouta on 15/07/28. + */ +public class BlogEntries extends ArrayList { + + public BlogEntry getEntryFrom(String article) { + for (BlogEntry e : this) { + if (TextUtils.isEmpty(e.url)) { + continue; + } + if (e.url.equals(article)) { + return e; + } + } + return null; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("BlogEntries : ["); + for (BlogEntry e : this) { + if (e == null) { + continue; + } + sb.append(e.toString()).append("\n"); + } + sb.append("]"); + return sb.toString(); + } +} diff --git a/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntry.java b/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntry.java new file mode 100644 index 0000000..9de02f2 --- /dev/null +++ b/app/src/main/java/shts/jp/android/nogifeed/models/BlogEntry.java @@ -0,0 +1,73 @@ +package shts.jp.android.nogifeed.models; + +import android.os.Parcel; +import android.os.Parcelable; + +import shts.jp.android.nogifeed.utils.UrlUtils; + +public class BlogEntry implements Parcelable { + + final String date; + final String title; + final String url; + final String author; + final String comment; + + public BlogEntry(String date, String title, String url, String author, String comment) { + this.date = date; + this.title = title; + this.url = url; + this.author = author; + this.comment = comment; + } + + public String getProfileImageUrl() { + return UrlUtils.getImageUrlFromArticleUrl(url); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("date(").append(date).append(") "); + sb.append("title(").append(title).append(") "); + sb.append("url(").append(url).append(") "); + sb.append("author(").append(author).append(") "); + sb.append("comment(").append(comment).append(") "); + return sb.toString(); + } + + protected BlogEntry(Parcel in) { + date = in.readString(); + title = in.readString(); + url = in.readString(); + author = in.readString(); + comment = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(date); + dest.writeString(title); + dest.writeString(url); + dest.writeString(author); + dest.writeString(comment); + } + + @SuppressWarnings("unused") + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public BlogEntry createFromParcel(Parcel in) { + return new BlogEntry(in); + } + + @Override + public BlogEntry[] newArray(int size) { + return new BlogEntry[size]; + } + }; +} \ No newline at end of file