Skip to main content

Overview

The episode management system allows you to organize and track your podcast listening experience. All episode states are persisted to localStorage, ensuring your preferences are saved across sessions.

Episode States

Each episode can be in one or more of the following states:
  • Started - Episodes you’ve begun listening to
  • Not Started - Episodes you haven’t played yet
  • Completed - Episodes you’ve finished listening to
  • Favorites - Episodes you’ve marked as favorites
  • Listen Later - Episodes saved for future listening

Managing Favorites

Adding to Favorites

Click the heart icon on any episode card or detail page to mark it as a favorite.
1

Find the Episode

Navigate to any episode card or detail page
2

Click Heart Icon

Click the heart outline icon (hollow heart)
3

Confirm

The heart fills in to confirm the episode is favorited

Implementation

The favorite toggle functionality is handled by Redux:
toggleFavorite: (state, action) => {
    const songTitle = action.payload.title;
    const isFavorite = state.favoriteEpisodes.includes(songTitle);

    if (isFavorite) {
        state.favoriteEpisodes = state.favoriteEpisodes.filter(
            (title) => title !== songTitle
        );
    } else {
        state.favoriteEpisodes.push(songTitle);
    }

    localStorage.setItem("nsnPodcastFavorites", JSON.stringify(state.favoriteEpisodes));
}
Favorites are stored in localStorage under the key nsnPodcastFavorites as a JSON array of episode titles.

Viewing Favorites

Filter to show only favorite episodes by clicking the heart icon in the filter bar on the main page.

Listen Later

Saving Episodes for Later

The Listen Later feature allows you to queue episodes you want to hear soon.
toggleListenLater: (state, action) => {
    const songTitle = action.payload.title;
    const isListenLater = state.listenLaterEpisodes.includes(songTitle);

    if (isListenLater) {
        state.listenLaterEpisodes = state.listenLaterEpisodes.filter(
            (title) => title !== songTitle
        );
    } else {
        state.listenLaterEpisodes.push(songTitle);
    }

    localStorage.setItem(
        "nsnPodcastListenLater",
        JSON.stringify(state.listenLaterEpisodes)
    );
}

Using Listen Later

1

Mark Episode

Click the clock icon on an episode card
2

Access Queue

Click the clock filter button to view all saved episodes
3

Start Listening

Play episodes from your Listen Later queue
4

Auto-Remove

Episodes can be manually removed by clicking the icon again
Use Listen Later to build a personalized queue of episodes you plan to hear soon, separate from your favorites.

Completion Tracking

Automatic Completion

Episodes are automatically marked as completed when:
  1. Playback reaches the end of the episode
  2. The handleEnded event fires
const handleEnded = () => {
    dispatch(updatePlaybackTime({ title: currentPodcast.title, time: 0 }));
    dispatch(markAsCompleted(currentPodcast.title));
};

Manual Completion

You can also manually mark episodes as completed:
const handleCompleteClick = () => {
    if (isCompleted) {
        dispatch(removeFromCompleted(podcast.title));
    } else {
        dispatch(markAsCompleted(podcast.title));
    }
};
You cannot manually mark an episode as completed while it’s currently playing. The button will be disabled during playback.

Completion State Management

markAsCompleted: (state, action) => {
    const songTitle = action.payload;
    if (!state.completedEpisodes.includes(songTitle)) {
        state.completedEpisodes.push(songTitle);
        localStorage.setItem(
            "nsnPodcastCompleted",
            JSON.stringify(state.completedEpisodes)
        );
    }
},
removeFromCompleted: (state, action) => {
    const songTitle = action.payload;
    state.completedEpisodes = state.completedEpisodes.filter(
        (title) => title !== songTitle
    );
    localStorage.setItem("nsnPodcastCompleted", JSON.stringify(state.completedEpisodes));
}

Progress Tracking

Started Episodes

Episodes automatically enter the “Started” state when:
  • You begin playback for the first time
  • Playback time is saved and greater than 0 seconds
const isStarted = playbackTimes[song.title] > 0;
const isCompleted = completedEpisodes.includes(song.title);

Visual Indicators

Episode cards display status with icons: Headphones Icon - Shows for started episodes with playback time:
{isStarted && !isCompleted && (
    <div className={styles.favoriteContainer}>
        <BootstrapTooltip
            title={
                <Typography style={{ fontSize: "14px", fontWeight: "bold", textAlign: "center" }}>
                    {`Empezado - ${formatTime(playbackTime)}`}
                    <br />
                    {!isPlaying && "Clic para eliminar el tiempo"}
                </Typography>
            }
            placement="top"
            arrow
        >
            <Headphones
                style={{ color: "#17D891", position: "absolute", top: "78px", right: "0px" }}
                onClick={(e) => handleRemoveStarted(title, e)}
            />
        </BootstrapTooltip>
    </div>
)}
Hover over the headphones icon to see the exact playback time where you left off.

Removing Progress

Clearing Playback Time

You can remove saved playback time to start an episode fresh:
const handleRemoveStarted = (title, e) => {
    e.stopPropagation();
    if (!isPlaying) {
        showConfirmToast(
            "¿Estás seguro de que quieres eliminar el tiempo de reproducción guardado?",
            () => {
                dispatch(deleteEpisode(title));
                dispatch(removePlaybackTime(title));
                toast.success("Tiempo de reproducción eliminado", {
                    position: isMobile ? "bottom-center" : "bottom-left",
                    style: {
                        backgroundColor: "rgba(33, 33, 33, 0.9)",
                        color: "#ffffff",
                        borderRadius: "8px",
                        padding: "10px",
                        boxShadow: "0px 4px 15px rgba(0, 0, 0, 0.2)"
                    }
                });
            }
        );
    }
};
You cannot remove playback time while an episode is currently playing. The action is blocked to prevent data inconsistency.

Bulk Operations

The Settings page provides bulk operations for episode management:

Clear All Favorites

clearFavorites: (state) => {
    state.favoriteEpisodes = [];
    localStorage.setItem("nsnPodcastFavorites", JSON.stringify([]));
}

Clear Listen Later Queue

clearListenLater: (state) => {
    state.listenLaterEpisodes = [];
    localStorage.setItem("nsnPodcastListenLater", JSON.stringify([]));
}

Clear Started Episodes

clearStarted: (state) => {
    state.listenedEpisodes = [];
    localStorage.setItem("nsnPodcastListened", JSON.stringify([]));
}

Clear Completed Episodes

clearCompleted: (state) => {
    state.completedEpisodes = [];
    localStorage.setItem("nsnPodcastCompleted", JSON.stringify([]));
}
Bulk clear operations cannot be undone. A confirmation dialog appears before executing these actions.

LocalStorage Keys

The application uses the following localStorage keys:
KeyPurposeFormat
nsnPodcastFavoritesFavorite episodesJSON array of titles
nsnPodcastListenLaterListen later queueJSON array of titles
nsnPodcastCompletedCompleted episodesJSON array of titles
nsnPodcastListenedListened episodesJSON array of titles
nsnPlayerVolumeVolume settingFloat (0-1)
nsnPlaybackTimesPlayback positionsJSON object (title: seconds)
All episode management features work offline and sync automatically across browser tabs on the same device.

Best Practices

1

Mark Favorites

Star episodes you loved to easily find them later
2

Use Listen Later

Queue up episodes when you discover them but aren’t ready to listen
3

Track Completion

Let episodes auto-complete or manually mark them to keep your library organized
4

Regular Cleanup

Periodically review and clear old entries from your lists

Build docs developers (and LLMs) love