minor improvements

This commit is contained in:
Xilin Jia 2024-02-21 15:56:53 +01:00
parent 824893cbfc
commit 31624b7797
84 changed files with 710 additions and 672 deletions

View File

@ -171,7 +171,7 @@ object EspressoTestUtils {
init(InstrumentationRegistry.getInstrumentation().targetContext)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
}

View File

@ -108,11 +108,11 @@ class PlaybackServiceMediaPlayerTest {
f.preferences = prefs
f.items = mutableListOf()
val i = FeedItem(0, "t", "i", "l", Date(), FeedItem.UNPLAYED, f)
f.items!!.add(i)
f.items.add(i)
val media = FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0, 0)
i.setMedia(media)
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(f)
Assert.assertTrue(media.id != 0L)
adapter.close()
@ -130,14 +130,18 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
} else {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
2L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
}
else -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
}
}
} catch (e: AssertionFailedError) {
if (assertionError == null) assertionError = e
@ -168,14 +172,18 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
} else {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
2L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
}
else -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
}
}
} catch (e: AssertionFailedError) {
if (assertionError == null) assertionError = e
@ -207,16 +215,22 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 4L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
} else if (countDownLatch.count == 3L) {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
} else if (countDownLatch.count == 1L) {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
4L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
}
3L -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
}
2L -> {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
}
1L -> {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
}
}
countDownLatch.countDown()
} catch (e: AssertionFailedError) {
@ -247,18 +261,25 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 5L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
} else if (countDownLatch.count == 4L) {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
} else if (countDownLatch.count == 3L) {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
} else if (countDownLatch.count == 1L) {
Assert.assertEquals(PlayerStatus.PLAYING, newInfo.playerStatus)
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
5L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
}
4L -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
}
3L -> {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
}
2L -> {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
}
1L -> {
Assert.assertEquals(PlayerStatus.PLAYING, newInfo.playerStatus)
}
}
countDownLatch.countDown()
} catch (e: AssertionFailedError) {
@ -288,14 +309,18 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
} else {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
2L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
}
else -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
}
}
} catch (e: AssertionFailedError) {
if (assertionError == null) assertionError = e
@ -325,14 +350,18 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
} else {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
2L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
countDownLatch.countDown()
}
else -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
countDownLatch.countDown()
}
}
} catch (e: AssertionFailedError) {
if (assertionError == null) assertionError = e
@ -362,16 +391,22 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 4L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
} else if (countDownLatch.count == 3L) {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
} else if (countDownLatch.count == 1L) {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
4L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
}
3L -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
}
2L -> {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
}
1L -> {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
}
}
countDownLatch.countDown()
} catch (e: AssertionFailedError) {
@ -401,18 +436,25 @@ class PlaybackServiceMediaPlayerTest {
try {
checkPSMPInfo(newInfo)
check(newInfo!!.playerStatus != PlayerStatus.ERROR) { "MediaPlayer error" }
if (countDownLatch.count == 0L) {
Assert.fail()
} else if (countDownLatch.count == 5L) {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
} else if (countDownLatch.count == 4L) {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
} else if (countDownLatch.count == 3L) {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
} else if (countDownLatch.count == 2L) {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
} else if (countDownLatch.count == 1L) {
Assert.assertEquals(PlayerStatus.PLAYING, newInfo.playerStatus)
when (countDownLatch.count) {
0L -> {
Assert.fail()
}
5L -> {
Assert.assertEquals(PlayerStatus.INITIALIZING, newInfo.playerStatus)
}
4L -> {
Assert.assertEquals(PlayerStatus.INITIALIZED, newInfo.playerStatus)
}
3L -> {
Assert.assertEquals(PlayerStatus.PREPARING, newInfo.playerStatus)
}
2L -> {
Assert.assertEquals(PlayerStatus.PREPARED, newInfo.playerStatus)
}
1L -> {
Assert.assertEquals(PlayerStatus.PLAYING, newInfo.playerStatus)
}
}
} catch (e: AssertionFailedError) {
if (assertionError == null) assertionError = e

View File

@ -43,7 +43,7 @@ class PlaybackServiceTaskManagerTest {
init(context)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
setShakeToReset(false)
setVibrate(false)
@ -61,15 +61,15 @@ class PlaybackServiceTaskManagerTest {
val f = Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url", false)
f.items = mutableListOf()
for (i in 0 until NUM_ITEMS) {
f.items!!.add(FeedItem(0, pref + i, pref + i, "link", Date(), FeedItem.PLAYED, f))
f.items.add(FeedItem(0, pref + i, pref + i, "link", Date(), FeedItem.PLAYED, f))
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(f)
adapter.setQueue(f.items!!)
adapter.setQueue(f.items)
adapter.close()
for (item in f.items!!) {
for (item in f.items) {
Assert.assertTrue(item.id != 0L)
}
return f.items

View File

@ -189,7 +189,7 @@ class UITestUtils(private val context: Context) {
localFeedDataAdded = true
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(*hostedFeeds.toTypedArray<Feed>())
adapter.setQueue(queue)
adapter.close()

View File

@ -35,6 +35,7 @@ import com.google.android.material.snackbar.Snackbar
import ac.mdiq.podcini.R
import ac.mdiq.podcini.core.preferences.ThemeSwitcher.getNoTitleTheme
import ac.mdiq.podcini.core.receiver.MediaButtonReceiver.Companion.createIntent
import ac.mdiq.podcini.core.storage.DBReader
import ac.mdiq.podcini.core.sync.queue.SynchronizationQueueSink
import ac.mdiq.podcini.core.util.download.FeedUpdateManager
import ac.mdiq.podcini.core.util.download.FeedUpdateManager.restartUpdateAlarm
@ -103,6 +104,8 @@ class MainActivity : CastEnabledActivity() {
.build()
}
DBReader.updateFeedList()
val fm = supportFragmentManager
if (fm.findFragmentByTag(MAIN_FRAGMENT_TAG) == null) {
if (UserPreferences.DEFAULT_PAGE_REMEMBER != defaultPage) {

View File

@ -423,7 +423,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
viewBinding.titleLabel.text = feed.title
viewBinding.authorLabel.text = feed.author
headerBinding.txtvDescription.text = HtmlToPlainText.getPlainText(feed.description)
headerBinding.txtvDescription.text = HtmlToPlainText.getPlainText(feed.description?:"")
viewBinding.subscribeButton.setOnClickListener { v: View? ->
if (feedInFeedlist()) {

View File

@ -1,28 +1,7 @@
package ac.mdiq.podcini.activity
import ac.mdiq.podcini.activity.MainActivity
import android.content.DialogInterface
import android.content.Intent
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.*
import android.view.View.OnTouchListener
import android.view.animation.*
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.media3.common.util.UnstableApi
import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import ac.mdiq.podcini.R
import ac.mdiq.podcini.activity.MainActivity
import ac.mdiq.podcini.core.service.playback.PlaybackService.Companion.getPlayerActivityIntent
import ac.mdiq.podcini.core.service.playback.PlaybackService.Companion.isCasting
import ac.mdiq.podcini.core.storage.DBReader
@ -53,6 +32,27 @@ import ac.mdiq.podcini.storage.preferences.UserPreferences.rewindSecs
import ac.mdiq.podcini.storage.preferences.UserPreferences.setShowRemainTimeSetting
import ac.mdiq.podcini.storage.preferences.UserPreferences.shouldShowRemainingTime
import ac.mdiq.podcini.ui.appstartintent.MainActivityStarter
import android.content.DialogInterface
import android.content.Intent
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.*
import android.view.View.OnTouchListener
import android.view.animation.*
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.media3.common.util.UnstableApi
import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable

View File

@ -49,10 +49,10 @@ class FeedItemlistDescriptionAdapter(context: Context, resource: Int, objects: L
holder.title!!.text = item!!.title
holder.pubDate!!.text = formatAbbrev(context, item.pubDate)
if (item.description != null) {
val description = HtmlToPlainText.getPlainText(item.description)
?.replace("\n".toRegex(), " ")
?.replace("\\s+".toRegex(), " ")
?.trim { it <= ' ' }
val description = HtmlToPlainText.getPlainText(item.description!!)
.replace("\n".toRegex(), " ")
.replace("\\s+".toRegex(), " ")
.trim { it <= ' ' }
holder.description!!.text = description
holder.description!!.maxLines = MAX_LINES_COLLAPSED
}

View File

@ -19,7 +19,7 @@ class PlaybackControlsDialog : DialogFragment() {
@UnstableApi override fun onStart() {
super.onStart()
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
setupAudioTracks()
}

View File

@ -46,7 +46,7 @@ class SleepTimerDialog : DialogFragment() {
@UnstableApi override fun onStart() {
super.onStart()
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
}
}

View File

@ -42,7 +42,7 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
@UnstableApi override fun onStart() {
super.onStart()
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
updateSpeed(SpeedChangedEvent(controller!!.currentPlaybackSpeedMultiplier))
}

View File

@ -279,7 +279,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
}
private fun newPlaybackController(): PlaybackController {
return object : PlaybackController(activity) {
return object : PlaybackController(requireActivity()) {
override fun updatePlayButtonShowsPlay(showPlay: Boolean) {
butPlay.setIsShowPlay(showPlay)
}
@ -295,10 +295,10 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
}
private fun updateUi(media: Playable?) {
if (controller == null || media == null) {
if (controller != null) duration = controller!!.duration
if (media == null) {
return
}
duration = controller!!.duration
updatePosition(PlaybackPositionEvent(media.getPosition(), media.getDuration()))
updatePlaybackSpeedButton(SpeedChangedEvent(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media)))
setChapterDividers(media)
@ -460,7 +460,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
val isFeedMedia = media is FeedMedia
toolbar.menu?.findItem(R.id.open_feed_item)?.setVisible(isFeedMedia)
if (isFeedMedia) {
if (media != null && isFeedMedia) {
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, (media as FeedMedia).getItem())
}

View File

@ -91,7 +91,7 @@ class ChaptersFragment : AppCompatDialogFragment() {
CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT)
recyclerView.layoutParams = wrapHeight
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
this@ChaptersFragment.loadMediaInfo(false)
}

View File

@ -56,6 +56,7 @@ import org.greenrobot.eventbus.ThreadMode
*/
class CoverFragment : Fragment() {
private lateinit var viewBinding: CoverFragmentBinding
private var controller: PlaybackController? = null
private var disposable: Disposable? = null
private var displayedChapterIndex = -1
@ -80,7 +81,7 @@ class CoverFragment : Fragment() {
viewBinding.butPrevChapter.setOnClickListener { v: View? -> seekToPrevChapter() }
viewBinding.butNextChapter.setOnClickListener { v: View? -> seekToNextChapter() }
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
this@CoverFragment.loadMediaInfo(false)
}

View File

@ -89,7 +89,7 @@ class ExternalPlayerFragment : Fragment() {
if (controller == null) {
return@setOnClickListener
}
if (controller!!.getMedia() != null && controller!!.getMedia()!!.getMediaType() == MediaType.VIDEO && controller!!.status != PlayerStatus.PLAYING) {
if (controller!!.getMedia()?.getMediaType() == MediaType.VIDEO && controller!!.status != PlayerStatus.PLAYING) {
controller!!.playPause()
requireContext().startActivity(getPlayerActivityIntent(requireContext(), controller!!.getMedia()!!))
} else {
@ -101,7 +101,7 @@ class ExternalPlayerFragment : Fragment() {
@UnstableApi
private fun setupPlaybackController(): PlaybackController {
return object : PlaybackController(activity) {
return object : PlaybackController(requireActivity()) {
override fun updatePlayButtonShowsPlay(showPlay: Boolean) {
butPlay.setIsShowPlay(showPlay)
}

View File

@ -195,7 +195,7 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
txtvTitle.text = feed!!.title
txtvTitle.setMaxLines(6)
val description: String = HtmlToPlainText.getPlainText(feed!!.description)?:""
val description: String = HtmlToPlainText.getPlainText(feed!!.description?:"")
txtvDescription.text = description

View File

@ -55,7 +55,7 @@ class ItemDescriptionFragment : Fragment() {
}
})
registerForContextMenu(webvDescription)
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
load()
}
@ -91,10 +91,12 @@ class ItemDescriptionFragment : Fragment() {
return@create
}
if (media is FeedMedia) {
if (media.getItem() == null) {
media.setItem(DBReader.getFeedItem(media.itemId))
var item = media.getItem()
if (item == null) {
item = DBReader.getFeedItem(media.itemId)
media.setItem(item)
}
if (media.getItem() != null) DBReader.loadDescriptionOfFeedItem(media.getItem()!!)
if (item != null && item.description == null) DBReader.loadDescriptionOfFeedItem(item)
}
val shownotesCleaner = ShownotesCleaner(context, media.getDescription()?:"", media.getDuration())
emitter.onSuccess(shownotesCleaner.processShownotes())

View File

@ -156,7 +156,7 @@ class ItemFragment : Fragment() {
})
EventBus.getDefault().register(this)
controller = object : PlaybackController(activity) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
// Do nothing
}

View File

@ -459,7 +459,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
}
private fun loadItems(restoreScrollPosition: Boolean) {
Log.d(TAG, "loadItems()")
Log.d(TAG, "loadItems() called")
disposable?.dispose()
if (queue.isEmpty()) {

View File

@ -97,10 +97,11 @@ class HomeFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
private fun addSection(section: Fragment?) {
if (section == null) return
val containerView = FragmentContainerView(requireContext())
containerView.id = View.generateViewId()
viewBinding.homeContainer.addView(containerView)
if (section != null) childFragmentManager.beginTransaction().add(containerView.id, section).commit()
childFragmentManager.beginTransaction().add(containerView.id, section).commit()
}
private fun getSection(tag: String): Fragment? {

View File

@ -31,7 +31,8 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class DownloadsSection : HomeSection() {
private var adapter: EpisodeItemListAdapter? = null
private lateinit var adapter: EpisodeItemListAdapter
private var disposable: Disposable? = null
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@ -50,7 +51,7 @@ class DownloadsSection : HomeSection() {
}
}
}
adapter?.setDummyViews(NUM_EPISODES)
adapter.setDummyViews(NUM_EPISODES)
viewBinding.recyclerView.adapter = adapter
val swipeActions = SwipeActions(this, CompletedDownloadsFragment.TAG)
@ -75,10 +76,7 @@ class DownloadsSection : HomeSection() {
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: PlaybackPositionEvent) {
if (adapter == null) {
return
}
for (i in 0 until adapter!!.itemCount) {
for (i in 0 until adapter.itemCount) {
val holder: EpisodeItemViewHolder? = viewBinding.recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
if (holder != null && holder.isCurrentlyPlayingItem) {
holder.notifyPlaybackPositionUpdated(event)
@ -117,8 +115,8 @@ class DownloadsSection : HomeSection() {
if (downloads.size > NUM_EPISODES) {
downloads = downloads.subList(0, NUM_EPISODES)
}
adapter?.setDummyViews(0)
adapter?.updateItems(downloads)
adapter.setDummyViews(0)
adapter.updateItems(downloads)
}, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}

View File

@ -29,7 +29,8 @@ import org.greenrobot.eventbus.ThreadMode
import java.util.*
class EpisodesSurpriseSection : HomeSection() {
private var listAdapter: HorizontalItemListAdapter? = null
private lateinit var listAdapter: HorizontalItemListAdapter
private var disposable: Disposable? = null
private var episodes: MutableList<FeedItem> = ArrayList<FeedItem>()
@ -52,7 +53,7 @@ class EpisodesSurpriseSection : HomeSection() {
}
}
}
listAdapter?.setDummyViews(NUM_EPISODES)
listAdapter.setDummyViews(NUM_EPISODES)
viewBinding.recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
viewBinding.recyclerView.adapter = listAdapter
val paddingHorizontal: Int = (12 * resources.displayMetrics.density).toInt()
@ -94,7 +95,7 @@ class EpisodesSurpriseSection : HomeSection() {
if (pos >= 0) {
episodes.removeAt(pos)
episodes.add(pos, item)
listAdapter?.notifyItemChangedCompat(pos)
listAdapter.notifyItemChangedCompat(pos)
}
i++
}
@ -104,17 +105,14 @@ class EpisodesSurpriseSection : HomeSection() {
fun onEventMainThread(event: EpisodeDownloadEvent) {
for (downloadUrl in event.urls) {
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(episodes, downloadUrl)
if (pos >= 0) listAdapter?.notifyItemChangedCompat(pos)
if (pos >= 0) listAdapter.notifyItemChangedCompat(pos)
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: PlaybackPositionEvent) {
if (listAdapter == null) {
return
}
for (i in 0 until listAdapter!!.itemCount) {
for (i in 0 until listAdapter.itemCount) {
val holder: HorizontalItemViewHolder? = viewBinding.recyclerView.findViewHolderForAdapterPosition(i) as? HorizontalItemViewHolder
if (holder != null && holder.isCurrentlyPlayingItem) {
holder.notifyPlaybackPositionUpdated(event)
@ -131,8 +129,8 @@ class EpisodesSurpriseSection : HomeSection() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ episodes: List<FeedItem> ->
this.episodes = episodes.toMutableList()
listAdapter?.setDummyViews(0)
listAdapter?.updateData(episodes)
listAdapter.setDummyViews(0)
listAdapter.updateData(episodes)
}, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}

View File

@ -32,7 +32,8 @@ import org.greenrobot.eventbus.ThreadMode
import java.util.*
class InboxSection : HomeSection() {
private var adapter: EpisodeItemListAdapter? = null
private lateinit var adapter: EpisodeItemListAdapter
private var items: List<FeedItem> = ArrayList<FeedItem>()
private var disposable: Disposable? = null
@ -51,7 +52,7 @@ class InboxSection : HomeSection() {
) { item: MenuItem -> this@InboxSection.onContextItemSelected(item) }
}
}
adapter?.setDummyViews(NUM_EPISODES)
adapter.setDummyViews(NUM_EPISODES)
viewBinding.recyclerView.adapter = adapter
val swipeActions = SwipeActions(this, InboxFragment.TAG)
@ -89,7 +90,7 @@ class InboxSection : HomeSection() {
for (downloadUrl in event.urls) {
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(items, downloadUrl)
if (pos >= 0) {
adapter?.notifyItemChangedCompat(pos)
adapter.notifyItemChangedCompat(pos)
}
}
}
@ -112,8 +113,8 @@ class InboxSection : HomeSection() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ data: Pair<List<FeedItem>, Int> ->
items = data.first
adapter?.setDummyViews(0)
adapter?.updateItems(items)
adapter.setDummyViews(0)
adapter.updateItems(items)
viewBinding.numNewItemsLabel.visibility = View.VISIBLE
if (data.second >= 100) {
viewBinding.numNewItemsLabel.text = String.format(Locale.getDefault(), "%d+", 99)

View File

@ -29,9 +29,10 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class QueueSection : HomeSection() {
private var listAdapter: HorizontalItemListAdapter? = null
private var disposable: Disposable? = null
private var queue: MutableList<FeedItem>? = ArrayList()
private lateinit var listAdapter: HorizontalItemListAdapter
private var queue: MutableList<FeedItem> = ArrayList()
@UnstableApi override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, savedInstanceState: Bundle?
@ -44,7 +45,7 @@ class QueueSection : HomeSection() {
) { item: MenuItem -> this@QueueSection.onContextItemSelected(item) }
}
}
listAdapter?.setDummyViews(NUM_EPISODES)
listAdapter.setDummyViews(NUM_EPISODES)
viewBinding.recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
viewBinding.recyclerView.adapter = listAdapter
val paddingHorizontal: Int = (12 * resources.displayMetrics.density).toInt()
@ -74,18 +75,18 @@ class QueueSection : HomeSection() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: FeedItemEvent) {
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
if (queue == null) {
if (queue.isEmpty()) {
return
}
var i = 0
val size: Int = event.items.size
while (i < size) {
val item: FeedItem = event.items[i]
val pos: Int = FeedItemUtil.indexOfItemWithId(queue!!, item.id)
val pos: Int = FeedItemUtil.indexOfItemWithId(queue, item.id)
if (pos >= 0) {
queue!!.removeAt(pos)
queue!!.add(pos, item)
listAdapter?.notifyItemChangedCompat(pos)
queue.removeAt(pos)
queue.add(pos, item)
listAdapter.notifyItemChangedCompat(pos)
}
i++
}
@ -93,23 +94,20 @@ class QueueSection : HomeSection() {
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: EpisodeDownloadEvent) {
if (queue == null) return
if (queue.isEmpty()) return
for (downloadUrl in event.urls) {
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(queue!!, downloadUrl)
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(queue, downloadUrl)
if (pos >= 0) {
listAdapter?.notifyItemChangedCompat(pos)
listAdapter.notifyItemChangedCompat(pos)
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: PlaybackPositionEvent) {
if (listAdapter == null) {
return
}
var foundCurrentlyPlayingItem = false
var currentlyPlayingItemIsFirst = true
for (i in 0 until listAdapter!!.itemCount) {
for (i in 0 until listAdapter.itemCount) {
val holder: HorizontalItemViewHolder =
viewBinding.recyclerView.findViewHolderForAdapterPosition(i) as? HorizontalItemViewHolder ?: continue
if (holder.isCurrentlyPlayingItem) {
@ -140,8 +138,8 @@ class QueueSection : HomeSection() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ queue: List<FeedItem> ->
this.queue = queue.toMutableList()
listAdapter?.setDummyViews(0)
listAdapter?.updateData(queue)
listAdapter.setDummyViews(0)
listAdapter.updateData(queue)
}, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}

View File

@ -27,7 +27,7 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class SubscriptionsSection : HomeSection() {
private var listAdapter: HorizontalFeedListAdapter? = null
private lateinit var listAdapter: HorizontalFeedListAdapter
private var disposable: Disposable? = null
@UnstableApi override fun onCreateView(inflater: LayoutInflater,
@ -45,7 +45,7 @@ class SubscriptionsSection : HomeSection() {
}
}
}
listAdapter?.setDummyViews(NUM_FEEDS)
listAdapter.setDummyViews(NUM_FEEDS)
viewBinding.recyclerView.adapter = listAdapter
val paddingHorizontal: Int = (12 * resources.displayMetrics.density).toInt()
viewBinding.recyclerView.setPadding(paddingHorizontal, 0, paddingHorizontal, 0)
@ -93,8 +93,8 @@ class SubscriptionsSection : HomeSection() {
feeds.add(stats[i].feed)
i++
}
listAdapter?.setDummyViews(0)
listAdapter?.updateData(feeds)
listAdapter.setDummyViews(0)
listAdapter.updateData(feeds)
}, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}

View File

@ -33,13 +33,13 @@ object ChapterMerger {
return if (score(chapters1) > score(chapters2)) chapters1 else chapters2
}
if (TextUtils.isEmpty(chapterTarget.imageUrl)) {
if (chapterTarget.imageUrl.isNullOrEmpty()) {
chapterTarget.imageUrl = chapterOther.imageUrl
}
if (TextUtils.isEmpty(chapterTarget.link)) {
if (chapterTarget.link.isNullOrEmpty()) {
chapterTarget.link = chapterOther.link
}
if (TextUtils.isEmpty(chapterTarget.title)) {
if (chapterTarget.title.isNullOrEmpty()) {
chapterTarget.title = chapterOther.title
}
}
@ -54,9 +54,9 @@ object ChapterMerger {
var score = 0
for (chapter in chapters) {
score = (score
+ (if (TextUtils.isEmpty(chapter.title)) 0 else 1)
+ (if (TextUtils.isEmpty(chapter.link)) 0 else 1)
+ (if (TextUtils.isEmpty(chapter.imageUrl)) 0 else 1))
+ (if (chapter.title.isNullOrEmpty()) 0 else 1)
+ (if (chapter.link.isNullOrEmpty()) 0 else 1)
+ (if (chapter.imageUrl.isNullOrEmpty()) 0 else 1))
}
return score
}

View File

@ -38,9 +38,8 @@ import kotlin.concurrent.Volatile
* Manages the MediaPlayer object of the PlaybackService.
*/
@UnstableApi
class LocalPSMP(context: Context,
callback: PSMPCallback
) : PlaybackServiceMediaPlayer(context, callback) {
class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMediaPlayer(context, callback) {
private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
@Volatile

View File

@ -1863,7 +1863,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
private const val TAG = "PlaybackService"
// TODO: need to experiment this value
private const val POSITION_EVENT_INTERVAL = 10L
private const val POSITION_EVENT_INTERVAL = 5L
const val ACTION_PLAYER_STATUS_CHANGED: String = "action.ac.mdiq.podcini.core.service.playerStatusChanged"
private const val AVRCP_ACTION_PLAYER_STATUS_CHANGED = "com.android.music.playstatechanged"

View File

@ -212,12 +212,10 @@ class PlaybackServiceTaskManager(private val context: Context,
*/
@Synchronized
fun startChapterLoader(media: Playable) {
if (chapterLoaderFuture != null) {
chapterLoaderFuture!!.dispose()
chapterLoaderFuture = null
}
chapterLoaderFuture?.dispose()
chapterLoaderFuture = null
if (media.getChapters().isEmpty()) {
if (!media.chaptersLoaded()) {
chapterLoaderFuture = Completable.create { emitter: CompletableEmitter ->
ChapterUtils.loadChapters(media, context, false)
emitter.onComplete()

View File

@ -30,6 +30,7 @@ import kotlin.math.min
*/
object DBReader {
private const val TAG = "DBReader"
private var feeds: MutableList<Feed> = mutableListOf()
/**
* Maximum size of the list returned by [.getDownloadLog].
@ -38,36 +39,52 @@ object DBReader {
@JvmStatic
fun getFeedList(): List<Feed> {
Log.d(TAG, "Extracting Feedlist")
return feeds
// Log.d(TAG, "Extracting Feedlist")
// val adapter = getInstance()
// adapter.open()
// try {
// return getFeedList(adapter)
// } finally {
// adapter.close()
// }
}
// fun getFeedList(adapter: PodDBAdapter): List<Feed> {
// if (feeds != null) return feeds!!
// updateFeedList(adapter)
// return feeds!!
// }
fun updateFeedList() {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getFeedList(adapter)
updateFeedList(adapter)
} finally {
adapter.close()
}
}
fun getFeedList(adapter: PodDBAdapter?): List<Feed> {
adapter!!.allFeedsCursor.use { cursor ->
val feeds: MutableList<Feed> = ArrayList(cursor.count)
fun updateFeedList(adapter: PodDBAdapter) {
adapter.allFeedsCursor.use { cursor ->
feeds = ArrayList(cursor.count)
while (cursor.moveToNext()) {
val feed = extractFeedFromCursorRow(cursor)
feeds.add(feed)
}
return feeds
}
}
@JvmStatic
fun getFeedListDownloadUrls(): List<String> {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.feedCursorDownloadUrls.use { cursor ->
val result: MutableList<String> =
ArrayList(cursor.count)
val result: MutableList<String> = ArrayList(cursor.count)
while (cursor.moveToNext()) {
val url = cursor.getString(1)
if (url != null && !url.startsWith(Feed.PREFIX_LOCAL_FOLDER)) {
@ -113,8 +130,6 @@ object DBReader {
* @param items The FeedItems whose Feed-objects should be loaded.
*/
private fun loadFeedDataOfFeedItemList(items: List<FeedItem>) {
val feeds = getFeedList()
val feedIndex: MutableMap<Long, Feed> = ArrayMap(feeds.size)
for (feed in feeds) {
feedIndex[feed.id] = feed
@ -150,7 +165,7 @@ object DBReader {
Log.d(TAG, "getFeedItemList() called with: feed = [$feed]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getItemsOfFeedCursor(feed!!, filter).use { cursor ->
val items = extractItemlistFromCursor(adapter, cursor).toMutableList()
@ -170,7 +185,7 @@ object DBReader {
fun extractItemlistFromCursor(itemlistCursor: Cursor): List<FeedItem> {
Log.d(TAG, "extractItemlistFromCursor() called with: itemlistCursor = [$itemlistCursor]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return extractItemlistFromCursor(adapter, itemlistCursor)
} finally {
@ -202,7 +217,7 @@ object DBReader {
@JvmStatic
fun getQueue(adapter: PodDBAdapter?): List<FeedItem> {
Log.d(TAG, "getQueue()")
// Log.d(TAG, "getQueue()")
adapter!!.queueCursor.use { cursor ->
val items = extractItemlistFromCursor(adapter, cursor)
loadAdditionalFeedItemListData(items)
@ -213,8 +228,13 @@ object DBReader {
@JvmStatic
fun getQueueIDList(): LongList {
Log.d(TAG, "getQueueIDList() called")
// val stackTraceElements = Thread.currentThread().stackTrace
// stackTraceElements.forEach { element ->
// println(element)
// }
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getQueueIDList(adapter)
} finally {
@ -237,7 +257,7 @@ object DBReader {
Log.d(TAG, "getQueue() called")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getQueue(adapter)
} finally {
@ -249,7 +269,7 @@ object DBReader {
Log.d(TAG, "getFavoriteIDList() called")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getFavoritesIdsCursor(0, Int.MAX_VALUE).use { cursor ->
val favoriteIDs = LongList(cursor.count)
@ -273,7 +293,7 @@ object DBReader {
fun getEpisodes(offset: Int, limit: Int, filter: FeedItemFilter?, sortOrder: SortOrder?): List<FeedItem> {
Log.d(TAG, "getRecentlyPublishedEpisodes() called with: offset=$offset, limit=$limit")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getEpisodesCursor(offset, limit, filter, sortOrder).use { cursor ->
val items = extractItemlistFromCursor(adapter, cursor)
@ -288,7 +308,7 @@ object DBReader {
@JvmStatic
fun getTotalEpisodeCount(filter: FeedItemFilter?): Int {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getEpisodeCountCursor(filter).use { cursor ->
if (cursor.moveToFirst()) {
@ -303,7 +323,7 @@ object DBReader {
fun getRandomEpisodes(limit: Int, seed: Int): List<FeedItem> {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getRandomEpisodesCursor(limit, seed).use { cursor ->
val items = extractItemlistFromCursor(adapter, cursor)
@ -328,7 +348,7 @@ object DBReader {
Log.d(TAG, "getPlaybackHistory() called")
val adapter = getInstance()
adapter!!.open()
adapter.open()
var mediaCursor: Cursor? = null
var itemCursor: Cursor? = null
@ -356,7 +376,7 @@ object DBReader {
@JvmStatic
fun getPlaybackHistoryLength(): Long {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return adapter.completedMediaLength
@ -370,7 +390,7 @@ object DBReader {
Log.d(TAG, "getDownloadLog() called")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE).use { cursor ->
val downloadLog: MutableList<DownloadResult> =
@ -397,7 +417,7 @@ object DBReader {
Log.d(TAG, "getFeedDownloadLog() called with: feed = [$feedId]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId).use { cursor ->
val downloadLog: MutableList<DownloadResult> = ArrayList(cursor.count)
@ -434,7 +454,7 @@ object DBReader {
*/
fun getFeed(feedId: Long, filtered: Boolean): Feed? {
Log.d(TAG, "getFeed() called with: feedId = [$feedId]")
val adapter = getInstance() ?: return null
val adapter = getInstance()
adapter.open()
try {
adapter.getFeedCursor(feedId).use { cursor ->
@ -484,7 +504,7 @@ object DBReader {
Log.d(TAG, "getFeedItem() called with: itemId = [$itemId]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getFeedItem(itemId, adapter)
} finally {
@ -501,7 +521,7 @@ object DBReader {
fun getNextInQueue(item: FeedItem): FeedItem? {
Log.d(TAG, "getNextInQueue() called with: " + "itemId = [" + item.id + "]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
var nextItem: FeedItem? = null
try {
@ -524,7 +544,7 @@ object DBReader {
fun getPausedQueue(limit: Int): List<FeedItem> {
Log.d(TAG, "getPausedQueue() called ")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getPausedQueueCursor(limit).use { cursor ->
val items = extractItemlistFromCursor(adapter, cursor)
@ -569,7 +589,7 @@ object DBReader {
Log.d(TAG, "getImageAuthentication() called with: imageUrl = [$imageUrl]")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getImageAuthentication(imageUrl, adapter)
} finally {
@ -606,7 +626,7 @@ object DBReader {
@JvmStatic
fun getFeedItemByGuidOrEpisodeUrl(guid: String?, episodeUrl: String): FeedItem? {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return getFeedItemByGuidOrEpisodeUrl(guid, episodeUrl, adapter)
} finally {
@ -627,7 +647,7 @@ object DBReader {
// println(element)
// }
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getDescriptionOfItem(item).use { cursor ->
if (cursor.moveToFirst()) {
@ -650,14 +670,14 @@ object DBReader {
*/
@JvmStatic
fun loadChaptersOfFeedItem(item: FeedItem): List<Chapter>? {
Log.d(TAG, "loadChaptersOfFeedItem() called with: item = [$item]")
Log.d(TAG, "loadChaptersOfFeedItem() called with: item = [${item.title}]")
// TODO: need to find out who are often calling this
// val stackTraceElements = Thread.currentThread().stackTrace
// stackTraceElements.forEach { element ->
// println(element)
// }
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
return loadChaptersOfFeedItem(adapter, item)
} finally {
@ -689,7 +709,7 @@ object DBReader {
@JvmStatic
fun getFeedMedia(mediaId: Long): FeedMedia? {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getSingleFeedMediaCursor(mediaId).use { mediaCursor ->
@ -714,7 +734,7 @@ object DBReader {
fun getFeedItemsWithUrl(urls: List<String?>?): List<FeedItem> {
Log.d(TAG, "getFeedItemsWithUrl() called ")
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
adapter.getFeedItemCursorByUrl(urls!!).use { itemCursor ->
val items = extractItemlistFromCursor(adapter, itemCursor).toMutableList()
@ -730,7 +750,7 @@ object DBReader {
fun getMonthlyTimeStatistics(): List<MonthlyStatisticsItem> {
val months: MutableList<MonthlyStatisticsItem> = ArrayList()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.monthlyStatisticsCursor.use { cursor ->
val indexMonth = cursor.getColumnIndexOrThrow("month")
val indexYear = cursor.getColumnIndexOrThrow("year")
@ -756,7 +776,7 @@ object DBReader {
timeFilterFrom: Long, timeFilterTo: Long
): StatisticsResult {
val adapter = getInstance()
adapter!!.open()
adapter.open()
val result = StatisticsResult()
adapter.getFeedStatisticsCursor(includeMarkedAsPlayed, timeFilterFrom, timeFilterTo).use { cursor ->
@ -792,7 +812,7 @@ object DBReader {
fun getTimeBetweenReleaseAndPlayback(timeFilterFrom: Long, timeFilterTo: Long): Long {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.getTimeBetweenReleaseAndPlayback(timeFilterFrom, timeFilterTo).use { cursor ->
cursor.moveToFirst()
val result = cursor.getString(0).toLong()
@ -810,13 +830,13 @@ object DBReader {
fun getNavDrawerData(subscriptionsFilter: SubscriptionsFilter?): NavDrawerData {
Log.d(TAG, "getNavDrawerData() called with: " + "")
val adapter = getInstance()
adapter!!.open()
adapter.open()
val feedCounters: Map<Long, Int> = adapter.getFeedCounters(feedCounterSetting)
var feeds = getFeedList(adapter)
// getFeedList(adapter)
if (subscriptionsFilter != null) {
feeds = subscriptionsFilter.filter(feeds, feedCounters as Map<Long?, Int>)
feeds = subscriptionsFilter.filter(feeds, feedCounters as Map<Long?, Int>).toMutableList()
}
val comparator: Comparator<Feed>
@ -875,7 +895,7 @@ object DBReader {
}
}
feeds = feeds.sortedWith(comparator)
feeds.sortWith(comparator)
val queueSize = adapter.queueSize
val numNewItems = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.NEW))
val numDownloadedItems = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.DOWNLOADED))

View File

@ -58,7 +58,7 @@ import java.util.concurrent.*
@UnstableApi @JvmStatic
fun removeFeedWithDownloadUrl(context: Context?, downloadUrl: String) {
val adapter = getInstance()
adapter!!.open()
adapter.open()
val cursor = adapter.feedCursorDownloadUrls
var feedID: Long = 0
if (cursor.moveToFirst()) {
@ -200,7 +200,7 @@ import java.util.concurrent.*
val unlistedItems: MutableList<FeedItem> = ArrayList()
val adapter = getInstance()
adapter!!.open()
adapter.open()
// Look up feed in the feedslist
val savedFeed = searchFeedByIdentifyingValueOrID(newFeed)
@ -339,6 +339,7 @@ import java.util.concurrent.*
} else {
DBWriter.setCompleteFeed(savedFeed).get()
}
DBReader.updateFeedList(adapter)
if (removeUnlistedItems) {
DBWriter.deleteFeedItems(context, unlistedItems).get()
}
@ -420,7 +421,7 @@ import java.util.concurrent.*
@Throws(Exception::class)
override fun call(): T? {
val adapter = getInstance()
adapter!!.open()
adapter.open()
execute(adapter)
adapter.close()
return result

View File

@ -126,9 +126,9 @@ import java.util.concurrent.TimeUnit
media.setFile_url(null)
media.setHasEmbeddedPicture(false)
val adapter = getInstance()
adapter?.open()
adapter?.setMedia(media)
adapter?.close()
adapter.open()
adapter.setMedia(media)
adapter.close()
}
if (media.id == currentlyPlayingFeedMediaId) {
@ -174,9 +174,9 @@ import java.util.concurrent.TimeUnit
// delete feed
val adapter = getInstance()
adapter?.open()
adapter?.removeFeed(feed)
adapter?.close()
adapter.open()
adapter.removeFeed(feed)
adapter.close()
if (!feed.isLocalFeed && feed.download_url != null) {
SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.download_url!!)
@ -220,12 +220,12 @@ import java.util.concurrent.TimeUnit
}
val adapter = getInstance()
adapter?.open()
adapter.open()
if (removedFromQueue.isNotEmpty()) {
adapter?.setQueue(queue)
adapter.setQueue(queue)
}
adapter?.removeFeedItems(items)
adapter?.close()
adapter.removeFeedItems(items)
adapter.close()
for (item in removedFromQueue) {
EventBus.getDefault().post(irreversibleRemoved(item))
@ -246,9 +246,9 @@ import java.util.concurrent.TimeUnit
fun clearPlaybackHistory(): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.clearPlaybackHistory()
adapter?.close()
adapter.open()
adapter.clearPlaybackHistory()
adapter.close()
EventBus.getDefault().post(PlaybackHistoryEvent.listUpdated())
}
}
@ -259,9 +259,9 @@ import java.util.concurrent.TimeUnit
fun clearDownloadLog(): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.clearDownloadLog()
adapter?.close()
adapter.open()
adapter.clearDownloadLog()
adapter.close()
EventBus.getDefault().post(DownloadLogEvent.listUpdated())
}
}
@ -292,9 +292,9 @@ import java.util.concurrent.TimeUnit
media!!.setPlaybackCompletionDate(date)
val adapter = getInstance()
adapter?.open()
adapter?.setFeedMediaPlaybackCompletionDate(media)
adapter?.close()
adapter.open()
adapter.setFeedMediaPlaybackCompletionDate(media)
adapter.close()
EventBus.getDefault().post(PlaybackHistoryEvent.listUpdated())
}
}
@ -307,9 +307,9 @@ import java.util.concurrent.TimeUnit
fun addDownloadStatus(status: DownloadResult?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setDownloadStatus(status!!)
adapter?.close()
adapter.open()
adapter.setDownloadStatus(status!!)
adapter.close()
EventBus.getDefault().post(DownloadLogEvent.listUpdated())
}
}
@ -329,7 +329,7 @@ import java.util.concurrent.TimeUnit
): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter.open()
val queue = getQueue(adapter).toMutableList()
val item: FeedItem?
@ -337,7 +337,7 @@ import java.util.concurrent.TimeUnit
item = getFeedItem(itemId)
if (item != null) {
queue.add(index, item)
adapter?.setQueue(queue)
adapter.setQueue(queue)
item.addTag(FeedItem.TAG_QUEUE)
EventBus.getDefault().post(added(item, index))
EventBus.getDefault().post(updated(item))
@ -347,7 +347,7 @@ import java.util.concurrent.TimeUnit
}
}
adapter?.close()
adapter.close()
if (performAutoDownload) {
autodownloadUndownloadedItems(context)
}
@ -402,7 +402,7 @@ import java.util.concurrent.TimeUnit
return@runOnDbThread
}
val adapter = getInstance()
adapter?.open()
adapter.open()
val queue = getQueue(adapter).toMutableList()
var queueModified = false
@ -432,7 +432,7 @@ import java.util.concurrent.TimeUnit
}
if (queueModified) {
applySortOrder(queue, events)
adapter?.setQueue(queue)
adapter.setQueue(queue)
for (event in events) {
EventBus.getDefault().post(event)
}
@ -441,7 +441,7 @@ import java.util.concurrent.TimeUnit
markItemPlayed(FeedItem.UNPLAYED, *markAsUnplayedIds.toArray())
}
}
adapter?.close()
adapter.close()
if (performAutoDownload) {
autodownloadUndownloadedItems(context)
}
@ -482,9 +482,9 @@ import java.util.concurrent.TimeUnit
fun clearQueue(): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.clearQueue()
adapter?.close()
adapter.open()
adapter.clearQueue()
adapter.close()
EventBus.getDefault().post(cleared())
}
}
@ -518,7 +518,7 @@ import java.util.concurrent.TimeUnit
return
}
val adapter = getInstance()
adapter?.open()
adapter.open()
val queue = getQueue(adapter).toMutableList()
var queueModified = false
@ -543,7 +543,7 @@ import java.util.concurrent.TimeUnit
}
}
if (queueModified) {
adapter?.setQueue(queue)
adapter.setQueue(queue)
for (event in events) {
EventBus.getDefault().post(event)
}
@ -551,7 +551,7 @@ import java.util.concurrent.TimeUnit
} else {
Log.w(TAG, "Queue was not modified by call to removeQueueItem")
}
adapter?.close()
adapter.close()
if (performAutoDownload) {
autodownloadUndownloadedItems(context)
}
@ -567,9 +567,9 @@ import java.util.concurrent.TimeUnit
fun addFavoriteItem(item: FeedItem): Future<*> {
return runOnDbThread {
val adapter = getInstance()?.open()
adapter?.addFavoriteItem(item)
adapter?.close()
val adapter = getInstance().open()
adapter.addFavoriteItem(item)
adapter.close()
item.addTag(FeedItem.TAG_FAVORITE)
EventBus.getDefault().post(FavoritesEvent())
EventBus.getDefault().post(updated(item))
@ -578,9 +578,9 @@ import java.util.concurrent.TimeUnit
fun removeFavoriteItem(item: FeedItem): Future<*> {
return runOnDbThread {
val adapter = getInstance()?.open()
adapter?.removeFavoriteItem(item)
adapter?.close()
val adapter = getInstance().open()
adapter.removeFavoriteItem(item)
adapter.close()
item.removeTag(FeedItem.TAG_FAVORITE)
EventBus.getDefault().post(FavoritesEvent())
EventBus.getDefault().post(updated(item))
@ -658,7 +658,7 @@ import java.util.concurrent.TimeUnit
to: Int, broadcastUpdate: Boolean
) {
val adapter = getInstance()
adapter?.open()
adapter.open()
val queue = getQueue(adapter).toMutableList()
if (queue.isNotEmpty()) {
@ -666,7 +666,7 @@ import java.util.concurrent.TimeUnit
val item: FeedItem = queue.removeAt(from)
queue.add(to, item)
adapter?.setQueue(queue)
adapter.setQueue(queue)
if (broadcastUpdate) {
EventBus.getDefault().post(moved(item, to))
}
@ -674,15 +674,15 @@ import java.util.concurrent.TimeUnit
} else {
Log.e(TAG, "moveQueueItemHelper: Could not load queue")
}
adapter?.close()
adapter.close()
}
fun resetPagedFeedPage(feed: Feed?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.resetPagedFeedPage(feed!!)
adapter?.close()
adapter.open()
adapter.resetPagedFeedPage(feed!!)
adapter.close()
}
}
@ -711,9 +711,9 @@ import java.util.concurrent.TimeUnit
): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setFeedItemRead(played, *itemIds)
adapter?.close()
adapter.open()
adapter.setFeedItemRead(played, *itemIds)
adapter.close()
if (broadcastUpdate) {
EventBus.getDefault().post(UnreadItemsUpdateEvent())
}
@ -740,10 +740,10 @@ import java.util.concurrent.TimeUnit
): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setFeedItemRead(played, itemId, mediaId,
adapter.open()
adapter.setFeedItemRead(played, itemId, mediaId,
resetMediaPosition)
adapter?.close()
adapter.close()
EventBus.getDefault().post(UnreadItemsUpdateEvent())
}
}
@ -756,9 +756,9 @@ import java.util.concurrent.TimeUnit
fun removeFeedNewFlag(feedId: Long): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED, feedId)
adapter?.close()
adapter.open()
adapter.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED, feedId)
adapter.close()
EventBus.getDefault().post(UnreadItemsUpdateEvent())
}
}
@ -770,9 +770,9 @@ import java.util.concurrent.TimeUnit
fun removeAllNewFlags(): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED)
adapter?.close()
adapter.open()
adapter.setFeedItems(FeedItem.NEW, FeedItem.UNPLAYED)
adapter.close()
EventBus.getDefault().post(UnreadItemsUpdateEvent())
}
}
@ -780,9 +780,9 @@ import java.util.concurrent.TimeUnit
fun addNewFeed(context: Context, vararg feeds: Feed): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setCompleteFeed(*feeds)
adapter?.close()
adapter.open()
adapter.setCompleteFeed(*feeds)
adapter.close()
for (feed in feeds) {
if (!feed.isLocalFeed && feed.download_url != null) {
@ -798,18 +798,18 @@ import java.util.concurrent.TimeUnit
fun setCompleteFeed(vararg feeds: Feed): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.setCompleteFeed(*feeds)
adapter?.close()
adapter.open()
adapter.setCompleteFeed(*feeds)
adapter.close()
}
}
fun setItemList(items: List<FeedItem>): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter?.open()
adapter?.storeFeedItemlist(items)
adapter?.close()
adapter.open()
adapter.storeFeedItemlist(items)
adapter.close()
EventBus.getDefault().post(updated(items))
}
}
@ -823,7 +823,7 @@ import java.util.concurrent.TimeUnit
fun setFeedMedia(media: FeedMedia?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setMedia(media)
adapter.close()
}
@ -838,7 +838,7 @@ import java.util.concurrent.TimeUnit
fun setFeedMediaPlaybackInformation(media: FeedMedia?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedMediaPlaybackInformation(media!!)
adapter.close()
}
@ -854,7 +854,7 @@ import java.util.concurrent.TimeUnit
fun setFeedItem(item: FeedItem?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setSingleFeedItem(item!!)
adapter.close()
EventBus.getDefault().post(updated(item))
@ -868,7 +868,7 @@ import java.util.concurrent.TimeUnit
Log.d(TAG, "updateFeedDownloadURL(original: $original, updated: $updated)")
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedDownloadUrl(original, updated)
adapter.close()
}
@ -882,7 +882,7 @@ import java.util.concurrent.TimeUnit
fun setFeedPreferences(preferences: FeedPreferences): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedPreferences(preferences)
adapter.close()
EventBus.getDefault().post(FeedListUpdateEvent(preferences.feedID))
@ -913,7 +913,7 @@ import java.util.concurrent.TimeUnit
): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedLastUpdateFailed(feedId, lastUpdateFailed)
adapter.close()
EventBus.getDefault().post(FeedListUpdateEvent(feedId))
@ -923,7 +923,7 @@ import java.util.concurrent.TimeUnit
fun setFeedCustomTitle(feed: Feed): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedCustomTitle(feed.id, feed.getCustomTitle())
adapter.close()
EventBus.getDefault().post(FeedListUpdateEvent(feed))
@ -945,7 +945,7 @@ import java.util.concurrent.TimeUnit
val permutor = getPermutor(sortOrder)
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
val queue = getQueue(adapter).toMutableList()
permutor.reorder(queue)
@ -969,7 +969,7 @@ import java.util.concurrent.TimeUnit
Log.d(TAG, "setFeedItemsFilter() called with: feedId = [$feedId], filterValues = [$filterValues]")
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedItemFilter(feedId, filterValues)
adapter.close()
EventBus.getDefault().post(FeedEvent(FeedEvent.Action.FILTER_CHANGED, feedId))
@ -983,7 +983,7 @@ import java.util.concurrent.TimeUnit
fun setFeedItemSortOrder(feedId: Long, sortOrder: SortOrder?): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setFeedItemSortOrder(feedId, sortOrder)
adapter.close()
EventBus.getDefault().post(FeedEvent(FeedEvent.Action.SORT_ORDER_CHANGED, feedId))
@ -996,7 +996,7 @@ import java.util.concurrent.TimeUnit
fun resetStatistics(): Future<*> {
return runOnDbThread {
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.resetAllMediaPlayedDuration()
adapter.close()
}

View File

@ -46,7 +46,7 @@ object ChapterUtils {
@JvmStatic
fun loadChapters(playable: Playable, context: Context, forceRefresh: Boolean) {
if (playable.getChapters().isNotEmpty() && !forceRefresh) {
if (playable.chaptersLoaded() && !forceRefresh) {
// Already loaded
return
}
@ -72,6 +72,7 @@ object ChapterUtils {
val chaptersFromMediaFile = loadChaptersFromMediaFile(playable, context)
val chaptersMergePhase1 = merge(chaptersFromDatabase, chaptersFromMediaFile)
val chapters = merge(chaptersMergePhase1, chaptersFromPodcastIndex)
Log.d(TAG, "loadChapters chapters size: ${chapters?.size?:0} ${playable.getEpisodeTitle()}")
if (chapters == null) {
// Do not try loading again. There are no chapters.
playable.setChapters(listOf())
@ -135,19 +136,19 @@ object ChapterUtils {
}
}
fun loadChaptersFromUrl(url: String, forceRefresh: Boolean): List<Chapter>? {
fun loadChaptersFromUrl(url: String, forceRefresh: Boolean): List<Chapter> {
if (forceRefresh) {
return loadChaptersFromUrl(url, CacheControl.FORCE_NETWORK)
}
val cachedChapters = loadChaptersFromUrl(url, CacheControl.FORCE_CACHE)
if (cachedChapters == null || cachedChapters.size <= 1) {
if (cachedChapters.size <= 1) {
// Some publishers use one dummy chapter before actual chapters are available
return loadChaptersFromUrl(url, CacheControl.FORCE_NETWORK)
}
return cachedChapters
}
private fun loadChaptersFromUrl(url: String, cacheControl: CacheControl): List<Chapter>? {
private fun loadChaptersFromUrl(url: String, cacheControl: CacheControl): List<Chapter> {
var response: Response? = null
try {
val request: Request = Builder().url(url).cacheControl(cacheControl).build()
@ -160,7 +161,7 @@ object ChapterUtils {
} finally {
response?.close()
}
return null
return listOf()
}
@Throws(IOException::class, ID3ReaderException::class)

View File

@ -249,7 +249,7 @@ class LongList @JvmOverloads constructor(initialCapacity: Int = 4) {
companion object {
fun of(vararg values: Long): LongList {
if (values == null || values.size == 0) {
if (values == null || values.isEmpty()) {
return LongList(0)
}
val result = LongList(values.size)

View File

@ -111,7 +111,7 @@ object NetworkUtils {
private val isInAllowedWifiNetwork: Boolean
get() {
val wm = context!!.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val selectedNetworks = Arrays.asList(*UserPreferences.autodownloadSelectedNetworks)
val selectedNetworks = listOf(*UserPreferences.autodownloadSelectedNetworks)
return selectedNetworks.contains(wm.connectionInfo.networkId.toString())
}

View File

@ -87,8 +87,11 @@ object ShareUtils {
@JvmStatic
fun shareFeedItemFile(context: Context, media: FeedMedia) {
val lurl = media.getLocalMediaUrl()
if (lurl.isNullOrEmpty()) return
val fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority),
File(media.getLocalMediaUrl()))
File(lurl))
IntentBuilder(context)
.setType(media.mime_type)

View File

@ -4,6 +4,6 @@ import ac.mdiq.podcini.model.feed.Chapter
class ChapterStartTimeComparator : Comparator<Chapter> {
override fun compare(lhs: Chapter, rhs: Chapter): Int {
return java.lang.Long.compare(lhs.start, rhs.start)
return lhs.start.compareTo(rhs.start)
}
}

View File

@ -175,11 +175,11 @@ class ShownotesCleaner(context: Context, private val rawShownotes: String, priva
@JvmStatic
fun getTimecodeLinkTime(link: String?): Int {
if (isTimecodeLink(link)) {
val m = TIMECODE_LINK_REGEX.matcher(link)
val m = TIMECODE_LINK_REGEX.matcher(link!!)
try {
if (m.find()) {
return m.group(1).toInt()
return m.group(1)?.toInt()?:0
}
} catch (e: NumberFormatException) {
e.printStackTrace()

View File

@ -1,24 +0,0 @@
package ac.mdiq.podcini.core.util.playback
import android.content.Context
import android.media.MediaPlayer
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlaybackException
import ac.mdiq.podcini.core.R
import ac.mdiq.podcini.core.service.playback.ExoPlayerWrapper
/** Utility class for MediaPlayer errors. */
@UnstableApi
object MediaPlayerError {
/** Get a human-readable string for a specific error code. */
fun getErrorString(context: Context, code: Int): String {
val resId = when (code) {
MediaPlayer.MEDIA_ERROR_SERVER_DIED -> R.string.playback_error_server_died
MediaPlayer.MEDIA_ERROR_UNSUPPORTED, ExoPlayerWrapper.ERROR_CODE_OFFSET + ExoPlaybackException.TYPE_RENDERER -> R.string.playback_error_unsupported
MediaPlayer.MEDIA_ERROR_TIMED_OUT -> R.string.playback_error_timeout
ExoPlayerWrapper.ERROR_CODE_OFFSET + ExoPlaybackException.TYPE_SOURCE -> R.string.playback_error_source
else -> R.string.playback_error_unknown
}
return context.getString(resId) + " (" + code + ")"
}
}

View File

@ -30,9 +30,9 @@ import org.greenrobot.eventbus.ThreadMode
* control playback instead of communicating with the PlaybackService directly.
*/
@UnstableApi
abstract class PlaybackController(private val activity: FragmentActivity?) {
abstract class PlaybackController(private val activity: FragmentActivity) {
private var playbackService: PlaybackService? = null
private var media: Playable? = null
var status: PlayerStatus = PlayerStatus.STOPPED
private set
@ -73,16 +73,16 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
initialized = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
activity?.registerReceiver(statusUpdate, IntentFilter(
activity.registerReceiver(statusUpdate, IntentFilter(
PlaybackService.ACTION_PLAYER_STATUS_CHANGED), Context.RECEIVER_NOT_EXPORTED)
activity?.registerReceiver(notificationReceiver, IntentFilter(
activity.registerReceiver(notificationReceiver, IntentFilter(
PlaybackServiceInterface.ACTION_PLAYER_NOTIFICATION), Context.RECEIVER_NOT_EXPORTED)
} else {
activity?.registerReceiver(statusUpdate, IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED))
activity?.registerReceiver(notificationReceiver, IntentFilter(PlaybackServiceInterface.ACTION_PLAYER_NOTIFICATION))
activity.registerReceiver(statusUpdate, IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED))
activity.registerReceiver(notificationReceiver, IntentFilter(PlaybackServiceInterface.ACTION_PLAYER_NOTIFICATION))
}
// activity?.registerReceiver(statusUpdate, IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED))
// activity?.registerReceiver(notificationReceiver, IntentFilter(PlaybackServiceInterface.ACTION_PLAYER_NOTIFICATION))
// activity.registerReceiver(statusUpdate, IntentFilter(PlaybackService.ACTION_PLAYER_STATUS_CHANGED))
// activity.registerReceiver(notificationReceiver, IntentFilter(PlaybackServiceInterface.ACTION_PLAYER_NOTIFICATION))
if (!released) {
bindToService()
@ -100,13 +100,13 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
Log.d(TAG, "Releasing PlaybackController")
try {
activity?.unregisterReceiver(statusUpdate)
activity.unregisterReceiver(statusUpdate)
} catch (e: IllegalArgumentException) {
// ignore
}
try {
activity?.unregisterReceiver(notificationReceiver)
activity.unregisterReceiver(notificationReceiver)
} catch (e: IllegalArgumentException) {
// ignore
}
@ -122,7 +122,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
private fun unbind() {
try {
activity?.unbindService(mConnection)
activity.unbindService(mConnection)
} catch (e: IllegalArgumentException) {
// ignore
}
@ -144,7 +144,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
private fun bindToService() {
Log.d(TAG, "Trying to connect to service")
check(PlaybackService.isRunning) { "Trying to bind but service is not running" }
val bound = activity?.bindService(Intent(activity, PlaybackService::class.java), mConnection, 0)
val bound = activity.bindService(Intent(activity, PlaybackService::class.java), mConnection, 0)
Log.d(TAG, "Result for service binding: $bound")
}
@ -171,7 +171,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
private val statusUpdate: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "Received statusUpdate Intent.")
// Log.d(TAG, "Received statusUpdate Intent.")
if (playbackService != null) {
val info = playbackService!!.pSMPInfo
status = info.playerStatus
@ -218,7 +218,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
* should be used to update the GUI or start/cancel background threads.
*/
private fun handleStatus() {
Log.d(TAG, "status: $status")
Log.d(TAG, "handleStatus() called status: $status")
checkMediaInfoLoaded()
when (status) {
PlayerStatus.PLAYING -> updatePlayButtonShowsPlay(false)
@ -267,7 +267,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
fun playPause() {
if (media == null) return
if (playbackService == null) {
if (activity != null) PlaybackServiceStarter(activity, media!!).start()
PlaybackServiceStarter(activity, media!!).start()
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!")
return
}
@ -280,7 +280,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
playbackService!!.prepare()
}
else -> {
if (activity != null) PlaybackServiceStarter(activity, media!!)
PlaybackServiceStarter(activity, media!!)
.callEvenIfRunning(true)
.start()
Log.w(TAG, "Play/Pause button was pressed and PlaybackService state was unknown")
@ -289,46 +289,28 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
}
val position: Int
get() = if (playbackService != null) {
playbackService!!.currentPosition
} else if (getMedia() != null) {
getMedia()!!.getPosition()
} else {
Playable.INVALID_TIME
}
get() = playbackService?.currentPosition ?: getMedia()?.getPosition()?:Playable.INVALID_TIME
val duration: Int
get() = if (playbackService != null) {
playbackService!!.duration
} else if (getMedia() != null) {
getMedia()!!.getDuration()
} else {
Playable.INVALID_TIME
}
get() = playbackService?.duration ?: getMedia()?.getDuration()?:Playable.INVALID_TIME
fun getMedia(): Playable? {
if (media == null && activity != null) {
media = PlaybackPreferences.createInstanceFromPreferences(activity)
}
if (media == null && playbackService != null) media = playbackService!!.pSMPInfo.playable
if (media == null) media = PlaybackPreferences.createInstanceFromPreferences(activity)
return media
}
fun sleepTimerActive(): Boolean {
return playbackService != null && playbackService!!.sleepTimerActive()
return playbackService?.sleepTimerActive() ?: false
}
fun disableSleepTimer() {
if (playbackService != null) {
playbackService!!.disableSleepTimer()
}
playbackService?.disableSleepTimer()
}
val sleepTimerTimeLeft: Long
get() = if (playbackService != null) {
playbackService!!.sleepTimerTimeLeft
} else {
Playable.INVALID_TIME.toLong()
}
get() = playbackService?.sleepTimerTimeLeft ?: Playable.INVALID_TIME.toLong()
fun extendSleepTimer(extendTime: Long) {
val timeLeft = sleepTimerTimeLeft
@ -338,26 +320,24 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
}
fun setSleepTimer(time: Long) {
if (playbackService != null) {
playbackService!!.setSleepTimer(time)
}
playbackService?.setSleepTimer(time)
}
fun seekTo(time: Int) {
if (playbackService != null) {
playbackService!!.seekTo(time)
} else if (getMedia() is FeedMedia) {
val media = getMedia() as FeedMedia?
media!!.setPosition(time)
DBWriter.setFeedItem(media.getItem())
EventBus.getDefault().post(PlaybackPositionEvent(time, getMedia()!!.getDuration()))
} else {
val media = getMedia()
if (media is FeedMedia) {
media.setPosition(time)
DBWriter.setFeedItem(media.getItem())
EventBus.getDefault().post(PlaybackPositionEvent(time, media.getDuration()))
}
}
}
fun setVideoSurface(holder: SurfaceHolder?) {
if (playbackService != null) {
playbackService!!.setVideoSurface(holder)
}
playbackService?.setVideoSurface(holder)
}
fun setPlaybackSpeed(speed: Float) {
@ -369,21 +349,15 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
}
fun setSkipSilence(skipSilence: Boolean) {
if (playbackService != null) {
playbackService!!.skipSilence(skipSilence)
}
playbackService?.skipSilence(skipSilence)
}
val currentPlaybackSpeedMultiplier: Float
get() = if (playbackService != null) {
playbackService!!.currentPlaybackSpeed
} else {
getCurrentPlaybackSpeed(getMedia())
}
get() = playbackService?.currentPlaybackSpeed ?: getCurrentPlaybackSpeed(getMedia())
val audioTracks: List<String>
get() {
if (playbackService == null || playbackService!!.audioTracks.isNullOrEmpty()) {
if (playbackService == null || playbackService!!.audioTracks.isEmpty()) {
return emptyList()
}
return playbackService!!.audioTracks.filterNotNull().map { it }
@ -391,16 +365,11 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
val selectedAudioTrack: Int
get() {
if (playbackService == null) {
return -1
}
return playbackService!!.selectedAudioTrack
return playbackService?.selectedAudioTrack?: -1
}
fun setAudioTrack(track: Int) {
if (playbackService != null) {
playbackService!!.setAudioTrack(track)
}
playbackService?.setAudioTrack(track)
}
val isPlayingVideoLocally: Boolean
@ -409,20 +378,14 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
} else if (playbackService != null) {
PlaybackService.currentMediaType == MediaType.VIDEO
} else {
getMedia() != null && getMedia()!!.getMediaType() == MediaType.VIDEO
getMedia()?.getMediaType() == MediaType.VIDEO
}
val videoSize: Pair<Int, Int>?
get() = if (playbackService != null) {
playbackService!!.videoSize
} else {
null
}
get() = playbackService?.videoSize
fun notifyVideoSurfaceAbandoned() {
if (playbackService != null) {
playbackService!!.notifyVideoSurfaceAbandoned()
}
playbackService?.notifyVideoSurfaceAbandoned()
}
val isStreaming: Boolean
@ -430,5 +393,7 @@ abstract class PlaybackController(private val activity: FragmentActivity?) {
companion object {
private const val TAG = "PlaybackController"
private var media: Playable? = null
}
}

View File

@ -11,6 +11,7 @@ import ac.mdiq.podcini.model.playback.Playable
@UnstableApi
class PlaybackServiceStarter(private val context: Context, private val media: Playable) {
private var shouldStreamThisTime = false
private var callEvenIfRunning = false

View File

@ -62,7 +62,7 @@ class FeedDiscoverer {
val uri = Uri.parse(strUrl)
if (uri.isRelative) {
val res = Uri.parse(baseUrl).buildUpon().path(strUrl).build()
return if ((res != null)) res.toString() else null
return res?.toString()
} else {
return strUrl
}

View File

@ -1,6 +1,5 @@
package ac.mdiq.podcini.core.util.syndication
import android.text.TextUtils
import org.apache.commons.lang3.StringUtils
import org.jsoup.Jsoup
import org.jsoup.internal.StringUtil
@ -37,7 +36,7 @@ class HtmlToPlainText {
* @param element the root element to format
* @return formatted text
*/
fun getPlainText(element: Element?): String {
fun getPlainText(element: Element): String {
val formatter = FormattingVisitor()
// walk the DOM, and call .head() and .tail() for each node
NodeTraversor.traverse(formatter, element)
@ -52,14 +51,19 @@ class HtmlToPlainText {
// hit when the node is first seen
override fun head(node: Node, depth: Int) {
val name = node.nodeName()
if (node is TextNode) {
append(node.text()) // TextNodes carry all user-readable text in the DOM.
} else if (name == "li") {
append("\n * ")
} else if (name == "dt") {
append(" ")
} else if (StringUtil.`in`(name, "p", "h1", "h2", "h3", "h4", "h5", "tr")) {
append("\n")
when {
node is TextNode -> {
append(node.text()) // TextNodes carry all user-readable text in the DOM.
}
name == "li" -> {
append("\n * ")
}
name == "dt" -> {
append(" ")
}
StringUtil.`in`(name, "p", "h1", "h2", "h3", "h4", "h5", "tr") -> {
append("\n")
}
}
}
@ -95,13 +99,13 @@ class HtmlToPlainText {
* @param str String with any encoding
* @return Human readable text with minimal HTML formatting
*/
fun getPlainText(str: String?): String? {
fun getPlainText(str: String): String {
var str = str
if (!TextUtils.isEmpty(str) && isHtml(str)) {
if (str.isNotEmpty() && isHtml(str)) {
val formatter = HtmlToPlainText()
val feedDescription = Jsoup.parse(str)
str = StringUtils.trim(formatter.getPlainText(feedDescription))
} else if (TextUtils.isEmpty(str)) {
} else if (str.isEmpty()) {
str = ""
}
@ -116,7 +120,7 @@ class HtmlToPlainText {
*/
private fun isHtml(str: String?): Boolean {
val htmlTagPattern = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>"
return Pattern.compile(htmlTagPattern).matcher(str).find()
return Pattern.compile(htmlTagPattern).matcher(str.toString()).find()
}
}
}

View File

@ -65,7 +65,7 @@ class LocalFeedUpdaterTest {
PodDBAdapter.init(context!!)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
mapDummyMetadata(LOCAL_FEED_DIR1)

View File

@ -60,7 +60,7 @@ open class DbCleanupTests {
PodDBAdapter.init(context!!)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
val prefEdit = PreferenceManager
@ -136,7 +136,7 @@ open class DbCleanupTests {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
if (addToQueue) {
adapter.setQueue(items)
@ -200,11 +200,11 @@ open class DbCleanupTests {
// add candidate for performAutoCleanup
val feeds = DbTestUtils.saveFeedlist(1, 1, true)
val m: FeedMedia = feeds[0].items!!.get(0).media!!
val m: FeedMedia = feeds[0].items[0].media!!
m.setDownloaded(true)
m.setFile_url("file")
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setMedia(m)
adapter.close()

View File

@ -43,7 +43,7 @@ class DbNullCleanupAlgorithmTest {
PodDBAdapter.init(context!!)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
val prefEdit = PreferenceManager.getDefaultSharedPreferences(context!!.applicationContext).edit()
@ -95,7 +95,7 @@ class DbNullCleanupAlgorithmTest {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()

View File

@ -46,7 +46,7 @@ class DbReaderTest {
PodDBAdapter.init(context)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
}
@ -73,7 +73,7 @@ class DbReaderTest {
@Test
fun testGetFeedListSortOrder() {
val adapter = getInstance()
adapter!!.open()
adapter.open()
val feed1 = Feed(0, null, "A", "link", "d", null, null, null, "rss", "A", null, "", "", true)
val feed2 = Feed(0, null, "b", "link", "d", null, null, null, "rss", "b", null, "", "", true)
@ -167,7 +167,7 @@ class DbReaderTest {
}
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setQueue(queue)
adapter.close()
return queue
@ -219,7 +219,7 @@ class DbReaderTest {
}
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.storeFeedItemlist(downloaded)
adapter.close()
return downloaded
@ -258,7 +258,7 @@ class DbReaderTest {
}
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.storeFeedItemlist(newItems)
adapter.close()
return newItems
@ -298,7 +298,7 @@ class DbReaderTest {
val adapter = getInstance()
for (playedItems in mutableListOf(0, 1, 20, 100)) {
adapter!!.open()
adapter.open()
for (i in 0 until playedItems) {
val m: FeedMedia = feed.items[i].media!!
m.setPlaybackCompletionDate(Date((i + 1).toLong()))
@ -331,7 +331,7 @@ class DbReaderTest {
val numNew = 2
val feeds = DbTestUtils.saveFeedlist(numFeeds, numItems, true)
val adapter = getInstance()
adapter!!.open()
adapter.open()
for (i in 0 until numNew) {
val item: FeedItem = feeds[0].items[i]
item.setNew()
@ -445,7 +445,7 @@ class DbReaderTest {
val ids = LongArray(playedItems)
val adapter = getInstance()
adapter!!.open()
adapter.open()
for (i in 0 until playedItems) {
val m: FeedMedia = feed.items[i].media!!
m.setPlaybackCompletionDate(Date((i + 1).toLong()))

View File

@ -46,7 +46,7 @@ class DbTasksTest {
PodDBAdapter.init(context!!)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
}
@ -63,14 +63,14 @@ class DbTasksTest {
val feed = Feed("url", null, "title")
feed.items = mutableListOf()
for (i in 0 until numItems) {
feed.items?.add(FeedItem(0, "item $i", "id $i", "link $i",
feed.items.add(FeedItem(0, "item $i", "id $i", "link $i",
Date(), FeedItem.UNPLAYED, feed))
}
val newFeed = updateFeed(context!!, feed, false)
Assert.assertEquals(feed.id, newFeed!!.id)
Assert.assertTrue(feed.id != 0L)
for (item in feed.items!!) {
for (item in feed.items) {
Assert.assertFalse(item.isPlayed())
Assert.assertTrue(item.id != 0L)
}
@ -99,11 +99,11 @@ class DbTasksTest {
val feed = Feed("url", null, "title")
feed.items = mutableListOf()
for (i in 0 until numItemsOld) {
feed.items?.add(FeedItem(0, "item $i", "id $i", "link $i",
feed.items.add(FeedItem(0, "item $i", "id $i", "link $i",
Date(i.toLong()), FeedItem.PLAYED, feed))
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -112,14 +112,14 @@ class DbTasksTest {
val feedID = feed.id
feed.id = 0
val itemIDs: MutableList<Long> = ArrayList()
for (item in feed.items!!) {
for (item in feed.items) {
Assert.assertTrue(item.id != 0L)
itemIDs.add(item.id)
item.id = 0
}
for (i in numItemsOld until numItemsNew + numItemsOld) {
feed.items?.add(0, FeedItem(0, "item $i", "id $i", "link $i",
feed.items.add(0, FeedItem(0, "item $i", "id $i", "link $i",
Date(i.toLong()), FeedItem.UNPLAYED, feed))
}
@ -141,7 +141,7 @@ class DbTasksTest {
feed.items = (mutableListOf(item))
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -159,7 +159,7 @@ class DbTasksTest {
Assert.assertNotSame(newFeed, feed)
val feedFromDB = getFeed(newFeed!!.id)
val feedItemFromDB: FeedItem = feedFromDB!!.items!![0]
val feedItemFromDB: FeedItem = feedFromDB!!.items[0]
Assert.assertTrue(feedItemFromDB.isNew)
}
@ -168,16 +168,16 @@ class DbTasksTest {
val feed = Feed("url", null, "title")
feed.items = mutableListOf()
for (i in 0..9) {
feed.items?.add(
feed.items.add(
FeedItem(0, "item $i", "id $i", "link $i", Date(i.toLong()), FeedItem.PLAYED, feed))
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
// delete some items
feed.items?.subList(0, 2)?.clear()
feed.items.subList(0, 2).clear()
val newFeed = updateFeed(context!!, feed, true)
assertEquals(8, newFeed?.items?.size) // 10 - 2 = 8 items
@ -194,10 +194,10 @@ class DbTasksTest {
FeedItem(0, "item $i", "id $i", "link $i", Date(i.toLong()), FeedItem.PLAYED, feed)
val media = FeedMedia(item, "download url $i", 123, "media/mp3")
item.setMedia(media)
feed.items?.add(item)
feed.items.add(item)
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -219,11 +219,11 @@ class DbTasksTest {
private fun updatedFeedTest(newFeed: Feed?, feedID: Long, itemIDs: List<Long>, numItemsOld: Int, numItemsNew: Int) {
Assert.assertEquals(feedID, newFeed!!.id)
assertEquals(numItemsNew + numItemsOld, newFeed.items?.size)
newFeed.items?.reverse()
assertEquals(numItemsNew + numItemsOld, newFeed.items.size)
newFeed.items.reverse()
var lastDate = Date(0)
for (i in 0 until numItemsOld) {
val item: FeedItem = newFeed.items!![i]
val item: FeedItem = newFeed.items[i]
Assert.assertSame(newFeed, item.feed)
Assert.assertEquals(itemIDs[i], item.id)
Assert.assertTrue(item.isPlayed())
@ -231,7 +231,7 @@ class DbTasksTest {
lastDate = item.pubDate!!
}
for (i in numItemsOld until numItemsNew + numItemsOld) {
val item: FeedItem = newFeed.items!![i]
val item: FeedItem = newFeed.items[i]
Assert.assertSame(newFeed, item.feed)
Assert.assertTrue(item.id != 0L)
Assert.assertFalse(item.isPlayed())
@ -254,7 +254,7 @@ class DbTasksTest {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
return feed

View File

@ -28,7 +28,7 @@ internal object DbTestUtils {
val feeds: MutableList<Feed> = ArrayList()
val adapter = getInstance()
adapter!!.open()
adapter.open()
for (i in 0 until numFeeds) {
val f = Feed(0, null, "feed $i", "link$i", "descr", null, null,
null, null, "id$i", null, null, "url$i", false)
@ -53,7 +53,7 @@ internal object DbTestUtils {
f.items.sortWith(FeedItemPubdateComparator())
adapter.setCompleteFeed(f)
Assert.assertTrue(f.id != 0L)
for (item in f.items!!) {
for (item in f.items) {
Assert.assertTrue(item.id != 0L)
}
feeds.add(f)

View File

@ -71,7 +71,7 @@ class DbWriterTest {
PodDBAdapter.init(context!!)
deleteDatabase()
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.close()
val prefEdit = PreferenceManager.getDefaultSharedPreferences(
@ -144,7 +144,7 @@ class DbWriterTest {
items.add(item)
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
Assert.assertTrue(media!!.id != 0L)
@ -181,7 +181,7 @@ class DbWriterTest {
queue.add(item)
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.setQueue(queue)
adapter.close()
@ -225,7 +225,7 @@ class DbWriterTest {
}
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -243,7 +243,7 @@ class DbWriterTest {
}
adapter = getInstance()
adapter!!.open()
adapter.open()
var c = adapter.getFeedCursor(feed.id)
Assert.assertEquals(0, c.count.toLong())
c.close()
@ -269,7 +269,7 @@ class DbWriterTest {
feed.imageUrl = ("url")
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -278,7 +278,7 @@ class DbWriterTest {
deleteFeed(context!!, feed.id)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
val c = adapter.getFeedCursor(feed.id)
Assert.assertEquals(0, c.count.toLong())
c.close()
@ -303,7 +303,7 @@ class DbWriterTest {
}
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -315,7 +315,7 @@ class DbWriterTest {
deleteFeed(context!!, feed.id)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
var c = adapter.getFeedCursor(feed.id)
Assert.assertEquals(0, c.count.toLong())
c.close()
@ -349,7 +349,7 @@ class DbWriterTest {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -410,7 +410,7 @@ class DbWriterTest {
}
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -423,7 +423,7 @@ class DbWriterTest {
deleteFeed(context!!, feed.id)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
var c = adapter.getFeedCursor(feed.id)
Assert.assertEquals(0, c.count.toLong())
c.close()
@ -453,7 +453,7 @@ class DbWriterTest {
}
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -461,7 +461,7 @@ class DbWriterTest {
deleteFeedItems(context!!, itemsToDelete)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
for (i in 0 until feed.items.size) {
val feedItem: FeedItem = feed.items[i]
val c = adapter.getFeedItemCursor(feedItem.id.toString())
@ -484,7 +484,7 @@ class DbWriterTest {
feed.items.add(item)
item.setMedia(media)
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
Assert.assertTrue(media.id != 0L)
@ -497,7 +497,7 @@ class DbWriterTest {
var media: FeedMedia? = playbackHistorySetup(null)
addItemToPlaybackHistory(media)[TIMEOUT, TimeUnit.SECONDS]
val adapter = getInstance()
adapter!!.open()
adapter.open()
media = getFeedMedia(media!!.id)
adapter.close()
@ -513,7 +513,7 @@ class DbWriterTest {
var media: FeedMedia? = playbackHistorySetup(Date(oldDate))
addItemToPlaybackHistory(media)[TIMEOUT, TimeUnit.SECONDS]
val adapter = getInstance()
adapter!!.open()
adapter.open()
media = getFeedMedia(media!!.id)
adapter.close()
@ -534,7 +534,7 @@ class DbWriterTest {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -561,7 +561,7 @@ class DbWriterTest {
feed.items.add(item)
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -569,7 +569,7 @@ class DbWriterTest {
addQueueItem(context, item)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
val cursor = adapter.queueIDCursor
Assert.assertTrue(cursor.moveToFirst())
Assert.assertEquals(item.id, cursor.getLong(0))
@ -587,7 +587,7 @@ class DbWriterTest {
feed.items.add(item)
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -595,7 +595,7 @@ class DbWriterTest {
addQueueItem(context, item)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
var cursor = adapter.queueIDCursor
Assert.assertTrue(cursor.moveToFirst())
Assert.assertEquals(item.id, cursor.getLong(0))
@ -604,7 +604,7 @@ class DbWriterTest {
addQueueItem(context, item)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
cursor = adapter.queueIDCursor
Assert.assertTrue(cursor.moveToFirst())
Assert.assertEquals(item.id, cursor.getLong(0))
@ -619,7 +619,7 @@ class DbWriterTest {
val numItems = 10
val feed = queueTestSetupMultipleItems(numItems)
val adapter = getInstance()
adapter!!.open()
adapter.open()
val cursor = adapter.queueIDCursor
Assert.assertTrue(cursor.moveToFirst())
Assert.assertEquals(numItems.toLong(), cursor.count.toLong())
@ -643,7 +643,7 @@ class DbWriterTest {
queueTestSetupMultipleItems(numItems)
clearQueue()[TIMEOUT, TimeUnit.SECONDS]
val adapter = getInstance()
adapter!!.open()
adapter.open()
val cursor = adapter.queueIDCursor
Assert.assertFalse(cursor.moveToFirst())
cursor.close()
@ -659,13 +659,13 @@ class DbWriterTest {
for (removeIndex in 0 until numItems) {
val item: FeedItem = feed.items[removeIndex]
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setQueue(feed.items.toList())
adapter.close()
removeQueueItem(context!!, false, item)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
val queue = adapter.queueIDCursor
Assert.assertEquals((numItems - 1).toLong(), queue.count.toLong())
for (i in 0 until queue.count) {
@ -732,7 +732,7 @@ class DbWriterTest {
}
var adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -748,13 +748,13 @@ class DbWriterTest {
val fromID: Long = feed.items[from].id
adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setQueue(feed.items)
adapter.close()
moveQueueItem(from, to, false)[TIMEOUT, TimeUnit.SECONDS]
adapter = getInstance()
adapter!!.open()
adapter.open()
val queue = adapter.queueIDCursor
Assert.assertEquals(numItems.toLong(), queue.count.toLong())
Assert.assertTrue(queue.moveToPosition(from))
@ -782,7 +782,7 @@ class DbWriterTest {
}
val adapter = getInstance()
adapter!!.open()
adapter.open()
adapter.setCompleteFeed(feed)
adapter.close()
@ -824,10 +824,10 @@ class DbWriterTest {
private fun withPodDB(action: Consumer<PodDBAdapter?>) {
val adapter = getInstance()
try {
adapter!!.open()
adapter.open()
action.accept(adapter)
} finally {
adapter!!.close()
adapter.close()
}
}

View File

@ -4,7 +4,7 @@ import ac.mdiq.podcini.model.feed.FeedItem
class QueueEvent private constructor(@JvmField val action: Action,
@JvmField val item: FeedItem?,
@JvmField val items: List<FeedItem>?,
@JvmField val items: List<FeedItem>,
@JvmField val position: Int
) {
enum class Action {
@ -14,38 +14,38 @@ class QueueEvent private constructor(@JvmField val action: Action,
companion object {
@JvmStatic
fun added(item: FeedItem?, position: Int): QueueEvent {
return QueueEvent(Action.ADDED, item, null, position)
fun added(item: FeedItem, position: Int): QueueEvent {
return QueueEvent(Action.ADDED, item, listOf(), position)
}
@JvmStatic
fun setQueue(queue: List<FeedItem>?): QueueEvent {
fun setQueue(queue: List<FeedItem>): QueueEvent {
return QueueEvent(Action.SET_QUEUE, null, queue, -1)
}
@JvmStatic
fun removed(item: FeedItem?): QueueEvent {
return QueueEvent(Action.REMOVED, item, null, -1)
fun removed(item: FeedItem): QueueEvent {
return QueueEvent(Action.REMOVED, item, listOf(), -1)
}
@JvmStatic
fun irreversibleRemoved(item: FeedItem?): QueueEvent {
return QueueEvent(Action.IRREVERSIBLE_REMOVED, item, null, -1)
fun irreversibleRemoved(item: FeedItem): QueueEvent {
return QueueEvent(Action.IRREVERSIBLE_REMOVED, item, listOf(), -1)
}
@JvmStatic
fun cleared(): QueueEvent {
return QueueEvent(Action.CLEARED, null, null, -1)
return QueueEvent(Action.CLEARED, null, listOf(), -1)
}
@JvmStatic
fun sorted(sortedQueue: List<FeedItem>?): QueueEvent {
fun sorted(sortedQueue: List<FeedItem>): QueueEvent {
return QueueEvent(Action.SORTED, null, sortedQueue, -1)
}
@JvmStatic
fun moved(item: FeedItem?, newPosition: Int): QueueEvent {
return QueueEvent(Action.MOVED, item, null, newPosition)
fun moved(item: FeedItem, newPosition: Int): QueueEvent {
return QueueEvent(Action.MOVED, item, listOf(), newPosition)
}
}
}

View File

@ -123,7 +123,7 @@ class FeedItem : FeedComponent, Serializable {
this.title = title
this.itemIdentifier = itemIdentifier
this.link = link
this.pubDate = if ((pubDate != null)) pubDate.clone() as Date else null
this.pubDate = if (pubDate != null) pubDate.clone() as Date else null
this.playState = state
this.feed = feed
this.hasChapters = false
@ -145,7 +145,7 @@ class FeedItem : FeedComponent, Serializable {
this.title = title
this.itemIdentifier = itemIdentifier
this.link = link
this.pubDate = if ((pubDate != null)) pubDate.clone() as Date else null
this.pubDate = if (pubDate != null) pubDate.clone() as Date else null
this.playState = state
this.feed = feed
this.hasChapters = hasChapters
@ -246,7 +246,7 @@ class FeedItem : FeedComponent, Serializable {
}
fun isPlayed(): Boolean {
return playState === PLAYED
return playState == PLAYED
}
fun setPlayed(played: Boolean) {
@ -299,7 +299,7 @@ class FeedItem : FeedComponent, Serializable {
}
fun hasChapters(): Boolean {
return hasChapters
return chapters?.isNotEmpty() ?: hasChapters
}
fun disableAutoDownload() {

View File

@ -274,6 +274,10 @@ class FeedMedia : FeedFile, Playable {
return item!!.chapters!!
}
override fun chaptersLoaded(): Boolean {
return item?.chapters != null
}
override fun getWebsiteLink(): String? {
if (item == null) {
return null

View File

@ -29,6 +29,8 @@ interface Playable : Parcelable, Serializable {
*/
fun getChapters(): List<Chapter>
fun chaptersLoaded(): Boolean
/**
* Returns a link to a website that is meant to be shown in a browser
*/

View File

@ -124,6 +124,10 @@ class RemoteMedia : Playable {
return chapters ?: listOf()
}
override fun chaptersLoaded(): Boolean {
return chapters != null
}
override fun getEpisodeTitle(): String {
return episodeTitle!!
}

View File

@ -30,34 +30,43 @@ object UrlChecker {
var url = url
url = url.trim { it <= ' ' }
val lowerCaseUrl = url.lowercase() // protocol names are case insensitive
if (lowerCaseUrl.startsWith("feed://")) {
Log.d(TAG, "Replacing feed:// with http://")
return prepareUrl(url.substring("feed://".length))
} else if (lowerCaseUrl.startsWith("pcast://")) {
Log.d(TAG, "Removing pcast://")
return prepareUrl(url.substring("pcast://".length))
} else if (lowerCaseUrl.startsWith("pcast:")) {
Log.d(TAG, "Removing pcast:")
return prepareUrl(url.substring("pcast:".length))
} else if (lowerCaseUrl.startsWith("itpc")) {
Log.d(TAG, "Replacing itpc:// with http://")
return prepareUrl(url.substring("itpc://".length))
} else if (lowerCaseUrl.startsWith(AP_SUBSCRIBE)) {
Log.d(TAG, "Removing podcini-subscribe://")
return prepareUrl(url.substring(AP_SUBSCRIBE.length))
} else if (lowerCaseUrl.contains(AP_SUBSCRIBE_DEEPLINK)) {
Log.d(TAG, "Removing $AP_SUBSCRIBE_DEEPLINK")
val removedWebsite = url.substring(url.indexOf("?url=") + "?url=".length)
return try {
prepareUrl(URLDecoder.decode(removedWebsite, "UTF-8"))
} catch (e: UnsupportedEncodingException) {
prepareUrl(removedWebsite)
when {
lowerCaseUrl.startsWith("feed://") -> {
Log.d(TAG, "Replacing feed:// with http://")
return prepareUrl(url.substring("feed://".length))
}
lowerCaseUrl.startsWith("pcast://") -> {
Log.d(TAG, "Removing pcast://")
return prepareUrl(url.substring("pcast://".length))
}
lowerCaseUrl.startsWith("pcast:") -> {
Log.d(TAG, "Removing pcast:")
return prepareUrl(url.substring("pcast:".length))
}
lowerCaseUrl.startsWith("itpc") -> {
Log.d(TAG, "Replacing itpc:// with http://")
return prepareUrl(url.substring("itpc://".length))
}
lowerCaseUrl.startsWith(AP_SUBSCRIBE) -> {
Log.d(TAG, "Removing podcini-subscribe://")
return prepareUrl(url.substring(AP_SUBSCRIBE.length))
}
lowerCaseUrl.contains(AP_SUBSCRIBE_DEEPLINK) -> {
Log.d(TAG, "Removing $AP_SUBSCRIBE_DEEPLINK")
val removedWebsite = url.substring(url.indexOf("?url=") + "?url=".length)
return try {
prepareUrl(URLDecoder.decode(removedWebsite, "UTF-8"))
} catch (e: UnsupportedEncodingException) {
prepareUrl(removedWebsite)
}
}
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> {
Log.d(TAG, "Adding http:// at the beginning of the URL")
return "http://$url"
}
else -> {
return url
}
} else if (!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://"))) {
Log.d(TAG, "Adding http:// at the beginning of the URL")
return "http://$url"
} else {
return url
}
}

View File

@ -11,7 +11,7 @@ import java.util.*
import java.util.concurrent.CountDownLatch
class CombinedSearcher : PodcastSearcher {
override fun search(query: String): Single<List<PodcastSearchResult?>?>? {
override fun search(query: String): Single<List<PodcastSearchResult?>?> {
val disposables = ArrayList<Disposable>()
val singleResults: MutableList<List<PodcastSearchResult?>?> = ArrayList(
Collections.nCopies<List<PodcastSearchResult?>?>(PodcastSearcherRegistry.searchProviders.size, null))
@ -23,9 +23,8 @@ class CombinedSearcher : PodcastSearcher {
latch.countDown()
continue
}
val index = i
disposables.add(searcher.search(query)!!.subscribe({ e: List<PodcastSearchResult?>? ->
singleResults[index] = e
disposables.add(searcher.search(query).subscribe({ e: List<PodcastSearchResult?>? ->
singleResults[i] = e
latch.countDown()
}, { throwable: Throwable? ->
Log.d(TAG, Log.getStackTraceString(throwable))
@ -79,7 +78,7 @@ class CombinedSearcher : PodcastSearcher {
return results
}
override fun lookupUrl(url: String): Single<String>? {
override fun lookupUrl(url: String): Single<String> {
return PodcastSearcherRegistry.lookupUrl(url)
}

View File

@ -10,7 +10,7 @@ import io.reactivex.schedulers.Schedulers
class FyydPodcastSearcher : PodcastSearcher {
private val client = FyydClient(getHttpClient())
override fun search(query: String): Single<List<PodcastSearchResult?>?>? {
override fun search(query: String): Single<List<PodcastSearchResult?>?> {
return Single.create { subscriber: SingleEmitter<List<PodcastSearchResult?>?> ->
val response = client.searchPodcasts(
query, 10)
@ -30,7 +30,7 @@ class FyydPodcastSearcher : PodcastSearcher {
.observeOn(AndroidSchedulers.mainThread())
}
override fun lookupUrl(url: String): Single<String>? {
override fun lookupUrl(url: String): Single<String> {
return Single.just(url)
}

View File

@ -10,7 +10,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class GpodnetPodcastSearcher : PodcastSearcher {
override fun search(query: String): Single<List<PodcastSearchResult?>?>? {
override fun search(query: String): Single<List<PodcastSearchResult?>?> {
return Single.create { subscriber: SingleEmitter<List<PodcastSearchResult?>?> ->
try {
val service = GpodnetService(getHttpClient(),
@ -31,7 +31,7 @@ class GpodnetPodcastSearcher : PodcastSearcher {
.observeOn(AndroidSchedulers.mainThread())
}
override fun lookupUrl(url: String): Single<String>? {
override fun lookupUrl(url: String): Single<String> {
return Single.just(url)
}

View File

@ -15,7 +15,7 @@ import java.net.URLEncoder
import java.util.regex.Pattern
class ItunesPodcastSearcher : PodcastSearcher {
override fun search(query: String): Single<List<PodcastSearchResult?>?>? {
override fun search(query: String): Single<List<PodcastSearchResult?>?> {
return Single.create<List<PodcastSearchResult?>?> { subscriber: SingleEmitter<List<PodcastSearchResult?>?> ->
val encodedQuery = try {
URLEncoder.encode(query, "UTF-8")
@ -58,7 +58,7 @@ class ItunesPodcastSearcher : PodcastSearcher {
.observeOn(AndroidSchedulers.mainThread())
}
override fun lookupUrl(url: String): Single<String>? {
override fun lookupUrl(url: String): Single<String> {
val pattern = Pattern.compile(PATTERN_BY_ID)
val matcher = pattern.matcher(url)
val lookupUrl = if (matcher.find()) ("https://itunes.apple.com/lookup?id=" + matcher.group(1)) else url

View File

@ -18,7 +18,7 @@ class ItunesTopListLoader(private val context: Context) {
@Throws(JSONException::class, IOException::class)
fun loadToplist(country: String, limit: Int, subscribed: List<Feed>): List<PodcastSearchResult> {
val client = getHttpClient()
var feedString: String
val feedString: String
var loadCountry = country
if (COUNTRY_CODE_UNSET == country) {
loadCountry = Locale.getDefault().country

View File

@ -17,9 +17,9 @@ import java.security.MessageDigest
import java.util.*
class PodcastIndexPodcastSearcher : PodcastSearcher {
override fun search(query: String): Single<List<PodcastSearchResult?>?>? {
override fun search(query: String): Single<List<PodcastSearchResult?>?> {
return Single.create { subscriber: SingleEmitter<List<PodcastSearchResult?>?> ->
var encodedQuery = try {
val encodedQuery = try {
URLEncoder.encode(query, "UTF-8")
} catch (e: UnsupportedEncodingException) {
// this won't ever be thrown
@ -57,7 +57,7 @@ class PodcastIndexPodcastSearcher : PodcastSearcher {
.observeOn(AndroidSchedulers.mainThread())
}
override fun lookupUrl(url: String): Single<String>? {
override fun lookupUrl(url: String): Single<String> {
return Single.just(url)
}

View File

@ -36,9 +36,9 @@ class PodcastSearchResult private constructor(
*/
fun fromItunes(json: JSONObject): PodcastSearchResult {
val title = json.optString("collectionName", "")
val imageUrl = json.optString("artworkUrl100", null)
val feedUrl = json.optString("feedUrl", null)
val author = json.optString("artistName", null)
val imageUrl: String? = json.optString("artworkUrl100").takeIf { it.isNotEmpty() }
val feedUrl: String? = json.optString("feedUrl").takeIf { it.isNotEmpty() }
val author: String? = json.optString("artistName").takeIf { it.isNotEmpty() }
return PodcastSearchResult(title, imageUrl, feedUrl, author)
}
@ -90,9 +90,9 @@ class PodcastSearchResult private constructor(
fun fromPodcastIndex(json: JSONObject): PodcastSearchResult {
val title = json.optString("title", "")
val imageUrl = json.optString("image", null)
val feedUrl = json.optString("url", null)
val author = json.optString("author", null)
val imageUrl: String? = json.optString("image").takeIf { it.isNotEmpty() }
val feedUrl: String? = json.optString("url").takeIf { it.isNotEmpty() }
val author: String? = json.optString("author").takeIf { it.isNotEmpty() }
return PodcastSearchResult(title, imageUrl, feedUrl, author)
}
}

View File

@ -3,9 +3,9 @@ package ac.mdiq.podcini.net.discovery
import io.reactivex.Single
interface PodcastSearcher {
fun search(query: String): Single<List<PodcastSearchResult?>?>?
fun search(query: String): Single<List<PodcastSearchResult?>?>
fun lookupUrl(resultUrl: String): Single<String>?
fun lookupUrl(resultUrl: String): Single<String>
fun urlNeedsLookup(resultUrl: String): Boolean

View File

@ -19,7 +19,7 @@ object PodcastSearcherRegistry {
}
private set
fun lookupUrl(url: String): Single<String>? {
fun lookupUrl(url: String): Single<String> {
for (searchProviderInfo in searchProviders) {
if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java
&& searchProviderInfo.searcher.urlNeedsLookup(url)) {

View File

@ -15,7 +15,7 @@ import javax.net.ssl.TrustManager
* This fixes issues with old Android versions that abort if the server does not know TLS 1.0
*/
class PodciniSslSocketFactory(trustManager: TrustManager) : SSLSocketFactory() {
private var factory: SSLSocketFactory? = null
private lateinit var factory: SSLSocketFactory
init {
try {
@ -37,51 +37,51 @@ class PodciniSslSocketFactory(trustManager: TrustManager) : SSLSocketFactory() {
}
override fun getDefaultCipherSuites(): Array<String> {
return factory!!.defaultCipherSuites
return factory.defaultCipherSuites
}
override fun getSupportedCipherSuites(): Array<String> {
return factory!!.supportedCipherSuites
return factory.supportedCipherSuites
}
@Throws(IOException::class)
override fun createSocket(): Socket {
val result = factory!!.createSocket() as SSLSocket
val result = factory.createSocket() as SSLSocket
configureSocket(result)
return result
}
@Throws(IOException::class)
override fun createSocket(var1: String, var2: Int): Socket {
val result = factory!!.createSocket(var1, var2) as SSLSocket
val result = factory.createSocket(var1, var2) as SSLSocket
configureSocket(result)
return result
}
@Throws(IOException::class)
override fun createSocket(var1: Socket, var2: String, var3: Int, var4: Boolean): Socket {
val result = factory!!.createSocket(var1, var2, var3, var4) as SSLSocket
val result = factory.createSocket(var1, var2, var3, var4) as SSLSocket
configureSocket(result)
return result
}
@Throws(IOException::class)
override fun createSocket(var1: InetAddress, var2: Int): Socket {
val result = factory!!.createSocket(var1, var2) as SSLSocket
val result = factory.createSocket(var1, var2) as SSLSocket
configureSocket(result)
return result
}
@Throws(IOException::class)
override fun createSocket(var1: String, var2: Int, var3: InetAddress, var4: Int): Socket {
val result = factory!!.createSocket(var1, var2, var3, var4) as SSLSocket
val result = factory.createSocket(var1, var2, var3, var4) as SSLSocket
configureSocket(result)
return result
}
@Throws(IOException::class)
override fun createSocket(var1: InetAddress, var2: Int, var3: InetAddress, var4: Int): Socket {
val result = factory!!.createSocket(var1, var2, var3, var4) as SSLSocket
val result = factory.createSocket(var1, var2, var3, var4) as SSLSocket
configureSocket(result)
return result
}

View File

@ -46,7 +46,7 @@ class CompositeX509TrustManager(private val trustManagers: List<X509TrustManager
override fun getAcceptedIssuers(): Array<X509Certificate> {
val certificates: MutableList<X509Certificate> = ArrayList()
for (trustManager in trustManagers) {
certificates.addAll(Arrays.asList(*trustManager.acceptedIssuers))
certificates.addAll(listOf(*trustManager.acceptedIssuers))
}
return certificates.toTypedArray<X509Certificate>()
}

View File

@ -3,7 +3,6 @@ package ac.mdiq.podcini.net.ssl
import ac.mdiq.podcini.net.ssl.BackportTrustManager.create
import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient.Builder
import java.util.*
object SslClientSetup {
fun installCertificates(builder: Builder) {

View File

@ -1,8 +1,7 @@
package ac.mdiq.podcini.net.sync.model
import android.text.TextUtils
import android.util.Log
import ac.mdiq.podcini.model.feed.FeedItem
import android.util.Log
import org.json.JSONException
import org.json.JSONObject
import java.text.ParseException
@ -87,7 +86,7 @@ class EpisodeAction private constructor(builder: Builder) {
obj.put("action", this.actionString)
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
formatter.timeZone = TimeZone.getTimeZone("UTC")
obj.put("timestamp", formatter.format(this.timestamp))
if (this.timestamp != null) obj.put("timestamp", formatter.format(this.timestamp))
if (this.action == Action.PLAY) {
obj.put("started", this.started)
obj.put("position", this.position)
@ -190,10 +189,10 @@ class EpisodeAction private constructor(builder: Builder) {
*/
@JvmStatic
fun readFromJsonObject(`object`: JSONObject): EpisodeAction? {
val podcast = `object`.optString("podcast", null)
val episode = `object`.optString("episode", null)
val actionString = `object`.optString("action", null)
if (TextUtils.isEmpty(podcast) || TextUtils.isEmpty(episode) || TextUtils.isEmpty(actionString)) {
val podcast = `object`.optString("podcast")
val episode = `object`.optString("episode")
val actionString = `object`.optString("action")
if (podcast.isNullOrEmpty() || episode.isNullOrEmpty() || actionString.isNullOrEmpty()) {
return null
}
val action: Action
@ -203,8 +202,8 @@ class EpisodeAction private constructor(builder: Builder) {
return null
}
val builder = Builder(podcast, episode, action)
val utcTimestamp = `object`.optString("timestamp", null)
if (!TextUtils.isEmpty(utcTimestamp)) {
val utcTimestamp = `object`.optString("timestamp")
if (utcTimestamp.isNotEmpty()) {
try {
val parser = SimpleDateFormat(PATTERN_ISO_DATEFORMAT, Locale.US)
parser.timeZone = TimeZone.getTimeZone("UTC")
@ -213,8 +212,8 @@ class EpisodeAction private constructor(builder: Builder) {
e.printStackTrace()
}
}
val guid = `object`.optString("guid", null)
if (!TextUtils.isEmpty(guid)) {
val guid = `object`.optString("guid")
if (guid.isNotEmpty()) {
builder.guid(guid)
}
if (action == Action.PLAY) {

View File

@ -1,9 +1,9 @@
package ac.mdiq.podcini.parser.feed
import android.util.Log
import ac.mdiq.podcini.model.feed.Feed
import ac.mdiq.podcini.parser.feed.UnsupportedFeedtypeException
import ac.mdiq.podcini.parser.feed.util.TypeGetter
import android.util.Log
import org.apache.commons.io.input.XmlStreamReader
import org.xml.sax.InputSource
import org.xml.sax.SAXException

View File

@ -5,7 +5,7 @@ import org.json.JSONException
import org.json.JSONObject
object PodcastIndexChapterParser {
fun parse(jsonStr: String?): List<Chapter>? {
fun parse(jsonStr: String): List<Chapter> {
try {
val chapters: MutableList<Chapter> = ArrayList()
val obj = JSONObject(jsonStr)
@ -13,15 +13,15 @@ object PodcastIndexChapterParser {
for (i in 0 until objChapters.length()) {
val jsonObject = objChapters.getJSONObject(i)
val startTime = jsonObject.optInt("startTime", 0)
val title = jsonObject.optString("title")
val link = jsonObject.optString("url")
val img = jsonObject.optString("img")
val title = jsonObject.optString("title").takeIf { it.isNotEmpty() }
val link = jsonObject.optString("url").takeIf { it.isNotEmpty() }
val img = jsonObject.optString("img").takeIf { it.isNotEmpty() }
chapters.add(Chapter(startTime * 1000L, title, link, img))
}
return chapters
} catch (e: JSONException) {
e.printStackTrace()
}
return null
return listOf()
}
}

View File

@ -4,20 +4,25 @@ import androidx.core.text.HtmlCompat
import ac.mdiq.podcini.parser.feed.namespace.Namespace
/** Represents Atom Element which contains text (content, title, summary). */
class AtomText(name: String?, namespace: Namespace?, private val type: String?) : SyndElement(
name!!, namespace!!) {
class AtomText(name: String?, namespace: Namespace?, private val type: String?) : SyndElement(name!!, namespace!!) {
private var content: String? = null
val processedContent: String?
/** Processes the content according to the type and returns it. */
get() = if (type == null) {
content
} else if (type == TYPE_HTML) {
HtmlCompat.fromHtml(content!!, HtmlCompat.FROM_HTML_MODE_LEGACY).toString()
} else if (type == TYPE_XHTML) {
content
} else { // Handle as text by default
content
get() = when (type) {
null -> {
content
}
TYPE_HTML -> {
HtmlCompat.fromHtml(content!!, HtmlCompat.FROM_HTML_MODE_LEGACY).toString()
}
TYPE_XHTML -> {
content
}
else -> { // Handle as text by default
content
}
}
fun setContent(content: String?) {

View File

@ -205,7 +205,7 @@ class Atom : Namespace() {
/**
* Regexp to test whether an Element is a Text Element.
*/
private const val isText = (TITLE + "|" + CONTENT + "|" + SUBTITLE + "|" + SUMMARY)
private const val isText = ("$TITLE|$CONTENT|$SUBTITLE|$SUMMARY")
private const val isFeed = FEED + "|" + Rss20.CHANNEL
private const val isFeedItem = ENTRY + "|" + Rss20.ITEM

View File

@ -8,14 +8,19 @@ object DurationParser {
fun inMillis(durationStr: String): Long {
val parts = durationStr.trim { it <= ' ' }.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
return if (parts.size == 1) {
toMillis(parts[0])
} else if (parts.size == 2) {
toMillis("0", parts[0], parts[1])
} else if (parts.size == 3) {
toMillis(parts[0], parts[1], parts[2])
} else {
throw NumberFormatException()
return when (parts.size) {
1 -> {
toMillis(parts[0])
}
2 -> {
toMillis("0", parts[0], parts[1])
}
3 -> {
toMillis(parts[0], parts[1], parts[2])
}
else -> {
throw NumberFormatException()
}
}
}

View File

@ -100,7 +100,7 @@ class TypeGetter {
try {
reader.close()
} catch (e: IOException) {
Log.d(TAG, "IOException: " + reader.toString())
Log.d(TAG, "IOException: $reader")
e.printStackTrace()
}
}
@ -111,9 +111,11 @@ class TypeGetter {
}
private fun createReader(feed: Feed): Reader? {
if (feed.file_url == null) return null
val reader: Reader
try {
reader = XmlStreamReader(File(feed.file_url))
reader = XmlStreamReader(File(feed.file_url!!))
} catch (e: FileNotFoundException) {
Log.d(TAG, "FileNotFoundException: " + feed.file_url)
e.printStackTrace()

View File

@ -147,12 +147,16 @@ open class ID3Reader(private val inputStream: CountingInputStream) {
@Throws(IOException::class)
fun readEncodedString(encoding: Int, max: Int): String {
return if (encoding == ENCODING_UTF16_WITH_BOM.toInt() || encoding == ENCODING_UTF16_WITHOUT_BOM.toInt()) {
readEncodedString2(Charset.forName("UTF-16"), max)
} else if (encoding == ENCODING_UTF8.toInt()) {
readEncodedString2(Charset.forName("UTF-8"), max)
} else {
readEncodedString1(Charset.forName("ISO-8859-1"), max)
return when (encoding) {
ENCODING_UTF16_WITH_BOM.toInt(), ENCODING_UTF16_WITHOUT_BOM.toInt() -> {
readEncodedString2(Charset.forName("UTF-16"), max)
}
ENCODING_UTF8.toInt() -> {
readEncodedString2(Charset.forName("UTF-8"), max)
}
else -> {
readEncodedString1(Charset.forName("ISO-8859-1"), max)
}
}
}

View File

@ -1,4 +1,3 @@
package ac.mdiq.podcini.parser.media.id3.model
class FrameHeader(id: String?, size: Int, flags: Short) : Header(
id!!, size)
class FrameHeader(id: String?, size: Int, flags: Short) : Header(id!!, size)

View File

@ -1,9 +1,7 @@
package ac.mdiq.podcini.parser.media.id3.model
class TagHeader(id: String?, size: Int, @JvmField val version: Short, private val flags: Byte) : Header(
id!!, size) {
class TagHeader(id: String?, size: Int, @JvmField val version: Short, private val flags: Byte) : Header(id!!, size) {
override fun toString(): String {
return ("TagHeader [version=" + version + ", flags=" + flags + ", id="
+ id + ", size=" + size + "]")
return ("TagHeader [version=" + version + ", flags=" + flags + ", id=" + id + ", size=" + size + "]")
}
}

View File

@ -1,9 +1,8 @@
package ac.mdiq.podcini.parser.media.vorbis
import android.util.Log
import ac.mdiq.podcini.model.feed.Chapter
import ac.mdiq.podcini.parser.media.BuildConfig
import ac.mdiq.podcini.parser.media.vorbis.VorbisCommentReaderException
import android.util.Log
import java.io.InputStream
import java.util.concurrent.TimeUnit
@ -22,24 +21,24 @@ class VorbisCommentChapterReader(input: InputStream?) : VorbisCommentReader(inpu
val attribute = getAttributeTypeFromKey(key)
val id = getIdFromKey(key)
var chapter = getChapterById(id.toLong())
if (attribute == null) {
if (getChapterById(id.toLong()) == null) {
// new chapter
val start = getStartTimeFromValue(value)
chapter = Chapter()
chapter.chapterId = "" + id
chapter.start = start
chapters.add(chapter)
} else {
throw VorbisCommentReaderException("Found chapter with duplicate ID ($key, $value)")
when (attribute) {
null -> {
if (getChapterById(id.toLong()) == null) {
// new chapter
val start = getStartTimeFromValue(value)
chapter = Chapter()
chapter.chapterId = "" + id
chapter.start = start
chapters.add(chapter)
} else {
throw VorbisCommentReaderException("Found chapter with duplicate ID ($key, $value)")
}
}
} else if (attribute == CHAPTER_ATTRIBUTE_TITLE) {
if (chapter != null) {
chapter.title = value
CHAPTER_ATTRIBUTE_TITLE -> {
if (chapter != null) chapter.title = value
}
} else if (attribute == CHAPTER_ATTRIBUTE_LINK) {
if (chapter != null) {
chapter.link = value
CHAPTER_ATTRIBUTE_LINK -> {
if (chapter != null) chapter.link = value
}
}
}

View File

@ -2,7 +2,6 @@ package ac.mdiq.podcini.parser.media.vorbis
internal class VorbisCommentHeader(val vendorString: String, val userCommentLength: Long) {
override fun toString(): String {
return ("VorbisCommentHeader [vendorString=" + vendorString
+ ", userCommentLength=" + userCommentLength + "]")
return ("VorbisCommentHeader [vendorString=" + vendorString + ", userCommentLength=" + userCommentLength + "]")
}
}

View File

@ -12,7 +12,7 @@ class VorbisCommentMetadataReader(input: InputStream?) : VorbisCommentReader(inp
public override fun onContentVectorValue(key: String?, value: String?) {
if (KEY_DESCRIPTION == key || KEY_COMMENT == key) {
if (description == null || value!!.length > description!!.length) {
if (description == null || (value != null && value.length > description!!.length)) {
description = value
}
}

View File

@ -1,7 +1,6 @@
package ac.mdiq.podcini.parser.media.vorbis
import android.util.Log
import ac.mdiq.podcini.parser.media.vorbis.VorbisCommentReaderException
import org.apache.commons.io.EndianUtils
import org.apache.commons.io.IOUtils
import java.io.IOException
@ -136,7 +135,7 @@ abstract class VorbisCommentReader internal constructor(private val input: Input
while (posInHaystack < 0) {
posInHaystack += haystack.size
}
posInHaystack = posInHaystack % haystack.size
posInHaystack %= haystack.size
if (haystack[posInHaystack] != needle[needle.size - 1 - i]) {
return false
}

View File

@ -217,8 +217,8 @@ class PodDBAdapter private constructor() {
db.beginTransactionNonExclusive()
for (feed in feeds) {
setFeed(feed)
if (feed.items != null) {
for (item in feed.items!!) {
if (feed.items.isNotEmpty()) {
for (item in feed.items) {
updateOrInsertFeedItem(item, false)
}
}
@ -546,8 +546,8 @@ class PodDBAdapter private constructor() {
fun removeFeed(feed: Feed) {
try {
db.beginTransactionNonExclusive()
if (feed.items != null) {
removeFeedItems(feed.items!!)
if (feed.items.isNotEmpty()) {
removeFeedItems(feed.items)
}
// delete download log entries for feed
db.delete(TABLE_NAME_DOWNLOAD_LOG, "$KEY_FEEDFILE=? AND $KEY_FEEDFILETYPE=?",
@ -1427,11 +1427,11 @@ class PodDBAdapter private constructor() {
@JvmStatic
@Synchronized
fun getInstance(): PodDBAdapter? {
fun getInstance(): PodDBAdapter {
if (instance == null) {
instance = PodDBAdapter()
}
return instance
return instance!!
}
/**
@ -1449,14 +1449,14 @@ class PodDBAdapter private constructor() {
@JvmStatic
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun tearDownTests() {
getInstance()!!.dbHelper.close()
getInstance().dbHelper.close()
instance = null
}
@JvmStatic
fun deleteDatabase(): Boolean {
val adapter = getInstance()
adapter!!.open()
adapter.open()
try {
for (tableName in ALL_TABLES) {
adapter.db.delete(tableName, "1", null)

View File

@ -172,7 +172,7 @@ object UserPreferences {
var hiddenDrawerItems: List<String?>?
get() {
val hiddenItems = prefs!!.getString(PREF_HIDDEN_DRAWER_ITEMS, "")
return ArrayList(Arrays.asList(*TextUtils.split(hiddenItems, ",")))
return ArrayList(listOf(*TextUtils.split(hiddenItems, ",")))
}
set(items) {
val str = TextUtils.join(",", items!!)
@ -186,7 +186,7 @@ object UserPreferences {
get() {
val buttons = TextUtils.split(
prefs!!.getString(PREF_FULL_NOTIFICATION_BUTTONS,
NOTIFICATION_BUTTON_SKIP.toString() + "," + NOTIFICATION_BUTTON_PLAYBACK_SPEED), ",")
"$NOTIFICATION_BUTTON_SKIP,$NOTIFICATION_BUTTON_PLAYBACK_SPEED"), ",")
val notificationButtons: MutableList<Int> = ArrayList()
for (button in buttons) {