4, partial 5
This commit is contained in:
65
src/types/auth.ts
Normal file
65
src/types/auth.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Authentication types for PodTUI
|
||||
* Authentication is optional and disabled by default
|
||||
*/
|
||||
|
||||
/** User profile information */
|
||||
export interface User {
|
||||
id: string
|
||||
email: string
|
||||
name: string
|
||||
createdAt: Date
|
||||
lastLoginAt?: Date
|
||||
syncEnabled: boolean
|
||||
}
|
||||
|
||||
/** Authentication state */
|
||||
export interface AuthState {
|
||||
user: User | null
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
error: AuthError | null
|
||||
}
|
||||
|
||||
/** Authentication error */
|
||||
export interface AuthError {
|
||||
code: AuthErrorCode
|
||||
message: string
|
||||
}
|
||||
|
||||
/** Error codes for authentication */
|
||||
export enum AuthErrorCode {
|
||||
INVALID_CREDENTIALS = "INVALID_CREDENTIALS",
|
||||
INVALID_CODE = "INVALID_CODE",
|
||||
CODE_EXPIRED = "CODE_EXPIRED",
|
||||
NETWORK_ERROR = "NETWORK_ERROR",
|
||||
UNKNOWN_ERROR = "UNKNOWN_ERROR",
|
||||
}
|
||||
|
||||
/** Login credentials */
|
||||
export interface LoginCredentials {
|
||||
email: string
|
||||
password: string
|
||||
}
|
||||
|
||||
/** Code validation request */
|
||||
export interface CodeValidationRequest {
|
||||
code: string
|
||||
}
|
||||
|
||||
/** OAuth provider types */
|
||||
export enum OAuthProvider {
|
||||
GOOGLE = "google",
|
||||
APPLE = "apple",
|
||||
}
|
||||
|
||||
/** OAuth provider configuration */
|
||||
export interface OAuthProviderConfig {
|
||||
id: OAuthProvider
|
||||
name: string
|
||||
enabled: boolean
|
||||
description: string
|
||||
}
|
||||
|
||||
/** Auth screen types for navigation */
|
||||
export type AuthScreen = "login" | "code" | "oauth" | "profile"
|
||||
86
src/types/episode.ts
Normal file
86
src/types/episode.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Episode type definitions for PodTUI
|
||||
*/
|
||||
|
||||
/** Episode playback status */
|
||||
export enum EpisodeStatus {
|
||||
NOT_STARTED = "not_started",
|
||||
PLAYING = "playing",
|
||||
PAUSED = "paused",
|
||||
COMPLETED = "completed",
|
||||
}
|
||||
|
||||
/** Core episode information */
|
||||
export interface Episode {
|
||||
/** Unique identifier */
|
||||
id: string
|
||||
/** Parent podcast ID */
|
||||
podcastId: string
|
||||
/** Episode title */
|
||||
title: string
|
||||
/** Episode description/show notes */
|
||||
description: string
|
||||
/** Audio file URL */
|
||||
audioUrl: string
|
||||
/** Duration in seconds */
|
||||
duration: number
|
||||
/** Publication date */
|
||||
pubDate: Date
|
||||
/** Episode number (if available) */
|
||||
episodeNumber?: number
|
||||
/** Season number (if available) */
|
||||
seasonNumber?: number
|
||||
/** Episode type (full, trailer, bonus) */
|
||||
episodeType?: EpisodeType
|
||||
/** Whether episode is explicit */
|
||||
explicit?: boolean
|
||||
/** Episode image URL (if different from podcast) */
|
||||
imageUrl?: string
|
||||
/** File size in bytes */
|
||||
fileSize?: number
|
||||
/** MIME type */
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
/** Episode type enumeration */
|
||||
export enum EpisodeType {
|
||||
FULL = "full",
|
||||
TRAILER = "trailer",
|
||||
BONUS = "bonus",
|
||||
}
|
||||
|
||||
/** Episode playback progress */
|
||||
export interface Progress {
|
||||
/** Episode ID */
|
||||
episodeId: string
|
||||
/** Current position in seconds */
|
||||
position: number
|
||||
/** Total duration in seconds */
|
||||
duration: number
|
||||
/** Last played timestamp */
|
||||
timestamp: Date
|
||||
/** Playback speed (1.0 = normal) */
|
||||
playbackSpeed?: number
|
||||
}
|
||||
|
||||
/** Episode with playback state */
|
||||
export interface EpisodeWithProgress extends Episode {
|
||||
/** Current playback status */
|
||||
status: EpisodeStatus
|
||||
/** Playback progress */
|
||||
progress?: Progress
|
||||
}
|
||||
|
||||
/** Episode list item for display */
|
||||
export interface EpisodeListItem {
|
||||
/** Episode data */
|
||||
episode: Episode
|
||||
/** Podcast title (for display in feeds) */
|
||||
podcastTitle: string
|
||||
/** Podcast cover URL */
|
||||
podcastCoverUrl?: string
|
||||
/** Current status */
|
||||
status: EpisodeStatus
|
||||
/** Progress percentage (0-100) */
|
||||
progressPercent: number
|
||||
}
|
||||
116
src/types/feed.ts
Normal file
116
src/types/feed.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Feed type definitions for PodTUI
|
||||
*/
|
||||
|
||||
import type { Podcast } from "./podcast"
|
||||
import type { Episode, EpisodeStatus } from "./episode"
|
||||
|
||||
/** Feed visibility */
|
||||
export enum FeedVisibility {
|
||||
PUBLIC = "public",
|
||||
PRIVATE = "private",
|
||||
}
|
||||
|
||||
/** Feed information */
|
||||
export interface Feed {
|
||||
/** Unique identifier */
|
||||
id: string
|
||||
/** Associated podcast */
|
||||
podcast: Podcast
|
||||
/** Episodes in this feed */
|
||||
episodes: Episode[]
|
||||
/** Whether feed is public or private */
|
||||
visibility: FeedVisibility
|
||||
/** Source ID that provided this feed */
|
||||
sourceId: string
|
||||
/** Last updated timestamp */
|
||||
lastUpdated: Date
|
||||
/** Custom feed name (user-defined) */
|
||||
customName?: string
|
||||
/** User notes about this feed */
|
||||
notes?: string
|
||||
/** Whether feed is pinned/favorited */
|
||||
isPinned: boolean
|
||||
/** Feed color for UI */
|
||||
color?: string
|
||||
}
|
||||
|
||||
/** Feed item for display in lists */
|
||||
export interface FeedItem {
|
||||
/** Episode data */
|
||||
episode: Episode
|
||||
/** Parent podcast */
|
||||
podcast: Podcast
|
||||
/** Feed ID */
|
||||
feedId: string
|
||||
/** Episode status */
|
||||
status: EpisodeStatus
|
||||
/** Progress percentage (0-100) */
|
||||
progressPercent: number
|
||||
/** Whether this item is new (unplayed) */
|
||||
isNew: boolean
|
||||
}
|
||||
|
||||
/** Feed filter options */
|
||||
export interface FeedFilter {
|
||||
/** Filter by visibility */
|
||||
visibility?: FeedVisibility | "all"
|
||||
/** Filter by source ID */
|
||||
sourceId?: string
|
||||
/** Filter by pinned status */
|
||||
pinnedOnly?: boolean
|
||||
/** Search query for filtering */
|
||||
searchQuery?: string
|
||||
/** Sort field */
|
||||
sortBy?: FeedSortField
|
||||
/** Sort direction */
|
||||
sortDirection?: "asc" | "desc"
|
||||
}
|
||||
|
||||
/** Feed sort fields */
|
||||
export enum FeedSortField {
|
||||
/** Sort by last updated */
|
||||
UPDATED = "updated",
|
||||
/** Sort by title */
|
||||
TITLE = "title",
|
||||
/** Sort by episode count */
|
||||
EPISODE_COUNT = "episodeCount",
|
||||
/** Sort by most recent episode */
|
||||
LATEST_EPISODE = "latestEpisode",
|
||||
}
|
||||
|
||||
/** Feed list display options */
|
||||
export interface FeedListOptions {
|
||||
/** Show episode count */
|
||||
showEpisodeCount: boolean
|
||||
/** Show last updated */
|
||||
showLastUpdated: boolean
|
||||
/** Show source indicator */
|
||||
showSource: boolean
|
||||
/** Compact mode */
|
||||
compact: boolean
|
||||
}
|
||||
|
||||
/** Default feed list options */
|
||||
export const DEFAULT_FEED_LIST_OPTIONS: FeedListOptions = {
|
||||
showEpisodeCount: true,
|
||||
showLastUpdated: true,
|
||||
showSource: false,
|
||||
compact: false,
|
||||
}
|
||||
|
||||
/** Feed statistics */
|
||||
export interface FeedStats {
|
||||
/** Total feed count */
|
||||
totalFeeds: number
|
||||
/** Public feed count */
|
||||
publicFeeds: number
|
||||
/** Private feed count */
|
||||
privateFeeds: number
|
||||
/** Total episode count across all feeds */
|
||||
totalEpisodes: number
|
||||
/** Unplayed episode count */
|
||||
unplayedEpisodes: number
|
||||
/** In-progress episode count */
|
||||
inProgressEpisodes: number
|
||||
}
|
||||
40
src/types/podcast.ts
Normal file
40
src/types/podcast.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Podcast type definitions for PodTUI
|
||||
*/
|
||||
|
||||
/** Core podcast information */
|
||||
export interface Podcast {
|
||||
/** Unique identifier */
|
||||
id: string
|
||||
/** Podcast title */
|
||||
title: string
|
||||
/** Podcast description/summary */
|
||||
description: string
|
||||
/** Cover image URL */
|
||||
coverUrl?: string
|
||||
/** RSS feed URL */
|
||||
feedUrl: string
|
||||
/** Author/creator name */
|
||||
author?: string
|
||||
/** Podcast categories */
|
||||
categories?: string[]
|
||||
/** Language code (e.g., 'en', 'es') */
|
||||
language?: string
|
||||
/** Website URL */
|
||||
websiteUrl?: string
|
||||
/** Last updated timestamp */
|
||||
lastUpdated: Date
|
||||
/** Whether the podcast is currently subscribed */
|
||||
isSubscribed: boolean
|
||||
}
|
||||
|
||||
/** Podcast with episodes included */
|
||||
export interface PodcastWithEpisodes extends Podcast {
|
||||
/** List of episodes */
|
||||
episodes: Episode[]
|
||||
/** Total episode count */
|
||||
totalEpisodes: number
|
||||
}
|
||||
|
||||
/** Episode import - needed for PodcastWithEpisodes */
|
||||
import type { Episode } from "./episode"
|
||||
103
src/types/source.ts
Normal file
103
src/types/source.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Podcast source type definitions for PodTUI
|
||||
*/
|
||||
|
||||
/** Source type enumeration */
|
||||
export enum SourceType {
|
||||
/** RSS feed URL */
|
||||
RSS = "rss",
|
||||
/** API-based source (iTunes, Spotify, etc.) */
|
||||
API = "api",
|
||||
/** Custom/user-defined source */
|
||||
CUSTOM = "custom",
|
||||
}
|
||||
|
||||
/** Podcast source configuration */
|
||||
export interface PodcastSource {
|
||||
/** Unique identifier */
|
||||
id: string
|
||||
/** Source display name */
|
||||
name: string
|
||||
/** Source type */
|
||||
type: SourceType
|
||||
/** Base URL for the source */
|
||||
baseUrl: string
|
||||
/** API key (if required) */
|
||||
apiKey?: string
|
||||
/** Whether source is enabled */
|
||||
enabled: boolean
|
||||
/** Source icon/logo URL */
|
||||
iconUrl?: string
|
||||
/** Source description */
|
||||
description?: string
|
||||
/** Rate limit (requests per minute) */
|
||||
rateLimit?: number
|
||||
/** Last successful fetch */
|
||||
lastFetch?: Date
|
||||
}
|
||||
|
||||
/** Search query configuration */
|
||||
export interface SearchQuery {
|
||||
/** Search query text */
|
||||
query: string
|
||||
/** Source IDs to search (empty = all enabled sources) */
|
||||
sourceIds: string[]
|
||||
/** Optional filters */
|
||||
filters?: SearchFilters
|
||||
}
|
||||
|
||||
/** Search filters */
|
||||
export interface SearchFilters {
|
||||
/** Filter by language */
|
||||
language?: string
|
||||
/** Filter by category */
|
||||
category?: string
|
||||
/** Filter by explicit content */
|
||||
explicit?: boolean
|
||||
/** Sort by field */
|
||||
sortBy?: SearchSortField
|
||||
/** Sort direction */
|
||||
sortDirection?: "asc" | "desc"
|
||||
/** Results limit */
|
||||
limit?: number
|
||||
/** Results offset for pagination */
|
||||
offset?: number
|
||||
}
|
||||
|
||||
/** Search sort fields */
|
||||
export enum SearchSortField {
|
||||
RELEVANCE = "relevance",
|
||||
DATE = "date",
|
||||
TITLE = "title",
|
||||
POPULARITY = "popularity",
|
||||
}
|
||||
|
||||
/** Search result */
|
||||
export interface SearchResult {
|
||||
/** Source that returned this result */
|
||||
sourceId: string
|
||||
/** Podcast data */
|
||||
podcast: import("./podcast").Podcast
|
||||
/** Relevance score (0-1) */
|
||||
score?: number
|
||||
}
|
||||
|
||||
/** Default podcast sources */
|
||||
export const DEFAULT_SOURCES: PodcastSource[] = [
|
||||
{
|
||||
id: "itunes",
|
||||
name: "Apple Podcasts",
|
||||
type: SourceType.API,
|
||||
baseUrl: "https://itunes.apple.com/search",
|
||||
enabled: true,
|
||||
description: "Search the Apple Podcasts directory",
|
||||
},
|
||||
{
|
||||
id: "rss",
|
||||
name: "RSS Feed",
|
||||
type: SourceType.RSS,
|
||||
baseUrl: "",
|
||||
enabled: true,
|
||||
description: "Add podcasts via RSS feed URL",
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user