mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2024-12-22 16:50:04 +02:00
With Nitter
This commit is contained in:
parent
2caa24c79b
commit
f47866660e
5 changed files with 107 additions and 88 deletions
|
@ -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.api.Status;
|
||||||
import app.fedilab.android.client.entities.misskey.MisskeyNote;
|
import app.fedilab.android.client.entities.misskey.MisskeyNote;
|
||||||
import app.fedilab.android.client.entities.nitter.Nitter;
|
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 app.fedilab.android.client.entities.peertube.PeertubeVideo;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.Body;
|
import retrofit2.http.Body;
|
||||||
|
@ -233,7 +232,7 @@ public interface MastodonTimelinesService {
|
||||||
);
|
);
|
||||||
|
|
||||||
@GET("{account}/rss")
|
@GET("{account}/rss")
|
||||||
Call<NitterAccount> getNitterAccount(
|
Call<Nitter> getNitterAccount(
|
||||||
@Path("account") String account
|
@Path("account") String account
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
package app.fedilab.android.client.entities.nitter;
|
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 android.content.Context;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import androidx.annotation.NonNull;
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import org.simpleframework.xml.Element;
|
import org.simpleframework.xml.Element;
|
||||||
import org.simpleframework.xml.ElementList;
|
import org.simpleframework.xml.ElementList;
|
||||||
|
import org.simpleframework.xml.Namespace;
|
||||||
|
import org.simpleframework.xml.Path;
|
||||||
import org.simpleframework.xml.Root;
|
import org.simpleframework.xml.Root;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -27,19 +40,26 @@ import okhttp3.OkHttpClient;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
|
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
|
||||||
|
|
||||||
@Root(name = "rss", strict = false)
|
@Root(name = "rss", strict = false)
|
||||||
public class Nitter implements Serializable {
|
public class Nitter implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
public static HashMap<String, NitterAccount> accounts = new HashMap<>();
|
public static HashMap<String, Nitter> accounts = new HashMap<>();
|
||||||
@Element(name = "channel")
|
|
||||||
public Channel channel;
|
@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) {
|
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()
|
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||||
.readTimeout(60, TimeUnit.SECONDS)
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
.connectTimeout(60, TimeUnit.SECONDS)
|
.connectTimeout(60, TimeUnit.SECONDS)
|
||||||
|
@ -48,7 +68,6 @@ public class Nitter implements Serializable {
|
||||||
.build();
|
.build();
|
||||||
Retrofit retrofit = new Retrofit.Builder()
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
.baseUrl("https://" + instance)
|
.baseUrl("https://" + instance)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.addConverterFactory(SimpleXmlConverterFactory.create())
|
.addConverterFactory(SimpleXmlConverterFactory.create())
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.build();
|
.build();
|
||||||
|
@ -57,21 +76,21 @@ public class Nitter implements Serializable {
|
||||||
|
|
||||||
public static Status convert(Context context, String instance, FeedItem feedItem) {
|
public static Status convert(Context context, String instance, FeedItem feedItem) {
|
||||||
Status status = new Status();
|
Status status = new Status();
|
||||||
status.id = feedItem.pubDate.toString();
|
status.id = feedItem.pubDate;
|
||||||
status.content = feedItem.title;
|
status.content = feedItem.title;
|
||||||
status.text = feedItem.title;
|
status.text = feedItem.title;
|
||||||
status.visibility = "public";
|
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.uri = feedItem.guid;
|
||||||
status.url = feedItem.link;
|
status.url = feedItem.link;
|
||||||
if (feedItem.creator != null && !accounts.containsValue(feedItem.creator)) {
|
if (!accounts.containsValue(feedItem.creator)) {
|
||||||
MastodonTimelinesService mastodonTimelinesService = initInstanceXMLOnly(context, instance);
|
MastodonTimelinesService mastodonTimelinesService = initInstanceXMLOnly(context, instance);
|
||||||
Call<NitterAccount> accountCall = mastodonTimelinesService.getNitterAccount(instance);
|
Call<Nitter> accountCall = mastodonTimelinesService.getNitterAccount(feedItem.creator.replace("@", ""));
|
||||||
if (accountCall != null) {
|
if (accountCall != null) {
|
||||||
try {
|
try {
|
||||||
Response<NitterAccount> publicTlResponse = accountCall.execute();
|
Response<Nitter> publicTlResponse = accountCall.execute();
|
||||||
if (publicTlResponse.isSuccessful()) {
|
if (publicTlResponse.isSuccessful()) {
|
||||||
NitterAccount nitterAccount = publicTlResponse.body();
|
Nitter nitterAccount = publicTlResponse.body();
|
||||||
accounts.put(feedItem.creator, nitterAccount);
|
accounts.put(feedItem.creator, nitterAccount);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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) {
|
if (nitterAccount != null) {
|
||||||
app.fedilab.android.client.entities.api.Account account = new app.fedilab.android.client.entities.api.Account();
|
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.id = feedItem.guid;
|
||||||
account.acct = names[1];
|
account.acct = names[1];
|
||||||
account.username = names[1];
|
account.username = names[1];
|
||||||
account.display_name = names[0];
|
account.display_name = names[0];
|
||||||
account.avatar = nitterAccount.channel.image.url;
|
account.avatar = nitterAccount.image.url;
|
||||||
account.avatar_static = nitterAccount.channel.image.url;
|
account.avatar_static = nitterAccount.image.url;
|
||||||
account.url = nitterAccount.channel.image.link;
|
account.url = nitterAccount.image.link;
|
||||||
status.account = account;
|
status.account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
|
if (feedItem.description != null) {
|
||||||
Matcher matcher = imgPattern.matcher(feedItem.description);
|
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
|
||||||
String description = feedItem.description;
|
Matcher matcher = imgPattern.matcher(feedItem.description);
|
||||||
ArrayList<Attachment> attachmentList = new ArrayList<>();
|
String description = feedItem.description;
|
||||||
while (matcher.find()) {
|
ArrayList<Attachment> attachmentList = new ArrayList<>();
|
||||||
description = description.replaceAll(Pattern.quote(matcher.group()), "");
|
while (matcher.find()) {
|
||||||
Attachment attachment = new Attachment();
|
description = description.replaceAll(Pattern.quote(matcher.group()), "");
|
||||||
attachment.type = "image";
|
Attachment attachment = new Attachment();
|
||||||
attachment.url = matcher.group(1);
|
attachment.type = "image";
|
||||||
attachment.preview_url = matcher.group(1);
|
attachment.url = matcher.group(1);
|
||||||
attachment.id = matcher.group(1);
|
attachment.preview_url = matcher.group(1);
|
||||||
attachmentList.add(attachment);
|
attachment.id = matcher.group(1);
|
||||||
|
attachmentList.add(attachment);
|
||||||
|
}
|
||||||
|
status.media_attachments = attachmentList;
|
||||||
}
|
}
|
||||||
status.media_attachments = attachmentList;
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Root(name = "channel", strict = false)
|
@Root(name = "image", strict = false)
|
||||||
public static class Channel implements Serializable {
|
public static class Image implements Serializable {
|
||||||
@ElementList(name = "item")
|
@Element(name = "title")
|
||||||
public List<FeedItem> mFeedItems;
|
public String title;
|
||||||
|
@Element(name = "url")
|
||||||
|
public String url;
|
||||||
|
@Element(name = "link")
|
||||||
|
public String link;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Root(name = "item", strict = false)
|
@Root(name = "item", strict = false)
|
||||||
public static class FeedItem implements Serializable {
|
public static class FeedItem implements Serializable {
|
||||||
@ElementList(name = "dc:creator", required = false)
|
@Namespace(prefix = "dc")
|
||||||
|
@Element(name = "creator", required = false)
|
||||||
public String creator;
|
public String creator;
|
||||||
@ElementList(name = "title")
|
@Element(name = "title", required = false)
|
||||||
public String title;
|
public String title;
|
||||||
@ElementList(name = "description", required = false)
|
@Element(name = "description", required = false)
|
||||||
public String description;
|
public String description;
|
||||||
@ElementList(name = "pubDate")
|
@Element(name = "pubDate", required = false)
|
||||||
public Date pubDate;
|
public String pubDate;
|
||||||
@ElementList(name = "guid", required = false)
|
@Element(name = "guid", required = false)
|
||||||
public String guid;
|
public String guid;
|
||||||
@ElementList(name = "link", required = false)
|
@Element(name = "link", required = false)
|
||||||
public String link;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -590,6 +590,30 @@ public class Helper {
|
||||||
return date;
|
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
|
* Converts dp to pixel
|
||||||
|
|
|
@ -94,10 +94,8 @@ public class TimelinesVM extends AndroidViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MastodonTimelinesService initInstanceXMLOnly(String instance) {
|
private MastodonTimelinesService initInstanceXMLOnly(String instance) {
|
||||||
Gson gson = new GsonBuilder().setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();
|
|
||||||
Retrofit retrofit = new Retrofit.Builder()
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
.baseUrl("https://" + instance)
|
.baseUrl("https://" + instance)
|
||||||
//.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.addConverterFactory(SimpleXmlConverterFactory.create())
|
.addConverterFactory(SimpleXmlConverterFactory.create())
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.build();
|
.build();
|
||||||
|
@ -180,8 +178,8 @@ public class TimelinesVM extends AndroidViewModel {
|
||||||
if (publicTlResponse.isSuccessful()) {
|
if (publicTlResponse.isSuccessful()) {
|
||||||
Nitter rssResponse = publicTlResponse.body();
|
Nitter rssResponse = publicTlResponse.body();
|
||||||
List<Status> statusList = new ArrayList<>();
|
List<Status> statusList = new ArrayList<>();
|
||||||
if (rssResponse != null && rssResponse.channel != null && rssResponse.channel.mFeedItems != null) {
|
if (rssResponse != null && rssResponse.mFeedItems != null) {
|
||||||
for (Nitter.FeedItem feedItem : rssResponse.channel.mFeedItems) {
|
for (Nitter.FeedItem feedItem : rssResponse.mFeedItems) {
|
||||||
Status status = Nitter.convert(getApplication(), instance, feedItem);
|
Status status = Nitter.convert(getApplication(), instance, feedItem);
|
||||||
statusList.add(status);
|
statusList.add(status);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue