From f47866660ea8e97a621cd575d2d603f51d35b29c Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 29 Jun 2022 14:13:33 +0200 Subject: [PATCH] With Nitter --- .../endpoints/MastodonTimelinesService.java | 3 +- .../client/entities/nitter/Nitter.java | 126 +++++++++++------- .../client/entities/nitter/NitterAccount.java | 36 ----- .../app/fedilab/android/helper/Helper.java | 24 ++++ .../viewmodel/mastodon/TimelinesVM.java | 6 +- 5 files changed, 107 insertions(+), 88 deletions(-) delete mode 100644 app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.java diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java index de296828..ffe82566 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java @@ -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; @@ -233,7 +232,7 @@ public interface MastodonTimelinesService { ); @GET("{account}/rss") - Call getNitterAccount( + Call getNitterAccount( @Path("account") String account ); diff --git a/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java b/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java index 5dc87f84..7d49b26d 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java +++ b/app/src/main/java/app/fedilab/android/client/entities/nitter/Nitter.java @@ -1,18 +1,31 @@ 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 . */ 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; @@ -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 accounts = new HashMap<>(); - @Element(name = "channel") - public Channel channel; + public static HashMap 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 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) @@ -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(); @@ -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 accountCall = mastodonTimelinesService.getNitterAccount(instance); + Call accountCall = mastodonTimelinesService.getNitterAccount(feedItem.creator.replace("@", "")); if (accountCall != null) { try { - Response publicTlResponse = accountCall.execute(); + Response publicTlResponse = accountCall.execute(); if (publicTlResponse.isSuccessful()) { - NitterAccount nitterAccount = publicTlResponse.body(); + Nitter nitterAccount = publicTlResponse.body(); accounts.put(feedItem.creator, nitterAccount); } } catch (Exception e) { @@ -79,58 +98,73 @@ 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; } - Pattern imgPattern = Pattern.compile("]*src=\"([^\"]+)\"[^>]*>"); - Matcher matcher = imgPattern.matcher(feedItem.description); - String description = feedItem.description; - ArrayList attachmentList = new ArrayList<>(); - while (matcher.find()) { - description = description.replaceAll(Pattern.quote(matcher.group()), ""); - Attachment attachment = new Attachment(); - attachment.type = "image"; - attachment.url = matcher.group(1); - attachment.preview_url = matcher.group(1); - attachment.id = matcher.group(1); - attachmentList.add(attachment); + if (feedItem.description != null) { + Pattern imgPattern = Pattern.compile("]*src=\"([^\"]+)\"[^>]*>"); + Matcher matcher = imgPattern.matcher(feedItem.description); + String description = feedItem.description; + ArrayList attachmentList = new ArrayList<>(); + while (matcher.find()) { + description = description.replaceAll(Pattern.quote(matcher.group()), ""); + Attachment attachment = new Attachment(); + attachment.type = "image"; + attachment.url = matcher.group(1); + attachment.preview_url = matcher.group(1); + attachment.id = matcher.group(1); + attachmentList.add(attachment); + } + status.media_attachments = attachmentList; } - status.media_attachments = attachmentList; - return status; } - @Root(name = "channel", strict = false) - public static class Channel implements Serializable { - @ElementList(name = "item") - public List 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; + } } + } diff --git a/app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.java b/app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.java deleted file mode 100644 index b17fbf38..00000000 --- a/app/src/main/java/app/fedilab/android/client/entities/nitter/NitterAccount.java +++ /dev/null @@ -1,36 +0,0 @@ -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 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; - } - - -} diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 361ef13e..20b76d84 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -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 diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index 8b35c02a..d5a65f74 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -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(); @@ -180,8 +178,8 @@ public class TimelinesVM extends AndroidViewModel { if (publicTlResponse.isSuccessful()) { Nitter rssResponse = publicTlResponse.body(); List 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); }