forked from raycast/extensions
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update spanish-tv-guide extension (raycast#12728)
* Update spanish-tv-guide extension - Update changelog - Merge pull request #1 from doktor500/tv-guide-v2 - Formatting - Refactor - Imrpove markdown - Always display up to date channel schedule - Rename file - Rename to DTO - Bump dependencies - Fix imports - Fix time issue - Display if a program is live - Set selected program based on user interaction - Refactor types - Fix timezone issue - Move get program details to repository - Add maybe type - Rename property - Display program details - Fix lint - Optimise icon generation process - Extract toId function - Drop previous broadcasted programs when the list is too long - Fix flickering issue - Fix keys - Restructure directories - Refactor Channel details component - Refactor Channel component - Extract icon utils - Refactor channels component - Fix lint - Use navigation api - Selected channel view - Create all channels view - Use reducer - Remove type - Fix lint - Update raycast username - User friendly error handling - Set live stream icon - Bump dependencies - Wait for icons to be loaded - Fix metadata and readme - Update CHANGELOG.md - Fix lint - Cleanup - Update changelog - Extract constant - Bump dependencies - Resize icons - Optimize - Pull contributions - Remove live logic - Update demo.gif - Fix title - Add screenshot - Fix icon - Bump dependencies - Initial version * Update spanish-tv-guide extension - Fix lint issues - Renamet metadata directory to docs - Fix changelog typo - Update changelog date * Add eslint file * Downgrade eslint to 8.X
- Loading branch information
Showing
22 changed files
with
1,147 additions
and
747 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"root": true, | ||
"extends": ["@raycast"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 15 additions & 11 deletions
26
extensions/spanish-tv-guide/src/components/ChannelDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,34 @@ | ||
import { Fragment } from "react"; | ||
import { Color, Icon, List } from "@raycast/api"; | ||
|
||
import { ChannelSchedule } from "../modules/tv/domain/tvSchedule"; | ||
import { ChannelScheduleDto, ProgramDto } from "../modules/tv/domain/tvScheduleDto"; | ||
import { getTime } from "../utils/dateUtils"; | ||
|
||
const { Item } = List; | ||
|
||
const ChannelDetails = (channel: ChannelSchedule) => ( | ||
export const ChannelDetails = (channel: ChannelScheduleDto) => ( | ||
<Item.Detail | ||
metadata={ | ||
<Item.Detail.Metadata> | ||
<Item.Detail.Metadata.Label title={`${channel.name}`} icon={channel.icon} /> | ||
<Item.Detail.Metadata.Separator /> | ||
{channel.schedule.map((program, index) => ( | ||
<Fragment key={index}> | ||
<Item.Detail.Metadata.Label | ||
title={program.description} | ||
icon={program.live ? Icon.Livestream : ""} | ||
text={{ value: getTime(program.startTime), color: Color.SecondaryText }} | ||
/> | ||
<Item.Detail.Metadata.Separator /> | ||
</Fragment> | ||
<Program key={index} program={program} /> | ||
))} | ||
</Item.Detail.Metadata> | ||
} | ||
/> | ||
); | ||
|
||
export default ChannelDetails; | ||
const Program = ({ program }: { program: ProgramDto }) => { | ||
return ( | ||
<Fragment> | ||
<Item.Detail.Metadata.Label | ||
title={program.title} | ||
icon={program.isCurrentlyLive ? Icon.Clock : ""} | ||
text={{ value: getTime(program.startTime), color: Color.SecondaryText }} | ||
/> | ||
<Item.Detail.Metadata.Separator /> | ||
</Fragment> | ||
); | ||
}; |
61 changes: 61 additions & 0 deletions
61
extensions/spanish-tv-guide/src/components/ChannelList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React from "react"; | ||
import { Action, ActionPanel, List, useNavigation } from "@raycast/api"; | ||
|
||
import { State } from "../index"; | ||
import { ChannelScheduleDto, TvScheduleDto, upToDateChannelSchedule } from "../modules/tv/domain/tvScheduleDto"; | ||
import { ChannelDetails } from "./ChannelDetails"; | ||
import { SelectedChannel } from "./SelectedChannel"; | ||
import { iconPath } from "../utils/iconUtils"; | ||
import { isEmpty, isNull } from "../utils/objectUtils"; | ||
import { toId } from "../utils/stringUtils"; | ||
|
||
const SELECT_CHANNEL_ACTION = "Select Channel"; | ||
|
||
export const ChannelList = ({ state, setState }: { state: State; setState: React.Dispatch<Partial<State>> }) => { | ||
const { tvSchedule, selectedChannel } = state; | ||
|
||
const selectChannel = (channel: string | null) => { | ||
const selectedChannel = !isNull(channel); | ||
if (selectedChannel) setState({ selectedChannel: channel }); | ||
}; | ||
|
||
return ( | ||
<List | ||
selectedItemId={selectedChannel} | ||
isLoading={isEmpty(tvSchedule)} | ||
onSelectionChange={selectChannel} | ||
isShowingDetail={Boolean(state.selectedChannel)} | ||
> | ||
{tvSchedule.map((schedule) => ( | ||
<Channel key={schedule.name} tvSchedule={state.tvSchedule} channelSchedule={schedule} /> | ||
))} | ||
</List> | ||
); | ||
}; | ||
|
||
const Channel = (props: { tvSchedule: TvScheduleDto; channelSchedule: ChannelScheduleDto }) => { | ||
const { push } = useNavigation(); | ||
const { icon, name, schedule } = props.channelSchedule; | ||
const selectedChannel = props.tvSchedule.find((channel) => channel.name === name); | ||
|
||
const Actions = () => ( | ||
<ActionPanel> | ||
<Action | ||
title={SELECT_CHANNEL_ACTION} | ||
icon={iconPath(icon)} | ||
onAction={() => selectedChannel && push(<SelectedChannel channel={selectedChannel} />)} | ||
/> | ||
</ActionPanel> | ||
); | ||
|
||
return ( | ||
<List.Item | ||
key={name} | ||
id={toId(name)} | ||
title={name} | ||
icon={iconPath(icon)} | ||
detail={<ChannelDetails name={name} schedule={upToDateChannelSchedule(schedule)} icon={icon} />} | ||
actions={<Actions />} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,9 @@ | ||
import { Detail } from "@raycast/api"; | ||
import { ERROR_MESSAGE } from "../index"; | ||
|
||
const ErrorMessage = () => <Detail markdown={formattedError(ERROR_MESSAGE)} />; | ||
export const ERROR_MESSAGE = "Error fetching TV guide"; | ||
export const ErrorMessage = () => <Detail markdown={formattedError(ERROR_MESSAGE)} />; | ||
|
||
const formattedError = (error: string) => ` | ||
| ❗ | | ||
| :----------------: | | ||
| ${error} |`; | ||
|
||
export default ErrorMessage; |
63 changes: 63 additions & 0 deletions
63
extensions/spanish-tv-guide/src/components/SelectedChannel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React, { useState } from "react"; | ||
import { Action, ActionPanel, Icon, List, useNavigation } from "@raycast/api"; | ||
|
||
import { ChannelScheduleDto, ProgramDto, upToDateChannelSchedule } from "../modules/tv/domain/tvScheduleDto"; | ||
import { getTime } from "../utils/dateUtils"; | ||
import { iconPath } from "../utils/iconUtils"; | ||
import { SelectedProgram } from "./SelectedProgram"; | ||
|
||
type ProgramProps = { | ||
channel: ChannelScheduleDto; | ||
program: ProgramDto; | ||
index: number; | ||
onSelect: (index: number) => void; | ||
}; | ||
|
||
const SELECT_PROGRAM_ACTION = "Select Program"; | ||
|
||
export const SelectedChannel = ({ channel }: { channel: ChannelScheduleDto }) => { | ||
const schedule = upToDateChannelSchedule(channel.schedule); | ||
const currentLiveProgram = schedule.findIndex((program) => program.isCurrentlyLive); | ||
const [selectedProgramIndex, setSelectedProgramIndex] = useState<number>(currentLiveProgram); | ||
|
||
return ( | ||
<List selectedItemId={selectedProgramIndex.toString()} navigationTitle={channel.name}> | ||
<List.Section key={`channel-${channel.name}`}> | ||
<List.Item key={channel.name} title={`${channel.name}`} icon={iconPath(channel.icon)} /> | ||
</List.Section> | ||
<List.Section key={`schedule-${channel.name}`}> | ||
{schedule.map((program, index) => ( | ||
<Program key={index} channel={channel} program={program} index={index} onSelect={setSelectedProgramIndex} /> | ||
))} | ||
</List.Section> | ||
</List> | ||
); | ||
}; | ||
|
||
const Program = ({ channel, program, index, onSelect: setSelectedProgramIndex }: ProgramProps) => { | ||
const { push } = useNavigation(); | ||
|
||
const Actions = () => ( | ||
<ActionPanel> | ||
<Action | ||
title={SELECT_PROGRAM_ACTION} | ||
icon={iconPath(channel.icon)} | ||
onAction={() => { | ||
setSelectedProgramIndex(index); | ||
push(<SelectedProgram channel={channel} program={program} />); | ||
}} | ||
/> | ||
</ActionPanel> | ||
); | ||
|
||
return ( | ||
<List.Item | ||
key={index} | ||
id={index.toString()} | ||
title={`${getTime(program.startTime)} - ${program.title}`} | ||
icon={program.isCurrentlyLive ? Icon.Clock : ""} | ||
accessories={[{ icon: program.isLive ? Icon.Livestream : "" }]} | ||
actions={<Actions />} | ||
/> | ||
); | ||
}; |
39 changes: 39 additions & 0 deletions
39
extensions/spanish-tv-guide/src/components/SelectedProgram.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import { Detail } from "@raycast/api"; | ||
|
||
import { tvScheduleRepository } from "../modules/tv/repositories/tvScheduleRepository"; | ||
import { ChannelScheduleDto, ProgramDto, ProgramDetailsDto } from "../modules/tv/domain/tvScheduleDto"; | ||
import { getTime } from "../utils/dateUtils"; | ||
import { Maybe } from "../utils/objectUtils"; | ||
|
||
export const SelectedProgram = ({ channel, program }: { channel: ChannelScheduleDto; program: ProgramDto }) => { | ||
const [programDetails, setProgramDetails] = useState<Maybe<ProgramDetailsDto>>(); | ||
|
||
useEffect(() => void tvScheduleRepository.getProgramDetails(program).then(setProgramDetails), [program]); | ||
|
||
return ( | ||
programDetails && ( | ||
<Detail | ||
navigationTitle={channel.name} | ||
markdown={formattedProgramDetails(programDetails)} | ||
isLoading={!programDetails} | ||
metadata={ | ||
<Detail.Metadata> | ||
<Detail.Metadata.Label title={channel.name} icon={channel.icon} /> | ||
<Detail.Metadata.Label title={program.title} /> | ||
</Detail.Metadata> | ||
} | ||
/> | ||
) | ||
); | ||
}; | ||
|
||
const formattedProgramDetails = ({ title, startTime, image, description }: ProgramDetailsDto) => ` | ||
### ${getTime(startTime)} ${title} | ||
--- | ||
${description} | ||
 | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,37 @@ | ||
import { List, showToast, Toast } from "@raycast/api"; | ||
import { useEffect, useState } from "react"; | ||
import Jimp from "jimp"; | ||
import { showToast, Toast } from "@raycast/api"; | ||
import React, { useEffect, useReducer } from "react"; | ||
|
||
import { ChannelSchedule, TVSchedule } from "./modules/tv/domain/tvSchedule"; | ||
import ChannelDetails from "./components/ChannelDetails"; | ||
import { TvScheduleDto } from "./modules/tv/domain/tvScheduleDto"; | ||
import { tvScheduleRepository } from "./modules/tv/repositories/tvScheduleRepository"; | ||
import { isEmpty, isNull } from "./utils/objectUtils"; | ||
import ErrorMessage from "./components/ErrorMessage"; | ||
import { ERROR_MESSAGE, ErrorMessage } from "./components/ErrorMessage"; | ||
import { ChannelList } from "./components/ChannelList"; | ||
import { generateIcon } from "./utils/iconUtils"; | ||
|
||
export type State = { | ||
tvSchedule: TvScheduleDto; | ||
selectedChannel?: string; | ||
error?: Error; | ||
}; | ||
|
||
const ICONS_DIRECTORY = "/tmp/raycast/spanish-tv-guide/icons"; | ||
export const ERROR_MESSAGE = "Error fetching TV guide"; | ||
const initialState: State = { tvSchedule: [] }; | ||
const reducer = (state: State, newState: Partial<State>) => ({ ...state, ...newState }); | ||
|
||
const Command = () => { | ||
const [tvSchedule, setTvSchedule] = useState<TVSchedule>([]); | ||
const [isShowingDetail, setIsShowingDetail] = useState(false); | ||
const [iconsLoaded, setIconsLoaded] = useState(false); | ||
const [error, setError] = useState<Error | undefined>(); | ||
const [selectedChannel, setSelectedChannel] = useState<string | undefined>(); | ||
|
||
useEffect(() => void tvScheduleRepository.getAll().then(setTvSchedule).catch(setError), []); | ||
useEffect(() => void generateIcons(tvSchedule).then(() => setIconsLoaded(true)), [tvSchedule]); | ||
useEffect(() => error && void showToast({ style: Toast.Style.Failure, title: ERROR_MESSAGE }), [error]); | ||
|
||
const selectChannel = (channel: string | null) => { | ||
const channelSelected = !isNull(channel); | ||
if (channelSelected) setSelectedChannel(channel); | ||
setIsShowingDetail(channelSelected); | ||
const [state, setState] = useReducer(reducer, initialState); | ||
|
||
const initialize = async () => { | ||
return tvScheduleRepository | ||
.getAll() | ||
.then((tvSchedule) => cacheIcons(tvSchedule).then(() => setState({ tvSchedule }))) | ||
.catch((error) => setState({ error })); | ||
}; | ||
|
||
if (error) return <ErrorMessage />; | ||
|
||
return ( | ||
<List | ||
isLoading={isEmpty(tvSchedule) || !iconsLoaded} | ||
selectedItemId={selectedChannel} | ||
isShowingDetail={isShowingDetail} | ||
onSelectionChange={selectChannel} | ||
> | ||
{tvSchedule.map(renderChannel)} | ||
</List> | ||
); | ||
}; | ||
useEffect(() => void initialize(), []); | ||
useEffect(() => state.error && void showToast({ style: Toast.Style.Failure, title: ERROR_MESSAGE }), [state.error]); | ||
|
||
const renderChannel = ({ icon, name, schedule }: ChannelSchedule) => { | ||
const detail = <ChannelDetails name={name} schedule={schedule} icon={icon} />; | ||
return <List.Item key={name} title={name} detail={detail} icon={iconPath(icon)} />; | ||
return state.error ? <ErrorMessage /> : <ChannelList state={state} setState={setState} />; | ||
}; | ||
|
||
const generateIcons = (tvSchedule: TVSchedule) => Promise.all(tvSchedule.map(({ icon }) => generateIcon(icon))); | ||
const generateIcon = (icon: string) => Jimp.read(icon).then((image) => image.contain(256, 256).write(iconPath(icon))); | ||
const iconPath = (icon: string) => `${ICONS_DIRECTORY}/${iconName(icon)}`; | ||
const iconName = (icon: string) => icon.substring(icon.lastIndexOf("/") + 1); | ||
const cacheIcons = (tvSchedule: TvScheduleDto) => Promise.all(tvSchedule.map(({ icon }) => generateIcon(icon))); | ||
|
||
export default Command; |
13 changes: 0 additions & 13 deletions
13
extensions/spanish-tv-guide/src/modules/tv/domain/tvSchedule.ts
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.