search page added
This commit is contained in:
parent
eafdfe3f2b
commit
c33e446352
130
dialpods/App.tsx
130
dialpods/App.tsx
@ -5,6 +5,7 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {PropsWithChildren} from 'react';
|
import type {PropsWithChildren} from 'react';
|
||||||
import {
|
import {
|
||||||
@ -25,6 +26,14 @@ import {
|
|||||||
ReloadInstructions,
|
ReloadInstructions,
|
||||||
} from 'react-native/Libraries/NewAppScreen';
|
} from 'react-native/Libraries/NewAppScreen';
|
||||||
|
|
||||||
|
import McIcon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
import Fa6 from 'react-native-vector-icons/FontAwesome6';
|
||||||
|
import {NavigationContainer} from '@react-navigation/native';
|
||||||
|
|
||||||
|
// pages
|
||||||
|
import SearchPage from './pages/Search.tsx';
|
||||||
|
// <pages
|
||||||
|
|
||||||
type SectionProps = PropsWithChildren<{
|
type SectionProps = PropsWithChildren<{
|
||||||
title: string;
|
title: string;
|
||||||
}>;
|
}>;
|
||||||
@ -63,38 +72,51 @@ function App(): React.JSX.Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={backgroundStyle}>
|
<NavigationContainer>
|
||||||
<StatusBar
|
<SearchPage />
|
||||||
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
|
</NavigationContainer>
|
||||||
backgroundColor={backgroundStyle.backgroundColor}
|
|
||||||
/>
|
|
||||||
<ScrollView
|
|
||||||
contentInsetAdjustmentBehavior="automatic"
|
|
||||||
style={backgroundStyle}>
|
|
||||||
<Header />
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
backgroundColor: isDarkMode ? Colors.black : Colors.white,
|
|
||||||
}}>
|
|
||||||
<Section title="Step One">
|
|
||||||
Edit <Text style={styles.highlight}>App.tsx</Text> to change this
|
|
||||||
screen and then come back to see your edits.
|
|
||||||
</Section>
|
|
||||||
<Section title="See Your Changes">
|
|
||||||
<ReloadInstructions />
|
|
||||||
</Section>
|
|
||||||
<Section title="Debug">
|
|
||||||
<DebugInstructions />
|
|
||||||
</Section>
|
|
||||||
<Section title="Learn More">
|
|
||||||
Read the docs to discover what to do next:
|
|
||||||
</Section>
|
|
||||||
<LearnMoreLinks />
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// function App(): React.JSX.Element {
|
||||||
|
// const isDarkMode = useColorScheme() === 'dark';
|
||||||
|
|
||||||
|
// const backgroundStyle = {
|
||||||
|
// backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <SafeAreaView style={backgroundStyle}>
|
||||||
|
// <StatusBar
|
||||||
|
// barStyle={isDarkMode ? 'light-content' : 'dark-content'}
|
||||||
|
// backgroundColor={backgroundStyle.backgroundColor}
|
||||||
|
// />
|
||||||
|
// <ScrollView
|
||||||
|
// contentInsetAdjustmentBehavior="automatic"
|
||||||
|
// style={backgroundStyle}>
|
||||||
|
// <Header />
|
||||||
|
// <View
|
||||||
|
// style={{
|
||||||
|
// backgroundColor: isDarkMode ? Colors.black : Colors.white,
|
||||||
|
// }}>
|
||||||
|
// <Section title="Step One">
|
||||||
|
// Edit <Text style={styles.highlight}>App.tsx</Text> to change this
|
||||||
|
// screen and then come back to see your edits.
|
||||||
|
// </Section>
|
||||||
|
// <Section title="See Your Changes">
|
||||||
|
// <ReloadInstructions />
|
||||||
|
// </Section>
|
||||||
|
// <Section title="Debug">
|
||||||
|
// <DebugInstructions />
|
||||||
|
// </Section>
|
||||||
|
// <Section title="Learn More">
|
||||||
|
// Read the docs to discover what to do next:
|
||||||
|
// </Section>
|
||||||
|
// <LearnMoreLinks />
|
||||||
|
// </View>
|
||||||
|
// </ScrollView>
|
||||||
|
// </SafeAreaView>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
sectionContainer: {
|
sectionContainer: {
|
||||||
@ -116,3 +138,51 @@ const styles = StyleSheet.create({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
||||||
|
function TabNav() {
|
||||||
|
const Footer = createBottomTabNavigator();
|
||||||
|
return (
|
||||||
|
<Footer.Navigator>
|
||||||
|
<Footer.Screen
|
||||||
|
name="Home"
|
||||||
|
component={Home}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused, color, size}) => {
|
||||||
|
if (focused) return <McIcon name="home" size={30} />;
|
||||||
|
else return <McIcon name="home-outline" size={30} />;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Footer.Screen
|
||||||
|
name="Search"
|
||||||
|
component={Search}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused, color, size}) => {
|
||||||
|
if (focused) return <McIcon name="search-web" size={30} />;
|
||||||
|
else return <McIcon name="search-web" size={30} />;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Footer.Screen
|
||||||
|
name="Library"
|
||||||
|
component={Library}
|
||||||
|
options={{
|
||||||
|
tabBarIcon: ({focused, color, size}) => {
|
||||||
|
if (focused) return <McIcon name="rss-box" size={30} />;
|
||||||
|
else return <McIcon name="rss" size={30} />;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Footer.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Home() {
|
||||||
|
return <Text>Hi</Text>;
|
||||||
|
}
|
||||||
|
function Search() {
|
||||||
|
return <Text>Search</Text>;
|
||||||
|
}
|
||||||
|
function Library() {
|
||||||
|
return <Text>Library</Text>;
|
||||||
|
}
|
||||||
|
0
dialpods/logic/constants.ts
Normal file
0
dialpods/logic/constants.ts
Normal file
49
dialpods/logic/store.ts
Normal file
49
dialpods/logic/store.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import {create} from 'zustand';
|
||||||
|
import {createJSONStorage, persist} from 'zustand/middleware';
|
||||||
|
import {useShallow} from 'zustand/shallow';
|
||||||
|
import type {Podcasts} from './types/types';
|
||||||
|
|
||||||
|
interface UIState {
|
||||||
|
subs: Podcasts;
|
||||||
|
}
|
||||||
|
type ProcessState = {subs: Podcasts};
|
||||||
|
type WsMessage =
|
||||||
|
| {kind: 'error'; data: string}
|
||||||
|
| {
|
||||||
|
kind: 'state';
|
||||||
|
data: ProcessState;
|
||||||
|
};
|
||||||
|
// | {
|
||||||
|
// kind: 'post';
|
||||||
|
// data: Post['data'];
|
||||||
|
// stream_name: string;
|
||||||
|
// post_id: string;
|
||||||
|
// }
|
||||||
|
// | {
|
||||||
|
// kind: 'image';
|
||||||
|
// data: {
|
||||||
|
// image: string;
|
||||||
|
// uri: string;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// | {
|
||||||
|
// kind: 'profile';
|
||||||
|
// data: CuratorProfileInfo;
|
||||||
|
// };
|
||||||
|
const storeInner = create<UIState>()(
|
||||||
|
// persist(
|
||||||
|
(set, get) => ({
|
||||||
|
subs: {},
|
||||||
|
}),
|
||||||
|
// {
|
||||||
|
// name: 'dial_pods_store',
|
||||||
|
// storage: createJSONStorage(() => sessionStorage),
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
);
|
||||||
|
|
||||||
|
const useUIStore = <T extends (state: UIState) => any>(
|
||||||
|
selector: T,
|
||||||
|
): ReturnType<T> => storeInner(useShallow(selector));
|
||||||
|
|
||||||
|
export default useUIStore;
|
62
dialpods/logic/types/types.ts
Normal file
62
dialpods/logic/types/types.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
export type AsyncRes<T> = Promise<Result<T>>;
|
||||||
|
export type Result<T> = {ok: T} | {error: string};
|
||||||
|
|
||||||
|
export type Podcasts = Record<string, Podcast>;
|
||||||
|
export type Ack = null;
|
||||||
|
export type Podcast = SearchResult;
|
||||||
|
|
||||||
|
export type SearchResult = {image: string; name: string; url: string};
|
||||||
|
|
||||||
|
export type YoutubeChannel = {
|
||||||
|
channel: {
|
||||||
|
author: string;
|
||||||
|
authorUrl: string;
|
||||||
|
channelId: string;
|
||||||
|
published: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
entries: YoutubeItem[];
|
||||||
|
};
|
||||||
|
export type YoutubeItem = {
|
||||||
|
id: string;
|
||||||
|
videoId: string;
|
||||||
|
title: string;
|
||||||
|
published: string;
|
||||||
|
updated: string;
|
||||||
|
link: string;
|
||||||
|
thumbnail: string;
|
||||||
|
description: string;
|
||||||
|
views: number;
|
||||||
|
rating: {
|
||||||
|
count: number;
|
||||||
|
average: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type RSSFeed = {
|
||||||
|
podcast: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
link: string;
|
||||||
|
copyright: string;
|
||||||
|
language: string;
|
||||||
|
lastBuildDate?: string;
|
||||||
|
author: string;
|
||||||
|
type: string;
|
||||||
|
image: string;
|
||||||
|
// categories: Array<{ text: string; subcategories: string[] }>;
|
||||||
|
// podcastGuid: string;
|
||||||
|
};
|
||||||
|
episodes: RSSFeedItem[];
|
||||||
|
};
|
||||||
|
// TODO deal with CData encoding
|
||||||
|
export type RSSFeedItem = {
|
||||||
|
title: string;
|
||||||
|
link: string;
|
||||||
|
guid: {value: string; isPermaLink: boolean};
|
||||||
|
pubDate: string;
|
||||||
|
// author: string;
|
||||||
|
description: string;
|
||||||
|
// content: string;
|
||||||
|
enclosure: {url: string; length: number; type: string};
|
||||||
|
// podcastInfo: { season: string; episode: string };
|
||||||
|
};
|
336
dialpods/logic/utils.ts
Normal file
336
dialpods/logic/utils.ts
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
import {Result, RSSFeed, SearchResult, YoutubeChannel} from './types/types';
|
||||||
|
import DOMparser from 'react-native-html-parser';
|
||||||
|
|
||||||
|
export async function parseHTMLRes(htmls: string) {
|
||||||
|
const parser = new DOMparser.DOMParser();
|
||||||
|
const html = parser.parseFromString(htmls, 'text/html');
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
export function parseYoutubeChannel(
|
||||||
|
head: HTMLHeadElement,
|
||||||
|
): Result<SearchResult> {
|
||||||
|
const linkEl = head.querySelector('link[type="application/rss+xml"]');
|
||||||
|
if (!linkEl) return {error: `not found`};
|
||||||
|
const url = linkEl!.getAttribute('href');
|
||||||
|
if (!url) return {error: `not found`};
|
||||||
|
const og = head.querySelectorAll('meta');
|
||||||
|
let image = '';
|
||||||
|
let name = '';
|
||||||
|
for (const meta of og) {
|
||||||
|
if (image && name) break;
|
||||||
|
const n = meta.getAttribute('property');
|
||||||
|
if (n === 'og:image') image = meta.getAttribute('content')!;
|
||||||
|
if (n === 'og:title') name = meta.getAttribute('content')!;
|
||||||
|
}
|
||||||
|
if (image && name && url) return {ok: {image, name, url}};
|
||||||
|
else return {error: 'not found'};
|
||||||
|
}
|
||||||
|
export async function parseXMLRes(s: string) {
|
||||||
|
const parser = new DOMparser.DOMParser();
|
||||||
|
const xml = parser.parseFromString(s, 'text/xml');
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseRSSFeed(url: string, doc: Document): Result<SearchResult> {
|
||||||
|
const chan = doc.getElementsByTagName('channel')[0];
|
||||||
|
const title = chan.getElementsByTagName('title')[0];
|
||||||
|
const image = chan.getElementsByTagName('image')[0];
|
||||||
|
const imageURL = image.getElementsByTagName('url')[0];
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
ok: {
|
||||||
|
name: title.textContent!,
|
||||||
|
image: imageURL.textContent!,
|
||||||
|
url,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (_) {
|
||||||
|
return {error: 'not found'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const namespaces: any = {
|
||||||
|
itunes: 'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||||
|
podcast: 'https://podcastindex.org/namespace/1.0',
|
||||||
|
content: 'http://purl.org/rss/1.0/modules/content/',
|
||||||
|
dc: 'http://purl.org/dc/elements/1.1/',
|
||||||
|
atom: 'http://www.w3.org/2005/Atom',
|
||||||
|
podaccess: 'https://access.acast.com/schema/1.0',
|
||||||
|
media: 'http://search.yahoo.com/mrss/',
|
||||||
|
};
|
||||||
|
export function parseRSSFull(url: string, doc: Document): Result<RSSFeed> {
|
||||||
|
try {
|
||||||
|
// Helper function to get namespaced elements
|
||||||
|
const getNS = (element: Element, namespace: string, tagName: string) =>
|
||||||
|
element.getElementsByTagNameNS(namespaces[namespace], tagName)[0];
|
||||||
|
|
||||||
|
// Parse channel (podcast) information
|
||||||
|
const channel = doc.getElementsByTagName('channel')[0];
|
||||||
|
const podcastInfo = {
|
||||||
|
title: channel.getElementsByTagName('title')[0].textContent || '',
|
||||||
|
description:
|
||||||
|
channel.getElementsByTagName('description')[0].textContent || '',
|
||||||
|
link: channel.getElementsByTagName('link')[0].textContent || '',
|
||||||
|
copyright: channel.getElementsByTagName('copyright')[0].textContent || '',
|
||||||
|
language: channel.getElementsByTagName('language')[0].textContent || '',
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// lastBuildDate:
|
||||||
|
// channel.getElementsByTagName('lastBuildDate')[0],
|
||||||
|
// ),
|
||||||
|
|
||||||
|
// iTunes specific fields
|
||||||
|
author: getNS(channel, 'itunes', 'author').textContent || '',
|
||||||
|
type: getNS(channel, 'itunes', 'type').textContent || '',
|
||||||
|
// owner: {
|
||||||
|
// name:
|
||||||
|
// getNS(channel, 'itunes', 'owner')?.getElementsByTagNameNS(
|
||||||
|
// namespaces.itunes,
|
||||||
|
// 'name',
|
||||||
|
// )[0],
|
||||||
|
// ),
|
||||||
|
// email:
|
||||||
|
// getNS(channel, 'itunes', 'owner')?.getElementsByTagNameNS(
|
||||||
|
// namespaces.itunes,
|
||||||
|
// 'email',
|
||||||
|
// )[0],
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
image:
|
||||||
|
channel.getElementsByTagName('image')[0]?.getElementsByTagName('url')[0]
|
||||||
|
?.textContent || '',
|
||||||
|
|
||||||
|
// image: {
|
||||||
|
// url: channel
|
||||||
|
// .getElementsByTagName('image')[0]
|
||||||
|
// ?.getElementsByTagName('url')[0]?.textContent,
|
||||||
|
// itunesUrl: getNS(channel, 'itunes', 'image')?.getAttribute('href'),
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Categories
|
||||||
|
categories: Array.from(
|
||||||
|
channel.getElementsByTagNameNS(namespaces.itunes, 'category'),
|
||||||
|
).map(category => ({
|
||||||
|
text: category.getAttribute('text') || '',
|
||||||
|
subcategories: Array.from(
|
||||||
|
category.getElementsByTagNameNS(namespaces.itunes, 'category'),
|
||||||
|
).map(sub => sub.getAttribute('text') || ''),
|
||||||
|
})),
|
||||||
|
|
||||||
|
// Podcast namespace specific fields
|
||||||
|
// podcastGuid: getNS(channel, 'podcast', 'guid')),
|
||||||
|
// hosts: Array.from(
|
||||||
|
// channel.getElementsByTagNameNS(namespaces.podcast, 'person'),
|
||||||
|
// )
|
||||||
|
// .filter((person) => person.getAttribute('role') === 'Host')
|
||||||
|
// .map((person) => ({
|
||||||
|
// name: person.textContent,
|
||||||
|
// role: person.getAttribute('role'),
|
||||||
|
// img: person.getAttribute('img'),
|
||||||
|
// href: person.getAttribute('href'),
|
||||||
|
// })),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse episodes
|
||||||
|
const episodes = Array.from(doc.getElementsByTagName('item')).map(item => {
|
||||||
|
// Get episode images
|
||||||
|
const itunesImage = getNS(item, 'itunes', 'image');
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: item.getElementsByTagName('title')[0].textContent || '',
|
||||||
|
link: item.getElementsByTagName('link')[0].textContent || '',
|
||||||
|
guid: {
|
||||||
|
value: item.getElementsByTagName('guid')[0].textContent || '',
|
||||||
|
isPermaLink:
|
||||||
|
item
|
||||||
|
.getElementsByTagName('guid')[0]
|
||||||
|
?.getAttribute('isPermaLink') === 'true',
|
||||||
|
},
|
||||||
|
pubDate: item.getElementsByTagName('pubDate')[0].textContent || '',
|
||||||
|
|
||||||
|
// author: item.getElementsByTagName('author')[0],
|
||||||
|
|
||||||
|
// Episode content
|
||||||
|
description:
|
||||||
|
item.getElementsByTagName('description')[0].textContent || '',
|
||||||
|
|
||||||
|
// content:
|
||||||
|
// getNS(item, 'content', 'encoded'),
|
||||||
|
// )?.trim(),
|
||||||
|
|
||||||
|
// Media information
|
||||||
|
enclosure: {
|
||||||
|
url: item.getElementsByTagName('enclosure')[0]?.getAttribute('url')!,
|
||||||
|
length: parseInt(
|
||||||
|
item.getElementsByTagName('enclosure')[0]?.getAttribute('length')!,
|
||||||
|
),
|
||||||
|
type: item
|
||||||
|
.getElementsByTagName('enclosure')[0]
|
||||||
|
?.getAttribute('type')!,
|
||||||
|
},
|
||||||
|
|
||||||
|
// iTunes specific episode fields
|
||||||
|
// itunesInfo: {
|
||||||
|
// episode: getNS(item, 'itunes', 'episode')),
|
||||||
|
// season: getNS(item, 'itunes', 'season')),
|
||||||
|
// duration: getNS(item, 'itunes', 'duration')),
|
||||||
|
// explicit: getNS(item, 'itunes', 'explicit')),
|
||||||
|
// episodeType:
|
||||||
|
// getNS(item, 'itunes', 'episodeType'),
|
||||||
|
// ),
|
||||||
|
// image: itunesImage
|
||||||
|
// ? itunesImage.getAttribute('href')
|
||||||
|
// : null,
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Podcast namespace fields
|
||||||
|
// podcastInfo: {
|
||||||
|
// season: getNS(item, 'podcast', 'season')),
|
||||||
|
// episode: getNS(item, 'podcast', 'episode')),
|
||||||
|
// hosts: Array.from(
|
||||||
|
// item.getElementsByTagNameNS(
|
||||||
|
// namespaces.podcast,
|
||||||
|
// 'person',
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// .filter(
|
||||||
|
// (person) => person.getAttribute('role') === 'Host',
|
||||||
|
// )
|
||||||
|
// .map((person) => ({
|
||||||
|
// name: person.textContent,
|
||||||
|
// role: person.getAttribute('role'),
|
||||||
|
// img: person.getAttribute('img'),
|
||||||
|
// href: person.getAttribute('href'),
|
||||||
|
// })),
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: {
|
||||||
|
podcast: podcastInfo,
|
||||||
|
episodes,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {error: 'error parsing feed'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseYTFeed(doc: Document): Result<YoutubeChannel> {
|
||||||
|
// Create parser and parse XML string
|
||||||
|
// Define namespaces used in the document
|
||||||
|
const namespaces = {
|
||||||
|
media: 'http://search.yahoo.com/mrss/',
|
||||||
|
yt: 'http://www.youtube.com/xml/schemas/2015',
|
||||||
|
atom: 'http://www.w3.org/2005/Atom',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to safely get text content
|
||||||
|
const getTextContent = (element: Element) => element.textContent!;
|
||||||
|
|
||||||
|
// Parse each entry
|
||||||
|
const entries = Array.from(doc.getElementsByTagName('entry')).map(entry => {
|
||||||
|
// Get media:group element
|
||||||
|
const mediaGroup = entry.getElementsByTagNameNS(
|
||||||
|
namespaces.media,
|
||||||
|
'group',
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
// Get statistics and rating from media:community
|
||||||
|
const mediaCommunity = mediaGroup.getElementsByTagNameNS(
|
||||||
|
namespaces.media,
|
||||||
|
'community',
|
||||||
|
)[0];
|
||||||
|
const statistics = mediaCommunity.getElementsByTagNameNS(
|
||||||
|
namespaces.media,
|
||||||
|
'statistics',
|
||||||
|
)[0];
|
||||||
|
const starRating = mediaCommunity.getElementsByTagNameNS(
|
||||||
|
namespaces.media,
|
||||||
|
'starRating',
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: getTextContent(entry.getElementsByTagName('id')[0]),
|
||||||
|
videoId: getTextContent(
|
||||||
|
entry.getElementsByTagNameNS(namespaces.yt, 'videoId')[0],
|
||||||
|
),
|
||||||
|
title: getTextContent(entry.getElementsByTagName('title')[0]),
|
||||||
|
published: getTextContent(entry.getElementsByTagName('published')[0]),
|
||||||
|
updated: getTextContent(entry.getElementsByTagName('updated')[0]),
|
||||||
|
link: entry.getElementsByTagName('link')[0]?.getAttribute('href')!,
|
||||||
|
|
||||||
|
// Media group information
|
||||||
|
thumbnail: mediaGroup
|
||||||
|
.getElementsByTagNameNS(namespaces.media, 'thumbnail')[0]
|
||||||
|
?.getAttribute('url')!,
|
||||||
|
description: getTextContent(
|
||||||
|
mediaGroup.getElementsByTagNameNS(namespaces.media, 'description')[0],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Statistics
|
||||||
|
views: parseInt(statistics?.getAttribute('views') || '0'),
|
||||||
|
rating: {
|
||||||
|
count: parseInt(starRating?.getAttribute('count') || '0'),
|
||||||
|
average: parseFloat(starRating?.getAttribute('average') || '0'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get channel information
|
||||||
|
const channelInfo = {
|
||||||
|
title: getTextContent(doc.getElementsByTagName('title')[0]),
|
||||||
|
channelId: getTextContent(
|
||||||
|
doc.getElementsByTagNameNS(namespaces.yt, 'channelId')[0],
|
||||||
|
),
|
||||||
|
published: getTextContent(doc.getElementsByTagName('published')[0]),
|
||||||
|
author: getTextContent(doc.getElementsByTagName('name')[0]),
|
||||||
|
authorUrl: getTextContent(doc.getElementsByTagName('uri')[0]),
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: {
|
||||||
|
channel: channelInfo,
|
||||||
|
entries: entries,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function abbreviate(s: string, length: number): string {
|
||||||
|
if (s.length <= length) return s;
|
||||||
|
else return s.substring(0, length) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function date_diff(date: Date) {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const s = now - date.getTime();
|
||||||
|
if (s < 60) {
|
||||||
|
return 'now';
|
||||||
|
} else if (s < 3600) {
|
||||||
|
return `${Math.ceil(s / 60)}minutes ago`;
|
||||||
|
} else if (s < 86400) {
|
||||||
|
return `${Math.ceil(s / 60 / 60)}hours ago`;
|
||||||
|
} else if (s < 32140800) {
|
||||||
|
return date.toLocaleString('default', {
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return date.toLocaleString('default', {
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function durationString(secs: number): string {
|
||||||
|
const hours = Math.floor(secs / 3600);
|
||||||
|
const minutes = Math.floor((secs % 3600) / 60);
|
||||||
|
const seconds = Math.floor(secs % 60);
|
||||||
|
return hours > 0
|
||||||
|
? `${hours}:${minutes.toString().padStart(2, '0')}:${seconds
|
||||||
|
.toString()
|
||||||
|
.padStart(2, '0')}`
|
||||||
|
: `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
||||||
|
}
|
464
dialpods/package-lock.json
generated
464
dialpods/package-lock.json
generated
@ -8,8 +8,18 @@
|
|||||||
"name": "dialpods",
|
"name": "dialpods",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-navigation/bottom-tabs": "^7.1.3",
|
||||||
|
"@react-navigation/native": "^7.0.13",
|
||||||
|
"@react-navigation/native-stack": "^7.1.14",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-native": "0.76.4"
|
"react-native": "0.76.4",
|
||||||
|
"react-native-fast-image": "^8.6.3",
|
||||||
|
"react-native-html-parser": "^0.1.0",
|
||||||
|
"react-native-safe-area-context": "^5.0.0",
|
||||||
|
"react-native-screens": "^4.3.0",
|
||||||
|
"react-native-url-polyfill": "^2.0.0",
|
||||||
|
"react-native-vector-icons": "^10.2.0",
|
||||||
|
"zustand": "^5.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
@ -23,6 +33,7 @@
|
|||||||
"@react-native/metro-config": "0.76.4",
|
"@react-native/metro-config": "0.76.4",
|
||||||
"@react-native/typescript-config": "0.76.4",
|
"@react-native/typescript-config": "0.76.4",
|
||||||
"@types/react": "^18.2.6",
|
"@types/react": "^18.2.6",
|
||||||
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
"@types/react-test-renderer": "^18.0.0",
|
"@types/react-test-renderer": "^18.0.0",
|
||||||
"babel-jest": "^29.6.3",
|
"babel-jest": "^29.6.3",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
@ -3411,6 +3422,111 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-navigation/bottom-tabs": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-cK5zE7OpZAgZLpFBnoH9AhZbSZfH9Qavdi3kIRd2vpQDtCfnnG5bQ2eM2u/IKHDLdI50Mhsf+srqYJgG2VcmVQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/elements": "^2.2.4",
|
||||||
|
"color": "^4.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-navigation/native": "^7.0.13",
|
||||||
|
"react": ">= 18.2.0",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-safe-area-context": ">= 4.0.0",
|
||||||
|
"react-native-screens": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/core": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-mfUPRdFCuHkaC+uU5iczqevn0PCTKzf6ApxFwgG9E8DfAVbAT7/piZEzFye2inaIRkipBwyNW40h+mEvYqE1og==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/routers": "^7.1.1",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
"nanoid": "3.3.7",
|
||||||
|
"query-string": "^7.1.3",
|
||||||
|
"react-is": "^18.2.0",
|
||||||
|
"use-latest-callback": "^0.2.1",
|
||||||
|
"use-sync-external-store": "^1.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/core/node_modules/react-is": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/elements": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-/H6Gu/Hn2E/pBQTkZEMbP5SDi7C2q96PrHGvsDJiFtxFgOJusA3+ygUguqTeTP402s/5KvJm47g0UloCMiECwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color": "^4.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-native-masked-view/masked-view": ">= 0.2.0",
|
||||||
|
"@react-navigation/native": "^7.0.13",
|
||||||
|
"react": ">= 18.2.0",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-safe-area-context": ">= 4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@react-native-masked-view/masked-view": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/native": {
|
||||||
|
"version": "7.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.13.tgz",
|
||||||
|
"integrity": "sha512-HLoMyp453qIDGjG72cJ2xLeGHHpP4PQve5gQvSn3o/6r2+DAmDuIcd/jXTMJGCHd2LeR9LfuqIvpiIlihg1iBg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/core": "^7.3.0",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"nanoid": "3.3.7",
|
||||||
|
"use-latest-callback": "^0.2.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 18.2.0",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/native-stack": {
|
||||||
|
"version": "7.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.1.14.tgz",
|
||||||
|
"integrity": "sha512-MH3iktneSL8JSttcgJBIb6zmDpaurbtMSQcYwCcsGoyq4fJ2pBIwJaViSa0KrNkMsWAMZEOY9O72rf1umu7VKw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/elements": "^2.2.4",
|
||||||
|
"warn-once": "^0.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-navigation/native": "^7.0.13",
|
||||||
|
"react": ">= 18.2.0",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-safe-area-context": ">= 4.0.0",
|
||||||
|
"react-native-screens": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-navigation/routers": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-OycWRj95p+/zENl9HU6tvvT6IUuxgVJirgsA0W9rQn3RC+9Hb0UVYA0+8avdt+WpMoWdrvwTxTXneB5mjYzHrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "3.3.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sideway/address": {
|
"node_modules/@sideway/address": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
||||||
@ -3576,6 +3692,27 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-native": {
|
||||||
|
"version": "0.70.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.70.19.tgz",
|
||||||
|
"integrity": "sha512-c6WbyCgWTBgKKMESj/8b4w+zWcZSsCforson7UdXtXMecG3MxCinYi6ihhrHVPyUrVzORsvEzK8zg32z4pK6Sg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-native-vector-icons": {
|
||||||
|
"version": "6.4.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.18.tgz",
|
||||||
|
"integrity": "sha512-YGlNWb+k5laTBHd7+uZowB9DpIK3SXUneZqAiKQaj1jnJCZM0x71GDim5JCTMi4IFkhc9m8H/Gm28T5BjyivUw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-native": "^0.70"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-test-renderer": {
|
"node_modules/@types/react-test-renderer": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz",
|
||||||
@ -4477,7 +4614,6 @@
|
|||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
"devOptional": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -4829,6 +4965,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/color": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1",
|
||||||
|
"color-string": "^1.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@ -4847,6 +4996,16 @@
|
|||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/color-string": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "^1.0.0",
|
||||||
|
"simple-swizzle": "^0.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/colorette": {
|
"node_modules/colorette": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
|
||||||
@ -5165,6 +5324,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decode-uri-component": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dedent": {
|
"node_modules/dedent": {
|
||||||
"version": "1.5.3",
|
"version": "1.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
|
||||||
@ -6318,7 +6486,6 @@
|
|||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
@ -6431,6 +6598,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filter-obj": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
@ -7074,7 +7250,6 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
"devOptional": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -9826,6 +10001,24 @@
|
|||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
@ -9997,7 +10190,6 @@
|
|||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -10553,7 +10745,6 @@
|
|||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
@ -10565,14 +10756,12 @@
|
|||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@ -10595,6 +10784,24 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/query-string": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"decode-uri-component": "^0.2.2",
|
||||||
|
"filter-obj": "^1.1.0",
|
||||||
|
"split-on-first": "^1.0.0",
|
||||||
|
"strict-uri-encode": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue": {
|
"node_modules/queue": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
||||||
@ -10677,6 +10884,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-freeze": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@ -10745,6 +10964,126 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-fast-image": {
|
||||||
|
"version": "8.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz",
|
||||||
|
"integrity": "sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==",
|
||||||
|
"license": "(MIT AND Apache-2.0)",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^17 || ^18",
|
||||||
|
"react-native": ">=0.60.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-html-parser": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-html-parser/-/react-native-html-parser-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-G5d0pk7TA9YgjVJhLRf2zMOOf1HXd8ItM9JYsTS2pXoEfSRfMfRU5iTj03LGwvHU2NT9kc18NDJeLgZY6+Bbvg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-safe-area-context": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-4K4TvEbRsTDYuSSJZfMNKuJNn1+qgrSkOBwRoreiHcuqy1egrHpkhPhoN1Zg1+b3BxcVXlKXtMIf4eVaG/DPJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-screens": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-G0u8BPgu2vcRZoQTlRpBXKa0ElQSDvDBlRe6ncWwCeBmd5Uqa2I3tQ6Vn6trIE6+yneW/nD4p5wihEHlAWZPEw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-freeze": "^1.0.0",
|
||||||
|
"warn-once": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-url-polyfill": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-My330Do7/DvKnEvwQc0WdcBnFPploYKp9CYlefDXzIdEaA+PAhDYllkvGeEroEzvc4Kzzj2O4yVdz8v6fjRvhA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url-without-unicode": "8.0.0-3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-vector-icons": {
|
||||||
|
"version": "10.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
|
||||||
|
"integrity": "sha512-n5HGcxUuVaTf9QJPs/W22xQpC2Z9u0nb0KgLPnVltP8vdUvOp6+R26gF55kilP/fV4eL4vsAHUqUjewppJMBOQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"yargs": "^16.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"fa-upgrade.sh": "bin/fa-upgrade.sh",
|
||||||
|
"fa5-upgrade": "bin/fa5-upgrade.sh",
|
||||||
|
"fa6-upgrade": "bin/fa6-upgrade.sh",
|
||||||
|
"generate-icon": "bin/generate-icon.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-vector-icons/node_modules/cliui": {
|
||||||
|
"version": "7.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
|
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-vector-icons/node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-vector-icons/node_modules/yargs": {
|
||||||
|
"version": "16.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||||
|
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^7.0.2",
|
||||||
|
"escalade": "^3.1.1",
|
||||||
|
"get-caller-file": "^2.0.5",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"y18n": "^5.0.5",
|
||||||
|
"yargs-parser": "^20.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-vector-icons/node_modules/yargs-parser": {
|
||||||
|
"version": "20.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||||
|
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native/node_modules/ansi-styles": {
|
"node_modules/react-native/node_modules/ansi-styles": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||||
@ -11454,6 +11793,21 @@
|
|||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-swizzle": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arrayish": "^0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/simple-swizzle/node_modules/is-arrayish": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@ -11535,6 +11889,15 @@
|
|||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/split-on-first": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sprintf-js": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
@ -11598,6 +11961,15 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strict-uri-encode": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
@ -12337,6 +12709,24 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-latest-callback": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
@ -12392,6 +12782,12 @@
|
|||||||
"makeerror": "1.0.12"
|
"makeerror": "1.0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/warn-once": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/wcwidth": {
|
"node_modules/wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
@ -12424,6 +12820,29 @@
|
|||||||
"webidl-conversions": "^3.0.0"
|
"webidl-conversions": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/whatwg-url-without-unicode": {
|
||||||
|
"version": "8.0.0-3",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
|
||||||
|
"integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "^5.4.3",
|
||||||
|
"punycode": "^2.1.1",
|
||||||
|
"webidl-conversions": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
@ -12676,6 +13095,35 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zustand": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-8qNdnJVJlHlrKXi50LDqqUNmUbuBjoKLrYQBnoChIbVph7vni+sY+YpvdjXG9YLd/Bxr6scMcR+rm5H3aSqPaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": ">=18.0.0",
|
||||||
|
"immer": ">=9.0.6",
|
||||||
|
"react": ">=18.0.0",
|
||||||
|
"use-sync-external-store": ">=1.2.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"immer": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"use-sync-external-store": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,18 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-navigation/bottom-tabs": "^7.1.3",
|
||||||
|
"@react-navigation/native": "^7.0.13",
|
||||||
|
"@react-navigation/native-stack": "^7.1.14",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-native": "0.76.4"
|
"react-native": "0.76.4",
|
||||||
|
"react-native-fast-image": "^8.6.3",
|
||||||
|
"react-native-html-parser": "^0.1.0",
|
||||||
|
"react-native-safe-area-context": "^5.0.0",
|
||||||
|
"react-native-screens": "^4.3.0",
|
||||||
|
"react-native-url-polyfill": "^2.0.0",
|
||||||
|
"react-native-vector-icons": "^10.2.0",
|
||||||
|
"zustand": "^5.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
@ -25,6 +35,7 @@
|
|||||||
"@react-native/metro-config": "0.76.4",
|
"@react-native/metro-config": "0.76.4",
|
||||||
"@react-native/typescript-config": "0.76.4",
|
"@react-native/typescript-config": "0.76.4",
|
||||||
"@types/react": "^18.2.6",
|
"@types/react": "^18.2.6",
|
||||||
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
"@types/react-test-renderer": "^18.0.0",
|
"@types/react-test-renderer": "^18.0.0",
|
||||||
"babel-jest": "^29.6.3",
|
"babel-jest": "^29.6.3",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
@ -36,4 +47,4 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0
dialpods/pages/Feed.tsx
Normal file
0
dialpods/pages/Feed.tsx
Normal file
0
dialpods/pages/Home.tsx
Normal file
0
dialpods/pages/Home.tsx
Normal file
0
dialpods/pages/Library.tsx
Normal file
0
dialpods/pages/Library.tsx
Normal file
0
dialpods/pages/Player.tsx
Normal file
0
dialpods/pages/Player.tsx
Normal file
211
dialpods/pages/Search.tsx
Normal file
211
dialpods/pages/Search.tsx
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
Image,
|
||||||
|
TouchableOpacity,
|
||||||
|
StyleSheet,
|
||||||
|
ActivityIndicator,
|
||||||
|
ScrollView,
|
||||||
|
} from 'react-native';
|
||||||
|
// import { corsProxy, saveFeed } from '../logic/api';
|
||||||
|
import {
|
||||||
|
parseHTMLRes,
|
||||||
|
parseRSSFeed,
|
||||||
|
parseXMLRes,
|
||||||
|
parseYoutubeChannel,
|
||||||
|
} from '../logic/utils';
|
||||||
|
import useUIStore from '../logic/store';
|
||||||
|
import type {SearchResult} from '../logic/types/types';
|
||||||
|
import {Button} from 'react-native';
|
||||||
|
|
||||||
|
function SearchScreen() {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [input, setInput] = useState('https://www.youtube.com/@bookclubradio');
|
||||||
|
const [results, setResults] = useState<SearchResult[]>([]);
|
||||||
|
|
||||||
|
console.log('search page loaded');
|
||||||
|
function handleButton() {
|
||||||
|
// handleURL(url);
|
||||||
|
console.log('button pressed', input);
|
||||||
|
const url = new URL(input);
|
||||||
|
console.log('got url', url);
|
||||||
|
handleYouTube(input);
|
||||||
|
}
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log('hi!!', input);
|
||||||
|
// if (!input) setResults([]);
|
||||||
|
// if (input.length > 2)
|
||||||
|
// try {
|
||||||
|
// } catch (_) {
|
||||||
|
// handleSearch(input);
|
||||||
|
// }
|
||||||
|
// }, [input]);
|
||||||
|
|
||||||
|
async function handleURL(url: URL) {
|
||||||
|
console.log('handling url');
|
||||||
|
// if (url.hostname.endsWith('youtube.com')) handleYouTube(url);
|
||||||
|
// else handleRSS(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleYouTube(url: string) {
|
||||||
|
console.log('handling youtube', url);
|
||||||
|
// if (!url.search) {
|
||||||
|
// const res = await corsProxy(url);
|
||||||
|
console.log('fetching', url);
|
||||||
|
const res = await fetch(url);
|
||||||
|
console.log('youtube response', res);
|
||||||
|
const txt = await res.text();
|
||||||
|
console.log('youtube text', txt);
|
||||||
|
const doc = await parseHTMLRes(txt);
|
||||||
|
console.log('doc', doc);
|
||||||
|
console.log('head', doc.head);
|
||||||
|
const mparsed = parseYoutubeChannel(doc.head);
|
||||||
|
console.log(mparsed, 'mparsed');
|
||||||
|
// if ('error' in mparsed) handleError(url.toString(), mparsed.error);
|
||||||
|
// else setResults(r => [...r, mparsed.ok]);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleRSS(url: URL) {
|
||||||
|
// const res = await corsProxy(url);
|
||||||
|
// const res = await fetch(url);
|
||||||
|
// if (!('ok' in res)) return handleError(url.toString(), 'error fetching');
|
||||||
|
// const s = res.ok;
|
||||||
|
// if (!('HTML' in s)) return handleError('', '');
|
||||||
|
// const doc = await parseXMLRes(s.HTML);
|
||||||
|
// try {
|
||||||
|
// const mparsed = parseRSSFeed(url.toString(), doc);
|
||||||
|
// if ('error' in mparsed) handleError(url.toString(), mparsed.error);
|
||||||
|
// else setResults(r => [...r, mparsed.ok]);
|
||||||
|
// } catch (e) {
|
||||||
|
// console.log('wtf happened', e);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSearch(input: string) {
|
||||||
|
setLoading(true);
|
||||||
|
console.log('searching', input);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError(source: string, error: string) {
|
||||||
|
const alert = {message: `${error}: ${source}`, timeout: 2000};
|
||||||
|
// setAlert(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
// resync();
|
||||||
|
setResults([]);
|
||||||
|
setInput('');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.navbar}>
|
||||||
|
<Text style={styles.navbarText}>Search</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<ScrollView style={styles.resultContainer}>
|
||||||
|
{results.map((result, index) => (
|
||||||
|
<SearchResultItem key={index} {...result} close={close} />
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<View style={styles.searchBar}>
|
||||||
|
<TextInput
|
||||||
|
style={styles.input}
|
||||||
|
placeholder="Search pod"
|
||||||
|
value={input}
|
||||||
|
onChangeText={setInput}
|
||||||
|
placeholderTextColor="#666"
|
||||||
|
/>
|
||||||
|
{loading && <ActivityIndicator color="#f97316" />}
|
||||||
|
</View>
|
||||||
|
<Button title="hi" onPress={handleButton} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SearchResultItem({
|
||||||
|
image,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
close,
|
||||||
|
}: SearchResult & {close: () => void}) {
|
||||||
|
async function save() {
|
||||||
|
// const r2 = await saveFeed({image, name, url});
|
||||||
|
// if ('ok' in r2) close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.resultItem}>
|
||||||
|
<Image source={{uri: image}} style={styles.resultImage} />
|
||||||
|
<Text style={styles.resultName}>{name}</Text>
|
||||||
|
<TouchableOpacity style={styles.saveButton} onPress={save}>
|
||||||
|
<Text style={styles.saveButtonText}>Save</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
},
|
||||||
|
navbar: {
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#e5e5e5',
|
||||||
|
},
|
||||||
|
navbarText: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
resultContainer: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
searchBar: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 16,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: 'black',
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
flex: 1,
|
||||||
|
height: 40,
|
||||||
|
marginRight: 8,
|
||||||
|
padding: 8,
|
||||||
|
color: 'black',
|
||||||
|
},
|
||||||
|
resultItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 24,
|
||||||
|
backgroundColor: '#d4d4d4',
|
||||||
|
marginBottom: 1,
|
||||||
|
},
|
||||||
|
resultImage: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
resultName: {
|
||||||
|
flex: 1,
|
||||||
|
color: 'black',
|
||||||
|
},
|
||||||
|
saveButton: {
|
||||||
|
backgroundColor: '#f97316',
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
saveButtonText: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default SearchScreen;
|
0
dialpods/pages/Settings.tsx
Normal file
0
dialpods/pages/Settings.tsx
Normal file
0
dialpods/pages/YTChannel.tsx
Normal file
0
dialpods/pages/YTChannel.tsx
Normal file
4
dialpods/src
Normal file
4
dialpods/src
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module 'react-native-html-parser' {
|
||||||
|
const content: any;
|
||||||
|
export default content;
|
||||||
|
}
|
@ -1,3 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "@react-native/typescript-config/tsconfig.json"
|
"extends": "@react-native/typescript-config/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user