import { useTranslation } from "next-i18next";
import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
import { MdOutlineSmartDisplay } from "react-icons/md";
import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { getURLSearchParams } from "utils/proxy/api-helpers";
import useWidgetAPI from "utils/proxy/use-widget-api";
function ticksToTime(ticks) {
const milliseconds = ticks / 10000;
const seconds = Math.floor((milliseconds / 1000) % 60);
const minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
const hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);
return { hours, minutes, seconds };
}
function ticksToString(ticks) {
const { hours, minutes, seconds } = ticksToTime(ticks);
const parts = [];
if (hours > 0) {
parts.push(hours);
}
parts.push(minutes);
parts.push(seconds);
return parts.map((part) => part.toString().padStart(2, "0")).join(":");
}
function generateStreamTitle(session, enableUser, showEpisodeNumber) {
const {
NowPlayingItem: { Name, SeriesName, Type, ParentIndexNumber, IndexNumber },
UserName,
} = session;
let streamTitle = "";
if (Type === "Episode" && showEpisodeNumber) {
const seasonStr = ParentIndexNumber ? `S${ParentIndexNumber.toString().padStart(2, "0")}` : "";
const episodeStr = IndexNumber ? `E${IndexNumber.toString().padStart(2, "0")}` : "";
streamTitle = `${SeriesName}: ${seasonStr} ยท ${episodeStr} - ${Name}`;
} else {
streamTitle = `${Name}${SeriesName ? ` - ${SeriesName}` : ""}`;
}
return enableUser ? `${streamTitle} (${UserName})` : streamTitle;
}
function SingleSessionEntry({ playCommand, session, enableUser, showEpisodeNumber }) {
const {
PlayState: { PositionTicks, IsPaused, IsMuted },
} = session;
const RunTimeTicks =
session.NowPlayingItem?.RunTimeTicks ?? session.NowPlayingItem?.CurrentProgram?.RunTimeTicks ?? 0;
const { IsVideoDirect, VideoDecoderIsHardware, VideoEncoderIsHardware } = session?.TranscodingInfo || {
IsVideoDirect: true,
}; // if no transcodinginfo its videodirect
const percent = Math.min(1, PositionTicks / RunTimeTicks) * 100;
const streamTitle = generateStreamTitle(session, enableUser, showEpisodeNumber);
return (
<>
{IsVideoDirect && }
{!IsVideoDirect && (!VideoDecoderIsHardware || !VideoEncoderIsHardware) && }
{!IsVideoDirect && VideoDecoderIsHardware && VideoEncoderIsHardware && (
)}
{IsPaused && (
{
playCommand(session, "Unpause");
}}
className="inline-block w-4 h-4 cursor-pointer -mt-[1px] mr-1 opacity-80"
/>
)}
{!IsPaused && (
{
playCommand(session, "Pause");
}}
className="inline-block w-4 h-4 cursor-pointer -mt-[1px] mr-1 opacity-80"
/>
)}
{IsMuted && }
{ticksToString(PositionTicks)}
/
{ticksToString(RunTimeTicks)}
>
);
}
function SessionEntry({ playCommand, session, enableUser, showEpisodeNumber }) {
const {
PlayState: { PositionTicks, IsPaused, IsMuted },
} = session;
const RunTimeTicks =
session.NowPlayingItem?.RunTimeTicks ?? session.NowPlayingItem?.CurrentProgram?.RunTimeTicks ?? 0;
const { IsVideoDirect, VideoDecoderIsHardware, VideoEncoderIsHardware } = session?.TranscodingInfo || {
IsVideoDirect: true,
}; // if no transcodinginfo its videodirect
const streamTitle = generateStreamTitle(session, enableUser, showEpisodeNumber);
const percent = Math.min(1, PositionTicks / RunTimeTicks) * 100;
return (
{IsPaused && (
{
playCommand(session, "Unpause");
}}
className="inline-block w-4 h-4 cursor-pointer -mt-[1px] mr-1 opacity-80"
/>
)}
{!IsPaused && (
{
playCommand(session, "Pause");
}}
className="inline-block w-4 h-4 cursor-pointer -mt-[1px] mr-1 opacity-80"
/>
)}
{IsMuted && }
{ticksToString(PositionTicks)}
{IsVideoDirect && }
{!IsVideoDirect && (!VideoDecoderIsHardware || !VideoEncoderIsHardware) && }
{!IsVideoDirect && VideoDecoderIsHardware && VideoEncoderIsHardware && }
);
}
function CountBlocks({ service, countData }) {
const { t } = useTranslation();
// allows filtering
// eslint-disable-next-line no-param-reassign
if (service.widget?.type === "jellyfin") service.widget.type = "emby";
if (!countData) {
return (
);
}
return (
);
}
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const {
data: sessionsData,
error: sessionsError,
mutate: sessionMutate,
} = useWidgetAPI(widget, "Sessions", {
refreshInterval: 5000,
});
const { data: countData, error: countError } = useWidgetAPI(widget, "Count", {
refreshInterval: 60000,
});
async function handlePlayCommand(session, command) {
const params = getURLSearchParams(widget, command);
params.append(
"segments",
JSON.stringify({
sessionId: session.Id,
}),
);
const url = `/api/services/proxy?${params.toString()}`;
await fetch(url, {
method: "POST",
}).then(() => {
sessionMutate();
});
}
if (sessionsError || countError) {
return ;
}
const enableBlocks = service.widget?.enableBlocks;
const enableNowPlaying = service.widget?.enableNowPlaying ?? true;
const enableUser = !!service.widget?.enableUser; // default is false
const expandOneStreamToTwoRows = service.widget?.expandOneStreamToTwoRows !== false; // default is true
const showEpisodeNumber = !!service.widget?.showEpisodeNumber; // default is false
if (!sessionsData || !countData) {
return (
<>
{enableBlocks && }
{enableNowPlaying && (
-
{expandOneStreamToTwoRows && (
-
)}
)}
>
);
}
if (enableNowPlaying) {
const playing = sessionsData
.filter((session) => session?.NowPlayingItem)
.sort((a, b) => {
if (a.PlayState.PositionTicks > b.PlayState.PositionTicks) {
return 1;
}
if (a.PlayState.PositionTicks < b.PlayState.PositionTicks) {
return -1;
}
return 0;
});
if (playing.length === 0) {
return (
<>
{enableBlocks && }
{t("emby.no_active")}
{expandOneStreamToTwoRows && (
-
)}
>
);
}
if (expandOneStreamToTwoRows && playing.length === 1) {
const session = playing[0];
return (
<>
{enableBlocks && }
handlePlayCommand(currentSession, command)}
session={session}
enableUser={enableUser}
showEpisodeNumber={showEpisodeNumber}
/>
>
);
}
return (
<>
{enableBlocks && }
{playing.map((session) => (
handlePlayCommand(currentSession, command)}
session={session}
enableUser={enableUser}
showEpisodeNumber={showEpisodeNumber}
/>
))}
>
);
}
if (enableBlocks) {
return ;
}
}