Loading app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +1 −2 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import app.fedilab.android.client.entities.api.MastodonList; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.misskey.MisskeyNote; import app.fedilab.android.client.entities.nitter.Nitter; import app.fedilab.android.client.entities.nitter.NitterAccount; import app.fedilab.android.client.entities.peertube.PeertubeVideo; import retrofit2.Call; import retrofit2.http.Body; Loading Loading @@ -233,7 +232,7 @@ public interface MastodonTimelinesService { ); @GET("{account}/rss") Call<NitterAccount> getNitterAccount( Call<Nitter> getNitterAccount( @Path("account") String account ); Loading app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java +80 −46 Original line number Diff line number Diff line package app.fedilab.android.client.entities.nitter; /* Copyright 2022 Thomas Schneider * * This file is a part of Fedilab * * 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. * * Fedilab 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 Fedilab; if not, * see <http://www.gnu.org/licenses>. */ import android.content.Context; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import androidx.annotation.NonNull; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Path; import org.simpleframework.xml.Root; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; Loading @@ -27,19 +40,26 @@ import okhttp3.OkHttpClient; import retrofit2.Call; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.simplexml.SimpleXmlConverterFactory; @Root(name = "rss", strict = false) public class Nitter implements Serializable { public static HashMap<String, NitterAccount> accounts = new HashMap<>(); @Element(name = "channel") public Channel channel; public static HashMap<String, Nitter> accounts = new HashMap<>(); @Element(name = "title") @Path("channel") public String title; @Element(name = "image") @Path("channel") public Image image; @ElementList(name = "item", inline = true) @Path("channel") public List<FeedItem> mFeedItems; public static MastodonTimelinesService initInstanceXMLOnly(Context context, String instance) { Gson gson = new GsonBuilder().setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .readTimeout(60, TimeUnit.SECONDS) .connectTimeout(60, TimeUnit.SECONDS) Loading @@ -48,7 +68,6 @@ public class Nitter implements Serializable { .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance) .addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(SimpleXmlConverterFactory.create()) .client(okHttpClient) .build(); Loading @@ -57,21 +76,21 @@ public class Nitter implements Serializable { public static Status convert(Context context, String instance, FeedItem feedItem) { Status status = new Status(); status.id = feedItem.pubDate.toString(); status.id = feedItem.pubDate; status.content = feedItem.title; status.text = feedItem.title; status.visibility = "public"; status.created_at = feedItem.pubDate; status.created_at = Helper.stringToDateWithFormat(context, feedItem.pubDate, "EEE, dd MMM yyyy HH:mm:ss zzz"); status.uri = feedItem.guid; status.url = feedItem.link; if (feedItem.creator != null && !accounts.containsValue(feedItem.creator)) { if (!accounts.containsValue(feedItem.creator)) { MastodonTimelinesService mastodonTimelinesService = initInstanceXMLOnly(context, instance); Call<NitterAccount> accountCall = mastodonTimelinesService.getNitterAccount(instance); Call<Nitter> accountCall = mastodonTimelinesService.getNitterAccount(feedItem.creator.replace("@", "")); if (accountCall != null) { try { Response<NitterAccount> publicTlResponse = accountCall.execute(); Response<Nitter> publicTlResponse = accountCall.execute(); if (publicTlResponse.isSuccessful()) { NitterAccount nitterAccount = publicTlResponse.body(); Nitter nitterAccount = publicTlResponse.body(); accounts.put(feedItem.creator, nitterAccount); } } catch (Exception e) { Loading @@ -79,20 +98,21 @@ public class Nitter implements Serializable { } } } NitterAccount nitterAccount = accounts.get(feedItem.creator); Nitter nitterAccount = accounts.get(feedItem.creator); if (nitterAccount != null) { app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account(); String[] names = nitterAccount.channel.image.title.split("/"); String[] names = nitterAccount.image.title.split("/"); account.id = feedItem.guid; account.acct = names[1]; account.username = names[1]; account.display_name = names[0]; account.avatar = nitterAccount.channel.image.url; account.avatar_static = nitterAccount.channel.image.url; account.url = nitterAccount.channel.image.link; account.avatar = nitterAccount.image.url; account.avatar_static = nitterAccount.image.url; account.url = nitterAccount.image.link; status.account = account; } if (feedItem.description != null) { Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>"); Matcher matcher = imgPattern.matcher(feedItem.description); String description = feedItem.description; Loading @@ -107,30 +127,44 @@ public class Nitter implements Serializable { attachmentList.add(attachment); } status.media_attachments = attachmentList; } return status; } @Root(name = "channel", strict = false) public static class Channel implements Serializable { @ElementList(name = "item") public List<FeedItem> mFeedItems; @Root(name = "image", strict = false) public static class Image implements Serializable { @Element(name = "title") public String title; @Element(name = "url") public String url; @Element(name = "link") public String link; } @Root(name = "item", strict = false) public static class FeedItem implements Serializable { @ElementList(name = "dc:creator", required = false) @Namespace(prefix = "dc") @Element(name = "creator", required = false) public String creator; @ElementList(name = "title") @Element(name = "title", required = false) public String title; @ElementList(name = "description", required = false) @Element(name = "description", required = false) public String description; @ElementList(name = "pubDate") public Date pubDate; @ElementList(name = "guid", required = false) @Element(name = "pubDate", required = false) public String pubDate; @Element(name = "guid", required = false) public String guid; @ElementList(name = "link", required = false) @Element(name = "link", required = false) public String link; @NonNull @Override public String toString() { return "creator: " + creator + "\r" + "title: " + title + "\r" + "description: " + description + "\r" + "pubDate: " + pubDate + "\r" + "guid: " + guid + "\r" + "link: " + link; } } } app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.javadeleted 100644 → 0 +0 −36 Original line number Diff line number Diff line package app.fedilab.android.client.entities.nitter; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; import java.io.Serializable; import java.util.HashMap; @Root(name = "rss", strict = false) public class NitterAccount implements Serializable { public static HashMap<String, NitterAccount> accounts = new HashMap<>(); @Element(name = "channel") public Channel channel; @Root(name = "channel", strict = false) public static class Channel implements Serializable { @Element(name = "image") public Image image; } @Root(name = "image", strict = false) public static class Image implements Serializable { @Element(name = "title") public String title; @Element(name = "url") public String url; @Element(name = "link") public String link; } } app/src/main/java/app/fedilab/android/helper/Helper.java +24 −0 Original line number Diff line number Diff line Loading @@ -590,6 +590,30 @@ public class Helper { return date; } /** * Convert String date from db to Date Object * * @param stringDate date to convert * @return Date */ public static Date stringToDateWithFormat(Context context, String stringDate, String format) { if (stringDate == null) return null; Locale userLocale; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { userLocale = context.getResources().getConfiguration().getLocales().get(0); } else { userLocale = context.getResources().getConfiguration().locale; } SimpleDateFormat dateFormat = new SimpleDateFormat(format, userLocale); Date date = null; try { date = dateFormat.parse(stringDate); } catch (java.text.ParseException ignored) { } return date; } /** * Converts dp to pixel Loading app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +2 −4 Original line number Diff line number Diff line Loading @@ -94,10 +94,8 @@ public class TimelinesVM extends AndroidViewModel { } private MastodonTimelinesService initInstanceXMLOnly(String instance) { Gson gson = new GsonBuilder().setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance) //.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(SimpleXmlConverterFactory.create()) .client(okHttpClient) .build(); Loading Loading @@ -180,8 +178,8 @@ public class TimelinesVM extends AndroidViewModel { if (publicTlResponse.isSuccessful()) { Nitter rssResponse = publicTlResponse.body(); List<Status> statusList = new ArrayList<>(); if (rssResponse != null && rssResponse.channel != null && rssResponse.channel.mFeedItems != null) { for (Nitter.FeedItem feedItem : rssResponse.channel.mFeedItems) { if (rssResponse != null && rssResponse.mFeedItems != null) { for (Nitter.FeedItem feedItem : rssResponse.mFeedItems) { Status status = Nitter.convert(getApplication(), instance, feedItem); statusList.add(status); } Loading Loading
app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +1 −2 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import app.fedilab.android.client.entities.api.MastodonList; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.misskey.MisskeyNote; import app.fedilab.android.client.entities.nitter.Nitter; import app.fedilab.android.client.entities.nitter.NitterAccount; import app.fedilab.android.client.entities.peertube.PeertubeVideo; import retrofit2.Call; import retrofit2.http.Body; Loading Loading @@ -233,7 +232,7 @@ public interface MastodonTimelinesService { ); @GET("{account}/rss") Call<NitterAccount> getNitterAccount( Call<Nitter> getNitterAccount( @Path("account") String account ); Loading
app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java +80 −46 Original line number Diff line number Diff line package app.fedilab.android.client.entities.nitter; /* Copyright 2022 Thomas Schneider * * This file is a part of Fedilab * * 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. * * Fedilab 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 Fedilab; if not, * see <http://www.gnu.org/licenses>. */ import android.content.Context; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import androidx.annotation.NonNull; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Path; import org.simpleframework.xml.Root; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; Loading @@ -27,19 +40,26 @@ import okhttp3.OkHttpClient; import retrofit2.Call; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.simplexml.SimpleXmlConverterFactory; @Root(name = "rss", strict = false) public class Nitter implements Serializable { public static HashMap<String, NitterAccount> accounts = new HashMap<>(); @Element(name = "channel") public Channel channel; public static HashMap<String, Nitter> accounts = new HashMap<>(); @Element(name = "title") @Path("channel") public String title; @Element(name = "image") @Path("channel") public Image image; @ElementList(name = "item", inline = true) @Path("channel") public List<FeedItem> mFeedItems; public static MastodonTimelinesService initInstanceXMLOnly(Context context, String instance) { Gson gson = new GsonBuilder().setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .readTimeout(60, TimeUnit.SECONDS) .connectTimeout(60, TimeUnit.SECONDS) Loading @@ -48,7 +68,6 @@ public class Nitter implements Serializable { .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance) .addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(SimpleXmlConverterFactory.create()) .client(okHttpClient) .build(); Loading @@ -57,21 +76,21 @@ public class Nitter implements Serializable { public static Status convert(Context context, String instance, FeedItem feedItem) { Status status = new Status(); status.id = feedItem.pubDate.toString(); status.id = feedItem.pubDate; status.content = feedItem.title; status.text = feedItem.title; status.visibility = "public"; status.created_at = feedItem.pubDate; status.created_at = Helper.stringToDateWithFormat(context, feedItem.pubDate, "EEE, dd MMM yyyy HH:mm:ss zzz"); status.uri = feedItem.guid; status.url = feedItem.link; if (feedItem.creator != null && !accounts.containsValue(feedItem.creator)) { if (!accounts.containsValue(feedItem.creator)) { MastodonTimelinesService mastodonTimelinesService = initInstanceXMLOnly(context, instance); Call<NitterAccount> accountCall = mastodonTimelinesService.getNitterAccount(instance); Call<Nitter> accountCall = mastodonTimelinesService.getNitterAccount(feedItem.creator.replace("@", "")); if (accountCall != null) { try { Response<NitterAccount> publicTlResponse = accountCall.execute(); Response<Nitter> publicTlResponse = accountCall.execute(); if (publicTlResponse.isSuccessful()) { NitterAccount nitterAccount = publicTlResponse.body(); Nitter nitterAccount = publicTlResponse.body(); accounts.put(feedItem.creator, nitterAccount); } } catch (Exception e) { Loading @@ -79,20 +98,21 @@ public class Nitter implements Serializable { } } } NitterAccount nitterAccount = accounts.get(feedItem.creator); Nitter nitterAccount = accounts.get(feedItem.creator); if (nitterAccount != null) { app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account(); String[] names = nitterAccount.channel.image.title.split("/"); String[] names = nitterAccount.image.title.split("/"); account.id = feedItem.guid; account.acct = names[1]; account.username = names[1]; account.display_name = names[0]; account.avatar = nitterAccount.channel.image.url; account.avatar_static = nitterAccount.channel.image.url; account.url = nitterAccount.channel.image.link; account.avatar = nitterAccount.image.url; account.avatar_static = nitterAccount.image.url; account.url = nitterAccount.image.link; status.account = account; } if (feedItem.description != null) { Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>"); Matcher matcher = imgPattern.matcher(feedItem.description); String description = feedItem.description; Loading @@ -107,30 +127,44 @@ public class Nitter implements Serializable { attachmentList.add(attachment); } status.media_attachments = attachmentList; } return status; } @Root(name = "channel", strict = false) public static class Channel implements Serializable { @ElementList(name = "item") public List<FeedItem> mFeedItems; @Root(name = "image", strict = false) public static class Image implements Serializable { @Element(name = "title") public String title; @Element(name = "url") public String url; @Element(name = "link") public String link; } @Root(name = "item", strict = false) public static class FeedItem implements Serializable { @ElementList(name = "dc:creator", required = false) @Namespace(prefix = "dc") @Element(name = "creator", required = false) public String creator; @ElementList(name = "title") @Element(name = "title", required = false) public String title; @ElementList(name = "description", required = false) @Element(name = "description", required = false) public String description; @ElementList(name = "pubDate") public Date pubDate; @ElementList(name = "guid", required = false) @Element(name = "pubDate", required = false) public String pubDate; @Element(name = "guid", required = false) public String guid; @ElementList(name = "link", required = false) @Element(name = "link", required = false) public String link; @NonNull @Override public String toString() { return "creator: " + creator + "\r" + "title: " + title + "\r" + "description: " + description + "\r" + "pubDate: " + pubDate + "\r" + "guid: " + guid + "\r" + "link: " + link; } } }
app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.javadeleted 100644 → 0 +0 −36 Original line number Diff line number Diff line package app.fedilab.android.client.entities.nitter; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; import java.io.Serializable; import java.util.HashMap; @Root(name = "rss", strict = false) public class NitterAccount implements Serializable { public static HashMap<String, NitterAccount> accounts = new HashMap<>(); @Element(name = "channel") public Channel channel; @Root(name = "channel", strict = false) public static class Channel implements Serializable { @Element(name = "image") public Image image; } @Root(name = "image", strict = false) public static class Image implements Serializable { @Element(name = "title") public String title; @Element(name = "url") public String url; @Element(name = "link") public String link; } }
app/src/main/java/app/fedilab/android/helper/Helper.java +24 −0 Original line number Diff line number Diff line Loading @@ -590,6 +590,30 @@ public class Helper { return date; } /** * Convert String date from db to Date Object * * @param stringDate date to convert * @return Date */ public static Date stringToDateWithFormat(Context context, String stringDate, String format) { if (stringDate == null) return null; Locale userLocale; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { userLocale = context.getResources().getConfiguration().getLocales().get(0); } else { userLocale = context.getResources().getConfiguration().locale; } SimpleDateFormat dateFormat = new SimpleDateFormat(format, userLocale); Date date = null; try { date = dateFormat.parse(stringDate); } catch (java.text.ParseException ignored) { } return date; } /** * Converts dp to pixel Loading
app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +2 −4 Original line number Diff line number Diff line Loading @@ -94,10 +94,8 @@ public class TimelinesVM extends AndroidViewModel { } private MastodonTimelinesService initInstanceXMLOnly(String instance) { Gson gson = new GsonBuilder().setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + instance) //.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(SimpleXmlConverterFactory.create()) .client(okHttpClient) .build(); Loading Loading @@ -180,8 +178,8 @@ public class TimelinesVM extends AndroidViewModel { if (publicTlResponse.isSuccessful()) { Nitter rssResponse = publicTlResponse.body(); List<Status> statusList = new ArrayList<>(); if (rssResponse != null && rssResponse.channel != null && rssResponse.channel.mFeedItems != null) { for (Nitter.FeedItem feedItem : rssResponse.channel.mFeedItems) { if (rssResponse != null && rssResponse.mFeedItems != null) { for (Nitter.FeedItem feedItem : rssResponse.mFeedItems) { Status status = Nitter.convert(getApplication(), instance, feedItem); statusList.add(status); } Loading