4.10.1 commit
This commit is contained in:
parent
b719267656
commit
eeea4bfd17
|
@ -158,8 +158,8 @@ android {
|
||||||
// Version code schema (not used):
|
// Version code schema (not used):
|
||||||
// "1.2.3-beta4" -> 1020304
|
// "1.2.3-beta4" -> 1020304
|
||||||
// "1.2.3" -> 1020395
|
// "1.2.3" -> 1020395
|
||||||
versionCode 3020138
|
versionCode 3020139
|
||||||
versionName "4.10.0"
|
versionName "4.10.1"
|
||||||
|
|
||||||
def commit = ""
|
def commit = ""
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -856,7 +856,7 @@ class LocalMediaPlayer(context: Context, callback: PSMPCallback) : MediaPlayerBa
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "LclPlaybackSvcMPlayer"
|
private const val TAG = "LocalMediaPlayer"
|
||||||
|
|
||||||
// from wrapper
|
// from wrapper
|
||||||
const val BUFFERING_STARTED: Int = -1
|
const val BUFFERING_STARTED: Int = -1
|
||||||
|
|
|
@ -360,14 +360,12 @@ class PodDBAdapter private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetPagedFeedPage(feed: Feed) {
|
fun resetPagedFeedPage(feed: Feed) {
|
||||||
val sql = ("UPDATE " + TABLE_NAME_FEEDS + " SET " + KEY_NEXT_PAGE_LINK + "=" + KEY_DOWNLOAD_URL + " WHERE " + KEY_ID + "=" + feed.id)
|
val sql = ("UPDATE $TABLE_NAME_FEEDS SET $KEY_NEXT_PAGE_LINK=$KEY_DOWNLOAD_URL WHERE $KEY_ID=${feed.id}")
|
||||||
db.execSQL(sql)
|
db.execSQL(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setFeedLastUpdateFailed(feedId: Long, failed: Boolean) {
|
fun setFeedLastUpdateFailed(feedId: Long, failed: Boolean) {
|
||||||
val sql = ("UPDATE " + TABLE_NAME_FEEDS
|
val sql = ("UPDATE $TABLE_NAME_FEEDS SET $KEY_LAST_UPDATE_FAILED=${if (failed) "1" else "0"} WHERE $KEY_ID=$feedId")
|
||||||
+ " SET " + KEY_LAST_UPDATE_FAILED + "=" + (if (failed) "1" else "0")
|
|
||||||
+ " WHERE " + KEY_ID + "=" + feedId)
|
|
||||||
db.execSQL(sql)
|
db.execSQL(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +429,7 @@ class PodDBAdapter private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeFavoriteItem(item: FeedItem) {
|
fun removeFavoriteItem(item: FeedItem) {
|
||||||
val deleteClause = String.format("DELETE FROM %s WHERE %s=%s AND %s=%s", TABLE_NAME_FAVORITES, KEY_FEEDITEM, item.id, KEY_FEED, item.feedId)
|
val deleteClause = "DELETE FROM $TABLE_NAME_FAVORITES WHERE $KEY_FEEDITEM=${item.id} AND $KEY_FEED=${item.feedId}"
|
||||||
db.execSQL(deleteClause)
|
db.execSQL(deleteClause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,8 +483,8 @@ class PodDBAdapter private constructor() {
|
||||||
|
|
||||||
db.beginTransactionNonExclusive()
|
db.beginTransactionNonExclusive()
|
||||||
db.delete(TABLE_NAME_SIMPLECHAPTERS, "$KEY_FEEDITEM IN ($itemIds)", null)
|
db.delete(TABLE_NAME_SIMPLECHAPTERS, "$KEY_FEEDITEM IN ($itemIds)", null)
|
||||||
db.delete(TABLE_NAME_DOWNLOAD_LOG, (KEY_FEEDFILETYPE + "=" + FeedMedia.FEEDFILETYPE_FEEDMEDIA)
|
db.delete(TABLE_NAME_DOWNLOAD_LOG,
|
||||||
+ " AND " + KEY_FEEDFILE + " IN (" + mediaIds + ")", null)
|
"$KEY_FEEDFILETYPE=${FeedMedia.FEEDFILETYPE_FEEDMEDIA} AND $KEY_FEEDFILE IN ($mediaIds)", null)
|
||||||
db.delete(TABLE_NAME_FEED_MEDIA, "$KEY_ID IN ($mediaIds)", null)
|
db.delete(TABLE_NAME_FEED_MEDIA, "$KEY_ID IN ($mediaIds)", null)
|
||||||
db.delete(TABLE_NAME_FEED_ITEMS, "$KEY_ID IN ($itemIds)", null)
|
db.delete(TABLE_NAME_FEED_ITEMS, "$KEY_ID IN ($itemIds)", null)
|
||||||
db.setTransactionSuccessful()
|
db.setTransactionSuccessful()
|
||||||
|
@ -588,25 +586,21 @@ class PodDBAdapter private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTranscriptOfItem(item: FeedItem): Cursor {
|
fun getTranscriptOfItem(item: FeedItem): Cursor {
|
||||||
val query = ("SELECT " + KEY_TRANSCRIPT + " FROM " + TABLE_NAME_FEED_ITEMS + " WHERE " + KEY_ID + "=" + item.id)
|
val query = ("SELECT $KEY_TRANSCRIPT FROM $TABLE_NAME_FEED_ITEMS WHERE $KEY_ID=${item.id}")
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSimpleChaptersOfFeedItemCursor(item: FeedItem): Cursor {
|
fun getSimpleChaptersOfFeedItemCursor(item: FeedItem): Cursor {
|
||||||
return db.query(TABLE_NAME_SIMPLECHAPTERS, null, "$KEY_FEEDITEM=?", arrayOf(item.id.toString()),
|
return db.query(TABLE_NAME_SIMPLECHAPTERS, null, "$KEY_FEEDITEM=?", arrayOf(item.id.toString()), null, null, null)
|
||||||
null, null, null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDownloadLog(feedFileType: Int, feedFileId: Long): Cursor {
|
fun getDownloadLog(feedFileType: Int, feedFileId: Long): Cursor {
|
||||||
val query = ("SELECT * FROM " + TABLE_NAME_DOWNLOAD_LOG +
|
val query = ("SELECT * FROM $TABLE_NAME_DOWNLOAD_LOG WHERE $KEY_FEEDFILE=$feedFileId AND $KEY_FEEDFILETYPE=$feedFileType ORDER BY $KEY_ID DESC")
|
||||||
" WHERE " + KEY_FEEDFILE + "=" + feedFileId + " AND " + KEY_FEEDFILETYPE + "=" + feedFileType
|
|
||||||
+ " ORDER BY " + KEY_ID + " DESC")
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDownloadLogCursor(limit: Int): Cursor {
|
fun getDownloadLogCursor(limit: Int): Cursor {
|
||||||
return db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null,
|
return db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null, null, "$KEY_COMPLETION_DATE DESC LIMIT $limit")
|
||||||
null, "$KEY_COMPLETION_DATE DESC LIMIT $limit")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val queueCursor: Cursor
|
val queueCursor: Cursor
|
||||||
|
@ -616,12 +610,7 @@ class PodDBAdapter private constructor() {
|
||||||
* cursor uses the FEEDITEM_SEL_FI_SMALL selection.
|
* cursor uses the FEEDITEM_SEL_FI_SMALL selection.
|
||||||
*/
|
*/
|
||||||
get() {
|
get() {
|
||||||
val query = ("SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
|
val query = ("SELECT $KEYS_FEED_ITEM_WITHOUT_DESCRIPTION, $KEYS_FEED_MEDIA FROM $TABLE_NAME_QUEUE INNER JOIN $TABLE_NAME_FEED_ITEMS ON $SELECT_KEY_ITEM_ID = $TABLE_NAME_QUEUE.$KEY_FEEDITEM$JOIN_FEED_ITEM_AND_MEDIA ORDER BY $TABLE_NAME_QUEUE.$KEY_ID")
|
||||||
+ " FROM " + TABLE_NAME_QUEUE
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " ON " + SELECT_KEY_ITEM_ID + " = " + TABLE_NAME_QUEUE + "." + KEY_FEEDITEM
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
|
||||||
+ " ORDER BY " + TABLE_NAME_QUEUE + "." + KEY_ID)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,43 +618,19 @@ class PodDBAdapter private constructor() {
|
||||||
get() = db.query(TABLE_NAME_QUEUE, arrayOf(KEY_FEEDITEM), null, null, null, null, "$KEY_ID ASC", null)
|
get() = db.query(TABLE_NAME_QUEUE, arrayOf(KEY_FEEDITEM), null, null, null, null, "$KEY_ID ASC", null)
|
||||||
|
|
||||||
fun getNextInQueue(item: FeedItem): Cursor {
|
fun getNextInQueue(item: FeedItem): Cursor {
|
||||||
val query = ("SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
|
val query = ("SELECT $KEYS_FEED_ITEM_WITHOUT_DESCRIPTION, $KEYS_FEED_MEDIA FROM $TABLE_NAME_QUEUE INNER JOIN $TABLE_NAME_FEED_ITEMS ON $SELECT_KEY_ITEM_ID = $TABLE_NAME_QUEUE.$KEY_FEEDITEM$JOIN_FEED_ITEM_AND_MEDIA WHERE Queue.ID > (SELECT Queue.ID FROM Queue WHERE Queue.FeedItem = ${item.id}) ORDER BY Queue.ID LIMIT 1")
|
||||||
+ " FROM " + TABLE_NAME_QUEUE
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " ON " + SELECT_KEY_ITEM_ID + " = " + TABLE_NAME_QUEUE + "." + KEY_FEEDITEM
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
|
||||||
+ " WHERE Queue.ID > (SELECT Queue.ID FROM Queue WHERE Queue.FeedItem = "
|
|
||||||
+ item.id
|
|
||||||
+ ")"
|
|
||||||
+ " ORDER BY Queue.ID"
|
|
||||||
+ " LIMIT 1")
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPausedQueueCursor(limit: Int): Cursor {
|
fun getPausedQueueCursor(limit: Int): Cursor {
|
||||||
val hasPositionOrRecentlyPlayed = (TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + " >= 1000"
|
val hasPositionOrRecentlyPlayed = ("$TABLE_NAME_FEED_MEDIA.$KEY_POSITION >= 1000 OR $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME >= ${System.currentTimeMillis() - 30000}")
|
||||||
+ " OR " + TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME
|
val query = ("SELECT $KEYS_FEED_ITEM_WITHOUT_DESCRIPTION, $KEYS_FEED_MEDIA FROM $TABLE_NAME_QUEUE INNER JOIN $TABLE_NAME_FEED_ITEMS ON $SELECT_KEY_ITEM_ID = $TABLE_NAME_QUEUE.$KEY_FEEDITEM$JOIN_FEED_ITEM_AND_MEDIA ORDER BY (CASE WHEN $hasPositionOrRecentlyPlayed THEN $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME ELSE 0 END) DESC , $TABLE_NAME_QUEUE.$KEY_ID LIMIT $limit")
|
||||||
+ " >= " + (System.currentTimeMillis() - 30000))
|
|
||||||
val query = ("SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
|
|
||||||
+ " FROM " + TABLE_NAME_QUEUE
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " ON " + SELECT_KEY_ITEM_ID + " = " + TABLE_NAME_QUEUE + "." + KEY_FEEDITEM
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
|
||||||
+ " ORDER BY (CASE WHEN " + hasPositionOrRecentlyPlayed + " THEN "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME + " ELSE 0 END) DESC , "
|
|
||||||
+ TABLE_NAME_QUEUE + "." + KEY_ID
|
|
||||||
+ " LIMIT " + limit)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFavoritesIdsCursor(offset: Int, limit: Int): Cursor {
|
fun getFavoritesIdsCursor(offset: Int, limit: Int): Cursor {
|
||||||
// Way faster than selecting all columns
|
// Way faster than selecting all columns
|
||||||
val query = ("SELECT " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID
|
val query = ("SELECT $TABLE_NAME_FEED_ITEMS.$KEY_ID FROM $TABLE_NAME_FEED_ITEMS INNER JOIN $TABLE_NAME_FAVORITES ON $TABLE_NAME_FEED_ITEMS.$KEY_ID = $TABLE_NAME_FAVORITES.$KEY_FEEDITEM ORDER BY $TABLE_NAME_FEED_ITEMS.$KEY_PUBDATE DESC LIMIT $offset, $limit")
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FAVORITES
|
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " = " + TABLE_NAME_FAVORITES + "." + KEY_FEEDITEM
|
|
||||||
+ " ORDER BY " + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC"
|
|
||||||
+ " LIMIT " + offset + ", " + limit)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,28 +653,22 @@ class PodDBAdapter private constructor() {
|
||||||
val orderByQuery = generateFrom(sortOrder)
|
val orderByQuery = generateFrom(sortOrder)
|
||||||
val filterQuery = generateFrom(filter!!)
|
val filterQuery = generateFrom(filter!!)
|
||||||
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
|
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
|
||||||
val query = (SELECT_FEED_ITEMS_AND_MEDIA + whereClause + "ORDER BY " + orderByQuery + " LIMIT " + offset + ", " + limit)
|
val query = ("$SELECT_FEED_ITEMS_AND_MEDIA${whereClause}ORDER BY $orderByQuery LIMIT $offset, $limit")
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEpisodeCountCursor(filter: FeedItemFilter?): Cursor {
|
fun getEpisodeCountCursor(filter: FeedItemFilter?): Cursor {
|
||||||
val filterQuery = generateFrom(filter!!)
|
val filterQuery = generateFrom(filter!!)
|
||||||
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
|
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
|
||||||
val query = ("SELECT count(" + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + ") FROM " + TABLE_NAME_FEED_ITEMS
|
val query = ("SELECT count($TABLE_NAME_FEED_ITEMS.$KEY_ID) FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA$whereClause")
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA + whereClause)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRandomEpisodesCursor(limit: Int, seed: Int): Cursor {
|
fun getRandomEpisodesCursor(limit: Int, seed: Int): Cursor {
|
||||||
val allItemsRandomOrder = (SELECT_FEED_ITEMS_AND_MEDIA
|
// Only from the last two years. Older episodes often contain broken covers and stuff like that
|
||||||
+ " WHERE (" + KEY_READ + " = " + FeedItem.NEW + " OR " + KEY_READ + " = " + FeedItem.UNPLAYED + ") " // Only from the last two years. Older episodes often contain broken covers and stuff like that
|
// Hide episodes that have been played but not completed
|
||||||
+ " AND " + KEY_PUBDATE + " > " + (System.currentTimeMillis() - 1000L * 3600L * 24L * 356L * 2) // Hide episodes that have been played but not completed
|
val allItemsRandomOrder = ("$SELECT_FEED_ITEMS_AND_MEDIA WHERE ($KEY_READ = ${FeedItem.NEW} OR $KEY_READ = ${FeedItem.UNPLAYED}) AND $KEY_PUBDATE > ${System.currentTimeMillis() - 1000L * 3600L * 24L * 356L * 2} AND ($KEY_LAST_PLAYED_TIME == 0 OR $KEY_LAST_PLAYED_TIME > ${System.currentTimeMillis() - 1000L * 3600L}) ORDER BY ${randomEpisodeNumber(seed)}")
|
||||||
+ " AND (" + KEY_LAST_PLAYED_TIME + " == 0"
|
val query = ("SELECT * FROM ($allItemsRandomOrder) GROUP BY $KEY_FEED ORDER BY ${randomEpisodeNumber(seed * 3)} DESC LIMIT $limit")
|
||||||
+ " OR " + KEY_LAST_PLAYED_TIME + " > " + (System.currentTimeMillis() - 1000L * 3600L) + ")"
|
|
||||||
+ " ORDER BY " + randomEpisodeNumber(seed))
|
|
||||||
val query = ("SELECT * FROM (" + allItemsRandomOrder + ")"
|
|
||||||
+ " GROUP BY " + KEY_FEED
|
|
||||||
+ " ORDER BY " + randomEpisodeNumber(seed * 3) + " DESC LIMIT " + limit)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,9 +705,7 @@ class PodDBAdapter private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFeedCursor(id: Long): Cursor {
|
fun getFeedCursor(id: Long): Cursor {
|
||||||
val query = ("SELECT " + KEYS_FEED
|
val query = ("SELECT $KEYS_FEED FROM $TABLE_NAME_FEEDS WHERE $SELECT_KEY_FEED_ID = $id")
|
||||||
+ " FROM " + TABLE_NAME_FEEDS
|
|
||||||
+ " WHERE " + SELECT_KEY_FEED_ID + " = " + id)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,88 +739,41 @@ class PodDBAdapter private constructor() {
|
||||||
whereClauseCondition = "$TABLE_NAME_FEED_ITEMS.$KEY_ITEM_IDENTIFIER=$escapedGuid"
|
whereClauseCondition = "$TABLE_NAME_FEED_ITEMS.$KEY_ITEM_IDENTIFIER=$escapedGuid"
|
||||||
}
|
}
|
||||||
|
|
||||||
val query = (SELECT_FEED_ITEMS_AND_MEDIA
|
val query = ("$SELECT_FEED_ITEMS_AND_MEDIA INNER JOIN $TABLE_NAME_FEEDS ON $TABLE_NAME_FEED_ITEMS.$KEY_FEED=$TABLE_NAME_FEEDS.$KEY_ID WHERE $whereClauseCondition")
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
|
|
||||||
+ " WHERE " + whereClauseCondition)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImageAuthenticationCursor(imageUrl: String?): Cursor {
|
fun getImageAuthenticationCursor(imageUrl: String?): Cursor {
|
||||||
val downloadUrl = DatabaseUtils.sqlEscapeString(imageUrl)
|
val downloadUrl = DatabaseUtils.sqlEscapeString(imageUrl)
|
||||||
val query = (""
|
val query = ("SELECT $KEY_USERNAME,$KEY_PASSWORD FROM $TABLE_NAME_FEED_ITEMS INNER JOIN $TABLE_NAME_FEEDS ON $TABLE_NAME_FEED_ITEMS.$KEY_FEED = $TABLE_NAME_FEEDS.$KEY_ID WHERE $TABLE_NAME_FEED_ITEMS.$KEY_IMAGE_URL=$downloadUrl UNION SELECT $KEY_USERNAME,$KEY_PASSWORD FROM $TABLE_NAME_FEEDS WHERE $TABLE_NAME_FEEDS.$KEY_IMAGE_URL=$downloadUrl")
|
||||||
+ "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + " = " + TABLE_NAME_FEEDS + "." + KEY_ID
|
|
||||||
+ " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE_URL + "=" + downloadUrl
|
|
||||||
+ " UNION SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEEDS
|
|
||||||
+ " WHERE " + TABLE_NAME_FEEDS + "." + KEY_IMAGE_URL + "=" + downloadUrl)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val monthlyStatisticsCursor: Cursor
|
val monthlyStatisticsCursor: Cursor
|
||||||
get() {
|
get() {
|
||||||
val query = ("SELECT SUM(" + KEY_PLAYED_DURATION + ") AS total_duration"
|
val query = ("SELECT SUM($KEY_PLAYED_DURATION) AS total_duration, strftime('%m', datetime($KEY_LAST_PLAYED_TIME/1000, 'unixepoch')) AS month, strftime('%Y', datetime($KEY_LAST_PLAYED_TIME/1000, 'unixepoch')) AS year FROM $TABLE_NAME_FEED_MEDIA WHERE $KEY_LAST_PLAYED_TIME > 0 AND $KEY_PLAYED_DURATION > 0 GROUP BY year, month ORDER BY year, month")
|
||||||
+ ", strftime('%m', datetime(" + KEY_LAST_PLAYED_TIME + "/1000, 'unixepoch')) AS month"
|
|
||||||
+ ", strftime('%Y', datetime(" + KEY_LAST_PLAYED_TIME + "/1000, 'unixepoch')) AS year"
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_MEDIA
|
|
||||||
+ " WHERE " + KEY_LAST_PLAYED_TIME + " > 0 AND " + KEY_PLAYED_DURATION + " > 0"
|
|
||||||
+ " GROUP BY year, month"
|
|
||||||
+ " ORDER BY year, month")
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFeedStatisticsCursor(includeMarkedAsPlayed: Boolean, timeFilterFrom: Long, timeFilterTo: Long): Cursor {
|
fun getFeedStatisticsCursor(includeMarkedAsPlayed: Boolean, timeFilterFrom: Long, timeFilterTo: Long): Cursor {
|
||||||
val lastPlayedTime = "$TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME"
|
val lastPlayedTime = "$TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME"
|
||||||
var wasStarted = (TABLE_NAME_FEED_MEDIA + "." + KEY_PLAYBACK_COMPLETION_DATE + " > 0"
|
var wasStarted = ("$TABLE_NAME_FEED_MEDIA.$KEY_PLAYBACK_COMPLETION_DATE > 0 AND $TABLE_NAME_FEED_MEDIA.$KEY_PLAYED_DURATION > 0")
|
||||||
+ " AND " + TABLE_NAME_FEED_MEDIA + "." + KEY_PLAYED_DURATION + " > 0")
|
|
||||||
if (includeMarkedAsPlayed) {
|
if (includeMarkedAsPlayed) {
|
||||||
wasStarted = ("(" + wasStarted + ") OR "
|
wasStarted = ("($wasStarted) OR $TABLE_NAME_FEED_ITEMS.$KEY_READ=${FeedItem.PLAYED} OR $TABLE_NAME_FEED_MEDIA.$KEY_POSITION> 0")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_READ + "=" + FeedItem.PLAYED + " OR "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + "> 0")
|
|
||||||
}
|
}
|
||||||
val timeFilter = ("$lastPlayedTime>=$timeFilterFrom AND $lastPlayedTime<$timeFilterTo")
|
val timeFilter = ("$lastPlayedTime>=$timeFilterFrom AND $lastPlayedTime<$timeFilterTo")
|
||||||
var playedTime = "$TABLE_NAME_FEED_MEDIA.$KEY_PLAYED_DURATION"
|
var playedTime = "$TABLE_NAME_FEED_MEDIA.$KEY_PLAYED_DURATION"
|
||||||
if (includeMarkedAsPlayed) {
|
if (includeMarkedAsPlayed) {
|
||||||
playedTime = ("(CASE WHEN " + playedTime + " != 0"
|
playedTime = ("(CASE WHEN $playedTime != 0 THEN $playedTime ELSE (CASE WHEN $TABLE_NAME_FEED_ITEMS.$KEY_READ=${FeedItem.PLAYED} THEN $TABLE_NAME_FEED_MEDIA.$KEY_DURATION ELSE 0 END) END)")
|
||||||
+ " THEN " + playedTime + " ELSE ("
|
|
||||||
+ "CASE WHEN " + TABLE_NAME_FEED_ITEMS + "." + KEY_READ + "=" + FeedItem.PLAYED
|
|
||||||
+ " THEN " + TABLE_NAME_FEED_MEDIA + "." + KEY_DURATION + " ELSE 0 END"
|
|
||||||
+ ") END)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val query = ("SELECT " + KEYS_FEED + ", "
|
val query = ("SELECT $KEYS_FEED, COUNT(*) AS num_episodes, MIN(CASE WHEN $lastPlayedTime > 0 THEN $lastPlayedTime ELSE ${Long.MAX_VALUE} END) AS oldest_date, SUM(CASE WHEN ($wasStarted) THEN 1 ELSE 0 END) AS episodes_started, IFNULL(SUM(CASE WHEN ($timeFilter) THEN ($playedTime) ELSE 0 END), 0) AS played_time, IFNULL(SUM($TABLE_NAME_FEED_MEDIA.$KEY_DURATION), 0) AS total_time, SUM(CASE WHEN $TABLE_NAME_FEED_MEDIA.$KEY_DOWNLOADED > 0 THEN 1 ELSE 0 END) AS num_downloaded, SUM(CASE WHEN $TABLE_NAME_FEED_MEDIA.$KEY_DOWNLOADED > 0 THEN $TABLE_NAME_FEED_MEDIA.$KEY_SIZE ELSE 0 END) AS download_size FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA INNER JOIN $TABLE_NAME_FEEDS ON $TABLE_NAME_FEED_ITEMS.$KEY_FEED=$TABLE_NAME_FEEDS.$KEY_ID GROUP BY $TABLE_NAME_FEEDS.$KEY_ID")
|
||||||
+ "COUNT(*) AS num_episodes, "
|
|
||||||
+ "MIN(CASE WHEN " + lastPlayedTime + " > 0"
|
|
||||||
+ " THEN " + lastPlayedTime + " ELSE " + Long.MAX_VALUE + " END) AS oldest_date, "
|
|
||||||
+ "SUM(CASE WHEN (" + wasStarted + ") THEN 1 ELSE 0 END) AS episodes_started, "
|
|
||||||
+ "IFNULL(SUM(CASE WHEN (" + timeFilter + ")"
|
|
||||||
+ " THEN (" + playedTime + ") ELSE 0 END), 0) AS played_time, "
|
|
||||||
+ "IFNULL(SUM(" + TABLE_NAME_FEED_MEDIA + "." + KEY_DURATION + "), 0) AS total_time, "
|
|
||||||
+ "SUM(CASE WHEN " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " > 0"
|
|
||||||
+ " THEN 1 ELSE 0 END) AS num_downloaded, "
|
|
||||||
+ "SUM(CASE WHEN " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " > 0"
|
|
||||||
+ " THEN " + TABLE_NAME_FEED_MEDIA + "." + KEY_SIZE + " ELSE 0 END) AS download_size"
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
|
||||||
+ " INNER JOIN " + TABLE_NAME_FEEDS
|
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID
|
|
||||||
+ " GROUP BY " + TABLE_NAME_FEEDS + "." + KEY_ID)
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTimeBetweenReleaseAndPlayback(timeFilterFrom: Long, timeFilterTo: Long): Cursor {
|
fun getTimeBetweenReleaseAndPlayback(timeFilterFrom: Long, timeFilterTo: Long): Cursor {
|
||||||
val from = (" FROM " + TABLE_NAME_FEED_ITEMS
|
val from = (" FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA WHERE $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME>=$timeFilterFrom AND $TABLE_NAME_FEED_ITEMS.$KEY_PUBDATE>=$timeFilterFrom AND $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME<$timeFilterTo")
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA
|
val query = ("SELECT $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME - $TABLE_NAME_FEED_ITEMS.$KEY_PUBDATE AS diff$from ORDER BY diff ASC LIMIT 1 OFFSET (SELECT count(*)/2 $from)")
|
||||||
+ " WHERE " + TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME + ">=" + timeFilterFrom
|
|
||||||
+ " AND " + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + ">=" + timeFilterFrom
|
|
||||||
+ " AND " + TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME + "<" + timeFilterTo)
|
|
||||||
val query = ("SELECT " + TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME
|
|
||||||
+ " - " + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " AS diff"
|
|
||||||
+ from
|
|
||||||
+ " ORDER BY diff ASC"
|
|
||||||
+ " LIMIT 1"
|
|
||||||
+ " OFFSET (SELECT count(*)/2 " + from + ")")
|
|
||||||
return db.rawQuery(query, null)
|
return db.rawQuery(query, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,12 +816,7 @@ class PodDBAdapter private constructor() {
|
||||||
limitFeeds = "$KEY_FEED IN ($builder) AND "
|
limitFeeds = "$KEY_FEED IN ($builder) AND "
|
||||||
}
|
}
|
||||||
|
|
||||||
val query = ("SELECT " + KEY_FEED + ", COUNT(" + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + ") AS count "
|
val query = ("SELECT $KEY_FEED, COUNT($TABLE_NAME_FEED_ITEMS.$KEY_ID) AS count FROM $TABLE_NAME_FEED_ITEMS LEFT JOIN $TABLE_NAME_FEED_MEDIA ON $TABLE_NAME_FEED_ITEMS.$KEY_ID=$TABLE_NAME_FEED_MEDIA.$KEY_FEEDITEM WHERE $limitFeeds $whereRead GROUP BY $KEY_FEED")
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " LEFT JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "=" + TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM
|
|
||||||
+ " WHERE " + limitFeeds + " "
|
|
||||||
+ whereRead + " GROUP BY " + KEY_FEED)
|
|
||||||
|
|
||||||
val c = db.rawQuery(query, null)
|
val c = db.rawQuery(query, null)
|
||||||
val result: MutableMap<Long, Int> = HashMap()
|
val result: MutableMap<Long, Int> = HashMap()
|
||||||
|
@ -933,10 +838,7 @@ class PodDBAdapter private constructor() {
|
||||||
|
|
||||||
val mostRecentItemDates: Map<Long, Long>
|
val mostRecentItemDates: Map<Long, Long>
|
||||||
get() {
|
get() {
|
||||||
val query = ("SELECT " + KEY_FEED + ","
|
val query = ("SELECT $KEY_FEED, MAX($TABLE_NAME_FEED_ITEMS.$KEY_PUBDATE) AS most_recent_pubdate FROM $TABLE_NAME_FEED_ITEMS GROUP BY $KEY_FEED")
|
||||||
+ " MAX(" + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + ") AS most_recent_pubdate"
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " GROUP BY " + KEY_FEED)
|
|
||||||
|
|
||||||
val c = db.rawQuery(query, null)
|
val c = db.rawQuery(query, null)
|
||||||
val result: MutableMap<Long, Long> = HashMap()
|
val result: MutableMap<Long, Long> = HashMap()
|
||||||
|
@ -953,16 +855,7 @@ class PodDBAdapter private constructor() {
|
||||||
|
|
||||||
val mostRecentUnreadItemDates: Map<Long, Long>
|
val mostRecentUnreadItemDates: Map<Long, Long>
|
||||||
get() {
|
get() {
|
||||||
// val query = ("SELECT " + KEY_FEED + ","
|
val query = ("SELECT $KEY_FEED, MAX(CASE WHEN $KEY_READ != 1 THEN $KEY_PUBDATE ELSE 0 END) AS most_recent_pubdate FROM $TABLE_NAME_FEED_ITEMS GROUP BY $KEY_FEED")
|
||||||
// + " MAX(" + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + ") AS most_recent_pubdate"
|
|
||||||
// + " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
// + " WHERE " + KEY_READ + " = 0"
|
|
||||||
// + " GROUP BY " + KEY_FEED)
|
|
||||||
|
|
||||||
val query = ("SELECT " + KEY_FEED + ","
|
|
||||||
+ " MAX(CASE WHEN " + KEY_READ + " != 1 THEN " + KEY_PUBDATE + " ELSE 0 END) AS most_recent_pubdate"
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ " GROUP BY " + KEY_FEED)
|
|
||||||
|
|
||||||
val c = db.rawQuery(query, null)
|
val c = db.rawQuery(query, null)
|
||||||
val result: MutableMap<Long, Long> = HashMap()
|
val result: MutableMap<Long, Long> = HashMap()
|
||||||
|
@ -1118,8 +1011,7 @@ class PodDBAdapter private constructor() {
|
||||||
Log.w("DBAdapter", "Upgrading from version $oldVersion to $newVersion.")
|
Log.w("DBAdapter", "Upgrading from version $oldVersion to $newVersion.")
|
||||||
DBUpgrader.upgrade(db, oldVersion, newVersion)
|
DBUpgrader.upgrade(db, oldVersion, newVersion)
|
||||||
|
|
||||||
db.execSQL("DELETE FROM " + TABLE_NAME_DOWNLOAD_LOG + " WHERE "
|
db.execSQL("DELETE FROM $TABLE_NAME_DOWNLOAD_LOG WHERE $KEY_COMPLETION_DATE<${System.currentTimeMillis() - 7L * 24L * 3600L * 1000L}")
|
||||||
+ KEY_COMPLETION_DATE + "<" + (System.currentTimeMillis() - 7L * 24L * 3600L * 1000L))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1206,104 +1098,34 @@ class PodDBAdapter private constructor() {
|
||||||
const val TABLE_NAME_FAVORITES: String = "Favorites"
|
const val TABLE_NAME_FAVORITES: String = "Favorites"
|
||||||
|
|
||||||
// SQL Statements for creating new tables
|
// SQL Statements for creating new tables
|
||||||
private const val TABLE_PRIMARY_KEY = (KEY_ID
|
private const val TABLE_PRIMARY_KEY = ("$KEY_ID INTEGER PRIMARY KEY AUTOINCREMENT ,")
|
||||||
+ " INTEGER PRIMARY KEY AUTOINCREMENT ,")
|
|
||||||
|
|
||||||
private const val CREATE_TABLE_FEEDS = ("CREATE TABLE "
|
private const val CREATE_TABLE_FEEDS = ("CREATE TABLE $TABLE_NAME_FEEDS ($TABLE_PRIMARY_KEY$KEY_TITLE TEXT,$KEY_CUSTOM_TITLE TEXT,$KEY_FILE_URL TEXT,$KEY_DOWNLOAD_URL TEXT,$KEY_DOWNLOADED INTEGER,$KEY_LINK TEXT,$KEY_DESCRIPTION TEXT,$KEY_PAYMENT_LINK TEXT,$KEY_LASTUPDATE TEXT,$KEY_LANGUAGE TEXT,$KEY_AUTHOR TEXT,$KEY_IMAGE_URL TEXT,$KEY_TYPE TEXT,$KEY_FEED_IDENTIFIER TEXT,$KEY_AUTO_DOWNLOAD_ENABLED INTEGER DEFAULT 1,$KEY_USERNAME TEXT,$KEY_PASSWORD TEXT,$KEY_INCLUDE_FILTER TEXT DEFAULT '',$KEY_EXCLUDE_FILTER TEXT DEFAULT '',$KEY_MINIMAL_DURATION_FILTER INTEGER DEFAULT -1,$KEY_KEEP_UPDATED INTEGER DEFAULT 1,$KEY_IS_PAGED INTEGER DEFAULT 0,$KEY_NEXT_PAGE_LINK TEXT,$KEY_HIDE TEXT,$KEY_SORT_ORDER TEXT,$KEY_LAST_UPDATE_FAILED INTEGER DEFAULT 0,$KEY_AUTO_DELETE_ACTION INTEGER DEFAULT 0,$KEY_FEED_PLAYBACK_SPEED REAL DEFAULT ${FeedPreferences.SPEED_USE_GLOBAL},$KEY_FEED_VOLUME_ADAPTION INTEGER DEFAULT 0,$KEY_FEED_TAGS TEXT,$KEY_FEED_SKIP_INTRO INTEGER DEFAULT 0,$KEY_FEED_SKIP_ENDING INTEGER DEFAULT 0,$KEY_EPISODE_NOTIFICATION INTEGER DEFAULT 0,$KEY_NEW_EPISODES_ACTION INTEGER DEFAULT 0)")
|
||||||
+ TABLE_NAME_FEEDS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
|
|
||||||
+ " TEXT," + KEY_CUSTOM_TITLE + " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
|
|
||||||
+ KEY_DOWNLOADED + " INTEGER," + KEY_LINK + " TEXT,"
|
|
||||||
+ KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
|
|
||||||
+ KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
|
|
||||||
+ " TEXT," + KEY_IMAGE_URL + " TEXT," + KEY_TYPE + " TEXT,"
|
|
||||||
+ KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD_ENABLED + " INTEGER DEFAULT 1,"
|
|
||||||
+ KEY_USERNAME + " TEXT,"
|
|
||||||
+ KEY_PASSWORD + " TEXT,"
|
|
||||||
+ KEY_INCLUDE_FILTER + " TEXT DEFAULT '',"
|
|
||||||
+ KEY_EXCLUDE_FILTER + " TEXT DEFAULT '',"
|
|
||||||
+ KEY_MINIMAL_DURATION_FILTER + " INTEGER DEFAULT -1,"
|
|
||||||
+ KEY_KEEP_UPDATED + " INTEGER DEFAULT 1,"
|
|
||||||
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_NEXT_PAGE_LINK + " TEXT,"
|
|
||||||
+ KEY_HIDE + " TEXT,"
|
|
||||||
+ KEY_SORT_ORDER + " TEXT,"
|
|
||||||
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + FeedPreferences.SPEED_USE_GLOBAL + ","
|
|
||||||
+ KEY_FEED_VOLUME_ADAPTION + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_FEED_TAGS + " TEXT,"
|
|
||||||
+ KEY_FEED_SKIP_INTRO + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_FEED_SKIP_ENDING + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_EPISODE_NOTIFICATION + " INTEGER DEFAULT 0,"
|
|
||||||
+ KEY_NEW_EPISODES_ACTION + " INTEGER DEFAULT 0)")
|
|
||||||
|
|
||||||
private const val CREATE_TABLE_FEED_ITEMS = ("CREATE TABLE "
|
private const val CREATE_TABLE_FEED_ITEMS = ("CREATE TABLE $TABLE_NAME_FEED_ITEMS ($TABLE_PRIMARY_KEY$KEY_TITLE TEXT,$KEY_PUBDATE INTEGER,$KEY_READ INTEGER,$KEY_LINK TEXT,$KEY_DESCRIPTION TEXT,$KEY_TRANSCRIPT TEXT,$KEY_PAYMENT_LINK TEXT,$KEY_MEDIA INTEGER,$KEY_FEED INTEGER,$KEY_HAS_CHAPTERS INTEGER,$KEY_ITEM_IDENTIFIER TEXT,$KEY_IMAGE_URL TEXT,$KEY_AUTO_DOWNLOAD_ENABLED INTEGER,$KEY_PODCASTINDEX_CHAPTER_URL TEXT)")
|
||||||
+ TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY
|
|
||||||
+ KEY_TITLE + " TEXT," + KEY_PUBDATE + " INTEGER,"
|
|
||||||
+ KEY_READ + " INTEGER," + KEY_LINK + " TEXT,"
|
|
||||||
+ KEY_DESCRIPTION + " TEXT," + KEY_TRANSCRIPT + " TEXT,"
|
|
||||||
+ KEY_PAYMENT_LINK + " TEXT,"
|
|
||||||
+ KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
|
|
||||||
+ KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
|
|
||||||
+ KEY_IMAGE_URL + " TEXT,"
|
|
||||||
+ KEY_AUTO_DOWNLOAD_ENABLED + " INTEGER,"
|
|
||||||
+ KEY_PODCASTINDEX_CHAPTER_URL + " TEXT)")
|
|
||||||
|
|
||||||
private const val CREATE_TABLE_FEED_MEDIA = ("CREATE TABLE "
|
private const val CREATE_TABLE_FEED_MEDIA = ("CREATE TABLE $TABLE_NAME_FEED_MEDIA ($TABLE_PRIMARY_KEY$KEY_DURATION INTEGER,$KEY_FILE_URL TEXT,$KEY_DOWNLOAD_URL TEXT,$KEY_DOWNLOADED INTEGER,$KEY_POSITION INTEGER,$KEY_SIZE INTEGER,$KEY_MIME_TYPE TEXT,$KEY_PLAYBACK_COMPLETION_DATE INTEGER,$KEY_FEEDITEM INTEGER,$KEY_PLAYED_DURATION INTEGER,$KEY_HAS_EMBEDDED_PICTURE INTEGER,$KEY_LAST_PLAYED_TIME INTEGER)")
|
||||||
+ TABLE_NAME_FEED_MEDIA + " (" + TABLE_PRIMARY_KEY + KEY_DURATION
|
|
||||||
+ " INTEGER," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL
|
|
||||||
+ " TEXT," + KEY_DOWNLOADED + " INTEGER," + KEY_POSITION
|
|
||||||
+ " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
|
|
||||||
+ KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
|
|
||||||
+ KEY_FEEDITEM + " INTEGER,"
|
|
||||||
+ KEY_PLAYED_DURATION + " INTEGER,"
|
|
||||||
+ KEY_HAS_EMBEDDED_PICTURE + " INTEGER,"
|
|
||||||
+ KEY_LAST_PLAYED_TIME + " INTEGER" + ")")
|
|
||||||
|
|
||||||
private const val CREATE_TABLE_DOWNLOAD_LOG = ("CREATE TABLE "
|
private const val CREATE_TABLE_DOWNLOAD_LOG = ("CREATE TABLE $TABLE_NAME_DOWNLOAD_LOG ($TABLE_PRIMARY_KEY$KEY_FEEDFILE INTEGER,$KEY_FEEDFILETYPE INTEGER,$KEY_REASON INTEGER,$KEY_SUCCESSFUL INTEGER,$KEY_COMPLETION_DATE INTEGER,$KEY_REASON_DETAILED TEXT,$KEY_DOWNLOADSTATUS_TITLE TEXT)")
|
||||||
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
|
|
||||||
+ " INTEGER," + KEY_FEEDFILETYPE + " INTEGER," + KEY_REASON
|
|
||||||
+ " INTEGER," + KEY_SUCCESSFUL + " INTEGER," + KEY_COMPLETION_DATE
|
|
||||||
+ " INTEGER," + KEY_REASON_DETAILED + " TEXT,"
|
|
||||||
+ KEY_DOWNLOADSTATUS_TITLE + " TEXT)")
|
|
||||||
|
|
||||||
private const val CREATE_TABLE_QUEUE = ("CREATE TABLE "
|
private const val 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 const val CREATE_TABLE_SIMPLECHAPTERS = ("CREATE TABLE "
|
private const val CREATE_TABLE_SIMPLECHAPTERS = ("CREATE TABLE $TABLE_NAME_SIMPLECHAPTERS ($TABLE_PRIMARY_KEY$KEY_TITLE TEXT,$KEY_START INTEGER,$KEY_FEEDITEM INTEGER,$KEY_LINK TEXT,$KEY_IMAGE_URL TEXT)")
|
||||||
+ TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
|
|
||||||
+ " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER,"
|
|
||||||
+ KEY_LINK + " TEXT," + KEY_IMAGE_URL + " TEXT)")
|
|
||||||
|
|
||||||
// SQL Statements for creating indexes
|
// SQL Statements for creating indexes
|
||||||
const val CREATE_INDEX_FEEDITEMS_FEED: String = ("CREATE INDEX "
|
const val CREATE_INDEX_FEEDITEMS_FEED: String = ("CREATE INDEX ${TABLE_NAME_FEED_ITEMS}_$KEY_FEED ON $TABLE_NAME_FEED_ITEMS ($KEY_FEED)")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_FEED + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
|
||||||
+ KEY_FEED + ")")
|
|
||||||
|
|
||||||
const val CREATE_INDEX_FEEDITEMS_PUBDATE: String = ("CREATE INDEX "
|
const val CREATE_INDEX_FEEDITEMS_PUBDATE: String = ("CREATE INDEX ${TABLE_NAME_FEED_ITEMS}_$KEY_PUBDATE ON $TABLE_NAME_FEED_ITEMS ($KEY_PUBDATE)")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_PUBDATE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
|
||||||
+ KEY_PUBDATE + ")")
|
|
||||||
|
|
||||||
const val CREATE_INDEX_FEEDITEMS_READ: String = ("CREATE INDEX "
|
const val CREATE_INDEX_FEEDITEMS_READ: String = ("CREATE INDEX ${TABLE_NAME_FEED_ITEMS}_$KEY_READ ON $TABLE_NAME_FEED_ITEMS ($KEY_READ)")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_READ + " ON " + TABLE_NAME_FEED_ITEMS + " ("
|
|
||||||
+ KEY_READ + ")")
|
|
||||||
|
|
||||||
const val CREATE_INDEX_QUEUE_FEEDITEM: String = ("CREATE INDEX "
|
const val CREATE_INDEX_QUEUE_FEEDITEM: String = ("CREATE INDEX ${TABLE_NAME_QUEUE}_$KEY_FEEDITEM ON $TABLE_NAME_QUEUE ($KEY_FEEDITEM)")
|
||||||
+ TABLE_NAME_QUEUE + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_QUEUE + " ("
|
|
||||||
+ KEY_FEEDITEM + ")")
|
|
||||||
|
|
||||||
const val CREATE_INDEX_FEEDMEDIA_FEEDITEM: String = ("CREATE INDEX "
|
const val CREATE_INDEX_FEEDMEDIA_FEEDITEM: String = ("CREATE INDEX ${TABLE_NAME_FEED_MEDIA}_$KEY_FEEDITEM ON $TABLE_NAME_FEED_MEDIA ($KEY_FEEDITEM)")
|
||||||
+ TABLE_NAME_FEED_MEDIA + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_FEED_MEDIA + " ("
|
|
||||||
+ KEY_FEEDITEM + ")")
|
|
||||||
|
|
||||||
const val CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM: String = ("CREATE INDEX "
|
const val CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM: String = ("CREATE INDEX ${TABLE_NAME_SIMPLECHAPTERS}_$KEY_FEEDITEM ON $TABLE_NAME_SIMPLECHAPTERS ($KEY_FEEDITEM)")
|
||||||
+ TABLE_NAME_SIMPLECHAPTERS + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_SIMPLECHAPTERS + " ("
|
|
||||||
+ KEY_FEEDITEM + ")")
|
|
||||||
|
|
||||||
const val CREATE_TABLE_FAVORITES: String = ("CREATE TABLE "
|
const val CREATE_TABLE_FAVORITES: String = ("CREATE TABLE $TABLE_NAME_FAVORITES($KEY_ID INTEGER PRIMARY KEY,$KEY_FEEDITEM INTEGER,$KEY_FEED INTEGER)")
|
||||||
+ TABLE_NAME_FAVORITES + "(" + KEY_ID + " INTEGER PRIMARY KEY,"
|
|
||||||
+ KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the tables in the database
|
* All the tables in the database
|
||||||
|
@ -1322,82 +1144,16 @@ class PodDBAdapter private constructor() {
|
||||||
const val SELECT_KEY_FEED_ID: String = "feed_id"
|
const val SELECT_KEY_FEED_ID: String = "feed_id"
|
||||||
|
|
||||||
private const val KEYS_FEED_ITEM_WITHOUT_DESCRIPTION =
|
private const val KEYS_FEED_ITEM_WITHOUT_DESCRIPTION =
|
||||||
(TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " AS " + SELECT_KEY_ITEM_ID + ", "
|
("$TABLE_NAME_FEED_ITEMS.$KEY_ID AS $SELECT_KEY_ITEM_ID, $TABLE_NAME_FEED_ITEMS.$KEY_TITLE, $TABLE_NAME_FEED_ITEMS.$KEY_PUBDATE, $TABLE_NAME_FEED_ITEMS.$KEY_READ, $TABLE_NAME_FEED_ITEMS.$KEY_LINK, $TABLE_NAME_FEED_ITEMS.$KEY_PAYMENT_LINK, $TABLE_NAME_FEED_ITEMS.$KEY_MEDIA, $TABLE_NAME_FEED_ITEMS.$KEY_FEED, $TABLE_NAME_FEED_ITEMS.$KEY_HAS_CHAPTERS, $TABLE_NAME_FEED_ITEMS.$KEY_ITEM_IDENTIFIER, $TABLE_NAME_FEED_ITEMS.$KEY_IMAGE_URL, $TABLE_NAME_FEED_ITEMS.$KEY_AUTO_DOWNLOAD_ENABLED, $TABLE_NAME_FEED_ITEMS.$KEY_PODCASTINDEX_CHAPTER_URL")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_TITLE + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_READ + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_LINK + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_MEDIA + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE_URL + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_AUTO_DOWNLOAD_ENABLED + ", "
|
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_PODCASTINDEX_CHAPTER_URL)
|
|
||||||
|
|
||||||
private const val KEYS_FEED_MEDIA = (TABLE_NAME_FEED_MEDIA + "." + KEY_ID + " AS " + SELECT_KEY_MEDIA_ID + ", "
|
private const val KEYS_FEED_MEDIA = ("$TABLE_NAME_FEED_MEDIA.$KEY_ID AS $SELECT_KEY_MEDIA_ID, $TABLE_NAME_FEED_MEDIA.$KEY_DURATION, $TABLE_NAME_FEED_MEDIA.$KEY_FILE_URL, $TABLE_NAME_FEED_MEDIA.$KEY_DOWNLOAD_URL, $TABLE_NAME_FEED_MEDIA.$KEY_DOWNLOADED, $TABLE_NAME_FEED_MEDIA.$KEY_POSITION, $TABLE_NAME_FEED_MEDIA.$KEY_SIZE, $TABLE_NAME_FEED_MEDIA.$KEY_MIME_TYPE, $TABLE_NAME_FEED_MEDIA.$KEY_PLAYBACK_COMPLETION_DATE, $TABLE_NAME_FEED_MEDIA.$KEY_FEEDITEM, $TABLE_NAME_FEED_MEDIA.$KEY_PLAYED_DURATION, $TABLE_NAME_FEED_MEDIA.$KEY_HAS_EMBEDDED_PICTURE, $TABLE_NAME_FEED_MEDIA.$KEY_LAST_PLAYED_TIME")
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_DURATION + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_FILE_URL + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOAD_URL + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_SIZE + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_MIME_TYPE + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_PLAYBACK_COMPLETION_DATE + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_PLAYED_DURATION + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_HAS_EMBEDDED_PICTURE + ", "
|
|
||||||
+ TABLE_NAME_FEED_MEDIA + "." + KEY_LAST_PLAYED_TIME)
|
|
||||||
|
|
||||||
private const val KEYS_FEED = (TABLE_NAME_FEEDS + "." + KEY_ID + " AS " + SELECT_KEY_FEED_ID + ", "
|
private const val KEYS_FEED = ("$TABLE_NAME_FEEDS.$KEY_ID AS $SELECT_KEY_FEED_ID, $TABLE_NAME_FEEDS.$KEY_TITLE, $TABLE_NAME_FEEDS.$KEY_CUSTOM_TITLE, $TABLE_NAME_FEEDS.$KEY_FILE_URL, $TABLE_NAME_FEEDS.$KEY_DOWNLOAD_URL, $TABLE_NAME_FEEDS.$KEY_DOWNLOADED, $TABLE_NAME_FEEDS.$KEY_LINK, $TABLE_NAME_FEEDS.$KEY_DESCRIPTION, $TABLE_NAME_FEEDS.$KEY_PAYMENT_LINK, $TABLE_NAME_FEEDS.$KEY_LASTUPDATE, $TABLE_NAME_FEEDS.$KEY_LANGUAGE, $TABLE_NAME_FEEDS.$KEY_AUTHOR, $TABLE_NAME_FEEDS.$KEY_IMAGE_URL, $TABLE_NAME_FEEDS.$KEY_TYPE, $TABLE_NAME_FEEDS.$KEY_FEED_IDENTIFIER, $TABLE_NAME_FEEDS.$KEY_IS_PAGED, $TABLE_NAME_FEEDS.$KEY_NEXT_PAGE_LINK, $TABLE_NAME_FEEDS.$KEY_LAST_UPDATE_FAILED, $TABLE_NAME_FEEDS.$KEY_AUTO_DOWNLOAD_ENABLED, $TABLE_NAME_FEEDS.$KEY_KEEP_UPDATED, $TABLE_NAME_FEEDS.$KEY_USERNAME, $TABLE_NAME_FEEDS.$KEY_PASSWORD, $TABLE_NAME_FEEDS.$KEY_HIDE, $TABLE_NAME_FEEDS.$KEY_SORT_ORDER, $TABLE_NAME_FEEDS.$KEY_AUTO_DELETE_ACTION, $TABLE_NAME_FEEDS.$KEY_FEED_VOLUME_ADAPTION, $TABLE_NAME_FEEDS.$KEY_INCLUDE_FILTER, $TABLE_NAME_FEEDS.$KEY_EXCLUDE_FILTER, $TABLE_NAME_FEEDS.$KEY_MINIMAL_DURATION_FILTER, $TABLE_NAME_FEEDS.$KEY_FEED_PLAYBACK_SPEED, $TABLE_NAME_FEEDS.$KEY_FEED_TAGS, $TABLE_NAME_FEEDS.$KEY_FEED_SKIP_INTRO, $TABLE_NAME_FEEDS.$KEY_FEED_SKIP_ENDING, $TABLE_NAME_FEEDS.$KEY_EPISODE_NOTIFICATION, $TABLE_NAME_FEEDS.$KEY_NEW_EPISODES_ACTION")
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_TITLE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_CUSTOM_TITLE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FILE_URL + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_DOWNLOAD_URL + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_DOWNLOADED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_LINK + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_DESCRIPTION + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_PAYMENT_LINK + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_LASTUPDATE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_LANGUAGE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_AUTHOR + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_IMAGE_URL + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_TYPE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_IS_PAGED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_NEXT_PAGE_LINK + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD_ENABLED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_KEEP_UPDATED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_USERNAME + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_PASSWORD + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_HIDE + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_SORT_ORDER + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_VOLUME_ADAPTION + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_MINIMAL_DURATION_FILTER + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_TAGS + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_INTRO + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_ENDING + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_EPISODE_NOTIFICATION + ", "
|
|
||||||
+ TABLE_NAME_FEEDS + "." + KEY_NEW_EPISODES_ACTION)
|
|
||||||
|
|
||||||
private const val JOIN_FEED_ITEM_AND_MEDIA = (" LEFT JOIN " + TABLE_NAME_FEED_MEDIA
|
private const val JOIN_FEED_ITEM_AND_MEDIA = (" LEFT JOIN $TABLE_NAME_FEED_MEDIA ON $TABLE_NAME_FEED_ITEMS.$KEY_ID=$TABLE_NAME_FEED_MEDIA.$KEY_FEEDITEM ")
|
||||||
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "=" + TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + " ")
|
|
||||||
|
|
||||||
private const val SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION =
|
private const val SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION = ("SELECT $KEYS_FEED_ITEM_WITHOUT_DESCRIPTION, $KEYS_FEED_MEDIA, $TABLE_NAME_FEED_ITEMS.$KEY_DESCRIPTION.$KEY_TRANSCRIPT FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA")
|
||||||
("SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA + ", "
|
private const val SELECT_FEED_ITEMS_AND_MEDIA = ("SELECT $KEYS_FEED_ITEM_WITHOUT_DESCRIPTION, $KEYS_FEED_MEDIA FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA")
|
||||||
+ TABLE_NAME_FEED_ITEMS + "." + KEY_DESCRIPTION + "." + KEY_TRANSCRIPT
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA)
|
|
||||||
private const val SELECT_FEED_ITEMS_AND_MEDIA =
|
|
||||||
("SELECT " + KEYS_FEED_ITEM_WITHOUT_DESCRIPTION + ", " + KEYS_FEED_MEDIA
|
|
||||||
+ " FROM " + TABLE_NAME_FEED_ITEMS
|
|
||||||
+ JOIN_FEED_ITEM_AND_MEDIA)
|
|
||||||
|
|
||||||
private lateinit var context: Context
|
private lateinit var context: Context
|
||||||
private var instance: PodDBAdapter? = null
|
private var instance: PodDBAdapter? = null
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ac.mdiq.podcini.ui.actions.actionbutton
|
||||||
import ac.mdiq.podcini.R
|
import ac.mdiq.podcini.R
|
||||||
import ac.mdiq.podcini.net.download.service.DownloadRequestCreator.getMediafilePath
|
import ac.mdiq.podcini.net.download.service.DownloadRequestCreator.getMediafilePath
|
||||||
import ac.mdiq.podcini.net.download.service.DownloadRequestCreator.getMediafilename
|
import ac.mdiq.podcini.net.download.service.DownloadRequestCreator.getMediafilename
|
||||||
import ac.mdiq.podcini.playback.AudioMediaOperation.MergeAudios
|
import ac.mdiq.podcini.util.AudioMediaOperation.mergeAudios
|
||||||
import ac.mdiq.podcini.storage.DBWriter
|
import ac.mdiq.podcini.storage.DBWriter
|
||||||
import ac.mdiq.podcini.storage.DBWriter.persistFeedItem
|
import ac.mdiq.podcini.storage.DBWriter.persistFeedItem
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||||
|
@ -77,9 +77,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||||
val result = tts?.setLanguage(Locale(item.feed!!.language!!))
|
val result = tts?.setLanguage(Locale(item.feed!!.language!!))
|
||||||
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
|
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
|
||||||
Log.w(TAG, "TTS language not supported ${item.feed?.language} $result")
|
Log.w(TAG, "TTS language not supported ${item.feed?.language} $result")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) { Toast.makeText(context, context.getString(R.string.language_not_supported_by_tts) + " ${item.feed?.language} $result", Toast.LENGTH_LONG).show() }
|
||||||
Toast.makeText(context, context.getString(R.string.language_not_supported_by_tts) + " ${item.feed?.language} $result", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,9 +115,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||||
status = tts?.synthesizeToFile(chunk, null, tempFile, tempFile.absolutePath) ?: 0
|
status = tts?.synthesizeToFile(chunk, null, tempFile, tempFile.absolutePath) ?: 0
|
||||||
Log.d(TAG, "status: $status chunk: ${chunk.substring(0, min(80, chunk.length))}")
|
Log.d(TAG, "status: $status chunk: ${chunk.substring(0, min(80, chunk.length))}")
|
||||||
if (status == TextToSpeech.ERROR) {
|
if (status == TextToSpeech.ERROR) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) { Toast.makeText(context, "Error generating audio file $tempFile.absolutePath", Toast.LENGTH_LONG).show() }
|
||||||
Toast.makeText(context, "Error generating audio file $tempFile.absolutePath", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
startIndex += chunkLength
|
startIndex += chunkLength
|
||||||
|
@ -131,7 +127,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||||
processing = 0.85f
|
processing = 0.85f
|
||||||
EventBus.getDefault().post(updated(item))
|
EventBus.getDefault().post(updated(item))
|
||||||
if (status == TextToSpeech.SUCCESS) {
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
MergeAudios(parts.toTypedArray(), mediaFile.absolutePath, null)
|
mergeAudios(parts.toTypedArray(), mediaFile.absolutePath, null)
|
||||||
|
|
||||||
// if (mediaFile.exists()) mediaFile.delete()
|
// if (mediaFile.exists()) mediaFile.delete()
|
||||||
// if (!mediaFile.exists()) {
|
// if (!mediaFile.exists()) {
|
||||||
|
@ -156,7 +152,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||||
f.delete()
|
f.delete()
|
||||||
}
|
}
|
||||||
ttsWorking = false
|
ttsWorking = false
|
||||||
} else Toast.makeText(context, R.string.episode_has_no_content, Toast.LENGTH_LONG).show()
|
} else withContext(Dispatchers.Main) { Toast.makeText(context, R.string.episode_has_no_content, Toast.LENGTH_LONG).show() }
|
||||||
|
|
||||||
item.setPlayed(false)
|
item.setPlayed(false)
|
||||||
processing = 1f
|
processing = 1f
|
||||||
|
|
|
@ -137,15 +137,17 @@ class EpisodeHomeFragment : Fragment() {
|
||||||
val result = tts?.setLanguage(Locale(currentItem!!.feed!!.language!!))
|
val result = tts?.setLanguage(Locale(currentItem!!.feed!!.language!!))
|
||||||
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
|
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
|
||||||
Log.w(TAG, "TTS language not supported ${currentItem?.feed?.language}")
|
Log.w(TAG, "TTS language not supported ${currentItem?.feed?.language}")
|
||||||
|
requireActivity().runOnUiThread {
|
||||||
Toast.makeText(context, getString(R.string.language_not_supported_by_tts) + " ${currentItem?.feed?.language}", Toast.LENGTH_LONG).show()
|
Toast.makeText(context, getString(R.string.language_not_supported_by_tts) + " ${currentItem?.feed?.language}", Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ttsReady = true
|
ttsReady = true
|
||||||
// semaphore.release()
|
// semaphore.release()
|
||||||
Log.d(TAG, "TTS init success")
|
Log.d(TAG, "TTS init success")
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "TTS init failed")
|
Log.w(TAG, "TTS init failed")
|
||||||
Toast.makeText(context, R.string.tts_init_failed, Toast.LENGTH_LONG).show()
|
requireActivity().runOnUiThread {Toast.makeText(context, R.string.tts_init_failed, Toast.LENGTH_LONG).show() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,9 +173,9 @@ class EpisodeHomeFragment : Fragment() {
|
||||||
// super.onPrepareMenu(menu)
|
// super.onPrepareMenu(menu)
|
||||||
Log.d(TAG, "onPrepareMenu called")
|
Log.d(TAG, "onPrepareMenu called")
|
||||||
val textSpeech = menu.findItem(R.id.text_speech)
|
val textSpeech = menu.findItem(R.id.text_speech)
|
||||||
textSpeech?.isVisible = readMode
|
textSpeech?.isVisible = readMode && tts != null
|
||||||
if (readMode) {
|
if (textSpeech?.isVisible == true) {
|
||||||
if (ttsPlaying) textSpeech?.setIcon(R.drawable.ic_pause) else textSpeech?.setIcon(R.drawable.ic_play_24dp)
|
if (ttsPlaying) textSpeech.setIcon(R.drawable.ic_pause) else textSpeech.setIcon(R.drawable.ic_play_24dp)
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.share_notes)?.setVisible(readMode)
|
menu.findItem(R.id.share_notes)?.setVisible(readMode)
|
||||||
menu.findItem(R.id.switchJS)?.setVisible(!readMode)
|
menu.findItem(R.id.switchJS)?.setVisible(!readMode)
|
||||||
|
@ -215,7 +217,8 @@ class EpisodeHomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
} else ttsPlaying = false
|
} else ttsPlaying = false
|
||||||
updateAppearance()
|
updateAppearance()
|
||||||
}
|
} else Toast.makeText(context, R.string.tts_not_available, Toast.LENGTH_LONG).show()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.share_notes -> {
|
R.id.share_notes -> {
|
||||||
|
|
|
@ -195,16 +195,28 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
adapter.endSelectMode()
|
adapter.endSelectMode()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
ioScope.launch {
|
|
||||||
if (!ttsReady) {
|
|
||||||
initializeTTS(requireContext())
|
|
||||||
semaphore.acquire()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val semaphore = Semaphore(0)
|
||||||
|
private fun initializeTTS(context: Context) {
|
||||||
|
Log.d(TAG, "starting TTS")
|
||||||
|
if (tts == null) {
|
||||||
|
tts = TextToSpeech(context) { status: Int ->
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
ttsReady = true
|
||||||
|
semaphore.release()
|
||||||
|
Log.d(TAG, "TTS init success")
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "TTS init failed")
|
||||||
|
requireActivity().runOnUiThread {
|
||||||
|
Toast.makeText(context, R.string.tts_init_failed, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
|
@ -523,7 +535,6 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
|
|
||||||
@UnstableApi private fun loadItems() {
|
@UnstableApi private fun loadItems() {
|
||||||
disposable?.dispose()
|
disposable?.dispose()
|
||||||
|
|
||||||
disposable = Observable.fromCallable<Feed?> { this.loadData() }
|
disposable = Observable.fromCallable<Feed?> { this.loadData() }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
@ -531,6 +542,23 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
{ result: Feed? ->
|
{ result: Feed? ->
|
||||||
feed = result
|
feed = result
|
||||||
Log.d(TAG, "loadItems subscribe called ${feed?.title}")
|
Log.d(TAG, "loadItems subscribe called ${feed?.title}")
|
||||||
|
if (feed != null) {
|
||||||
|
var hasNonMediaItems = false
|
||||||
|
for (item in feed!!.items) {
|
||||||
|
if (item.media == null) {
|
||||||
|
hasNonMediaItems = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasNonMediaItems) {
|
||||||
|
ioScope.launch {
|
||||||
|
if (!ttsReady) {
|
||||||
|
initializeTTS(requireContext())
|
||||||
|
semaphore.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
swipeActions.setFilter(feed?.itemFilter)
|
swipeActions.setFilter(feed?.itemFilter)
|
||||||
refreshHeaderView()
|
refreshHeaderView()
|
||||||
binding.progressBar.visibility = View.GONE
|
binding.progressBar.visibility = View.GONE
|
||||||
|
@ -649,22 +677,5 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
var tts: TextToSpeech? = null
|
var tts: TextToSpeech? = null
|
||||||
var ttsReady = false
|
var ttsReady = false
|
||||||
var ttsWorking = false
|
var ttsWorking = false
|
||||||
val semaphore = Semaphore(0)
|
|
||||||
|
|
||||||
fun initializeTTS(context: Context) {
|
|
||||||
Log.d(TAG, "starting TTS")
|
|
||||||
if (tts == null) {
|
|
||||||
tts = TextToSpeech(context) { status: Int ->
|
|
||||||
if (status == TextToSpeech.SUCCESS) {
|
|
||||||
ttsReady = true
|
|
||||||
semaphore.release()
|
|
||||||
Log.d(TAG, "TTS init success")
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "TTS init failed")
|
|
||||||
Toast.makeText(context, R.string.tts_init_failed, Toast.LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ac.mdiq.podcini.playback
|
package ac.mdiq.podcini.util
|
||||||
|
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
@ -6,7 +6,7 @@ import java.nio.ByteOrder
|
||||||
|
|
||||||
// converted to Kotlin from the java file: https://gist.github.com/DrustZ/d3d3fc8fcc1067433db4dd3079f8d187
|
// converted to Kotlin from the java file: https://gist.github.com/DrustZ/d3d3fc8fcc1067433db4dd3079f8d187
|
||||||
object AudioMediaOperation {
|
object AudioMediaOperation {
|
||||||
fun MergeAudios(selection: Array<String>, outpath: String?, callback: OperationCallbacks?) {
|
fun mergeAudios(selection: Array<String>, outpath: String?, callback: OperationCallbacks?) {
|
||||||
var RECORDER_SAMPLERATE = 0
|
var RECORDER_SAMPLERATE = 0
|
||||||
try {
|
try {
|
||||||
val amplifyOutputStream = DataOutputStream(BufferedOutputStream(FileOutputStream(outpath)))
|
val amplifyOutputStream = DataOutputStream(BufferedOutputStream(FileOutputStream(outpath)))
|
||||||
|
@ -145,7 +145,7 @@ object AudioMediaOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun RawToWave(rawfn: String?, wavefn: String?) {
|
fun rawToWave(rawfn: String, wavefn: String) {
|
||||||
val rawFile = File(rawfn)
|
val rawFile = File(rawfn)
|
||||||
val waveFile = File(wavefn)
|
val waveFile = File(wavefn)
|
||||||
val rawData = ByteArray(rawFile.length().toInt())
|
val rawData = ByteArray(rawFile.length().toInt())
|
||||||
|
@ -233,8 +233,8 @@ object AudioMediaOperation {
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun writeString(output: DataOutputStream, value: String) {
|
fun writeString(output: DataOutputStream, value: String) {
|
||||||
for (i in 0 until value.length) {
|
for (element in value) {
|
||||||
output.write(value[i].code)
|
output.write(element.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
<string name="web_content_not_available">Web content is not available</string>
|
<string name="web_content_not_available">Web content is not available</string>
|
||||||
<string name="language_not_supported_by_tts">The language is not supported by TTS</string>
|
<string name="language_not_supported_by_tts">The language is not supported by TTS</string>
|
||||||
<string name="tts_init_failed">TTS init failed</string>
|
<string name="tts_init_failed">TTS init failed</string>
|
||||||
|
<string name="tts_not_available">TTS engine not available</string>
|
||||||
<string name="episode_has_no_content">Episode has not content</string>
|
<string name="episode_has_no_content">Episode has not content</string>
|
||||||
|
|
||||||
<string name="notification_permission_text">Since Android 13, top level notification is needed for normal refresh and playback. You may disallow notifications of sub-catergories at your wish.</string>
|
<string name="notification_permission_text">Since Android 13, top level notification is needed for normal refresh and playback. You may disallow notifications of sub-catergories at your wish.</string>
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
## 4.10.1
|
||||||
|
|
||||||
|
* fixed crash issue when TTS engine is not available on device
|
||||||
|
* in feed item list view, only start TTS engine when some episodes have no media
|
||||||
|
|
||||||
## 4.10.0
|
## 4.10.0
|
||||||
|
|
||||||
* fixed media info on notification widget
|
* fixed media info on notification widget
|
||||||
|
@ -54,7 +59,7 @@
|
||||||
## 4.9.0
|
## 4.9.0
|
||||||
|
|
||||||
* fixed bug of player always expands when changing audio
|
* fixed bug of player always expands when changing audio
|
||||||
* migrated to media3's MediaSession and MediaLibraryService thought no new features added with this. some behavior might change or issues might arise, need to be mindful
|
* migrated to media3's MediaSession and MediaLibraryService though no new features added with this. some behavior might change or issues might arise, need to be mindful
|
||||||
* when video mode is temporarily audio only, click on image on audio player on a video episode also brings up the normal player detailed view
|
* when video mode is temporarily audio only, click on image on audio player on a video episode also brings up the normal player detailed view
|
||||||
* added a menu action item in player detailed view to turn to fullscreen video for video episode
|
* added a menu action item in player detailed view to turn to fullscreen video for video episode
|
||||||
* added episode home view accessible right from episode info view. episode home view has two display modes: webpage or reader.
|
* added episode home view accessible right from episode info view. episode home view has two display modes: webpage or reader.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
Version 4.10.1 brings several changes:
|
||||||
|
|
||||||
|
* fixed crash issue when TTS engine is not available on device
|
||||||
|
* in feed item list view, only start TTS engine when some episodes have no media
|
Loading…
Reference in New Issue