Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
17338c1
Feat(schemas): Update function schemas
parkcoool Nov 20, 2025
a2b40fa
Feat(schemas): Remove `lyricsProviders` field in track documents
parkcoool Nov 20, 2025
987cadf
Feat(func): Implement `getDetail`
parkcoool Nov 20, 2025
d323fad
Feat(func): Implement `getLyrics`
parkcoool Nov 20, 2025
b3af68a
Chore(func): Remove unused files
parkcoool Nov 20, 2025
3eed487
Feat(func): Implement `getTrackFromId`
parkcoool Nov 21, 2025
868ce6f
Feat(func): Implement `getTrackFromId`
parkcoool Nov 21, 2025
987ecc9
Merge branch 'refactor/simplify-fetch' of https://github.com/parkcooo…
parkcoool Nov 22, 2025
4bbb386
Chore(func): Rename `getTrackFromId.ts` to `getTrackFromId.flow.ts`
parkcoool Nov 22, 2025
57de265
Refactor(func): Adjust step order of `getDetail` flow
parkcoool Nov 22, 2025
cf1ecee
Chore(func): Delete unused files
parkcoool Nov 22, 2025
8fd737b
Feat(func): Implement `getTrackFromMetadataFlow` flow
parkcoool Nov 22, 2025
fcdf974
Feat(func): Add secret bindings to handlers
parkcoool Nov 22, 2025
01b7bbc
Refactor(func): Rename duration field from `durationMs` to `durationI…
parkcoool Nov 22, 2025
e128024
Fix(Func): Complete `getTrackFromMetadataFlow`
parkcoool Nov 22, 2025
7f4b721
Fix(func): Correct error logging message in `getTrackFromIdFlow`
parkcoool Nov 22, 2025
e524dfd
Feat(func): Add external ID retrieval in `searchSpotify`
parkcoool Nov 22, 2025
28d0ca6
Refactor(func): Update `streamLyricsAndTrackDetail` to yield chunks
parkcoool Nov 22, 2025
c55d22e
Refactor(func): Enhance `groupLyricsFlow` with detailed analysis stra…
parkcoool Nov 22, 2025
ac25491
Feat(fe): Add apis for new functions
parkcoool Nov 22, 2025
61a828d
Chore(fe): Remove unused files
parkcoool Nov 22, 2025
5713505
Feat(schemas): Add `TrackSetEventSchema`
parkcoool Nov 22, 2025
cc170a7
Feat(func): Stream track data in `getTrackFromIdFlow` and `getTrackFr…
parkcoool Nov 22, 2025
62b01d8
Refactor(schemas): Add `stream` field to get track flows
parkcoool Nov 22, 2025
5ec0fec
Feat(fe): Implement `useGetTrackFromIdQuery`
parkcoool Nov 22, 2025
e12a059
Feat(fe): Implement `useGetTrackFromMetadataQuery`
parkcoool Nov 22, 2025
e10860d
Feat(fe): Implement `TrackLoader` components
parkcoool Nov 22, 2025
5a65348
Refactor(fe): Simplify track fetching logic with `useGetTrackQuery` hook
parkcoool Nov 22, 2025
2a216ef
Fix(func): Update `getTrackFromIdFlow` to return streaming status ins…
parkcoool Nov 22, 2025
6af3402
Refactor(func): Improve error handling and streaming logic in track f…
parkcoool Nov 22, 2025
88476c2
Refactor(func): Remove data from ouput of getTrack flows
parkcoool Nov 22, 2025
e9179fd
Refactor(schemas): Remove nullable constraint from output schemas for…
parkcoool Nov 22, 2025
0e4ca84
Feat(fe): Add interface `GetTrackFlowResult` for `useGetTrackQuery` hook
parkcoool Nov 22, 2025
4d289ba
Refactor(schemas): Refactor event schemas
parkcoool Nov 23, 2025
b6b50a7
Feat(func): Update `translateLyris` to send chunks wihtout `event` field
parkcoool Nov 23, 2025
d1cfbd2
Refactor(func): Implement `generateTrackDetail` flow and `getTrackFro…
parkcoool Nov 23, 2025
12cc841
Refactor(func): Implement `generateTrackDetail` flow and `getTrackFro…
parkcoool Nov 23, 2025
606e590
Merge branch 'refactor/simplify-fetch' of https://github.com/parkcooo…
parkcoool Nov 24, 2025
26b1bc1
Chore(schemas): Improve DX by switching schemas to direct source imports
parkcoool Nov 24, 2025
d2dbca4
Feat(schemas): Redefine schemas
parkcoool Nov 24, 2025
52199eb
Refactor(func): Refactor whole backend structure
parkcoool Nov 24, 2025
73321d4
Chore(func): Configurate CI/CD for cloud functions deployment
parkcoool Nov 25, 2025
1368a61
Refactor(func): Refactor document structure for requesting track thro…
parkcoool Nov 25, 2025
b34f91b
Feat(fe): Refactor document structure for requesting track through do…
parkcoool Nov 27, 2025
81c9acc
Fix(func): Fix document path for `onTrackReuqestCreate`
parkcoool Nov 27, 2025
ff01bcb
Refactor(fe): Abstract stream channel logic in `useRequestTrack` to `…
parkcoool Nov 27, 2025
485f6f1
Feat(func): Rename `TrackRequest` to `StoryRequest` and `onTrackReque…
parkcoool Nov 29, 2025
94f3b91
Feat(func): Add `retrieveTrack` flow
parkcoool Nov 29, 2025
8fe1da3
Refactor(func): Move shared files to `shared` feature folder
parkcoool Nov 29, 2025
22c8b7e
Feat(fe): Add `retrieveTrack` function
parkcoool Nov 29, 2025
dc344cc
Feat(fe): Implement `useRequestStoryQuery` hook
parkcoool Nov 29, 2025
233f941
Feat(fe): Add `getStoryByTrackId` and `getTrackById` functions for fe…
parkcoool Nov 29, 2025
445876b
Feat(fe): Implement `StoryRequest` component
parkcoool Nov 29, 2025
7423a0d
Feat(fe): Refactor player components and implement track retrieval logic
parkcoool Nov 29, 2025
bd77817
Feat(fe): Refactor track and story fetching logic; Replace `useTrackA…
parkcoool Nov 30, 2025
433adb9
Feat(fe): Enhance loaing ui for `Summary` component
parkcoool Nov 30, 2025
46fb82c
Feat(fe): Refactor `Lyrics` and `Paragraph` components; Imeplement `u…
parkcoool Nov 30, 2025
9107e28
Feat(fe): Refactor `FromDevice` component to utilize `useStoryQuery` …
parkcoool Nov 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/deploy-functions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Deploy Firebase Functions

on:
push:
branches:
- main
paths:
- "apps/functions/**"
- "packages/schemas/**"
- ".github/workflows/deploy-functions.yml"

jobs:
deploy_functions:
runs-on: ubuntu-latest

steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install Dependencies
run: npm ci

- name: Build Functions
working-directory: apps/functions
run: npm run build

- name: Deploy to Firebase
uses: firebase/firebase-tools-action@v0.2
with:
args: deploy --only functions
env:
FIREBASE_CONFIG: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY }}
PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
firebase-debug.log
firestore-debug.log

dist
dist

dev-data
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class MediaModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
putString("album", metadata.getString(MediaMetadata.METADATA_KEY_ALBUM))
putDouble("duration", metadata.getLong(MediaMetadata.METADATA_KEY_DURATION).toDouble())
putBoolean("isPlaying", state.state == PlaybackState.STATE_PLAYING)
putString("coverUrl", albumArtBase64)
putString("albumArt", albumArtBase64)
}
}

Expand Down
10 changes: 0 additions & 10 deletions apps/frontend/apis/addTrack.ts

This file was deleted.

15 changes: 0 additions & 15 deletions apps/frontend/apis/generateDetail.ts

This file was deleted.

26 changes: 0 additions & 26 deletions apps/frontend/apis/getLyrics.ts

This file was deleted.

8 changes: 4 additions & 4 deletions apps/frontend/apis/getNewTracks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TrackDoc } from "@lymo/schemas/doc";
import type { Track } from "@lymo/schemas/doc";
import {
collection,
getDocs,
Expand All @@ -11,9 +11,9 @@ import {
import db from "@/core/firestore";

export default async function getNewTracks() {
const tracksCollection = collection(db, "tracks");
const q = query(tracksCollection, orderBy("createdAt", "desc"), limit(10));
const trackDocs = (await getDocs(q)) as FirebaseFirestoreTypes.QuerySnapshot<TrackDoc>;
const trackCollectionRef = collection(db, "tracks");
const q = query(trackCollectionRef, orderBy("createdAt", "desc"), limit(10));
const trackDocs = (await getDocs(q)) as FirebaseFirestoreTypes.QuerySnapshot<Track>;

const result = trackDocs.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
return result;
Expand Down
10 changes: 5 additions & 5 deletions apps/frontend/apis/getPopularTracks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TrackDoc } from "@lymo/schemas/doc";
import type { Track } from "@lymo/schemas/doc";
import {
collection,
getDocs,
Expand All @@ -11,14 +11,14 @@ import {
import db from "@/core/firestore";

export default async function getPopularTracks() {
const tracksCollection = collection(db, "tracks");
const trackCollectionRef = collection(db, "tracks");
const q = query(
tracksCollection,
orderBy("play", "desc"),
trackCollectionRef,
orderBy("stats.viewCount", "desc"),
orderBy("createdAt", "asc"),
limit(20)
);
const trackDocs = (await getDocs(q)) as FirebaseFirestoreTypes.QuerySnapshot<TrackDoc>;
const trackDocs = (await getDocs(q)) as FirebaseFirestoreTypes.QuerySnapshot<Track>;

const result = trackDocs.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
return result;
Expand Down
23 changes: 0 additions & 23 deletions apps/frontend/apis/getProvider.ts

This file was deleted.

32 changes: 32 additions & 0 deletions apps/frontend/apis/getStoryByTrackId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Story } from "@lymo/schemas/doc";
import { Language } from "@lymo/schemas/shared";
import {
collection,
getDocs,
limit,
query,
where,
type FirebaseFirestoreTypes,
} from "@react-native-firebase/firestore";

import db from "@/core/firestore";

interface GetStoryByTrackIdParams {
trackId: string;
language: Language;
}

export default async function getStoryByTrackId({ trackId, language }: GetStoryByTrackIdParams) {
const storyCollectionRef = collection(db, "stories");
const q = query(
storyCollectionRef,
where("language", "==", language),
where("trackId", "==", trackId),
limit(1)
);

const storyDoc = (await getDocs(q)).docs[0] as
| FirebaseFirestoreTypes.QueryDocumentSnapshot<Story>
| undefined;
return storyDoc?.data() ?? null;
}
22 changes: 0 additions & 22 deletions apps/frontend/apis/getTrack.ts

This file was deleted.

13 changes: 13 additions & 0 deletions apps/frontend/apis/getTrackById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Track } from "@lymo/schemas/doc";
import { collection, doc, type FirebaseFirestoreTypes } from "@react-native-firebase/firestore";

import db from "@/core/firestore";

export default async function getTrackById(trackId: string) {
const trackCollectionRef = collection(db, "tracks");
const trackDocRef = doc(
trackCollectionRef,
trackId
) as FirebaseFirestoreTypes.DocumentReference<Track>;
return (await trackDocRef.get()).data() ?? null;
}
33 changes: 0 additions & 33 deletions apps/frontend/apis/getTrackDetail.ts

This file was deleted.

9 changes: 9 additions & 0 deletions apps/frontend/apis/retrieveTrack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { RetrieveTrackInput, RetrieveTrackOutput } from "@lymo/schemas/functions";
import { httpsCallable } from "@react-native-firebase/functions";

import functions from "@/core/functions";

export const retrieveTrack = httpsCallable<RetrieveTrackInput, RetrieveTrackOutput>(
functions,
"retrieveTrack"
);
3 changes: 3 additions & 0 deletions apps/frontend/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { SettingProvider } from "@/contexts/useSettingStore";
import { SyncProvider } from "@/contexts/useSyncStore";
import { TrackSourceProvider } from "@/contexts/useTrackSourceStore";

import "@/core/firestore";
import "@/core/functions";

const queryClient = new QueryClient();

export default function RootLayout() {
Expand Down
19 changes: 12 additions & 7 deletions apps/frontend/app/player/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useQueryErrorResetBoundary } from "@tanstack/react-query";
import { Redirect } from "expo-router";
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { View } from "react-native";

import ErrorIndicator from "@/components/player/ErrorIndicator";
import LoadingIndicator from "@/components/player/LoadingIndicator";
import { DeviceTrackPlayer, ManualTrackPlayer } from "@/components/player/Player";
import FromDevice from "@/components/player/Player/FromDevice";
import FromManual from "@/components/player/Player/FromManual";
import { useTrackSourceStore } from "@/contexts/useTrackSourceStore";

export default function Player() {
Expand All @@ -19,10 +18,16 @@ export default function Player() {
return (
<View style={{ flex: 1 }}>
<ErrorBoundary FallbackComponent={ErrorIndicator} onReset={reset}>
<Suspense fallback={<LoadingIndicator {...trackSource?.track} />}>
{trackSource.from === "manual" && <ManualTrackPlayer trackId={trackSource.track.id} />}
{trackSource.from === "device" && <DeviceTrackPlayer {...trackSource.track} />}
</Suspense>
{trackSource.from === "manual" && (
<FromManual trackId={trackSource.track.id} track={trackSource.track} />
)}
{trackSource.from === "device" && (
<FromDevice
title={trackSource.track.title}
artist={trackSource.track.artist}
durationInSeconds={trackSource.track.duration}
/>
)}
</ErrorBoundary>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function DeviceMediaDetection() {
<View style={styles.wrapper}>
<View style={[styles.coverWrapper]}>
{/* 커버 이미지 */}
<Image source={{ uri: deviceMedia.coverUrl }} style={styles.cover} />
<Image source={{ uri: deviceMedia.albumArt }} style={styles.cover} />

{/* 그라데이션 오버레이 */}
<LinearGradient style={styles.coverGradient} colors={["transparent", colors.black]} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { Track } from "@lymo/schemas/doc";
import { Link } from "expo-router";
import { View, Text, FlatList } from "react-native";

Expand All @@ -15,10 +16,10 @@ export default function NewTracksSection() {
const { setTrackSource } = useTrackSourceStore();
const { setIsSynced } = useSyncStore();

const handlePlayTrack = (track: { id: string; title: string; coverUrl: string }) => {
const handlePlayTrack = (trackId: string, track: Track) => {
setTrackSource({
from: "manual",
track: track,
track: { ...track, id: trackId },
});
setIsSynced(false);
};
Expand All @@ -41,10 +42,8 @@ export default function NewTracksSection() {
<Link href={`/player`} key={track.id} asChild>
<CompactTrack
title={track.title}
coverUrl={track.coverUrl}
onPress={() =>
handlePlayTrack({ id: track.id, title: track.title, coverUrl: track.coverUrl })
}
albumArt={track.albumArt}
onPress={() => handlePlayTrack(track.id, track)}
/>
</Link>
)}
Expand Down
Loading