Skip to content

Commit

Permalink
6.12.0 commit
Browse files Browse the repository at this point in the history
  • Loading branch information
XilinJia committed Oct 22, 2024
1 parent a9f5990 commit 0c80171
Show file tree
Hide file tree
Showing 112 changed files with 791 additions and 1,403 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ An open source podcast instrument, attuned to Puccini ![Puccini](./images/Puccin
[<img src="./images/external/amazon.png" alt="Amazon" height="40">](https://www.amazon.com/%E8%B4%BE%E8%A5%BF%E6%9E%97-Podcini-R/dp/B0D9WR8P13)

#### Podcini.R 6.10 allows creating synthetic podcast and shelving any episdes to any synthetic podcasts
#### Podcini.R version 6.5 as a major step forward brings YouTube contents in the app. Channels can be searched, received from share, subscribed. Since 6.6, podcasts, playlists as well as single media from Youtube and YT Music can be shared to Podcini. For more see the Youtube section below or the changelogs
#### Podcini.R version 6.5 as a major step forward brings YouTube contents in the app. Channels can be searched, received from share, subscribed. Podcasts, playlists as well as single media from Youtube and YT Music can be shared to Podcini. For more see the Youtube section below or the changelogs
That means finally: [Nessun dorma](https://www.youtube.com/watch?v=cWc7vYjgnTs)
#### For Podcini to show up on car's HUD with Android Auto, please read AnroidAuto.md for instructions.
#### If you need to cast to an external speaker, you should install the "play" apk, not the "free" apk, that's about the difference between the two.
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ android {
testApplicationId "ac.mdiq.podcini.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

versionCode 3020277
versionName "6.11.7"
versionCode 3020278
versionName "6.12.0"

applicationId "ac.mdiq.podcini.R"
def commit = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class MediaPlayerBaseTest {
VolumeAdaptionSetting.OFF, null, null)
f.preferences = prefs
f.episodes.clear()
val i = Episode(0, "t", "i", "l", Date(), Episode.PlayState.UNPLAYED.code, f)
val i = Episode(0, "t", "i", "l", Date(), PlayState.UNPLAYED.code, f)
f.episodes.add(i)
val media = EpisodeMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0, 0)
i.setMedia(media)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TaskManagerTest {
val f = Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url")
f.episodes.clear()
for (i in 0 until NUM_ITEMS) {
f.episodes.add(Episode(0, pref + i, pref + i, "link", Date(), Episode.PlayState.PLAYED.code, f))
f.episodes.add(Episode(0, pref + i, pref + i, "link", Date(), PlayState.PLAYED.code, f))
}
// val adapter = getInstance()
// adapter.open()
Expand Down
3 changes: 2 additions & 1 deletion app/src/androidTest/kotlin/ac/test/podcini/ui/UITestUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package de.test.podcini.ui
import ac.mdiq.podcini.storage.model.Feed
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeMedia
import ac.mdiq.podcini.storage.model.PlayState
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
import android.content.Context
Expand Down Expand Up @@ -113,7 +114,7 @@ class UITestUtils(private val context: Context) {
val items: MutableList<Episode> = ArrayList()
for (j in 0 until NUM_ITEMS_PER_FEED) {
val item = Episode(j.toLong(), "Feed " + (i + 1) + ": Item " + (j + 1), "item$j",
"http://example.com/feed$i/item/$j", Date(), Episode.PlayState.UNPLAYED.code, feed)
"http://example.com/feed$i/item/$j", Date(), PlayState.UNPLAYED.code, feed)
items.add(item)

if (!hostTextOnlyFeeds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
.addTag(WORK_TAG_EPISODE_URL + item.media!!.downloadUrl)
if (enqueueDownloadedEpisodes()) {
if (item.feed?.preferences?.queue != null)
runBlocking { Queues.addToQueueSync(false, item, item.feed?.preferences?.queue) }
runBlocking { Queues.addToQueueSync(item, item.feed?.preferences?.queue) }
workRequest.addTag(WORK_DATA_WAS_QUEUED)
}
workRequest.setInputData(Data.Builder().putLong(WORK_DATA_MEDIA_ID, item.media!!.id).build())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ object LocalFeedUpdater {
}

private fun createFeedItem(feed: Feed, file: FastDocumentFile, context: Context): Episode {
val item = Episode(0L, file.name, UUID.randomUUID().toString(), file.name, Date(file.lastModified), Episode.PlayState.UNPLAYED.code, feed)
val item = Episode(0L, file.name, UUID.randomUUID().toString(), file.name, Date(file.lastModified), PlayState.UNPLAYED.code, feed)
item.disableAutoDownload()
val size = file.length
val media = EpisodeMedia(0, item, 0, 0, size, file.type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ object InTheatre {
}
upsert(curQueue_) {}
}
upsert(curQueue) {
it.update()
}
upsert(curQueue) { it.update() }
}

Logd(TAG, "starting curState")
Expand Down Expand Up @@ -135,10 +133,12 @@ object InTheatre {
val type = curState.curMediaType.toInt()
if (type == EpisodeMedia.PLAYABLE_TYPE_FEEDMEDIA) {
val mediaId = curState.curMediaId
Logd(TAG, "loadPlayableFromPreferences getting mediaId: $mediaId")
if (mediaId != 0L) {
curMedia = getEpisodeMedia(mediaId)
if (curEpisode != null) curEpisode = (curMedia as EpisodeMedia).episodeOrFetch()
}
Logd(TAG, "loadPlayableFromPreferences: curMedia: ${curMedia?.getIdentifier()}")
} else Log.e(TAG, "Could not restore Playable object from preferences")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ class PlaybackService : MediaLibraryService() {
if (ended || smartMarkAsPlayed || autoSkipped || (skipped && !shouldSkipKeepEpisode())) {
Logd(TAG, "onPostPlayback ended: $ended smartMarkAsPlayed: $smartMarkAsPlayed autoSkipped: $autoSkipped skipped: $skipped")
// only mark the item as played if we're not keeping it anyways
item = setPlayStateSync(Episode.PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!)
item = setPlayStateSync(PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!)
val action = item?.feed?.preferences?.autoDeleteAction
val shouldAutoDelete = (action == AutoDeleteAction.ALWAYS ||
(action == AutoDeleteAction.GLOBAL && item?.feed != null && shouldAutoDeleteItem(item!!.feed!!)))
Expand Down Expand Up @@ -1189,7 +1189,7 @@ class PlaybackService : MediaLibraryService() {
if (media != null) {
media.setPosition(position)
media.setLastPlayedTime(System.currentTimeMillis())
if (it.isNew) it.playState = Episode.PlayState.UNPLAYED.code
if (it.isNew) it.playState = PlayState.UNPLAYED.code
if (media.startPosition >= 0 && media.getPosition() > media.startPosition)
media.playedDuration = (media.playedDurationWhenStarted + media.getPosition() - media.startPosition)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ac.mdiq.podcini.storage.database.Queues.getInQueueEpisodeIds
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeFilter
import ac.mdiq.podcini.storage.model.EpisodeSortOrder
import ac.mdiq.podcini.storage.model.PlayState
import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.util.Log
Expand Down Expand Up @@ -182,7 +183,7 @@ object AutoCleanups {
val idsInQueues = getInQueueEpisodeIds()
val mostRecentDateForDeletion = calcMostRecentDateForDeletion(Date())
for (item in downloadedItems) {
if (item.media != null && item.media!!.downloaded && !idsInQueues.contains(item.id) && item.isPlayed() && !item.isFavorite) {
if (item.media != null && item.media!!.downloaded && !idsInQueues.contains(item.id) && item.playState >= PlayState.PLAYED.code && !item.isFavorite) {
val media = item.media
// make sure this candidate was played at least the proper amount of days prior to now
if (media?.playbackCompletionDate != null && media.playbackCompletionDate!!.before(mostRecentDateForDeletion)) candidates.add(item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.Episode.PlayState
import ac.mdiq.podcini.storage.model.EpisodeFilter
import ac.mdiq.podcini.storage.model.EpisodeMedia
import ac.mdiq.podcini.storage.model.EpisodeSortOrder
import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.utils.EpisodesPermutors.getPermutor
import ac.mdiq.podcini.storage.utils.FilesUtils.getMediafilename
import ac.mdiq.podcini.util.EventFlow
Expand Down Expand Up @@ -287,7 +283,7 @@ object Episodes {
var episode_ = episode
if (!episode.isManaged()) episode_ = realm.query(Episode::class).query("id == $0", episode.id).first().find() ?: episode
val result = upsert(episode_) {
if (played >= PlayState.NEW.code && played <= PlayState.BUILDING.code) it.playState = played
if (played != PlayState.UNSPECIFIED.code) it.playState = played
else {
if (it.playState == PlayState.PLAYED.code) it.playState = PlayState.UNPLAYED.code
else it.playState = PlayState.PLAYED.code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ object Feeds {
episode.feed = savedFeed
episode.id = idLong++
episode.feedId = savedFeed.id
episode.playState = PlayState.NEW.code
if (episode.media != null) {
episode.media!!.id = episode.id
if (!savedFeed.hasVideoMedia && episode.media!!.getMediaType() == MediaType.VIDEO) savedFeed.hasVideoMedia = true
Expand All @@ -300,7 +301,7 @@ object Feeds {
episode.setNew()
if (savedFeed.preferences?.autoAddNewToQueue == true) {
val q = savedFeed.preferences?.queue
if (q != null) runOnIOScope { addToQueueSync(false, episode, q) }
if (q != null) runOnIOScope { addToQueueSync(episode, q) }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object LogsAndStats {
feedTotalTime += m.duration
if (m.lastPlayedTime in timeFilterFrom..<timeFilterTo) {
if (includeMarkedAsPlayed) {
if ((m.playbackCompletionTime > 0 && m.playedDuration > 0) || m.episodeOrFetch()?.playState == Episode.PlayState.PLAYED.code || m.position > 0) {
if ((m.playbackCompletionTime > 0 && m.playedDuration > 0) || m.episodeOrFetch()?.playState == PlayState.PLAYED.code || m.position > 0) {
episodesStarted += 1
feedPlayedTime += m.duration
}
Expand Down
33 changes: 23 additions & 10 deletions app/src/main/kotlin/ac/mdiq/podcini/storage/database/Queues.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.upsert
Expand Down Expand Up @@ -77,9 +78,9 @@ object Queues {
appPrefs.edit().putString(UserPreferences.Prefs.prefEnqueueLocation.name, location.name).apply()
}

fun queueFromName(name: String): PlayQueue? {
return realm.query(PlayQueue::class).query("name == $0", name).first().find()
}
// fun queueFromName(name: String): PlayQueue? {
// return realm.query(PlayQueue::class).query("name == $0", name).first().find()
// }

fun getInQueueEpisodeIds(): Set<Long> {
Logd(TAG, "getQueueIDList() called")
Expand All @@ -98,13 +99,13 @@ object Queues {
* @param episodes the Episode objects that should be added to the queue.
*/
@UnstableApi @JvmStatic @Synchronized
fun addToQueue(markAsUnplayed: Boolean, vararg episodes: Episode) : Job {
fun addToQueue(vararg episodes: Episode) : Job {
Logd(TAG, "addToQueue( ... ) called")
return runOnIOScope {
if (episodes.isEmpty()) return@runOnIOScope

var queueModified = false
val markAsUnplayeds = mutableListOf<Episode>()
val setInQueue = mutableListOf<Episode>()
val events: MutableList<FlowEvent.QueueEvent> = ArrayList()
val updatedItems: MutableList<Episode> = ArrayList()
val positionCalculator = EnqueuePositionPolicy(enqueueLocation)
Expand All @@ -121,7 +122,7 @@ object Queues {
updatedItems.add(episode)
qItems.add(insertPosition, episode)
queueModified = true
if (episode.isNew) markAsUnplayeds.add(episode)
if (episode.playState < PlayState.INQUEUE.code) setInQueue.add(episode)
insertPosition++
}
if (queueModified) {
Expand All @@ -134,13 +135,13 @@ object Queues {
}
for (event in events) EventFlow.postEvent(event)

if (markAsUnplayed && markAsUnplayeds.size > 0) setPlayState(Episode.PlayState.UNPLAYED.code, false, *markAsUnplayeds.toTypedArray())
setPlayState(PlayState.INQUEUE.code, false, *setInQueue.toTypedArray())
// if (performAutoDownload) autodownloadEpisodeMedia(context)
}
}
}

suspend fun addToQueueSync(markAsUnplayed: Boolean, episode: Episode, queue_: PlayQueue? = null) {
suspend fun addToQueueSync(episode: Episode, queue_: PlayQueue? = null) {
Logd(TAG, "addToQueueSync( ... ) called")
val queue = queue_ ?: curQueue
if (queue.episodeIds.contains(episode.id)) return
Expand All @@ -157,7 +158,7 @@ object Queues {
}
if (queue.id == curQueue.id) curQueue = queueNew

if (markAsUnplayed && episode.isNew) setPlayState(Episode.PlayState.UNPLAYED.code, false, episode)
if (episode.playState < PlayState.INQUEUE.code) setPlayState(PlayState.INQUEUE.code, false, episode)
if (queue.id == curQueue.id) EventFlow.postEvent(FlowEvent.QueueEvent.added(episode, insertPosition))
// if (performAutoDownload) autodownloadEpisodeMedia(context)
}
Expand Down Expand Up @@ -194,6 +195,9 @@ object Queues {
it.episodeIds.clear()
it.update()
}
for (e in curQueue.episodes) {
if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
}
curQueue.episodes.clear()
EventFlow.postEvent(FlowEvent.QueueEvent.cleared())
}
Expand Down Expand Up @@ -230,7 +234,7 @@ object Queues {
var queue = queue_ ?: curQueue
if (queue.size() == 0) return

val events: MutableList<FlowEvent.QueueEvent> = ArrayList()
val events: MutableList<FlowEvent.QueueEvent> = mutableListOf()
val indicesToRemove: MutableList<Int> = mutableListOf()
val qItems = queue.episodes.toMutableList()
val eList = episodes.toList()
Expand All @@ -239,6 +243,7 @@ object Queues {
if (indexOfItemWithId(eList, episode.id) >= 0) {
Logd(TAG, "removing from queue: ${episode.id} ${episode.title}")
indicesToRemove.add(i)
if (episode.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, episode)
if (queue.id == curQueue.id) events.add(FlowEvent.QueueEvent.removed(episode))
}
}
Expand Down Expand Up @@ -270,6 +275,10 @@ object Queues {
if (q.size() == 0 || q.id == curQueue.id) continue
idsInQueuesToRemove = q.episodeIds.intersect(episodeIds.toSet()).toMutableSet()
if (idsInQueuesToRemove.isNotEmpty()) {
val eList = realm.query(Episode::class).query("id IN $0", idsInQueuesToRemove).find()
for (e in eList) {
if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
}
upsert(q) {
it.idsBinList.removeAll(idsInQueuesToRemove)
it.idsBinList.addAll(idsInQueuesToRemove)
Expand All @@ -288,6 +297,10 @@ object Queues {
}
idsInQueuesToRemove = q.episodeIds.intersect(episodeIds.toSet()).toMutableSet()
if (idsInQueuesToRemove.isNotEmpty()) {
val eList = realm.query(Episode::class).query("id IN $0", idsInQueuesToRemove).find()
for (e in eList) {
if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
}
curQueue = upsert(q) {
it.idsBinList.removeAll(idsInQueuesToRemove)
it.idsBinList.addAll(idsInQueuesToRemove)
Expand Down
20 changes: 17 additions & 3 deletions app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object RealmDB {
SubscriptionLog::class,
Chapter::class))
.name("Podcini.realm")
.schemaVersion(27)
.schemaVersion(28)
.migration({ mContext ->
val oldRealm = mContext.oldRealm // old realm using the previous schema
val newRealm = mContext.newRealm // new realm using the new schema
Expand Down Expand Up @@ -104,8 +104,22 @@ object RealmDB {
// )
// }
}
})
.build()
if (oldRealm.schemaVersion() < 28) {
Logd(TAG, "migrating DB from below 27")
mContext.enumerate(className = "Episode") { oldObject: DynamicRealmObject, newObject: DynamicMutableRealmObject? ->
newObject?.run {
if (oldObject.getValue<Long>(fieldName = "playState") == 1L) {
set("playState", 10L)
} else {
val media = oldObject.getObject(propertyName = "media")
var position = 0L
if (media != null) position = media.getValue(propertyName = "position", Long::class) ?: 0
if (position > 0) set("playState", 5L)
}
}
}
}
}).build()
realm = Realm.open(config)
}

Expand Down
21 changes: 6 additions & 15 deletions app/src/main/kotlin/ac/mdiq/podcini/storage/model/Episode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Episode : RealmObject {
var rating: Int = Rating.UNRATED.code

@Ignore
var isFavorite: Boolean = (rating == 2)
var isFavorite: Boolean = (rating == Rating.FAVORITE.code)
private set

var comment: String = ""
Expand Down Expand Up @@ -142,7 +142,7 @@ class Episode : RealmObject {
val isRemote = mutableStateOf(false)

constructor() {
this.playState = PlayState.UNPLAYED.code
this.playState = PlayState.NEW.code
}

/**
Expand Down Expand Up @@ -313,19 +313,10 @@ class Episode : RealmObject {
return result
}

fun shiftRating(): Int {
val nr = rating + 1
return if (nr <= Rating.FAVORITE.code) nr else Rating.TRASH.code
}

enum class PlayState(val code: Int) {
UNSPECIFIED(-2),
NEW(-1),
UNPLAYED(0),
PLAYED(1),
BUILDING(2),
ABANDONED(3)
}
// fun shiftRating(): Int {
// val nr = rating + 1
// return if (nr <= Rating.FAVORITE.code) nr else Rating.TRASH.code
// }

companion object {
val TAG: String = Episode::class.simpleName ?: "Anonymous"
Expand Down
Loading

0 comments on commit 0c80171

Please sign in to comment.