Skip to content

Commit

Permalink
Update channel status, when YT reports as "terminated"/"deleted"
Browse files Browse the repository at this point in the history
Display the status in the subs drawer, and do not fetch videos for
channels with not-ok state
  • Loading branch information
gzsombor committed Aug 18, 2024
1 parent 2be2fd2 commit e807331
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.Objects;

import free.rm.skytube.businessobjects.YouTube.newpipe.ChannelId;
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeException;
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeService;
import free.rm.skytube.businessobjects.YouTube.newpipe.VideoPager;
Expand All @@ -27,11 +28,11 @@
*/
public class NewPipeChannelVideos extends NewPipeVideos {

private String channelId;
private ChannelId channelId;

// Important, this is called from the channel tab
public void setQuery(String query) {
this.channelId = Objects.requireNonNull(query, "query missing");
this.channelId = new ChannelId(query);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,21 @@
package free.rm.skytube.businessobjects.YouTube.POJOs;

import free.rm.skytube.businessobjects.YouTube.newpipe.ChannelId;
import free.rm.skytube.businessobjects.model.Status;

public class ChannelView {
private final ChannelId id;
private final String title;
private final String thumbnailUrl;
private boolean newVideosSinceLastVisit;
private final Status status;

public ChannelView(ChannelId id, String title, String thumbnailUrl, boolean newVideosSinceLastVisit) {
public ChannelView(ChannelId id, String title, String thumbnailUrl, boolean newVideosSinceLastVisit, Status status) {
this.id = id;
this.title = title;
this.thumbnailUrl = thumbnailUrl;
this.newVideosSinceLastVisit = newVideosSinceLastVisit;
this.status = status;
}

public ChannelId getId() {
Expand All @@ -47,6 +50,10 @@ public boolean isNewVideosSinceLastVisit() {
return newVideosSinceLastVisit;
}

public Status status() {
return status;
}

public void setNewVideosSinceLastVisit(boolean newVideosSinceLastVisit) {
this.newVideosSinceLastVisit = newVideosSinceLastVisit;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,36 @@
*/
package free.rm.skytube.businessobjects.YouTube.POJOs;

import java.util.Objects;

import free.rm.skytube.businessobjects.YouTube.newpipe.ChannelId;
import free.rm.skytube.businessobjects.model.Status;

public final class PersistentChannel {
final YouTubeChannel channel;
final long channelPk;
final Long subscriptionPk;
final Status status;

public PersistentChannel(YouTubeChannel channel, long channelPk, Long subscriptionPk) {
this.channel = channel;
public PersistentChannel(YouTubeChannel channel, long channelPk, Long subscriptionPk, Status status) {
this.channel = Objects.requireNonNull(channel, "channel");
this.channelPk = channelPk;
this.subscriptionPk = subscriptionPk;
this.status = status;
}

public YouTubeChannel channel() {
return channel;
}

public Status status() {
return status;
}

public ChannelId getChannelId() {
return channel.getChannelId();
}

public long channelPk() {
return channelPk;
}
Expand All @@ -45,10 +60,10 @@ public boolean isSubscribed() {

public PersistentChannel with(YouTubeChannel newInstance) {
newInstance.setUserSubscribed(isSubscribed());
return new PersistentChannel(newInstance, channelPk, subscriptionPk);
return new PersistentChannel(newInstance, channelPk, subscriptionPk, status);
}

public PersistentChannel withSubscriptionPk(Long newSubscriptionPk) {
return new PersistentChannel(channel, channelPk, newSubscriptionPk);
return new PersistentChannel(channel, channelPk, newSubscriptionPk, status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;

Expand Down Expand Up @@ -42,8 +44,10 @@
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeException;
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeService;
import free.rm.skytube.businessobjects.YouTube.newpipe.PlaylistPager;
import free.rm.skytube.businessobjects.db.LocalChannelTable;
import free.rm.skytube.businessobjects.db.SubscriptionsDb;
import free.rm.skytube.businessobjects.interfaces.GetDesiredStreamListener;
import free.rm.skytube.businessobjects.model.Status;
import free.rm.skytube.gui.businessobjects.adapters.PlaylistsGridAdapter;
import free.rm.skytube.gui.businessobjects.adapters.VideoGridAdapter;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
Expand Down Expand Up @@ -203,11 +207,23 @@ private static List<YouTubeVideo> fetchVideos(@NonNull SubscriptionsDb subscript
});
return videos;
} catch (NewPipeException e) {
Log.e(TAG, "Error during fetching channel page for " + channelId + ",msg:" + e.getMessage(), e);
handleNewPipeException(channelId, e);
return Collections.emptyList();
}
}

private static void handleNewPipeException(@NonNull ChannelId channelId, @NonNull NewPipeException e) {
if (e.getCause() instanceof AccountTerminatedException) {
Log.e(TAG, "Account terminated for "+ channelId +" error: "+e.getMessage(), e);
SubscriptionsDb.getSubscriptionsDb().setChannelState(channelId, Status.ACCOUNT_TERMINATED);
} else if (e.getCause() instanceof ContentNotAvailableException) {
Log.e(TAG, "Channel doesn't exists "+ channelId +" error: "+e.getMessage(), e);
SubscriptionsDb.getSubscriptionsDb().setChannelState(channelId, Status.NOT_EXISTS);
} else {
Log.e(TAG, "Error during fetching channel page for " + channelId + ",msg:" + e.getMessage(), e);
}
}

/**
* Task to asynchronously get videos for a specific channel.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public List<YouTubePlaylist> getNextPlaylists() throws IOException, ExtractionEx
private synchronized Paging getPaging() throws NewPipeException, ParsingException {
SkyTubeApp.nonUiThread();
if (paging == null) {
NewPipeService.ChannelWithExtractor cwe = NewPipeService.get().getChannelWithExtractor(channel.getId());
NewPipeService.ChannelWithExtractor cwe = NewPipeService.get().getChannelWithExtractor(channel.getChannelId());
paging = new Paging(cwe.channel, cwe.findPlaylistTab());
}
return paging;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public StreamInfo getStreamInfoByVideoId(String videoId) throws ExtractionExcept
* @throws ExtractionException
* @throws IOException
*/
private List<YouTubeVideo> getChannelVideos(String channelId) throws NewPipeException {
private List<YouTubeVideo> getChannelVideos(ChannelId channelId) throws NewPipeException {
SkyTubeApp.nonUiThread();
VideoPagerWithChannel pager = getChannelPager(channelId);
List<YouTubeVideo> result = pager.getNextPageAsVideosAndUpdateChannel(null).channel().getYouTubeVideos();
Expand Down Expand Up @@ -255,7 +255,7 @@ public List<YouTubeVideo> getVideosFromFeedOrFromChannel(ChannelId channelId) th
} catch (IOException | ExtractionException | RuntimeException | NewPipeException e) {
Logger.e(this, "Unable to get videos from a feed " + channelId + " : "+ e.getMessage(), e);
}
return getChannelVideos(channelId.getRawId());
return getChannelVideos(channelId);
}

public VideoPager getTrending() throws NewPipeException {
Expand All @@ -269,7 +269,7 @@ public VideoPager getTrending() throws NewPipeException {
}
}

public VideoPagerWithChannel getChannelPager(String channelId) throws NewPipeException {
public VideoPagerWithChannel getChannelPager(ChannelId channelId) throws NewPipeException {
try {
Logger.e(this, "fetching channel info: "+ channelId);
ChannelWithExtractor channelExtractor = getChannelWithExtractor(channelId);
Expand All @@ -279,7 +279,7 @@ public VideoPagerWithChannel getChannelPager(String channelId) throws NewPipeExc
}
}

public ChannelWithExtractor getChannelWithExtractor(String channelId) throws NewPipeException {
public ChannelWithExtractor getChannelWithExtractor(ChannelId channelId) throws NewPipeException {
try {
ChannelExtractor channelExtractor = getChannelExtractor(channelId);

Expand Down Expand Up @@ -320,7 +320,7 @@ public CommentPager getCommentPager(String videoId) throws NewPipeException {
*/
public PersistentChannel getChannelDetails(ChannelId channelId, PersistentChannel persistentChannel) throws NewPipeException {
Logger.i(this, "Fetching channel details for " + channelId);
VideoPagerWithChannel pager = getChannelPager(channelId.getRawId());
VideoPagerWithChannel pager = getChannelPager(channelId);
// get the channel, and add all the videos from the first page
try {
return pager.getNextPageAsVideosAndUpdateChannel(persistentChannel);
Expand Down Expand Up @@ -359,11 +359,11 @@ private <X> X callParser(ParserCall<X> parser, X defaultValue) {
}
}

private ChannelExtractor getChannelExtractor(String channelId)
private ChannelExtractor getChannelExtractor(ChannelId channelId)
throws ExtractionException, IOException {
// Extract from it
ChannelExtractor channelExtractor = streamingService
.getChannelExtractor(getListLinkHandler(Objects.requireNonNull(channelId, "channelId")));
.getChannelExtractor(getListLinkHandler(Objects.requireNonNull(channelId, "channelId").getRawId()));
channelExtractor.fetchPage();
return channelExtractor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import free.rm.skytube.businessobjects.YouTube.newpipe.ChannelId;
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeException;
import free.rm.skytube.businessobjects.YouTube.newpipe.NewPipeService;
import free.rm.skytube.businessobjects.model.Status;
import free.rm.skytube.gui.businessobjects.views.ChannelSubscriber;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Completable;
Expand Down Expand Up @@ -79,7 +80,15 @@ public static PersistentChannel getChannelOrRefresh(Context context, ChannelId c
needsRefresh = persistentChannel.channel().getLastCheckTime() < System.currentTimeMillis() - (24 * 60 * 60 * 1000L);
}
if (needsRefresh && SkyTubeApp.isConnected(context)) {
return NewPipeService.get().getChannelDetails(channelId, persistentChannel);
try {
return NewPipeService.get().getChannelDetails(channelId, persistentChannel);
} catch (NewPipeException newPipeException) {
if (persistentChannel != null && persistentChannel.status() != Status.OK) {
Log.e(TAG, "Channel is blocked/terminated - and kept that way: "+ persistentChannel+", message:"+newPipeException.getMessage());
return persistentChannel;
}
throw newPipeException;
}
}
return persistentChannel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@

import android.database.sqlite.SQLiteDatabase;

import androidx.annotation.NonNull;

import com.github.skytube.components.utils.Column;
import com.github.skytube.components.utils.SQLiteHelper;
import com.google.common.base.Joiner;

import free.rm.skytube.businessobjects.YouTube.POJOs.PersistentChannel;
import free.rm.skytube.businessobjects.YouTube.newpipe.ChannelId;
import free.rm.skytube.businessobjects.model.Status;

public class LocalChannelTable {

public static final String TABLE_NAME = "Channel";
public static final String COL_CHANNEL_ID_name = "Channel_Id";
public static final String COL_LAST_VIDEO_TS = "Last_Video_TS";
Expand Down Expand Up @@ -77,6 +82,11 @@ public static void updateLatestVideoTimestamp(SQLiteDatabase db, PersistentChann
latestPublishTimestamp, persistentChannel.subscriptionPk()});
}

public static void updateChannelStatus(SQLiteDatabase db, @NonNull ChannelId channelId, @NonNull Status status) {
db.execSQL("update " + TABLE_NAME + " set " + COL_STATE.name() + " = ? where " + COL_CHANNEL_ID.name() + " = ?",
new Object[] { status.code, channelId.getRawId() });
}

public static void addChannelIdIndex(SQLiteDatabase db) {
SQLiteHelper.createIndex(db, "IDX_channel_channelId", TABLE_NAME, COL_CHANNEL_ID);
}
Expand Down
Loading

0 comments on commit e807331

Please sign in to comment.