Compare commits
19 Commits
Author | SHA1 | Date |
---|---|---|
akaessens | ec681e45e1 | |
akaessens | a38bf1dcc1 | |
akaessens | 9d56911c04 | |
akaessens | 2ef6a35862 | |
akaessens | 43458af11c | |
akaessens | 2a67c74f57 | |
akaessens | 8f8d0d07a8 | |
akaessens | 7fdfd38cdc | |
akaessens | b4d37fbc3f | |
akaessens | 2b035b6975 | |
akaessens | 32da94c275 | |
akaessens | 866889db27 | |
akaessens | 6248e79021 | |
akaessens | e8893fd712 | |
akaessens | 6c00e63d1f | |
akaessens | b37fa14d96 | |
akaessens | c6e25fdcfb | |
akaessens | 1ec5c5ea41 | |
akaessens | e051e66188 |
|
@ -2,9 +2,7 @@ name: Android CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -13,9 +11,9 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: set up JDK 1.8
|
- uses: actions/setup-java@v2
|
||||||
uses: actions/setup-java@v1
|
|
||||||
with:
|
with:
|
||||||
java-version: 1.8
|
distribution: 'adopt'
|
||||||
|
java-version: '11'
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
|
10
CHANGELOG.md
|
@ -1,4 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
## v0.5.0 (15)
|
||||||
|
- parallelize multiple event scraping
|
||||||
|
- add scraping history
|
||||||
|
- allow entering page name without URL format
|
||||||
|
- updated dependencies
|
||||||
|
## v0.4.4 (14)
|
||||||
|
- Fix Android 11 intents (to open Calendar or Maps)
|
||||||
|
## v0.4.3 (13)
|
||||||
|
- Add spanish translation thanks to @sguinetti
|
||||||
|
- update dependencies
|
||||||
## v0.4.2 (12)
|
## v0.4.2 (12)
|
||||||
- Fix scraping not working when cookies need to be accepted
|
- Fix scraping not working when cookies need to be accepted
|
||||||
- Android 11 ready
|
- Android 11 ready
|
||||||
|
|
|
@ -33,7 +33,8 @@ This Android app is written in Java and is using the Gradle build system. To com
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
|
|
||||||
<img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" alt="Screenshot 1" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" alt="Screenshot 2" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" alt="Screenshot 3" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" alt="Screenshot 4" width="200">
|
<img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" alt="Screenshot 1" width="150"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" alt="Screenshot 2" width="150"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" alt="Screenshot 3" width="150"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" alt="Screenshot 4" width="150"> <img
|
||||||
|
src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png" alt="Screenshot 5" width="150">
|
||||||
|
|
||||||
# Donations
|
# Donations
|
||||||
I develop this application in my free time. If you like it, you can donate at <a href="https://www.paypal.me/andreaskaessens">PayPal</a>.
|
I develop this application in my free time. If you like it, you can donate at <a href="https://www.paypal.me/andreaskaessens">PayPal</a>.
|
||||||
|
|
|
@ -7,8 +7,8 @@ android {
|
||||||
applicationId "com.akdev.nofbeventscraper"
|
applicationId "com.akdev.nofbeventscraper"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 13
|
versionCode 15
|
||||||
versionName "0.4.3"
|
versionName "0.5.0"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -25,31 +25,31 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
// androidx
|
// androidx
|
||||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.navigation:navigation-fragment:2.3.5'
|
implementation 'androidx.navigation:navigation-fragment:2.3.5'
|
||||||
implementation 'androidx.navigation:navigation-ui:2.3.5'
|
implementation 'androidx.navigation:navigation-ui:2.3.5'
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
implementation "androidx.webkit:webkit:1.4.0"
|
implementation "androidx.webkit:webkit:1.4.0"
|
||||||
|
|
||||||
// JSON save/restore shared preference
|
// JSON save/restore shared preference
|
||||||
implementation 'com.google.code.gson:gson:2.8.5'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
|
|
||||||
// Theme
|
// Theme
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
|
|
||||||
// Scraping
|
// Scraping
|
||||||
implementation 'org.jsoup:jsoup:1.13.1'
|
implementation 'org.jsoup:jsoup:1.14.1'
|
||||||
|
|
||||||
// Image loading and transforming
|
// Image loading and transforming
|
||||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||||
|
|
||||||
// animations and transformations
|
// animations and transformations
|
||||||
implementation 'jp.wasabeef:picasso-transformations:2.2.1'
|
implementation 'jp.wasabeef:picasso-transformations:2.4.0'
|
||||||
implementation 'jp.wasabeef:recyclerview-animators:3.0.0'
|
implementation 'jp.wasabeef:recyclerview-animators:4.0.2'
|
||||||
// tests
|
// tests
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,58 @@
|
||||||
package com.akdev.nofbeventscraper;
|
package com.akdev.nofbeventscraper;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.jsoup.Connection;
|
import org.jsoup.Connection;
|
||||||
|
import org.jsoup.HttpStatusException;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class DocumentReceiver {
|
public class DocumentReceiver {
|
||||||
|
|
||||||
public static org.jsoup.nodes.Document getDocument(String url) {
|
public static org.jsoup.nodes.Document getDocument(String url) throws HttpStatusException, IOException {
|
||||||
|
|
||||||
org.jsoup.nodes.Document document;
|
org.jsoup.nodes.Document document;
|
||||||
|
|
||||||
|
// use default android user agent
|
||||||
|
String user_agent = "Mozilla/5.0 (X11; Linux x86_64)";
|
||||||
|
|
||||||
|
Log.d("scraperLog", "DocumentReceiver: " + url);
|
||||||
|
|
||||||
|
Connection connection = Jsoup.connect(url).userAgent(user_agent).followRedirects(true);
|
||||||
|
|
||||||
|
Connection.Response response = connection.execute();
|
||||||
|
|
||||||
|
document = response.parse();
|
||||||
|
|
||||||
|
Log.d("scraperLog", "Document title: " + document.title());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// use default android user agent
|
// accept cookies needed?
|
||||||
String user_agent = "Mozilla/5.0 (X11; Linux x86_64)";
|
Element form = document.select("form[method=post]").first();
|
||||||
|
String action = form.attr("action");
|
||||||
|
|
||||||
Connection connection = Jsoup.connect(url).userAgent(user_agent).followRedirects(true);
|
List<String> names = form.select("input").eachAttr("name");
|
||||||
|
List<String> values = form.select("input").eachAttr("value");
|
||||||
|
|
||||||
Connection.Response response = connection.execute();
|
Map<String, String> data = new HashMap<String, String>();
|
||||||
|
|
||||||
document = response.parse();
|
for (int i = 0; i < names.size(); i++) {
|
||||||
|
data.put(names.get(i), values.get(i));
|
||||||
try {
|
|
||||||
// accept cookies needed?
|
|
||||||
Element form = document.select("form[method=post]").first();
|
|
||||||
String action = form.attr("action");
|
|
||||||
|
|
||||||
List<String> names = form.select("input").eachAttr("name");
|
|
||||||
List<String> values = form.select("input").eachAttr("value");
|
|
||||||
|
|
||||||
Map<String, String> data = new HashMap<String, String>();
|
|
||||||
|
|
||||||
for (int i = 0; i < names.size(); i++) {
|
|
||||||
data.put(names.get(i), values.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
document = connection.url("https://mbasic.facebook.com" + action)
|
|
||||||
.cookies(response.cookies())
|
|
||||||
.method(Connection.Method.POST)
|
|
||||||
.data(data)
|
|
||||||
.post();
|
|
||||||
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
document = connection.url("https://mbasic.facebook.com" + action)
|
||||||
|
.cookies(response.cookies())
|
||||||
|
.method(Connection.Method.POST)
|
||||||
|
.data(data)
|
||||||
|
.post();
|
||||||
|
|
||||||
|
} catch (Exception ignore) {
|
||||||
}
|
}
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.akdev.nofbeventscraper;
|
||||||
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -14,6 +15,7 @@ import android.view.WindowManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
@ -116,8 +118,12 @@ public class EventAdapter extends
|
||||||
|
|
||||||
Uri intent_uri = Uri.parse(map_search);
|
Uri intent_uri = Uri.parse(map_search);
|
||||||
Intent map_intent = new Intent(Intent.ACTION_VIEW, intent_uri);
|
Intent map_intent = new Intent(Intent.ACTION_VIEW, intent_uri);
|
||||||
if (map_intent.resolveActivity(view.getContext().getPackageManager()) != null) {
|
|
||||||
|
try {
|
||||||
view.getContext().startActivity(map_intent);
|
view.getContext().startActivity(map_intent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast toast=Toast.makeText(view.getContext(),"no App installed", Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -145,8 +151,11 @@ public class EventAdapter extends
|
||||||
String desc = event.url + "\n\n" + event.description;
|
String desc = event.url + "\n\n" + event.description;
|
||||||
intent.putExtra(CalendarContract.Events.DESCRIPTION, desc);
|
intent.putExtra(CalendarContract.Events.DESCRIPTION, desc);
|
||||||
|
|
||||||
if (intent.resolveActivity(view.getContext().getPackageManager()) != null) {
|
try {
|
||||||
view.getContext().startActivity(intent);
|
view.getContext().startActivity(intent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast toast=Toast.makeText(view.getContext(),"no App installed", Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -213,7 +222,12 @@ public class EventAdapter extends
|
||||||
share_intent.setType("text/plain");
|
share_intent.setType("text/plain");
|
||||||
share_intent.putExtra(Intent.EXTRA_TEXT, event.url);
|
share_intent.putExtra(Intent.EXTRA_TEXT, event.url);
|
||||||
|
|
||||||
view.getContext().startActivity(Intent.createChooser(share_intent, null));
|
try {
|
||||||
|
view.getContext().startActivity(share_intent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast toast=Toast.makeText(view.getContext(),"no App installed", Toast.LENGTH_SHORT);
|
||||||
|
toast.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package com.akdev.nofbeventscraper;
|
package com.akdev.nofbeventscraper;
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.jsoup.HttpStatusException;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -143,9 +145,10 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
|
|
||||||
Document document = DocumentReceiver.getDocument(url);
|
Log.d("scraperLog", "doInBackground: "+url);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Document document = DocumentReceiver.getDocument(url);
|
||||||
if (document == null) {
|
if (document == null) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
|
@ -188,7 +191,10 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
|
||||||
|
|
||||||
this.event = new FbEvent(url, name, start_date, end_date, description, location, image_url);
|
this.event = new FbEvent(url, name, start_date, end_date, description, location, image_url);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (HttpStatusException e) {
|
||||||
|
this.error = R.string.error_url;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
this.error = R.string.error_connection;
|
this.error = R.string.error_connection;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.os.AsyncTask;
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.jsoup.HttpStatusException;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -95,13 +96,17 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
|
||||||
url = null;
|
url = null;
|
||||||
event_links = event_links.subList(0, max);
|
event_links = event_links.subList(0, max);
|
||||||
}
|
}
|
||||||
|
} catch (HttpStatusException e) {
|
||||||
|
this.error = R.string.error_url;
|
||||||
|
return null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
this.error = R.string.error_connection;
|
this.error = R.string.error_connection;
|
||||||
|
return null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
this.error = R.string.error_unknown;
|
this.error = R.string.error_unknown;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
} while (url != null);
|
} while (url != null);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.akdev.nofbeventscraper;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
@ -152,8 +153,10 @@ public class FbScraper {
|
||||||
*/
|
*/
|
||||||
void scrapeEvent(String event_url) {
|
void scrapeEvent(String event_url) {
|
||||||
FbEventScraper scraper = new FbEventScraper(this, event_url);
|
FbEventScraper scraper = new FbEventScraper(this, event_url);
|
||||||
|
|
||||||
|
Log.d("scraperLog", "scrapeEvent: "+event_url);
|
||||||
tasks.add(scraper);
|
tasks.add(scraper);
|
||||||
scraper.execute();
|
scraper.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,6 +168,7 @@ public class FbScraper {
|
||||||
void scrapeEventResultCallback(FbEvent event, int error) {
|
void scrapeEventResultCallback(FbEvent event, int error) {
|
||||||
|
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
|
Log.d("scraperLog", "scrapeEventResultCallback: "+event.url);
|
||||||
main.get().addEvent(event);
|
main.get().addEvent(event);
|
||||||
main.get().input_helper(main.get().getString(R.string.done), false);
|
main.get().input_helper(main.get().getString(R.string.done), false);
|
||||||
} else if (url_type == url_type_enum.EVENT) {
|
} else if (url_type == url_type_enum.EVENT) {
|
||||||
|
@ -180,8 +184,10 @@ public class FbScraper {
|
||||||
void scrapePage(String page_url) {
|
void scrapePage(String page_url) {
|
||||||
FbPageScraper scraper = new FbPageScraper(this, page_url);
|
FbPageScraper scraper = new FbPageScraper(this, page_url);
|
||||||
|
|
||||||
|
Log.d("scraperLog", "scrapePage: "+page_url);
|
||||||
|
|
||||||
tasks.add(scraper);
|
tasks.add(scraper);
|
||||||
scraper.execute();
|
scraper.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,10 +199,11 @@ public class FbScraper {
|
||||||
protected void scrapePageResultCallback(List<String> event_urls, int error) {
|
protected void scrapePageResultCallback(List<String> event_urls, int error) {
|
||||||
|
|
||||||
if (event_urls.size() > 0) {
|
if (event_urls.size() > 0) {
|
||||||
|
Log.d("scraperLog", "scrapePageResultCallback: "+event_urls.toString());
|
||||||
for (String event_url : event_urls) {
|
for (String event_url : event_urls) {
|
||||||
try {
|
try {
|
||||||
String url = getEventUrl(event_url);
|
String url = getEventUrl(event_url);
|
||||||
|
Log.d("scraperLog", "scrapePageResultCallback: "+url);
|
||||||
scrapeEvent(url);
|
scrapeEvent(url);
|
||||||
} catch (URISyntaxException | MalformedURLException e) {
|
} catch (URISyntaxException | MalformedURLException e) {
|
||||||
// ignore this event
|
// ignore this event
|
||||||
|
@ -210,11 +217,15 @@ public class FbScraper {
|
||||||
protected void redirectUrl (String url) {
|
protected void redirectUrl (String url) {
|
||||||
FbRedirectionResolver resolver = new FbRedirectionResolver(this, url);
|
FbRedirectionResolver resolver = new FbRedirectionResolver(this, url);
|
||||||
|
|
||||||
resolver.execute();
|
Log.d("scraperLog", "redirectUrl: "+url);
|
||||||
|
|
||||||
|
resolver.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
protected void redirectionResultCallback(String url) {
|
protected void redirectionResultCallback(String url) {
|
||||||
this.input_url = url;
|
this.input_url = url;
|
||||||
|
|
||||||
|
Log.d("scraperLog", "redirectUrlCb: "+url);
|
||||||
|
|
||||||
// now try again with expanded url
|
// now try again with expanded url
|
||||||
this.run();
|
this.run();
|
||||||
}
|
}
|
||||||
|
@ -253,6 +264,17 @@ public class FbScraper {
|
||||||
url_type = url_type_enum.PAGE;
|
url_type = url_type_enum.PAGE;
|
||||||
scrapePage(page_url);
|
scrapePage(page_url);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (URISyntaxException | MalformedURLException e) {
|
||||||
|
url_type = url_type_enum.INVALID;
|
||||||
|
}
|
||||||
|
// check if only page name without prefix
|
||||||
|
try {
|
||||||
|
String page_url = getPageUrl("https://mbasic.facebook.com/"+input_url);
|
||||||
|
url_type = url_type_enum.PAGE;
|
||||||
|
scrapePage(page_url);
|
||||||
|
|
||||||
} catch (URISyntaxException | MalformedURLException e) {
|
} catch (URISyntaxException | MalformedURLException e) {
|
||||||
url_type = url_type_enum.INVALID;
|
url_type = url_type_enum.INVALID;
|
||||||
main.get().input_helper(main.get().getString(R.string.error_url), true);
|
main.get().input_helper(main.get().getString(R.string.error_url), true);
|
||||||
|
|
|
@ -12,6 +12,8 @@ import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.AutoCompleteTextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.view.menu.MenuBuilder;
|
import androidx.appcompat.view.menu.MenuBuilder;
|
||||||
|
@ -23,13 +25,13 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.appbar.AppBarLayout;
|
import com.google.android.material.appbar.AppBarLayout;
|
||||||
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ import static com.akdev.nofbeventscraper.FbEvent.createEventList;
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
protected ExtendedFloatingActionButton paste_button;
|
protected ExtendedFloatingActionButton paste_button;
|
||||||
protected TextInputEditText edit_text_uri_input;
|
protected AutoCompleteTextView edit_text_uri_input;
|
||||||
protected TextInputLayout layout_uri_input;
|
protected TextInputLayout layout_uri_input;
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,6 +51,28 @@ public class MainActivity extends AppCompatActivity {
|
||||||
EventAdapter adapter;
|
EventAdapter adapter;
|
||||||
LinearLayoutManager linear_layout_manager;
|
LinearLayoutManager linear_layout_manager;
|
||||||
|
|
||||||
|
List<String> history;
|
||||||
|
ArrayAdapter<String> history_adapter;
|
||||||
|
|
||||||
|
|
||||||
|
private List<String> getHistory() {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
String json = prefs.getString("history", "");
|
||||||
|
|
||||||
|
Type history_type = new TypeToken<List<String>>() {
|
||||||
|
}.getType();
|
||||||
|
List<String> list = gson.fromJson(json, history_type);
|
||||||
|
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<FbEvent> getSavedEvents() {
|
private List<FbEvent> getSavedEvents() {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
@ -81,6 +105,12 @@ public class MainActivity extends AppCompatActivity {
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getHistory().isEmpty()) {
|
||||||
|
history.clear();
|
||||||
|
history_adapter.clear();
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intent from IntentReceiver - read only once
|
* Intent from IntentReceiver - read only once
|
||||||
*/
|
*/
|
||||||
|
@ -106,6 +136,9 @@ public class MainActivity extends AppCompatActivity {
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = gson.toJson(events);
|
String json = gson.toJson(events);
|
||||||
prefs_edit.putString("events", json);
|
prefs_edit.putString("events", json);
|
||||||
|
|
||||||
|
json = gson.toJson(history);
|
||||||
|
prefs_edit.putString("history", json);
|
||||||
prefs_edit.apply();
|
prefs_edit.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +165,10 @@ public class MainActivity extends AppCompatActivity {
|
||||||
linear_layout_manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
linear_layout_manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
||||||
recycler_view.setLayoutManager(linear_layout_manager);
|
recycler_view.setLayoutManager(linear_layout_manager);
|
||||||
|
|
||||||
|
// restore history
|
||||||
|
this.history = getHistory();
|
||||||
|
history_adapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, history);
|
||||||
|
|
||||||
recycler_view.setItemAnimator(new FadeInAnimator());
|
recycler_view.setItemAnimator(new FadeInAnimator());
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,6 +234,14 @@ public class MainActivity extends AppCompatActivity {
|
||||||
};
|
};
|
||||||
layout_uri_input.setErrorIconOnClickListener(listener);
|
layout_uri_input.setErrorIconOnClickListener(listener);
|
||||||
layout_uri_input.setEndIconOnClickListener(listener);
|
layout_uri_input.setEndIconOnClickListener(listener);
|
||||||
|
edit_text_uri_input.setAdapter(history_adapter);
|
||||||
|
|
||||||
|
layout_uri_input.setStartIconOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
edit_text_uri_input.showDropDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -235,6 +280,9 @@ public class MainActivity extends AppCompatActivity {
|
||||||
scraper = new FbScraper(new WeakReference<>(this), url);
|
scraper = new FbScraper(new WeakReference<>(this), url);
|
||||||
|
|
||||||
scraper.run();
|
scraper.run();
|
||||||
|
|
||||||
|
history_adapter.insert(url, 0);
|
||||||
|
history.add(0, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,16 +43,20 @@ public class SettingsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
final SharedPreferences prefs = preference.getSharedPreferences();
|
final SharedPreferences prefs = preference.getSharedPreferences();
|
||||||
|
|
||||||
final String undo = prefs.getString("events", "");
|
final String events = prefs.getString("events", "");
|
||||||
prefs.edit().remove("events").apply();
|
prefs.edit().remove("events").apply();
|
||||||
|
|
||||||
|
final String history = prefs.getString("history", "");
|
||||||
|
prefs.edit().remove("history").apply();
|
||||||
|
|
||||||
Snackbar.make(getActivity().findViewById(android.R.id.content),
|
Snackbar.make(getActivity().findViewById(android.R.id.content),
|
||||||
getString(R.string.preferences_event_snackbar), Snackbar.LENGTH_SHORT)
|
getString(R.string.preferences_event_snackbar), Snackbar.LENGTH_SHORT)
|
||||||
.setAction(R.string.undo, new View.OnClickListener() {
|
.setAction(R.string.undo, new View.OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
prefs.edit().putString("events", undo).apply();
|
prefs.edit().putString("events", events).apply();
|
||||||
|
prefs.edit().putString("history", history).apply();
|
||||||
}
|
}
|
||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</vector>
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/layout_uri_input"
|
android:id="@+id/layout_uri_input"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
|
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
|
@ -26,9 +26,10 @@
|
||||||
app:endIconMode="clear_text"
|
app:endIconMode="clear_text"
|
||||||
app:errorIconDrawable="@drawable/ic_backspace_black"
|
app:errorIconDrawable="@drawable/ic_backspace_black"
|
||||||
app:helperText="@string/helper_add_link"
|
app:helperText="@string/helper_add_link"
|
||||||
app:helperTextEnabled="true">
|
app:helperTextEnabled="true"
|
||||||
|
app:startIconDrawable="@drawable/ic_history_black">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
android:id="@+id/edit_text_uri_input"
|
android:id="@+id/edit_text_uri_input"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
android:defaultValue="5"
|
android:defaultValue="5"
|
||||||
app:showSeekBarValue="true"
|
app:showSeekBarValue="true"
|
||||||
app:min="1"
|
app:min="1"
|
||||||
android:max="30"
|
android:max="100"
|
||||||
android:summary="@string/preferences_page_event_max_summary"
|
android:summary="@string/preferences_page_event_max_summary"
|
||||||
android:key="page_event_max"
|
android:key="page_event_max"
|
||||||
android:title="@string/preferences_page_event_max" />
|
android:title="@string/preferences_page_event_max" />
|
||||||
|
|
|
@ -4,11 +4,10 @@ buildscript {
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
mavenCentral()
|
||||||
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
@ -18,8 +17,7 @@ buildscript {
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
mavenCentral()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
- Fix Android 11 intents (to open Calendar or Maps)
|
|
@ -0,0 +1,4 @@
|
||||||
|
- parallelize multiple event scraping
|
||||||
|
- add scraping history
|
||||||
|
- allow entering page name without URL format
|
||||||
|
- updated dependencies
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 304 KiB |
Before Width: | Height: | Size: 245 KiB After Width: | Height: | Size: 290 KiB |
Before Width: | Height: | Size: 261 KiB After Width: | Height: | Size: 321 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 185 KiB |
|
@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
||||||
distributionSha256Sum=23e7d37e9bb4f8dabb8a3ea7fdee9dd0428b9b1a71d298aefd65b11dccea220f
|
distributionSha256Sum=bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d
|
||||||
|
|