mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-20 08:16:25 +00:00
refactor: clean up dead code and consolidate casting utilities
- Remove dead Chromecast files (ChromecastMiniPlayer, chromecast-player) - Remove dead AirPlay files (AirPlayMiniPlayer, airplay-player, useAirPlayPlayer) - Remove duplicate AirPlay utilities (options.ts, helpers.ts) - Consolidate unique Chromecast helpers into unified casting helpers - Add formatEpisodeInfo and shouldShowNextEpisodeCountdown - Update all imports to use unified casting utilities - Fix TypeScript errors: - Use correct MediaStatus properties (playerState vs isPaused/isBuffering) - Use getPlaystateApi from Jellyfin SDK - Use setStreamVolume for RemoteMediaClient - Fix calculateEndingTime signature - Fix segment auto-skip to use proper settings (skipIntro, skipOutro, etc) - Remove unused imports - Update ChromecastSettingsMenu to use unified types from casting/types.ts
This commit is contained in:
@@ -1,104 +0,0 @@
|
||||
/**
|
||||
* AirPlay Helper Functions
|
||||
* Utility functions for time formatting, quality checks, and data manipulation
|
||||
*/
|
||||
|
||||
import type { ConnectionQuality } from "./options";
|
||||
|
||||
/**
|
||||
* Format milliseconds to HH:MM:SS or MM:SS
|
||||
*/
|
||||
export const formatTime = (ms: number): string => {
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
||||
}
|
||||
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate ending time based on current progress and duration
|
||||
*/
|
||||
export const calculateEndingTime = (
|
||||
currentMs: number,
|
||||
durationMs: number,
|
||||
): string => {
|
||||
const remainingMs = durationMs - currentMs;
|
||||
const endTime = new Date(Date.now() + remainingMs);
|
||||
const hours = endTime.getHours();
|
||||
const minutes = endTime.getMinutes();
|
||||
const ampm = hours >= 12 ? "PM" : "AM";
|
||||
const displayHours = hours % 12 || 12;
|
||||
|
||||
return `${displayHours}:${minutes.toString().padStart(2, "0")} ${ampm}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine connection quality based on bitrate
|
||||
*/
|
||||
export const getConnectionQuality = (bitrate?: number): ConnectionQuality => {
|
||||
if (!bitrate) return "good";
|
||||
const mbps = bitrate / 1000000;
|
||||
|
||||
if (mbps >= 15) return "excellent";
|
||||
if (mbps >= 8) return "good";
|
||||
if (mbps >= 4) return "fair";
|
||||
return "poor";
|
||||
};
|
||||
|
||||
/**
|
||||
* Get poster URL for item with specified dimensions
|
||||
*/
|
||||
export const getPosterUrl = (
|
||||
baseUrl: string | undefined,
|
||||
itemId: string | undefined,
|
||||
tag: string | undefined,
|
||||
width: number,
|
||||
height: number,
|
||||
): string | null => {
|
||||
if (!baseUrl || !itemId) return null;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
maxWidth: width.toString(),
|
||||
maxHeight: height.toString(),
|
||||
quality: "90",
|
||||
...(tag && { tag }),
|
||||
});
|
||||
|
||||
return `${baseUrl}/Items/${itemId}/Images/Primary?${params.toString()}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Truncate title to max length with ellipsis
|
||||
*/
|
||||
export const truncateTitle = (title: string, maxLength: number): string => {
|
||||
if (title.length <= maxLength) return title;
|
||||
return `${title.substring(0, maxLength - 3)}...`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if current time is within a segment
|
||||
*/
|
||||
export const isWithinSegment = (
|
||||
currentMs: number,
|
||||
segment: { start: number; end: number } | null,
|
||||
): boolean => {
|
||||
if (!segment) return false;
|
||||
const currentSeconds = currentMs / 1000;
|
||||
return currentSeconds >= segment.start && currentSeconds <= segment.end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format bitrate to human-readable string
|
||||
*/
|
||||
export const formatBitrate = (bitrate: number): string => {
|
||||
const mbps = bitrate / 1000000;
|
||||
if (mbps >= 1) {
|
||||
return `${mbps.toFixed(1)} Mbps`;
|
||||
}
|
||||
return `${(bitrate / 1000).toFixed(0)} Kbps`;
|
||||
};
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* AirPlay Options and Types
|
||||
* Configuration constants and type definitions for AirPlay player
|
||||
*/
|
||||
|
||||
export interface AirPlayDevice {
|
||||
name: string;
|
||||
id: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface AirPlayPlayerState {
|
||||
isConnected: boolean;
|
||||
isPlaying: boolean;
|
||||
currentItem: any | null;
|
||||
currentDevice: AirPlayDevice | null;
|
||||
progress: number;
|
||||
duration: number;
|
||||
volume: number;
|
||||
showControls: boolean;
|
||||
}
|
||||
|
||||
export interface AirPlaySegmentData {
|
||||
intro: { start: number; end: number } | null;
|
||||
credits: { start: number; end: number } | null;
|
||||
recap: { start: number; end: number } | null;
|
||||
commercial: Array<{ start: number; end: number }>;
|
||||
preview: Array<{ start: number; end: number }>;
|
||||
}
|
||||
|
||||
export interface AudioTrack {
|
||||
index: number;
|
||||
language: string;
|
||||
codec: string;
|
||||
displayTitle: string;
|
||||
}
|
||||
|
||||
export interface SubtitleTrack {
|
||||
index: number;
|
||||
language: string;
|
||||
codec: string;
|
||||
displayTitle: string;
|
||||
isForced: boolean;
|
||||
}
|
||||
|
||||
export interface MediaSource {
|
||||
id: string;
|
||||
name: string;
|
||||
bitrate?: number;
|
||||
container: string;
|
||||
}
|
||||
|
||||
export const AIRPLAY_CONSTANTS = {
|
||||
POSTER_WIDTH: 300,
|
||||
POSTER_HEIGHT: 450,
|
||||
ANIMATION_DURATION: 300,
|
||||
CONTROL_HIDE_DELAY: 5000,
|
||||
PROGRESS_UPDATE_INTERVAL: 1000,
|
||||
SEEK_FORWARD_SECONDS: 10,
|
||||
SEEK_BACKWARD_SECONDS: 10,
|
||||
} as const;
|
||||
|
||||
export const DEFAULT_AIRPLAY_STATE: AirPlayPlayerState = {
|
||||
isConnected: false,
|
||||
isPlaying: false,
|
||||
currentItem: null,
|
||||
currentDevice: null,
|
||||
progress: 0,
|
||||
duration: 0,
|
||||
volume: 0.5,
|
||||
showControls: true,
|
||||
};
|
||||
|
||||
export type ConnectionQuality = "excellent" | "good" | "fair" | "poor";
|
||||
@@ -128,3 +128,35 @@ export const getProtocolIcon = (
|
||||
return "logo-apple";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Format episode info (e.g., "S1 E1" or "Episode 1")
|
||||
*/
|
||||
export const formatEpisodeInfo = (
|
||||
seasonNumber?: number | null,
|
||||
episodeNumber?: number | null,
|
||||
): string => {
|
||||
if (
|
||||
seasonNumber !== undefined &&
|
||||
seasonNumber !== null &&
|
||||
episodeNumber !== undefined &&
|
||||
episodeNumber !== null
|
||||
) {
|
||||
return `S${seasonNumber} E${episodeNumber}`;
|
||||
}
|
||||
if (episodeNumber !== undefined && episodeNumber !== null) {
|
||||
return `Episode ${episodeNumber}`;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if we should show next episode countdown
|
||||
*/
|
||||
export const shouldShowNextEpisodeCountdown = (
|
||||
remainingMs: number,
|
||||
hasNextEpisode: boolean,
|
||||
countdownStartSeconds: number,
|
||||
): boolean => {
|
||||
return hasNextEpisode && remainingMs <= countdownStartSeconds * 1000;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user