<commit_before>package de.danoeh.antennapod.core.storage;

import android.app.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import org.shredzone.flattr4j.model.Flattr;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
import de.danoeh.antennapod.core.util.flattr.FlattrThing;
import de.danoeh.antennapod.core.util.flattr.SimpleFlattrThing;
import de.greenrobot.event.EventBus;

/**
 * Provides methods for writing data to AntennaPod's database.
 * In general, DBWriter-methods will be executed on an internal ExecutorService.
 * Some methods return a Future-object which the caller can use for waiting for the method's completion. The returned Future's
 * will NOT contain any results.
 * The caller can also use the {@link EventDistributor} in order to be notified about the method's completion asynchronously.
 * This class will use the {@link EventDistributor} to notify listeners about changes in the database.
 */
public class DBWriter {

    private static final String TAG = "DBWriter";

    private static final ExecutorService dbExec;

    static {
        dbExec = Executors.newSingleThreadExecutor(r -> {
            Thread t = new Thread(r);
            t.setPriority(Thread.MIN_PRIORITY);
            return t;
        });
    }

    private DBWriter() {
    }

    /**
     * Deletes a downloaded FeedMedia file from the storage device.
     *
     * @param context A context that is used for opening a database connection.
     * @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
     */
    public static Future<?> deleteFeedMediaOfItem(final Context context,
                                                  final long mediaId) {
        return dbExec.submit(() -> {
            final FeedMedia media = DBReader.getFeedMedia(mediaId);
            if (media != null) {
                Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s",
                        media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded())));
                boolean result = false;
                if (media.isDownloaded()) {
                    // delete downloaded media file
                    File mediaFile = new File(media.getFile_url());
                    if (mediaFile.exists()) {
                        result = mediaFile.delete();
                    }
                    media.setDownloaded(false);
                    media.setFile_url(null);
                    media.setHasEmbeddedPicture(false);
                    PodDBAdapter adapter = PodDBAdapter.getInstance();
                    adapter.open();
                    adapter.setMedia(media);
                    adapter.close();

                    // If media is currently being played, change playback
                    // type to 'stream' and shutdown playback service
                    SharedPreferences prefs = PreferenceManager
                            .getDefaultSharedPreferences(context);
                    if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
                        if (media.getId() == PlaybackPreferences
                                .getCurrentlyPlayingFeedMediaId()) {
                            SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(
                                    PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM,
                                    true);
                            editor.commit();
                        }
                        if (PlaybackPreferences
                                .getCurrentlyPlayingFeedMediaId() == media
                                .getId()) {
                            context.sendBroadcast(new Intent(
                                    PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
                        }
                    }
                    // Gpodder: queue delete action for synchronization
                    if(GpodnetPreferences.loggedIn()) {
                        FeedItem item = media.getItem();
                        GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.DELETE)
                                .currentDeviceId()
                                .currentTimestamp()
                                .build();
                        GpodnetPreferences.enqueueEpisodeAction(action);
                    }
                }
                Log.d(TAG, "Deleting File. Result: " + result);
                EventBus.getDefault().post(FeedItemEvent.deletedMedia(Collections.singletonList(media.getItem())));
                EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
            }
        });
    }<commit_msg>Check successful file deletion<commit_after>package de.danoeh.antennapod.core.storage;

import android.app.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import android.widget.Toast;
import org.shredzone.flattr4j.model.Flattr;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
import de.danoeh.antennapod.core.util.flattr.FlattrThing;
import de.danoeh.antennapod.core.util.flattr.SimpleFlattrThing;
import de.greenrobot.event.EventBus;

/**
 * Provides methods for writing data to AntennaPod's database.
 * In general, DBWriter-methods will be executed on an internal ExecutorService.
 * Some methods return a Future-object which the caller can use for waiting for the method's completion. The returned Future's
 * will NOT contain any results.
 * The caller can also use the {@link EventDistributor} in order to be notified about the method's completion asynchronously.
 * This class will use the {@link EventDistributor} to notify listeners about changes in the database.
 */
public class DBWriter {

    private static final String TAG = "DBWriter";

    private static final ExecutorService dbExec;

    static {
        dbExec = Executors.newSingleThreadExecutor(r -> {
            Thread t = new Thread(r);
            t.setPriority(Thread.MIN_PRIORITY);
            return t;
        });
    }

    private DBWriter() {
    }

    /**
     * Deletes a downloaded FeedMedia file from the storage device.
     *
     * @param context A context that is used for opening a database connection.
     * @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
     */
    public static Future<?> deleteFeedMediaOfItem(final Context context,
                                                  final long mediaId) {
        return dbExec.submit(() -> {
            final FeedMedia media = DBReader.getFeedMedia(mediaId);
            if (media != null) {
                Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s",
                        media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded())));
                if (media.isDownloaded()) {
                    // delete downloaded media file
                    File mediaFile = new File(media.getFile_url());
                    if (mediaFile.exists()) {
                        if (!mediaFile.delete()) {
                            Toast.makeText(context, "Unable to delete file. Rebooting the device could help.",
                                    Toast.LENGTH_LONG).show();
                            return;
                        }
                    }
                    media.setDownloaded(false);
                    media.setFile_url(null);
                    media.setHasEmbeddedPicture(false);
                    PodDBAdapter adapter = PodDBAdapter.getInstance();
                    adapter.open();
                    adapter.setMedia(media);
                    adapter.close();

                    // If media is currently being played, change playback
                    // type to 'stream' and shutdown playback service
                    SharedPreferences prefs = PreferenceManager
                            .getDefaultSharedPreferences(context);
                    if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
                        if (media.getId() == PlaybackPreferences
                                .getCurrentlyPlayingFeedMediaId()) {
                            SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(
                                    PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM,
                                    true);
                            editor.commit();
                        }
                        if (PlaybackPreferences
                                .getCurrentlyPlayingFeedMediaId() == media
                                .getId()) {
                            context.sendBroadcast(new Intent(
                                    PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
                        }
                    }
                    // Gpodder: queue delete action for synchronization
                    if(GpodnetPreferences.loggedIn()) {
                        FeedItem item = media.getItem();
                        GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.DELETE)
                                .currentDeviceId()
                                .currentTimestamp()
                                .build();
                        GpodnetPreferences.enqueueEpisodeAction(action);
                    }
                }
                EventBus.getDefault().post(FeedItemEvent.deletedMedia(Collections.singletonList(media.getItem())));
                EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
            }
        });
    }
{'fraction_non_alphanumeric': 0.08530549110595514, 'fraction_numerical': 0.00015467904098994585, 'mean_word_length': 2.109160855974994, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 41, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7589972', 'n_tokens_mistral': 3455, 'n_tokens_neox': 3312, 'n_words': 695}