Add option to export subscriptions as HTML
This commit is contained in:
parent
fee2acb5ab
commit
695a73c09d
|
@ -1,5 +1,6 @@
|
|||
package de.danoeh.antennapod.asynctask;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -7,7 +8,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
|
||||
import de.danoeh.antennapod.core.export.ExportWriter;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.LangUtils;
|
||||
|
@ -16,18 +17,22 @@ import rx.Observable;
|
|||
/**
|
||||
* Writes an OPML file into the export directory in the background.
|
||||
*/
|
||||
public class OpmlExportWorker {
|
||||
public class ExportWorker {
|
||||
|
||||
public static final String EXPORT_DIR = "export/";
|
||||
private static final String TAG = "OpmlExportWorker";
|
||||
private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds.opml";
|
||||
private static final String EXPORT_DIR = "export/";
|
||||
private static final String TAG = "ExportWorker";
|
||||
private static final String DEFAULT_OUTPUT_NAME = "antennapod-feeds";
|
||||
|
||||
private ExportWriter exportWriter;
|
||||
private File output;
|
||||
|
||||
public OpmlExportWorker() {
|
||||
this(new File(UserPreferences.getDataFolder(EXPORT_DIR), DEFAULT_OUTPUT_NAME));
|
||||
public ExportWorker(ExportWriter exportWriter) {
|
||||
this(exportWriter, new File(UserPreferences.getDataFolder(EXPORT_DIR),
|
||||
DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()));
|
||||
}
|
||||
|
||||
public OpmlExportWorker(File output) {
|
||||
public ExportWorker(ExportWriter exportWriter, @NonNull File output) {
|
||||
this.exportWriter = exportWriter;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
|
@ -36,12 +41,11 @@ public class OpmlExportWorker {
|
|||
Log.w(TAG, "Overwriting previously exported file.");
|
||||
output.delete();
|
||||
}
|
||||
OpmlWriter opmlWriter = new OpmlWriter();
|
||||
return Observable.create(subscriber -> {
|
||||
OutputStreamWriter writer = null;
|
||||
try {
|
||||
writer = new OutputStreamWriter(new FileOutputStream(output), LangUtils.UTF_8);
|
||||
opmlWriter.writeDocument(DBReader.getFeedList(), writer);
|
||||
exportWriter.writeDocument(DBReader.getFeedList(), writer);
|
||||
subscriber.onNext(output);
|
||||
} catch (IOException e) {
|
||||
subscriber.onError(e);
|
|
@ -55,7 +55,10 @@ import de.danoeh.antennapod.activity.MainActivity;
|
|||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||
import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
|
||||
import de.danoeh.antennapod.activity.StatisticsActivity;
|
||||
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
|
||||
import de.danoeh.antennapod.asynctask.ExportWorker;
|
||||
import de.danoeh.antennapod.core.export.ExportWriter;
|
||||
import de.danoeh.antennapod.core.export.html.HtmlWriter;
|
||||
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
|
||||
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.GpodnetSyncService;
|
||||
|
@ -85,6 +88,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
|
||||
private static final String PREF_AUTO_FLATTR_PREFS = "prefAutoFlattrPrefs";
|
||||
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
|
||||
private static final String PREF_HTML_EXPORT = "prefHtmlExport";
|
||||
private static final String STATISTICS = "statistics";
|
||||
private static final String PREF_ABOUT = "prefAbout";
|
||||
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
||||
|
@ -181,7 +185,9 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||
}
|
||||
);
|
||||
ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener(
|
||||
preference -> exportOpml());
|
||||
preference -> export(new OpmlWriter()));
|
||||
ui.findPreference(PreferenceController.PREF_HTML_EXPORT).setOnPreferenceClickListener(
|
||||
preference -> export(new HtmlWriter()));
|
||||
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
|
||||
preference -> {
|
||||
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
|
||||
|
@ -438,7 +444,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||
setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
|
||||
}
|
||||
|
||||
private boolean exportOpml() {
|
||||
private boolean export(ExportWriter exportWriter) {
|
||||
Context context = ui.getActivity();
|
||||
final ProgressDialog progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setMessage(context.getString(R.string.exporting_label));
|
||||
|
@ -446,7 +452,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
|||
progressDialog.show();
|
||||
final AlertDialog.Builder alert = new AlertDialog.Builder(context)
|
||||
.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
|
||||
Observable<File> observable = new OpmlExportWorker().exportObservable();
|
||||
Observable<File> observable = new ExportWorker(exportWriter).exportObservable();
|
||||
subscription = observable.subscribeOn(Schedulers.newThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(output -> {
|
||||
|
|
|
@ -288,6 +288,9 @@
|
|||
<Preference
|
||||
android:key="prefOpmlExport"
|
||||
android:title="@string/opml_export_label"/>
|
||||
<Preference
|
||||
android:key="prefHtmlExport"
|
||||
android:title="@string/html_export_label"/>
|
||||
<Preference
|
||||
android:key="statistics"
|
||||
android:title="@string/statistics_label"/>
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Context;
|
|||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
@ -27,10 +28,10 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
|
||||
import de.danoeh.antennapod.core.BuildConfig;
|
||||
import de.danoeh.antennapod.core.export.opml.OpmlElement;
|
||||
import de.danoeh.antennapod.core.export.opml.OpmlReader;
|
||||
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.opml.OpmlElement;
|
||||
import de.danoeh.antennapod.core.opml.OpmlReader;
|
||||
import de.danoeh.antennapod.core.opml.OpmlWriter;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
|
@ -56,7 +57,9 @@ public class OpmlBackupAgent extends BackupAgentHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/** Class for backing up and restoring the OPML file. */
|
||||
/**
|
||||
* Class for backing up and restoring the OPML file.
|
||||
*/
|
||||
private static class OpmlBackupHelper implements BackupHelper {
|
||||
private static final String TAG = "OpmlBackupHelper";
|
||||
|
||||
|
@ -64,7 +67,9 @@ public class OpmlBackupAgent extends BackupAgentHelper {
|
|||
|
||||
private final Context mContext;
|
||||
|
||||
/** Checksum of restored OPML file */
|
||||
/**
|
||||
* Checksum of restored OPML file
|
||||
*/
|
||||
private byte[] mChecksum;
|
||||
|
||||
public OpmlBackupHelper(Context context) {
|
||||
|
@ -170,12 +175,7 @@ public class OpmlBackupAgent extends BackupAgentHelper {
|
|||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to restore OPML backup", e);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
IOUtils.closeQuietly(reader);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.danoeh.antennapod.core.export;
|
||||
|
||||
public class CommonSymbols {
|
||||
|
||||
public static final String HEAD = "head";
|
||||
public static final String BODY = "body";
|
||||
public static final String TITLE = "title";
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.danoeh.antennapod.core.export;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
|
||||
public interface ExportWriter {
|
||||
|
||||
void writeDocument(List<Feed> feeds, Writer writer)
|
||||
throws IllegalArgumentException, IllegalStateException, IOException;
|
||||
|
||||
String fileExtension();
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.danoeh.antennapod.core.export.html;
|
||||
|
||||
import de.danoeh.antennapod.core.export.CommonSymbols;
|
||||
|
||||
class HtmlSymbols extends CommonSymbols {
|
||||
|
||||
static final String HTML = "html";
|
||||
|
||||
static final String ORDERED_LIST = "ol";
|
||||
static final String LIST_ITEM = "li";
|
||||
|
||||
static String HEADING = "h1";
|
||||
|
||||
static final String LINK = "a";
|
||||
static final String LINK_DESTINATION = "href";
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package de.danoeh.antennapod.core.export.html;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.export.ExportWriter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
|
||||
/** Writes HTML documents. */
|
||||
public class HtmlWriter implements ExportWriter {
|
||||
|
||||
private static final String TAG = "HtmlWriter";
|
||||
private static final String ENCODING = "UTF-8";
|
||||
private static final String HTML_TITLE = "AntennaPod Subscriptions";
|
||||
|
||||
/**
|
||||
* Takes a list of feeds and a writer and writes those into an HTML
|
||||
* document.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws IllegalStateException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
@Override
|
||||
public void writeDocument(List<Feed> feeds, Writer writer)
|
||||
throws IllegalArgumentException, IllegalStateException, IOException {
|
||||
Log.d(TAG, "Starting to write document");
|
||||
XmlSerializer xs = Xml.newSerializer();
|
||||
xs.setOutput(writer);
|
||||
|
||||
xs.startDocument(ENCODING, false);
|
||||
xs.text("\n");
|
||||
xs.startTag(null, HtmlSymbols.HTML);
|
||||
xs.text("\n");
|
||||
xs.startTag(null, HtmlSymbols.HEAD);
|
||||
xs.text("\n");
|
||||
xs.startTag(null, HtmlSymbols.TITLE);
|
||||
xs.text(HTML_TITLE);
|
||||
xs.endTag(null, HtmlSymbols.TITLE);
|
||||
xs.text("\n");
|
||||
xs.endTag(null, HtmlSymbols.HEAD);
|
||||
xs.text("\n");
|
||||
|
||||
xs.startTag(null, HtmlSymbols.BODY);
|
||||
xs.text("\n");
|
||||
xs.startTag(null, HtmlSymbols.HEADING);
|
||||
xs.text(HTML_TITLE);
|
||||
xs.endTag(null, HtmlSymbols.HEADING);
|
||||
xs.text("\n");
|
||||
xs.startTag(null, HtmlSymbols.ORDERED_LIST);
|
||||
xs.text("\n");
|
||||
for (Feed feed : feeds) {
|
||||
xs.startTag(null, HtmlSymbols.LIST_ITEM);
|
||||
xs.text(feed.getTitle());
|
||||
if (!TextUtils.isEmpty(feed.getLink())) {
|
||||
xs.text(" [");
|
||||
xs.startTag(null, HtmlSymbols.LINK);
|
||||
xs.attribute(null, HtmlSymbols.LINK_DESTINATION, feed.getLink());
|
||||
xs.text("Website");
|
||||
xs.endTag(null, HtmlSymbols.LINK);
|
||||
xs.text("]");
|
||||
}
|
||||
xs.text(" [");
|
||||
xs.startTag(null, HtmlSymbols.LINK);
|
||||
xs.attribute(null, HtmlSymbols.LINK_DESTINATION, feed.getDownload_url());
|
||||
xs.text("Feed");
|
||||
xs.endTag(null, HtmlSymbols.LINK);
|
||||
xs.text("]");
|
||||
xs.endTag(null, HtmlSymbols.LIST_ITEM);
|
||||
xs.text("\n");
|
||||
}
|
||||
xs.endTag(null, HtmlSymbols.ORDERED_LIST);
|
||||
xs.endTag(null, HtmlSymbols.BODY);
|
||||
xs.text("\n");
|
||||
xs.endTag(null, HtmlSymbols.HTML);
|
||||
xs.text("\n");
|
||||
xs.endDocument();
|
||||
Log.d(TAG, "Finished writing document");
|
||||
}
|
||||
|
||||
public String fileExtension() {
|
||||
return "html";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
package de.danoeh.antennapod.core.export.opml;
|
||||
|
||||
import de.danoeh.antennapod.core.export.CommonSymbols;
|
||||
|
||||
/** Contains symbols for reading and writing OPML documents. */
|
||||
public final class OpmlSymbols {
|
||||
public final class OpmlSymbols extends CommonSymbols {
|
||||
|
||||
public static final String OPML = "opml";
|
||||
public static final String BODY = "body";
|
||||
public static final String OUTLINE = "outline";
|
||||
public static final String TEXT = "text";
|
||||
public static final String XMLURL = "xmlUrl";
|
||||
public static final String HTMLURL = "htmlUrl";
|
||||
public static final String TYPE = "type";
|
||||
public static final String VERSION = "version";
|
||||
public static final String HEAD = "head";
|
||||
public static final String TITLE = "title";
|
||||
public static final String DATE_CREATED = "dateCreated";
|
||||
static final String OUTLINE = "outline";
|
||||
static final String TEXT = "text";
|
||||
static final String XMLURL = "xmlUrl";
|
||||
static final String HTMLURL = "htmlUrl";
|
||||
static final String TYPE = "type";
|
||||
static final String VERSION = "version";
|
||||
static final String DATE_CREATED = "dateCreated";
|
||||
|
||||
private OpmlSymbols() {
|
||||
|
||||
|
|
|
@ -10,11 +10,13 @@ import java.io.Writer;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.export.ExportWriter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
|
||||
/** Writes OPML documents. */
|
||||
public class OpmlWriter {
|
||||
public class OpmlWriter implements ExportWriter {
|
||||
|
||||
private static final String TAG = "OpmlWriter";
|
||||
private static final String ENCODING = "UTF-8";
|
||||
private static final String OPML_VERSION = "2.0";
|
||||
|
@ -28,6 +30,7 @@ public class OpmlWriter {
|
|||
* @throws IllegalStateException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
@Override
|
||||
public void writeDocument(List<Feed> feeds, Writer writer)
|
||||
throws IllegalArgumentException, IllegalStateException, IOException {
|
||||
Log.d(TAG, "Starting to write document");
|
||||
|
@ -83,4 +86,9 @@ public class OpmlWriter {
|
|||
xs.endDocument();
|
||||
Log.d(TAG, "Finished writing document");
|
||||
}
|
||||
|
||||
public String fileExtension() {
|
||||
return "opml";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -451,6 +451,7 @@
|
|||
<string name="choose_file_from_filesystem">From local filesystem</string>
|
||||
<string name="choose_file_from_external_application">Use external application</string>
|
||||
<string name="opml_export_label">OPML export</string>
|
||||
<string name="html_export_label">HTML export</string>
|
||||
<string name="exporting_label">Exporting…</string>
|
||||
<string name="export_error_label">Export error</string>
|
||||
<string name="opml_export_success_title">OPML Export successful.</string>
|
||||
|
|
Loading…
Reference in New Issue