diff --git a/src/de/podfetcher/feed/FeedItem.java b/src/de/podfetcher/feed/FeedItem.java index 0ad35d6e3..2c127d570 100644 --- a/src/de/podfetcher/feed/FeedItem.java +++ b/src/de/podfetcher/feed/FeedItem.java @@ -1,5 +1,6 @@ package de.podfetcher.feed; +import java.util.ArrayList; import java.util.Date; @@ -19,6 +20,7 @@ public class FeedItem extends FeedComponent{ private Feed feed; protected boolean read; private String paymentLink; + private ArrayList simpleChapters; public FeedItem() { this.read = true; @@ -104,5 +106,12 @@ public class FeedItem extends FeedComponent{ this.paymentLink = paymentLink; } + public ArrayList getSimpleChapters() { + return simpleChapters; + } + + public void setSimpleChapters(ArrayList simpleChapters) { + this.simpleChapters = simpleChapters; + } } diff --git a/src/de/podfetcher/feed/FeedManager.java b/src/de/podfetcher/feed/FeedManager.java index 3533c676f..1e87b8879 100644 --- a/src/de/podfetcher/feed/FeedManager.java +++ b/src/de/podfetcher/feed/FeedManager.java @@ -454,6 +454,19 @@ public class FeedManager { if (!item.read) { unreadItems.add(item); } + + // extract chapters + Cursor chapterCursor = adapter.getSimpleChaptersOfFeedItemCursor(item); + if (chapterCursor.moveToFirst()) { + item.setSimpleChapters(new ArrayList()); + do { + SimpleChapter chapter = new SimpleChapter(chapterCursor.getLong(chapterCursor.getColumnIndex(PodDBAdapter.KEY_START)), + chapterCursor.getString(chapterCursor.getColumnIndex(PodDBAdapter.KEY_TITLE))); + item.getSimpleChapters().add(chapter); + } while (chapterCursor.moveToNext()); + } + chapterCursor.close(); + items.add(item); } while (itemlistCursor.moveToNext()); } diff --git a/src/de/podfetcher/feed/SimpleChapter.java b/src/de/podfetcher/feed/SimpleChapter.java new file mode 100644 index 000000000..c6c489bf2 --- /dev/null +++ b/src/de/podfetcher/feed/SimpleChapter.java @@ -0,0 +1,22 @@ +package de.podfetcher.feed; + +public class SimpleChapter extends FeedComponent { + public long getStart() { + return start; + } + + public SimpleChapter(long start, String title) { + super(); + this.start = start; + this.title = title; + } + + public String getTitle() { + return title; + } + /** Defines starting point in milliseconds. */ + private long start; + private String title; + + +} diff --git a/src/de/podfetcher/storage/PodDBAdapter.java b/src/de/podfetcher/storage/PodDBAdapter.java index 37db7759a..219e48c54 100644 --- a/src/de/podfetcher/storage/PodDBAdapter.java +++ b/src/de/podfetcher/storage/PodDBAdapter.java @@ -8,6 +8,7 @@ import de.podfetcher.feed.FeedCategory; import de.podfetcher.feed.FeedImage; import de.podfetcher.feed.FeedItem; import de.podfetcher.feed.FeedMedia; +import de.podfetcher.feed.SimpleChapter; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -53,7 +54,8 @@ public class PodDBAdapter { public static final String KEY_FEEDITEM = "feeditem"; public static final String KEY_CONTENT_ENCODED = "content_encoded"; public static final String KEY_PAYMENT_LINK = "payment_link"; - + public static final String KEY_START = "start"; + // Table names public static final String TABLE_NAME_FEEDS = "Feeds"; public static final String TABLE_NAME_FEED_ITEMS = "FeedItems"; @@ -62,6 +64,7 @@ public class PodDBAdapter { public static final String TABLE_NAME_FEED_MEDIA = "FeedMedia"; public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog"; public static final String TABLE_NAME_QUEUE = "Queue"; + public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters"; // SQL Statements for creating new tables private static final String TABLE_PRIMARY_KEY = KEY_ID @@ -77,10 +80,9 @@ public class PodDBAdapter { private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE " + TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE + " TEXT," + KEY_LINK + " TEXT," + KEY_DESCRIPTION + " TEXT," - + KEY_CONTENT_ENCODED + " TEXT," - + KEY_PUBDATE + " INTEGER," + KEY_MEDIA + " INTEGER," + KEY_FEED - + " INTEGER," + KEY_READ + " INTEGER," - + KEY_PAYMENT_LINK + " TEXT)"; + + KEY_CONTENT_ENCODED + " TEXT," + KEY_PUBDATE + " INTEGER," + + KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER," + KEY_READ + + " INTEGER," + KEY_PAYMENT_LINK + " TEXT)"; private static final String CREATE_TABLE_FEED_CATEGORIES = "CREATE TABLE " + TABLE_NAME_FEED_CATEGORIES + " (" + TABLE_PRIMARY_KEY + KEY_NAME @@ -102,11 +104,14 @@ public class PodDBAdapter { + " INTEGER," + KEY_FEEDFILETYPE + " INTEGER," + KEY_REASON + " INTEGER," + KEY_SUCCESSFUL + " INTEGER," + KEY_COMPLETION_DATE + " INTEGER)"; - + private static final String CREATE_TABLE_QUEUE = "CREATE TABLE " - + TABLE_NAME_QUEUE + "(" + KEY_ID + " INTEGER PRIMARY KEY," - + KEY_FEEDITEM + " INTEGER," - + KEY_FEED + " INTEGER)"; + + TABLE_NAME_QUEUE + "(" + KEY_ID + " INTEGER PRIMARY KEY," + + KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)"; + + private static final String CREATE_TABLE_SIMPLECHAPTERS = "CREATE TABLE " + + TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE + + " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER)"; /** * Used for storing download status entries to determine the type of the @@ -283,10 +288,29 @@ public class PodDBAdapter { db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[] { String.valueOf(item.getId()) }); } + if (item.getSimpleChapters() != null) { + setSimpleChapters(item); + } close(); return item.getId(); } + public void setSimpleChapters(FeedItem item) { + ContentValues values = new ContentValues(); + for (SimpleChapter chapter : item.getSimpleChapters()) { + values.put(KEY_TITLE, chapter.getTitle()); + values.put(KEY_START, chapter.getStart()); + values.put(KEY_FEEDITEM, item.getId()); + if (chapter.getId() == 0) { + chapter.setId(db + .insert(TABLE_NAME_SIMPLECHAPTERS, null, values)); + } else { + db.update(TABLE_NAME_SIMPLECHAPTERS, values, KEY_ID + "=?", + new String[] { String.valueOf(chapter.getId()) }); + } + } + } + /** * Inserts or updates a download status. * */ @@ -314,7 +338,7 @@ public class PodDBAdapter { close(); return status.getId(); } - + public void setQueue(ArrayList queue) { ContentValues values = new ContentValues(); open(); @@ -324,33 +348,37 @@ public class PodDBAdapter { values.put(KEY_ID, i); values.put(KEY_FEEDITEM, item.getId()); values.put(KEY_FEED, item.getFeed().getId()); - db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values, SQLiteDatabase.CONFLICT_REPLACE); + db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values, + SQLiteDatabase.CONFLICT_REPLACE); } close(); } - + public void removeFeedMedia(FeedMedia media) { open(); - db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?", new String[] {String.valueOf(media.getId())}); + db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?", + new String[] { String.valueOf(media.getId()) }); close(); } - + public void removeFeedImage(FeedImage image) { open(); - db.delete(TABLE_NAME_FEED_IMAGES, KEY_ID + "=?", new String[] {String.valueOf(image.getId())}); + db.delete(TABLE_NAME_FEED_IMAGES, KEY_ID + "=?", + new String[] { String.valueOf(image.getId()) }); close(); } - + /** Remove a FeedItem and its FeedMedia entry. */ public void removeFeedItem(FeedItem item) { if (item.getMedia() != null) { removeFeedMedia(item.getMedia()); - } + } open(); - db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?", new String[] {String.valueOf(item.getId())}); + db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?", + new String[] { String.valueOf(item.getId()) }); close(); } - + /** Remove a feed with all its FeedItems and Media entries. */ public void removeFeed(Feed feed) { if (feed.getImage() != null) { @@ -358,9 +386,10 @@ public class PodDBAdapter { } for (FeedItem item : feed.getItems()) { removeFeedItem(item); - } + } open(); - db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?", new String[] {String.valueOf(feed.getId())}); + db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?", + new String[] { String.valueOf(feed.getId()) }); close(); } @@ -440,16 +469,26 @@ public class PodDBAdapter { return c; } + public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) { + open(); + Cursor c = db + .query(CREATE_TABLE_SIMPLECHAPTERS, null, KEY_ID + "=?", + new String[] { String.valueOf(item.getId()) }, null, + null, null); + return c; + } + public final Cursor getDownloadLogCursor() { open(); Cursor c = db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null, null, null); return c; } - + public final Cursor getQueueCursor() { open(); - Cursor c = db.query(TABLE_NAME_QUEUE, null, null, null, null, null, null); + Cursor c = db.query(TABLE_NAME_QUEUE, null, null, null, null, null, + null); return c; } @@ -531,6 +570,7 @@ public class PodDBAdapter { db.execSQL(CREATE_TABLE_FEED_MEDIA); db.execSQL(CREATE_TABLE_DOWNLOAD_LOG); db.execSQL(CREATE_TABLE_QUEUE); + db.execSQL(CREATE_TABLE_SIMPLECHAPTERS); } @Override diff --git a/src/de/podfetcher/syndication/handler/SyndHandler.java b/src/de/podfetcher/syndication/handler/SyndHandler.java index d4b7482ea..5b8cbd01a 100644 --- a/src/de/podfetcher/syndication/handler/SyndHandler.java +++ b/src/de/podfetcher/syndication/handler/SyndHandler.java @@ -13,6 +13,7 @@ import de.podfetcher.syndication.namespace.atom.NSAtom; import de.podfetcher.syndication.namespace.content.NSContent; import de.podfetcher.syndication.namespace.itunes.NSITunes; import de.podfetcher.syndication.namespace.rss20.NSRSS20; +import de.podfetcher.syndication.namespace.simplechapters.NSSimpleChapters; /** Superclass for all SAX Handlers which process Syndication formats */ public class SyndHandler extends DefaultHandler { @@ -89,6 +90,9 @@ public class SyndHandler extends DefaultHandler { } else if (uri.equals(NSITunes.NSURI) && prefix.equals(NSITunes.NSTAG)) { state.namespaces.put(uri, new NSITunes()); Log.d(TAG, "Recognized ITunes namespace"); + } else if (uri.equals(NSSimpleChapters.NSURI) && prefix.equals(NSSimpleChapters.NSTAG)) { + state.namespaces.put(uri, new NSSimpleChapters()); + Log.d(TAG, "Recognized SimpleChapters namespace"); } } diff --git a/src/de/podfetcher/syndication/namespace/atom/NSAtom.java b/src/de/podfetcher/syndication/namespace/atom/NSAtom.java index 826954beb..5597f787f 100644 --- a/src/de/podfetcher/syndication/namespace/atom/NSAtom.java +++ b/src/de/podfetcher/syndication/namespace/atom/NSAtom.java @@ -80,14 +80,12 @@ public class NSAtom extends Namespace { new FeedMedia(state.getCurrentItem(), download_url, size, type)); } else if (rel.equals(LINK_REL_PAYMENT)) { - Log.d(TAG, "Found payment item link"); state.getCurrentItem().setPaymentLink(href); } } else if (parent.getName().matches(isFeed)) { if (rel == null || rel.equals(LINK_REL_ALTERNATE)) { state.getFeed().setLink(href); } else if (rel.equals(LINK_REL_PAYMENT)) { - Log.d(TAG, "Found payment link"); state.getFeed().setPaymentLink(href); } } diff --git a/src/de/podfetcher/syndication/namespace/simplechapters/NSSimpleChapters.java b/src/de/podfetcher/syndication/namespace/simplechapters/NSSimpleChapters.java new file mode 100644 index 000000000..4b3a69cbe --- /dev/null +++ b/src/de/podfetcher/syndication/namespace/simplechapters/NSSimpleChapters.java @@ -0,0 +1,43 @@ +package de.podfetcher.syndication.namespace.simplechapters; + +import java.util.ArrayList; + +import org.xml.sax.Attributes; + +import de.podfetcher.feed.SimpleChapter; +import de.podfetcher.syndication.handler.HandlerState; +import de.podfetcher.syndication.namespace.Namespace; +import de.podfetcher.syndication.namespace.SyndElement; +import de.podfetcher.syndication.util.SyndDateUtils; + +public class NSSimpleChapters extends Namespace { + public static final String NSTAG = "sc"; + public static final String NSURI = "http://podlove.org/simple-chapters"; + + public static final String CHAPTERS = "chapters"; + public static final String CHAPTER = "chapter"; + public static final String START = "start"; + public static final String TITLE = "title"; + + @Override + public SyndElement handleElementStart(String localName, HandlerState state, + Attributes attributes) { + if (localName.equals(CHAPTERS)) { + state.getCurrentItem().setSimpleChapters( + new ArrayList()); + } else if (localName.equals(CHAPTER)) { + state.getCurrentItem() + .getSimpleChapters() + .add(new SimpleChapter(SyndDateUtils + .parseTimeString(attributes.getValue(START)), + attributes.getValue(TITLE))); + } + + return new SyndElement(localName, this); + } + + @Override + public void handleElementEnd(String localName, HandlerState state) { + } + +} diff --git a/src/de/podfetcher/syndication/util/SyndDateUtils.java b/src/de/podfetcher/syndication/util/SyndDateUtils.java index 2559aaa77..3f8fcbfd3 100644 --- a/src/de/podfetcher/syndication/util/SyndDateUtils.java +++ b/src/de/podfetcher/syndication/util/SyndDateUtils.java @@ -84,4 +84,19 @@ public class SyndDateUtils { return result; } + /** Takes a string of the form [HH:]MM:SS[.mmm] and converts it to milliseconds. */ + public static long parseTimeString(final String time) { + String[] parts = time.split(":"); + long result = 0; + int idx = 0; + if (parts.length == 3) { + // string has hours + result += Integer.valueOf(parts[idx]) * 3600000; + idx++; + } + result += Integer.valueOf(parts[idx]) * 60000; + idx++; + result += ( Float.valueOf(parts[idx])) * 1000; + return result; + } }