Sid Gifari File Manager
🏠 Root
/
home
/
genremedia08
/
musicjukebox.overlookedtracks.com
/
public
/
build
/
assets
/
Editing: web-player-routes-bb2f14ca.js.map
{"version":3,"file":"web-player-routes-bb2f14ca.js","sources":["../../../node_modules/@tanstack/query-core/build/lib/infiniteQueryObserver.mjs","../../../node_modules/@tanstack/react-query/build/lib/useInfiniteQuery.mjs","../../../common/resources/client/ui/infinite-scroll/use-infinite-data.ts","../../../resources/client/web-player/channels/requests/use-paginated-channel-content.ts","../../../common/resources/client/ui/infinite-scroll/infinite-scroll-sentinel.tsx","../../../common/resources/client/utils/array/shuffle-array.ts","../../../common/resources/client/player/utils/player-local-storage.ts","../../../common/resources/client/utils/array/prepend-to-array-at-index.ts","../../../common/resources/client/player/utils/reset-media-session.ts","../../../common/resources/client/player/player-queue.ts","../../../common/resources/client/player/handle-player-keybinds.ts","../../../common/resources/client/player/utils/init-player-media-session.ts","../../../common/resources/client/player/utils/is-same-media.ts","../../../common/resources/client/player/state/fullscreen/screen-orientation.ts","../../../common/resources/client/utils/platform.ts","../../../node_modules/fscreen/dist/fscreen.esm.js","../../../common/resources/client/player/state/fullscreen/create-native-fullscreen-adapter.ts","../../../common/resources/client/player/state/fullscreen/create-iphone-fullscreen-adapter.ts","../../../common/resources/client/player/state/fullscreen/fullscreen-slice.ts","../../../common/resources/client/player/state/pip/chrome-pip-adapter.ts","../../../common/resources/client/player/state/pip/safari-pip-adapter.ts","../../../common/resources/client/player/state/pip/pip-slice.ts","../../../common/resources/client/player/state/player-store.tsx","../../../common/resources/client/player/player-context.tsx","../../../common/resources/client/player/hooks/use-player-store.tsx","../../../common/resources/client/player/hooks/use-player-actions.ts","../../../resources/client/web-player/requests/load-media-item-tracks.ts","../../../common/resources/client/player/utils/guess-player-provider.ts","../../../resources/client/web-player/tracks/utils/track-to-media-item.ts","../../../resources/client/web-player/tracks/equalizer-image/equalizer-white.gif","../../../resources/client/web-player/tracks/equalizer-image/equalizer-black.gif","../../../resources/client/web-player/tracks/equalizer-image/equalizer-image.tsx","../../../resources/client/web-player/playable-item/playback-toggle-button.tsx","../../../resources/client/web-player/queue-group-id.ts","../../../resources/client/web-player/playable-item/playable-grid-item.tsx","../../../resources/client/web-player/playlists/requests/use-auth-user-playlists.ts","../../../resources/client/web-player/playlists/requests/use-add-tracks-to-playlist.ts","../../../resources/client/web-player/use-auth-click-capture.ts","../../../resources/client/web-player/context-dialog/playlist-panel.tsx","../../../resources/client/web-player/context-dialog/context-dialog-layout.tsx","../../../resources/client/web-player/library/state/create-countable-store.ts","../../../resources/client/web-player/library/state/likes-store.ts","../../../resources/client/web-player/library/requests/use-add-items-to-library.ts","../../../resources/client/web-player/library/requests/use-remove-items-from-library.ts","../../../resources/client/web-player/context-dialog/toggle-in-library-menu-button.tsx","../../../resources/client/web-player/context-dialog/copy-link-menu-button.tsx","../../../resources/client/web-player/artists/requests/use-delete-artist.ts","../../../resources/client/web-player/radio/get-radio-link.ts","../../../resources/client/web-player/tracks/context-dialog/use-should-show-radio-button.ts","../../../resources/client/web-player/playlists/playlist-image.tsx","../../../resources/client/web-player/sharing/share-media-dialog.tsx","../../../resources/client/web-player/context-dialog/share-media-button.tsx","../../../resources/client/web-player/artists/artist-context-dialog.tsx","../../../resources/client/web-player/library/like-icon-button.tsx","../../../resources/client/web-player/artists/artist-grid-item.tsx","../../../resources/client/web-player/context-dialog/add-to-queue-menu-button.tsx","../../../resources/client/web-player/library/state/reposts-store.ts","../../../resources/client/web-player/reposts/use-toggle-repost.ts","../../../resources/client/web-player/context-dialog/toggle-repost-menu-button.tsx","../../../resources/client/web-player/albums/album-context-dialog.tsx","../../../resources/client/web-player/albums/album-grid-item.tsx","../../../resources/client/web-player/genres/genre-image.tsx","../../../resources/client/web-player/genres/genre-grid-item.tsx","../../../resources/client/web-player/tracks/requests/use-delete-tracks.ts","../../../resources/client/web-player/tracks/lyrics/requests/use-lyrics.ts","../../../common/resources/client/icons/media/media-microphone.tsx","../../../resources/client/web-player/tracks/lyrics/lyrics-dialog.tsx","../../../resources/client/web-player/tracks/context-dialog/track-context-dialog.tsx","../../../resources/client/web-player/tracks/track-grid-item.tsx","../../../resources/client/web-player/playlists/hooks/use-playlist-permissions.ts","../../../resources/client/web-player/playlists/hooks/use-is-following-playlist.ts","../../../resources/client/web-player/playlists/requests/use-delete-playlist.ts","../../../resources/client/web-player/playlists/requests/use-follow-playlist.ts","../../../resources/client/web-player/playlists/requests/use-unfollow-playlist.ts","../../../resources/client/web-player/playlists/playlist-context-dialog.tsx","../../../resources/client/web-player/playlists/playlist-page/follow-playlist-button.tsx","../../../resources/client/web-player/playlists/playlist-grid-item.tsx","../../../resources/client/web-player/users/user-default.svg","../../../resources/client/web-player/users/user-image.tsx","../../../resources/client/web-player/users/user-grid-item.tsx","../../../resources/client/web-player/channels/channel-content-grid-item.tsx","../../../resources/client/web-player/channels/antenna-icon.tsx","../../../resources/client/web-player/channels/channel-heading.tsx","../../../resources/client/web-player/channels/channel-content-grid.tsx","../../../resources/client/web-player/tracks/track-table/use-track-table-meta.ts","../../../resources/client/web-player/tracks/hooks/use-is-track-cued.ts","../../../resources/client/web-player/tracks/hooks/use-is-track-playing.ts","../../../resources/client/web-player/tracks/track-table/toggle-playback-column.tsx","../../../resources/client/web-player/tracks/track-table/track-name-column.tsx","../../../resources/client/web-player/tracks/context-dialog/table-track-context-dialog.tsx","../../../resources/client/web-player/tracks/track-table/track-options-column.tsx","../../../resources/client/web-player/tracks/track-table/track-table.tsx","../../../resources/client/web-player/playlists/virtual-table-body.tsx","../../../resources/client/web-player/channels/channel-track-table.tsx","../../../resources/client/web-player/tracks/requests/use-track-wave-data.ts","../../../resources/client/web-player/tracks/waveform/draw-waveform.ts","../../../resources/client/web-player/player-controls/seekbar/use-track-seekbar.ts","../../../resources/client/web-player/tracks/waveform/comment-bar-context.tsx","../../../resources/client/web-player/tracks/waveform/comment-bar.tsx","../../../resources/client/web-player/tracks/waveform/waveform.tsx","../../../resources/client/web-player/player-controls/seekbar/track-seekbar.tsx","../../../resources/client/web-player/tracks/utils/track-is-locally-uploaded.ts","../../../common/resources/client/comments/requests/use-create-comment.ts","../../../common/resources/client/comments/new-comment-form.tsx","../../../resources/client/web-player/tracks/waveform/comment-bar-new-comment-form.tsx","../../../resources/client/web-player/library/like-button.tsx","../../../resources/client/web-player/reposts/repost-button.tsx","../../../resources/client/web-player/tracks/media-item-stats.tsx","../../../resources/client/web-player/tracks/track-actions-bar.tsx","../../../resources/client/web-player/tracks/track-list/track-list-item.tsx","../../../resources/client/web-player/tracks/track-list/track-list.tsx","../../../resources/client/web-player/channels/channel-track-list.tsx","../../../node_modules/just-debounce-it/index.mjs","../../../resources/client/web-player/channels/channel-content-carousel.tsx","../../../resources/client/web-player/channels/channel-content.tsx","../../../common/resources/client/admin/ads/ad-host.tsx","../../../resources/client/web-player/channels/channel-page.tsx","../../../resources/client/web-player/tracks/requests/find-youtube-videos-for-track.ts","../../../resources/client/web-player/state/player-overlay-store.ts","../../../common/resources/client/player/providers/youtube/youtube-types.ts","../../../resources/client/web-player/state/player-store-options.ts","../../../resources/client/web-player/layout/sidenav.tsx","../../../common/resources/client/player/hooks/use-is-media-playing.ts","../../../resources/client/web-player/overlay/use-mini-player-is-hidden.ts","../../../resources/client/web-player/layout/queue/queue-track-context-dialog.tsx","../../../resources/client/web-player/layout/queue/queue-sidenav.tsx","../../../resources/client/web-player/player-controls/use-cued-track.ts","../../../common/resources/client/player/hooks/use-current-time.ts","../../../common/resources/client/icons/media/media-play.tsx","../../../common/resources/client/icons/media/media-pause.tsx","../../../common/resources/client/player/ui/controls/play-button.tsx","../../../common/resources/client/icons/media/media-previous.tsx","../../../common/resources/client/player/ui/controls/previous-button.tsx","../../../common/resources/client/icons/media/media-next.tsx","../../../common/resources/client/player/ui/controls/next-button.tsx","../../../resources/client/web-player/player-controls/buffering-indicator.tsx","../../../resources/client/web-player/player-controls/mobile-player-controls.tsx","../../../common/resources/client/player/ui/controls/seeking/seekbar.tsx","../../../common/resources/client/player/ui/controls/formatted-current-time.tsx","../../../common/resources/client/player/ui/controls/formatted-player-duration.tsx","../../../resources/client/web-player/player-controls/seekbar/main-seekbar.tsx","../../../common/resources/client/icons/media/media-shuffle.tsx","../../../common/resources/client/icons/media/media-shuffle-on.tsx","../../../common/resources/client/player/ui/controls/shuffle-button.tsx","../../../common/resources/client/icons/media/media-repeat.tsx","../../../common/resources/client/icons/media/media-repeat-on.tsx","../../../common/resources/client/player/ui/controls/repeat-button.tsx","../../../resources/client/web-player/player-controls/playback-controls.tsx","../../../resources/client/web-player/player-controls/lyrics-button.tsx","../../../resources/client/web-player/player-controls/download-track-button.tsx","../../../common/resources/client/icons/media/media-queue-list.tsx","../../../common/resources/client/icons/media/media-mute.tsx","../../../common/resources/client/icons/media/media-volume-low.tsx","../../../common/resources/client/icons/media/media-volume-high.tsx","../../../common/resources/client/player/ui/controls/volume-controls.tsx","../../../resources/client/web-player/player-controls/desktop-player-controls.tsx","../../../common/resources/client/utils/number/is-number.ts","../../../common/resources/client/utils/http/load-image.ts","../../../common/resources/client/player/providers/youtube/load-youtube-poster.ts","../../../common/resources/client/player/providers/youtube/handle-youtube-embed-message.tsx","../../../common/resources/client/player/providers/youtube/use-youtube-provider-src.ts","../../../common/resources/client/player/providers/youtube/youtube-provider.tsx","../../../common/resources/client/utils/dom/create-ref-loop.ts","../../../common/resources/client/player/providers/html-media/use-html-media-internal-state.ts","../../../common/resources/client/player/providers/html-media/use-html-media-events.ts","../../../common/resources/client/player/providers/html-media/use-html-media-api.ts","../../../common/resources/client/player/providers/html-video-provider.tsx","../../../common/resources/client/player/providers/html-audio-provider.tsx","../../../common/resources/client/player/ui/player-outlet.tsx","../../../common/resources/client/player/ui/controls/player-poster.tsx","../../../common/resources/client/icons/media/media-fullscreen.tsx","../../../common/resources/client/player/hooks/use-player-click-handler.ts","../../../resources/client/web-player/overlay/player-overlay.tsx","../../../resources/client/web-player/search/search-autocomplete.tsx","../../../resources/client/web-player/layout/player-navbar.tsx","../../../resources/client/web-player/layout/web-player-layout.tsx","../../../resources/client/web-player/layout/media-page-header-layout.tsx","../../../common/resources/client/ui/remote-favicon.tsx","../../../resources/client/web-player/user-profile/profile-links.tsx","../../../resources/client/web-player/user-profile/profile-description.tsx","../../../resources/client/web-player/artists/artist-page/artist-page-header.tsx","../../../resources/client/web-player/artists/artist-page/discography-panel/top-tracks-table.tsx","../../../resources/client/web-player/artists/requests/use-artist-albums.ts","../../../resources/client/web-player/artists/artist-page/discography-panel/no-discography-message.tsx","../../../resources/client/web-player/artists/artist-page/discography-panel/artist-albums-list.tsx","../../../resources/client/web-player/artists/artist-page/discography-panel/artist-albums-grid.tsx","../../../resources/client/web-player/artists/artist-page/discography-panel/discography-tab.tsx","../../../resources/client/web-player/artists/artist-page/similar-artists-panel.tsx","../../../node_modules/linkify-string/dist/linkify-string.es.js","../../../common/resources/client/utils/hooks/use-linkified-string.ts","../../../resources/client/web-player/artists/artist-page/artist-about-panel.tsx","../../../resources/client/web-player/artists/artist-page/artist-tracks-panel.tsx","../../../resources/client/web-player/albums/album-list/album-list-item.tsx","../../../resources/client/web-player/albums/album-list/album-list.tsx","../../../resources/client/web-player/artists/artist-page/artist-albums-panel.tsx","../../../resources/client/web-player/artists/artist-page/use-artist-page-tabs.tsx","../../../resources/client/web-player/users/user-follows-store.ts","../../../resources/client/web-player/users/use-follow-user.ts","../../../resources/client/web-player/users/use-unfollow-user.ts","../../../resources/client/web-player/artists/artist-page/followers-panel/follower-list-item.tsx","../../../resources/client/web-player/artists/artist-page/artist-followers-panel.tsx","../../../resources/client/web-player/artists/artist-page/artist-page-tabs.tsx","../../../resources/client/web-player/artists/artist-page/artist-page.tsx","../../../resources/client/web-player/playlists/requests/use-playlist.ts","../../../common/resources/client/ui/images/avatar-group.tsx","../../../resources/client/web-player/layout/bullet-separated-items.tsx","../../../resources/client/web-player/playlists/playlist-page/playlist-page-header.tsx","../../../common/resources/client/utils/array/move-multiple-items-in-array.ts","../../../resources/client/web-player/playlists/requests/use-reorder-playlist-tracks.ts","../../../resources/client/web-player/playlists/requests/use-remove-tracks-from-playlist.ts","../../../resources/client/web-player/playlists/playlist-page/playlist-track-context-dialog.tsx","../../../resources/client/web-player/playlists/playlist-page/playlist-table-row.tsx","../../../resources/client/web-player/layout/media-page-no-results-message.tsx","../../../resources/client/web-player/playlists/playlist-page/playlist-page.tsx","../../../common/resources/client/comments/requests/use-comments.ts","../../../common/resources/client/votes/requests/use-store-vote.ts","../../../common/resources/client/votes/thumb-buttons.tsx","../../../common/resources/client/reports/requests/use-submit-report.ts","../../../common/resources/client/comments/comment-list/comment-list-item.tsx","../../../common/resources/client/comments/comment-list/account-required-card.tsx","../../../common/resources/client/comments/comment-list/comment-list.tsx","../../../common/resources/client/ui/truncated-description.tsx","../../../resources/client/web-player/tracks/hooks/use-comment-permissions.ts","../../../resources/client/web-player/albums/album-page.tsx","../../../resources/client/web-player/library/requests/use-user-liked-tracks.ts","../../../resources/client/web-player/library/library-tracks-page.tsx","../../../resources/client/web-player/library/library-page-sort-dropdown.tsx","../../../resources/client/web-player/library/requests/use-user-liked-albums.ts","../../../resources/client/web-player/library/library-albums-page.tsx","../../../resources/client/web-player/library/requests/use-user-liked-artists.ts","../../../resources/client/web-player/library/library-artists-page.tsx","../../../resources/client/web-player/library/library-history-page.tsx","../../../resources/client/web-player/tracks/track-page.tsx","../../../resources/client/web-player/user-profile/requests/use-user-profile.tsx","../../../resources/client/web-player/user-profile/panels/profile-reposts-panel.tsx","../../../resources/client/web-player/user-profile/panels/profile-tracks-panel.tsx","../../../resources/client/web-player/library/requests/use-user-playlists.ts","../../../resources/client/web-player/user-profile/panels/profile-playlists-panel.tsx","../../../resources/client/web-player/user-profile/panels/profile-albums-panel.tsx","../../../resources/client/web-player/user-profile/panels/profile-artists-panel.tsx","../../../resources/client/web-player/user-profile/panels/profile-followers-panel.tsx","../../../resources/client/web-player/user-profile/panels/profile-followed-users-panel.tsx","../../../resources/client/web-player/user-profile/requests/use-update-user-profile.ts","../../../common/resources/client/ui/forms/combobox/form-combobox.tsx","../../../resources/client/web-player/user-profile/edit-profile-dialog.tsx","../../../resources/client/web-player/user-profile/header/profile-header.tsx","../../../resources/client/web-player/user-profile/user-profile-page.tsx","../../../resources/client/web-player/genres/tag-media-page.tsx","../../../resources/client/web-player/radio/requests/use-radio-recommendations.ts","../../../resources/client/web-player/radio/radio-page.tsx","../../../resources/client/web-player/search/search-results-page.tsx","../../../resources/client/web-player/library/library-page.tsx","../../../resources/client/web-player/library/library-playlists-page.tsx","../../../resources/client/web-player/tracks/track-embed.tsx","../../../resources/client/web-player/albums/album-embed.tsx","../../../resources/client/web-player/channels/homepage-channel-page.tsx","../../../resources/client/web-player/web-player-routes.tsx"],"sourcesContent":["import { QueryObserver } from './queryObserver.mjs';\nimport { infiniteQueryBehavior, hasNextPage, hasPreviousPage } from './infiniteQueryBehavior.mjs';\n\nclass InfiniteQueryObserver extends QueryObserver {\n // Type override\n // Type override\n // Type override\n // eslint-disable-next-line @typescript-eslint/no-useless-constructor\n constructor(client, options) {\n super(client, options);\n }\n\n bindMethods() {\n super.bindMethods();\n this.fetchNextPage = this.fetchNextPage.bind(this);\n this.fetchPreviousPage = this.fetchPreviousPage.bind(this);\n }\n\n setOptions(options, notifyOptions) {\n super.setOptions({ ...options,\n behavior: infiniteQueryBehavior()\n }, notifyOptions);\n }\n\n getOptimisticResult(options) {\n options.behavior = infiniteQueryBehavior();\n return super.getOptimisticResult(options);\n }\n\n fetchNextPage({\n pageParam,\n ...options\n } = {}) {\n return this.fetch({ ...options,\n meta: {\n fetchMore: {\n direction: 'forward',\n pageParam\n }\n }\n });\n }\n\n fetchPreviousPage({\n pageParam,\n ...options\n } = {}) {\n return this.fetch({ ...options,\n meta: {\n fetchMore: {\n direction: 'backward',\n pageParam\n }\n }\n });\n }\n\n createResult(query, options) {\n var _state$fetchMeta, _state$fetchMeta$fetc, _state$fetchMeta2, _state$fetchMeta2$fet, _state$data, _state$data2;\n\n const {\n state\n } = query;\n const result = super.createResult(query, options);\n const {\n isFetching,\n isRefetching\n } = result;\n const isFetchingNextPage = isFetching && ((_state$fetchMeta = state.fetchMeta) == null ? void 0 : (_state$fetchMeta$fetc = _state$fetchMeta.fetchMore) == null ? void 0 : _state$fetchMeta$fetc.direction) === 'forward';\n const isFetchingPreviousPage = isFetching && ((_state$fetchMeta2 = state.fetchMeta) == null ? void 0 : (_state$fetchMeta2$fet = _state$fetchMeta2.fetchMore) == null ? void 0 : _state$fetchMeta2$fet.direction) === 'backward';\n return { ...result,\n fetchNextPage: this.fetchNextPage,\n fetchPreviousPage: this.fetchPreviousPage,\n hasNextPage: hasNextPage(options, (_state$data = state.data) == null ? void 0 : _state$data.pages),\n hasPreviousPage: hasPreviousPage(options, (_state$data2 = state.data) == null ? void 0 : _state$data2.pages),\n isFetchingNextPage,\n isFetchingPreviousPage,\n isRefetching: isRefetching && !isFetchingNextPage && !isFetchingPreviousPage\n };\n }\n\n}\n\nexport { InfiniteQueryObserver };\n//# sourceMappingURL=infiniteQueryObserver.mjs.map\n","import { parseQueryArgs, InfiniteQueryObserver } from '@tanstack/query-core';\nimport { useBaseQuery } from './useBaseQuery.mjs';\n\nfunction useInfiniteQuery(arg1, arg2, arg3) {\n const options = parseQueryArgs(arg1, arg2, arg3);\n return useBaseQuery(options, InfiniteQueryObserver);\n}\n\nexport { useInfiniteQuery };\n//# sourceMappingURL=useInfiniteQuery.mjs.map\n","import {\n hashQueryKey,\n useInfiniteQuery,\n UseInfiniteQueryResult,\n} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {\n hasNextPage,\n PaginationResponse,\n} from '@common/http/backend-response/pagination-response';\nimport {useMemo, useRef, useState} from 'react';\nimport {SortDescriptor} from '@common/ui/tables/types/sort-descriptor';\nimport {GetDatatableDataParams} from '@common/datatable/requests/paginated-resources';\nimport {QueryKey} from '@tanstack/query-core/src/types';\n\nexport type UseInfiniteDataResult<\n T,\n E extends object = object\n> = UseInfiniteQueryResult<PaginationResponse<T> & E> & {\n items: T[];\n totalItems: number | null;\n // initial load is done and no results were returned from backend\n noResults: boolean;\n sortDescriptor: SortDescriptor;\n setSortDescriptor: (sortDescriptor: SortDescriptor) => void;\n searchQuery: string;\n setSearchQuery: (searchQuery: string) => void;\n};\n\nfunction buildQueryKey(\n {\n queryKey,\n defaultOrderDir,\n defaultOrderBy,\n queryParams,\n }: UseInfiniteDataProps<any>,\n sortDescriptor: SortDescriptor,\n searchQuery: string = ''\n) {\n // make sure to always set default order dir and col so query keys are consistent\n if (!sortDescriptor.orderBy) {\n sortDescriptor.orderBy = defaultOrderBy;\n }\n if (!sortDescriptor.orderDir) {\n sortDescriptor.orderDir = defaultOrderDir;\n }\n return [...queryKey, sortDescriptor, searchQuery, queryParams];\n}\n\ninterface Response<T> extends BackendResponse {\n pagination: PaginationResponse<T>;\n}\n\nexport interface UseInfiniteDataProps<T> {\n initialPage?: PaginationResponse<T> | null;\n queryKey: QueryKey;\n queryParams?: Record<string, string | number | null>;\n endpoint: string;\n defaultOrderBy?: SortDescriptor['orderBy'];\n defaultOrderDir?: SortDescriptor['orderDir'];\n // whether user can sort items manually (table header, dropdown, etc)\n willSortOrFilter?: boolean;\n // ordering is not available with cursor pagination\n paginate?: 'simple' | 'lengthAware' | 'cursor';\n transformResponse?: (response: Response<T>) => Response<T>;\n}\nexport function useInfiniteData<T, E extends object = {}>(\n props: UseInfiniteDataProps<T>\n): UseInfiniteDataResult<T, E> {\n const {\n initialPage,\n endpoint,\n defaultOrderBy,\n defaultOrderDir,\n queryParams,\n paginate,\n transformResponse,\n willSortOrFilter = false,\n } = props;\n const [searchQuery, setSearchQuery] = useState('');\n const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({\n orderBy: defaultOrderBy,\n orderDir: defaultOrderDir,\n });\n\n const queryKey = buildQueryKey(props, sortDescriptor, searchQuery);\n const initialQueryKey = useRef(hashQueryKey(queryKey)).current;\n\n const query = useInfiniteQuery({\n keepPreviousData: willSortOrFilter,\n queryKey,\n queryFn: ({pageParam}) => {\n const params: GetDatatableDataParams = {\n ...queryParams,\n perPage: initialPage?.per_page || queryParams?.perPage,\n query: searchQuery,\n paginate,\n ...sortDescriptor,\n };\n if (paginate === 'cursor') {\n params.cursor = pageParam;\n } else {\n params.page = pageParam || 1;\n }\n return fetchData<T>(endpoint, params, transformResponse);\n },\n getNextPageParam: lastResponse => {\n if (!hasNextPage(lastResponse.pagination)) {\n return undefined;\n }\n if ('next_cursor' in lastResponse.pagination) {\n return lastResponse.pagination.next_cursor;\n }\n return lastResponse.pagination.current_page + 1;\n },\n initialData: () => {\n // initial data will be for initial query key only, remove\n // initial data if query key changes, so query is reset\n if (!initialPage || hashQueryKey(queryKey) !== initialQueryKey) {\n return undefined;\n }\n\n return {\n pageParams: [undefined, 1],\n pages: [{pagination: initialPage}],\n };\n },\n });\n\n const items = useMemo(() => {\n return query.data?.pages.flatMap(p => p.pagination.data) || [];\n }, [query.data?.pages]);\n\n const firstPage = query.data?.pages[0].pagination;\n const totalItems =\n firstPage && 'total' in firstPage && firstPage.total\n ? firstPage.total\n : null;\n\n return {\n ...query,\n items,\n totalItems,\n noResults: query.data?.pages?.[0].pagination.data.length === 0,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n } as UseInfiniteDataResult<T, E>;\n}\n\nfunction fetchData<T>(\n endpoint: string,\n params: GetDatatableDataParams,\n transformResponse?: UseInfiniteDataProps<T>['transformResponse']\n): Promise<Response<T>> {\n return apiClient.get(endpoint, {params}).then(r => {\n if (transformResponse) {\n return transformResponse(r.data);\n }\n return r.data;\n });\n}\n","import {Channel, ChannelContentItem} from '@app/web-player/channels/channel';\nimport {useParams} from 'react-router-dom';\nimport {\n channelEndpoint,\n channelQueryKey,\n} from '@app/web-player/channels/requests/use-channel';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {SortDescriptor} from '@common/ui/tables/types/sort-descriptor';\n\nexport function usePaginatedChannelContent<\n T extends ChannelContentItem = ChannelContentItem\n>(channel: Channel<T>) {\n const {filter} = useParams();\n const [defaultOrderBy = 'popularity', defaultOrderDir = 'desc'] = (\n channel.config.contentOrder || ''\n ).split(':');\n return useInfiniteData<T>({\n initialPage: channel.content,\n queryKey: channelQueryKey(channel.id, {filter: filter || ''}),\n endpoint: channelEndpoint(channel.id),\n defaultOrderBy,\n defaultOrderDir: defaultOrderDir as SortDescriptor['orderDir'],\n paginate: 'simple',\n queryParams: {\n returnContentOnly: 'true',\n //used for dynamically specifying channel content.\n // In \"channel/1/jazz\" filter will be \"jazz\"\n filter: filter || '',\n },\n });\n}\n","import React, {ReactNode, useEffect, useRef, useState} from 'react';\nimport clsx from 'clsx';\nimport {UseInfiniteQueryResult} from '@tanstack/react-query/src/types';\nimport {Trans} from '@common/i18n/trans';\nimport {Button} from '@common/ui/buttons/button';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {ProgressCircle} from '@common/ui/progress/progress-circle';\n\nexport interface InfiniteScrollSentinelProps {\n loaderMarginTop?: string;\n children?: ReactNode;\n loadMoreExtraContent?: ReactNode;\n query: UseInfiniteQueryResult;\n style?: React.CSSProperties;\n className?: string;\n variant?: 'infiniteScroll' | 'loadMore';\n size?: 'sm' | 'md';\n}\nexport function InfiniteScrollSentinel({\n query: {isInitialLoading, fetchNextPage, isFetchingNextPage, hasNextPage},\n children,\n loaderMarginTop = 'mt-24',\n style,\n className,\n variant: _variant = 'infiniteScroll',\n loadMoreExtraContent,\n size = 'md',\n}: InfiniteScrollSentinelProps) {\n const sentinelRef = useRef<HTMLDivElement>(null);\n const isLoading = isFetchingNextPage || isInitialLoading;\n const [loadMoreClickCount, setLoadMoreClickCount] = useState(0);\n const innerVariant =\n _variant === 'loadMore' && loadMoreClickCount < 3\n ? 'loadMore'\n : 'infiniteScroll';\n\n useEffect(() => {\n const sentinelEl = sentinelRef.current;\n if (!sentinelEl || innerVariant === 'loadMore') return;\n const observer = new IntersectionObserver(([entry]) => {\n if (entry.isIntersecting && hasNextPage && !isLoading) {\n fetchNextPage();\n }\n });\n observer.observe(sentinelEl);\n return () => {\n observer.unobserve(sentinelEl);\n };\n }, [fetchNextPage, hasNextPage, isLoading, innerVariant]);\n\n let content: ReactNode;\n\n if (children) {\n // children might already be wrapped in AnimatePresence, so only wrap default loader with it\n content = isFetchingNextPage ? children : null;\n } else if (innerVariant === 'loadMore') {\n content = !isInitialLoading && hasNextPage && (\n <div className={clsx('flex items-center gap-8', loaderMarginTop)}>\n {loadMoreExtraContent}\n <Button\n size={size === 'md' ? 'sm' : 'xs'}\n className={clsx(\n size === 'sm' ? 'min-h-24 min-w-96' : 'min-h-36 min-w-112'\n )}\n variant=\"outline\"\n color=\"primary\"\n onClick={() => {\n fetchNextPage();\n setLoadMoreClickCount(loadMoreClickCount + 1);\n }}\n disabled={isLoading}\n >\n {loadMoreClickCount >= 2 && !isFetchingNextPage ? (\n <Trans message=\"Load all\" />\n ) : (\n <Trans message=\"Show more\" />\n )}\n </Button>\n </div>\n );\n } else {\n content = (\n <AnimatePresence>\n {isFetchingNextPage && (\n <m.div\n className={clsx('flex justify-center w-full', loaderMarginTop)}\n {...opacityAnimation}\n >\n <ProgressCircle size={size} isIndeterminate aria-label=\"loading\" />\n </m.div>\n )}\n </AnimatePresence>\n );\n }\n\n return (\n <div\n style={style}\n className={clsx('w-full', className, hasNextPage && 'min-h-36')}\n role=\"presentation\"\n >\n <div ref={sentinelRef} aria-hidden />\n {content}\n </div>\n );\n}\n","export function shuffleArray(items: any[], keepFirst = false) {\n let first = keepFirst ? items.shift() : null;\n\n let currentIndex = items.length,\n temporaryValue,\n randomIndex;\n\n while (0 !== currentIndex) {\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n\n temporaryValue = items[currentIndex];\n items[currentIndex] = items[randomIndex];\n items[randomIndex] = temporaryValue;\n }\n\n if (first) {\n items.unshift(first);\n }\n\n return [...items];\n}\n","import {getFromLocalStorage} from '@common/utils/hooks/local-storage';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport {PlayerState} from '@common/player/state/player-state';\n\nexport interface PersistablePlayerState {\n muted?: PlayerState['muted'];\n repeat?: PlayerState['repeat'];\n shuffling?: PlayerState['shuffling'];\n volume?: PlayerState['volume'];\n}\n\nexport interface PlayerInitialData {\n state?: PersistablePlayerState;\n queue?: PlayerState['originalQueue'];\n cuedMediaId?: string | number;\n}\n\nexport function getPlayerStateFromLocalStorage(\n id: string | number,\n options?: PlayerStoreOptions\n): PlayerInitialData {\n const defaultVolume = options?.defaultVolume || 30;\n return {\n state: {\n muted: getFromLocalStorage(`player.${id}.muted`) ?? false,\n repeat: getFromLocalStorage(`player.${id}.repeat`) ?? 'all',\n shuffling: getFromLocalStorage(`player.${id}.shuffling`) ?? false,\n volume: getFromLocalStorage(`player.${id}.volume`) ?? defaultVolume,\n },\n queue: getFromLocalStorage(`player.${id}.queue`, []),\n cuedMediaId: getFromLocalStorage(`player.${id}.cuedMediaId`),\n };\n}\n","export function prependToArrayAtIndex<T>(array: T[], toAdd: T[], index = 0): T[] {\n const copyOfArray = [...array];\n const tail = copyOfArray.splice(index + 1);\n return [...copyOfArray, ...toAdd, ...tail];\n}\n","export function resetMediaSession() {\n if ('mediaSession' in navigator) {\n const actionHandlers: MediaSessionAction[] = [\n 'play',\n 'pause',\n 'previoustrack',\n 'nexttrack',\n 'stop',\n 'seekbackward',\n 'seekforward',\n 'seekto',\n ];\n actionHandlers.forEach(action =>\n navigator.mediaSession.setActionHandler(action, null)\n );\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = 'none';\n }\n}\n","import {MediaItem} from '@common/player/media-item';\nimport {PlayerState} from '@common/player/state/player-state';\n\nexport function playerQueue(state: () => PlayerState) {\n const getPointer = (): number => {\n if (state().cuedMedia) {\n return (\n state().shuffledQueue.findIndex(\n item => item.id === state().cuedMedia?.id\n ) || 0\n );\n }\n return 0;\n };\n const getCurrent = (): MediaItem | undefined => {\n return state().shuffledQueue[getPointer()];\n };\n const getFirst = (): MediaItem | undefined => {\n return state().shuffledQueue[0];\n };\n const getLast = (): MediaItem | undefined => {\n return state().shuffledQueue[state().shuffledQueue.length - 1];\n };\n const getNext = (): MediaItem | undefined => {\n return state().shuffledQueue[getPointer() + 1];\n };\n const getPrevious = (): MediaItem | undefined => {\n return state().shuffledQueue[getPointer() - 1];\n };\n const isLast = (): boolean => {\n return getPointer() === state().originalQueue.length - 1;\n };\n\n return {\n getPointer,\n getCurrent,\n getFirst,\n getLast,\n getNext,\n getPrevious,\n isLast,\n };\n}\n","import {PlayerState} from '@common/player/state/player-state';\nimport {isCtrlOrShiftPressed} from '@common/utils/keybinds/is-ctrl-or-shift-pressed';\n\nexport function handlePlayerKeybinds(\n e: KeyboardEvent,\n state: () => PlayerState\n) {\n if (\n ['input', 'textarea'].includes(\n (e.target as HTMLElement)?.tagName.toLowerCase()\n )\n )\n return;\n\n if (e.key === ' ' || e.key === 'k') {\n e.preventDefault();\n if (state().isPlaying) {\n state().pause();\n } else {\n state().play();\n }\n }\n\n if (e.key === 'ArrowRight' && isCtrlOrShiftPressed(e)) {\n e.preventDefault();\n state().playNext();\n }\n\n if (e.key === 'ArrowLeft' && isCtrlOrShiftPressed(e)) {\n e.preventDefault();\n state().playPrevious();\n }\n}\n","import {Optional} from 'utility-types';\nimport {PlayerState} from '@common/player/state/player-state';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\n\nexport function initPlayerMediaSession(\n state: () => PlayerState,\n options: PlayerStoreOptions\n) {\n if ('mediaSession' in navigator) {\n const actionHandlers: Optional<\n Record<MediaSessionAction, MediaSessionActionHandler>\n > = {\n play: () => state().play(),\n pause: () => state().pause(),\n previoustrack: () => state().playPrevious(),\n nexttrack: () => state().playNext(),\n stop: () => state().stop(),\n seekbackward: () => state().seek(state().getCurrentTime() - 10),\n seekforward: () => state().seek(state().getCurrentTime() + 10),\n seekto: details => state().seek(details.seekTime || 0),\n };\n for (const key in actionHandlers) {\n try {\n navigator.mediaSession.setActionHandler(\n key as MediaSessionAction,\n actionHandlers[key as MediaSessionAction]!\n );\n } catch (error) {}\n }\n const cuedMedia = state().cuedMedia;\n if (cuedMedia) {\n options.setMediaSessionMetadata?.(cuedMedia);\n }\n }\n}\n","import {MediaItem} from '@common/player/media-item';\n\nexport function isSameMedia(a?: MediaItem, b?: MediaItem): boolean {\n if (!a || !b) return false;\n return a.id === b.id && a.groupId === b.groupId;\n}\n","export class ScreenOrientation {\n protected currentLock: OrientationLockType | undefined;\n\n async lock(lockType: OrientationLockType = 'landscape') {\n if (!this.canOrientScreen() || this.currentLock) return;\n try {\n await screen.orientation.lock(lockType);\n this.currentLock = lockType;\n } catch (e) {}\n }\n\n async unlock() {\n if (!this.canOrientScreen() || !this.currentLock) return;\n await screen.orientation.unlock();\n }\n\n canOrientScreen(): boolean {\n return (\n screen.orientation != null &&\n !!screen.orientation.lock &&\n !!screen.orientation.unlock\n );\n }\n}\n","export const IS_CLIENT = typeof window !== 'undefined';\nexport const UA = IS_CLIENT ? window.navigator?.userAgent.toLowerCase() : '';\nexport const IS_IOS = /iphone|ipad|ipod|ios|CriOS|FxiOS/.test(UA);\nexport const IS_ANDROID = /android/.test(UA);\nexport const IS_MOBILE = IS_CLIENT && (IS_IOS || IS_ANDROID);\nexport const IS_IPHONE =\n IS_CLIENT && /(iPhone|iPod)/gi.test(window.navigator?.platform);\nexport const IS_FIREFOX = /firefox/.test(UA);\n// @ts-ignore\nexport const IS_CHROME = IS_CLIENT && window.chrome;\nexport const IS_SAFARI =\n IS_CLIENT &&\n !IS_CHROME &&\n // @ts-ignore\n (window.safari || IS_IOS || /(apple|safari)/.test(UA));\n","var key = {\r\n fullscreenEnabled: 0,\r\n fullscreenElement: 1,\r\n requestFullscreen: 2,\r\n exitFullscreen: 3,\r\n fullscreenchange: 4,\r\n fullscreenerror: 5,\r\n fullscreen: 6\r\n};\r\nvar webkit = [\r\n 'webkitFullscreenEnabled',\r\n 'webkitFullscreenElement',\r\n 'webkitRequestFullscreen',\r\n 'webkitExitFullscreen',\r\n 'webkitfullscreenchange',\r\n 'webkitfullscreenerror',\r\n '-webkit-full-screen',\r\n];\r\nvar moz = [\r\n 'mozFullScreenEnabled',\r\n 'mozFullScreenElement',\r\n 'mozRequestFullScreen',\r\n 'mozCancelFullScreen',\r\n 'mozfullscreenchange',\r\n 'mozfullscreenerror',\r\n '-moz-full-screen',\r\n];\r\nvar ms = [\r\n 'msFullscreenEnabled',\r\n 'msFullscreenElement',\r\n 'msRequestFullscreen',\r\n 'msExitFullscreen',\r\n 'MSFullscreenChange',\r\n 'MSFullscreenError',\r\n '-ms-fullscreen',\r\n];\r\n// so it doesn't throw if no window or document\r\nvar document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {};\r\nvar vendor = (('fullscreenEnabled' in document && Object.keys(key)) ||\r\n (webkit[0] in document && webkit) ||\r\n (moz[0] in document && moz) ||\r\n (ms[0] in document && ms) ||\r\n []);\r\nvar fscreen = {\r\n requestFullscreen: function (element) { return element[vendor[key.requestFullscreen]](); },\r\n requestFullscreenFunction: function (element) { return element[vendor[key.requestFullscreen]]; },\r\n get exitFullscreen() { return document[vendor[key.exitFullscreen]].bind(document); },\r\n get fullscreenPseudoClass() { return \":\" + vendor[key.fullscreen]; },\r\n addEventListener: function (type, handler, options) { return document.addEventListener(vendor[key[type]], handler, options); },\r\n removeEventListener: function (type, handler, options) { return document.removeEventListener(vendor[key[type]], handler, options); },\r\n get fullscreenEnabled() { return Boolean(document[vendor[key.fullscreenEnabled]]); },\r\n set fullscreenEnabled(val) { },\r\n get fullscreenElement() { return document[vendor[key.fullscreenElement]]; },\r\n set fullscreenElement(val) { },\r\n get onfullscreenchange() { return document[(\"on\" + vendor[key.fullscreenchange]).toLowerCase()]; },\r\n set onfullscreenchange(handler) { return document[(\"on\" + vendor[key.fullscreenchange]).toLowerCase()] = handler; },\r\n get onfullscreenerror() { return document[(\"on\" + vendor[key.fullscreenerror]).toLowerCase()]; },\r\n set onfullscreenerror(handler) { return document[(\"on\" + vendor[key.fullscreenerror]).toLowerCase()] = handler; },\r\n};\n\nexport default fscreen;\n//# sourceMappingURL=fscreen.esm.js.map\n","import {FullscreenAdapter} from '@common/player/state/fullscreen/fullscreen-adapter';\nimport fscreen from 'fscreen';\n\nexport function createNativeFullscreenAdapter(\n host: HTMLElement,\n onChange: () => void\n): FullscreenAdapter {\n host = host.closest('.fullscreen-host') ?? host;\n return {\n isFullscreen: () => {\n if (fscreen.fullscreenElement === host) return true;\n try {\n // Throws in iOS Safari...\n return host.matches(\n // @ts-expect-error - `fullscreenPseudoClass` is missing from `@types/fscreen`.\n fscreen.fullscreenPseudoClass\n );\n } catch (error) {\n return false;\n }\n },\n canFullScreen: () => {\n return fscreen.fullscreenEnabled;\n },\n enter: () => {\n return fscreen.requestFullscreen(host);\n },\n exit: () => {\n return fscreen.exitFullscreen();\n },\n bindEvents: () => {\n fscreen.addEventListener('fullscreenchange', onChange);\n fscreen.addEventListener('fullscreenerror', onChange);\n },\n unbindEvents: () => {\n fscreen.removeEventListener('fullscreenchange', onChange);\n fscreen.removeEventListener('fullscreenerror', onChange);\n },\n };\n}\n","import {FullscreenAdapter} from '@common/player/state/fullscreen/fullscreen-adapter';\nimport {IS_IPHONE} from '@common/utils/platform';\n\nexport function createIphoneFullscreenAdapter(\n host: HTMLVideoElement,\n onChange: () => void\n): FullscreenAdapter {\n return {\n /**\n * @link https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1631913-webkitpresentationmode\n */\n isFullscreen: () => {\n return host.webkitPresentationMode === 'fullscreen';\n },\n /**\n * @link https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1628805-webkitsupportsfullscreen\n */\n canFullScreen: () => {\n return (\n IS_IPHONE &&\n typeof host.webkitSetPresentationMode === 'function' &&\n (host.webkitSupportsFullscreen ?? false)\n );\n },\n enter: () => {\n return host.webkitSetPresentationMode?.('fullscreen');\n },\n exit: () => {\n return host.webkitSetPresentationMode?.('inline');\n },\n bindEvents: () => {\n host.removeEventListener('webkitpresentationmodechanged', onChange);\n },\n unbindEvents: () => {\n host.addEventListener('webkitpresentationmodechanged', onChange);\n },\n };\n}\n","import {StateCreator} from 'zustand';\nimport {\n PlayerState,\n ProviderListeners,\n} from '@common/player/state/player-state';\nimport {ScreenOrientation} from '@common/player/state/fullscreen/screen-orientation';\nimport {IS_IPHONE} from '@common/utils/platform';\nimport {FullscreenAdapter} from '@common/player/state/fullscreen/fullscreen-adapter';\nimport {createNativeFullscreenAdapter} from '@common/player/state/fullscreen/create-native-fullscreen-adapter';\nimport {createIphoneFullscreenAdapter} from '@common/player/state/fullscreen/create-iphone-fullscreen-adapter';\nimport {PipSlice} from '@common/player/state/pip/pip-slice';\n\nexport interface FullscreenSlice {\n isFullscreen: boolean;\n canFullscreen: boolean;\n enterFullscreen: () => void;\n exitFullscreen: () => void;\n toggleFullscreen: () => void;\n initFullscreen: () => void;\n destroyFullscreen: () => void;\n}\n\ntype BaseSliceCreator = StateCreator<\n FullscreenSlice & PlayerState & PipSlice,\n [['zustand/immer', unknown]],\n [],\n FullscreenSlice\n>;\n\ntype StoreLice = BaseSliceCreator extends (...a: infer U) => infer R\n ? (...a: [...U, Set<Partial<ProviderListeners>>]) => R\n : never;\n\nconst iPhoneProviderBlacklist = ['youtube'];\n\nexport const createFullscreenSlice: StoreLice = (set, get) => {\n let subscription: () => void | undefined;\n const orientation = new ScreenOrientation();\n let adapter: FullscreenAdapter | undefined;\n\n const onFullscreenChange = async () => {\n const isFullscreen = adapter?.isFullscreen();\n if (isFullscreen) {\n // lock orientation to landscape\n orientation.lock();\n } else {\n orientation.unlock();\n }\n set({isFullscreen});\n };\n\n const isSupported = (): boolean => {\n // iPhone only allows putting video element in fullscreen, and\n // there's no way to get access to it with YouTube iframe api\n if (IS_IPHONE && iPhoneProviderBlacklist.includes(get().providerName!)) {\n return false;\n }\n return adapter?.canFullScreen() ?? false;\n };\n\n return {\n isFullscreen: false,\n canFullscreen: false,\n enterFullscreen: () => {\n if (!isSupported() || adapter?.isFullscreen()) return;\n\n // exit pip if it's active\n if (get().isPip) {\n get().exitPip();\n }\n return adapter?.enter();\n },\n exitFullscreen: () => {\n if (!adapter?.isFullscreen()) return;\n return adapter.exit();\n },\n toggleFullscreen: () => {\n if (get().isFullscreen) {\n get().exitFullscreen();\n } else {\n get().enterFullscreen();\n }\n },\n initFullscreen: () => {\n subscription = get().subscribe({\n providerReady: ({el}) => {\n // when changing adapters, remove previous adapter events and exit fullscreen\n adapter?.unbindEvents();\n if (get().isFullscreen) {\n adapter?.exit();\n }\n // create new adapter, and if fullscreen is supported, bind events\n adapter = IS_IPHONE\n ? createIphoneFullscreenAdapter(\n el as HTMLVideoElement,\n onFullscreenChange\n )\n : createNativeFullscreenAdapter(el, onFullscreenChange);\n const canFullscreen = isSupported();\n set({canFullscreen});\n if (canFullscreen) {\n adapter.bindEvents();\n }\n },\n });\n },\n destroyFullscreen: () => {\n get().exitFullscreen();\n subscription?.();\n },\n };\n};\n","import {PipAdapter} from '@common/player/state/pip/pip-adapter';\nimport {IS_CLIENT} from '@common/utils/platform';\n\nexport const createChromePipAdapter = (\n host: HTMLVideoElement,\n onChange: () => void\n): PipAdapter => {\n return {\n isSupported: () => canUsePiPInChrome(),\n isPip: () => {\n return host === document.pictureInPictureElement;\n },\n enter: () => {\n if (canUsePiPInChrome()) {\n return host.requestPictureInPicture();\n }\n },\n exit: () => {\n if (canUsePiPInChrome()) {\n return document.exitPictureInPicture();\n }\n },\n bindEvents: () => {\n if (canUsePiPInChrome()) {\n host.addEventListener('enterpictureinpicture', onChange);\n host.addEventListener('leavepictureinpicture', onChange);\n }\n },\n unbindEvents: () => {\n if (canUsePiPInChrome()) {\n host.removeEventListener('enterpictureinpicture', onChange);\n host.removeEventListener('leavepictureinpicture', onChange);\n }\n },\n };\n};\n\n/**\n * Checks if the native HTML5 video player can enter picture-in-picture (PIP) mode when using\n * the Chrome browser.\n *\n * @see https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture\n */\nlet _canUsePiPInChrome: boolean | undefined;\nconst canUsePiPInChrome = (): boolean => {\n if (!IS_CLIENT) return false;\n if (_canUsePiPInChrome == null) {\n const video = document.createElement('video');\n _canUsePiPInChrome =\n !!document.pictureInPictureEnabled && !video.disablePictureInPicture;\n }\n return _canUsePiPInChrome;\n};\n","import {PipAdapter} from '@common/player/state/pip/pip-adapter';\nimport {IS_CLIENT, IS_IPHONE} from '@common/utils/platform';\n\nexport const createSafariPipAdapter = (\n host: HTMLVideoElement,\n onChange: () => void\n): PipAdapter => {\n return {\n isSupported: () => canUsePiPInSafari(),\n isPip: () => {\n return host.webkitPresentationMode === 'picture-in-picture';\n },\n enter: () => {\n if (canUsePiPInSafari()) {\n return host.webkitSetPresentationMode?.('picture-in-picture');\n }\n },\n exit: () => {\n if (canUsePiPInSafari()) {\n return host.webkitSetPresentationMode?.('inline');\n }\n },\n bindEvents: () => {\n if (canUsePiPInSafari()) {\n host.addEventListener('webkitpresentationmodechanged', onChange);\n }\n },\n unbindEvents: () => {\n if (canUsePiPInSafari()) {\n host.removeEventListener('webkitpresentationmodechanged', onChange);\n }\n },\n };\n};\n\n/**\n * Checks if the native HTML5 video player can enter picture-in-picture (PIP) mode when using\n * the desktop Safari browser, iOS Safari appears to \"support\" PiP through the check, however PiP\n * does not function.\n *\n * @see https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls\n */\nlet _canUsePiPInSafari: boolean | undefined;\nconst canUsePiPInSafari = (): boolean => {\n if (!IS_CLIENT) return false;\n const video = document.createElement('video');\n if (_canUsePiPInSafari == null) {\n _canUsePiPInSafari =\n // @ts-ignore\n !!video.webkitSupportsPresentationMode &&\n // @ts-ignore\n !!video.webkitSetPresentationMode &&\n !IS_IPHONE;\n }\n return _canUsePiPInSafari;\n};\n","import {StateCreator} from 'zustand';\nimport {\n PlayerState,\n ProviderListeners,\n} from '@common/player/state/player-state';\nimport {PipAdapter} from '@common/player/state/pip/pip-adapter';\nimport {createChromePipAdapter} from '@common/player/state/pip/chrome-pip-adapter';\nimport {createSafariPipAdapter} from '@common/player/state/pip/safari-pip-adapter';\n\nexport interface PipSlice {\n isPip: boolean;\n canPip: boolean;\n enterPip: () => void;\n exitPip: () => void;\n togglePip: () => void;\n initPip: () => void;\n destroyPip: () => void;\n}\n\ntype BaseSliceCreator = StateCreator<\n PipSlice & PlayerState,\n [['zustand/immer', unknown]],\n [],\n PipSlice\n>;\n\ntype StoreLice = BaseSliceCreator extends (...a: infer U) => infer R\n ? (...a: [...U, Set<Partial<ProviderListeners>>]) => R\n : never;\n\nconst adapterFactories = [createChromePipAdapter, createSafariPipAdapter];\n\nexport const createPipSlice: StoreLice = (set, get) => {\n let subscription: () => void | undefined;\n let adapters: PipAdapter[] = [];\n\n const onPipChange = () => {\n set({isPip: adapters.some(a => a.isPip())});\n };\n\n const isSupported = (): boolean => {\n if (get().providerName !== 'htmlVideo') {\n return false;\n }\n return adapters.some(adapter => adapter.isSupported());\n };\n\n return {\n isPip: false,\n canPip: false,\n enterPip: async () => {\n if (get().isPip || !isSupported()) return;\n await adapters.find(a => a.isSupported())?.enter();\n },\n exitPip: async () => {\n if (!get().isPip) return;\n await adapters.find(a => a.isSupported())?.exit();\n },\n togglePip: () => {\n if (get().isPip) {\n get().exitPip();\n } else {\n get().enterPip();\n }\n },\n initPip: () => {\n subscription = get().subscribe({\n providerReady: ({el}) => {\n // when changing adapters, remove previous adapter events and exit pip\n adapters.every(a => a.unbindEvents());\n if (get().isPip) {\n adapters.every(a => a.exit());\n }\n // create new adapters, and if pip is supported on at least one, bind events\n adapters = adapterFactories.map(factory =>\n factory(el as HTMLVideoElement, onPipChange)\n );\n const canPip = isSupported();\n if (canPip) {\n adapters.every(a => a.bindEvents());\n }\n set({canPip});\n },\n });\n },\n destroyPip: () => {\n get().exitPip();\n subscription?.();\n },\n };\n};\n","import {createStore} from 'zustand';\nimport {immer} from 'zustand/middleware/immer';\nimport {MediaItem} from '@common/player/media-item';\nimport {setInLocalStorage as _setInLocalStorage} from '@common/utils/hooks/local-storage';\nimport {shuffleArray} from '@common/utils/array/shuffle-array';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport {getPlayerStateFromLocalStorage} from '@common/player/utils/player-local-storage';\nimport {prependToArrayAtIndex} from '@common/utils/array/prepend-to-array-at-index';\nimport deepMerge from 'deepmerge';\nimport {resetMediaSession} from '@common/player/utils/reset-media-session';\nimport {playerQueue} from '@common/player/player-queue';\nimport type {\n PlayerState,\n ProviderListeners,\n RepeatMode,\n} from '@common/player/state/player-state';\nimport {handlePlayerKeybinds} from '@common/player/handle-player-keybinds';\nimport {initPlayerMediaSession} from '@common/player/utils/init-player-media-session';\nimport {isSameMedia} from '@common/player/utils/is-same-media';\nimport {\n createFullscreenSlice,\n FullscreenSlice,\n} from '@common/player/state/fullscreen/fullscreen-slice';\nimport {createPipSlice, PipSlice} from '@common/player/state/pip/pip-slice';\nimport {subscribeWithSelector} from 'zustand/middleware';\n\n// todo: for play logging: https://css-tricks.com/send-an-http-request-on-page-exit/\n// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon\n\nexport const createPlayerStore = (\n id: string | number,\n options: PlayerStoreOptions\n) => {\n // initialData from options should take priority over local storage data\n const initialData = deepMerge(\n getPlayerStateFromLocalStorage(id, options),\n options.initialData || {}\n );\n\n const setInLocalStorage = (key: string, value: any) => {\n _setInLocalStorage(`player.${id}.${key}`, value);\n };\n\n return createStore<PlayerState & FullscreenSlice & PipSlice>()(\n subscribeWithSelector(\n immer((set, get, store) => {\n const listeners = new Set<Partial<ProviderListeners>>();\n const internalListeners: Partial<ProviderListeners> = {\n play: () => {\n set(s => {\n s.isPlaying = true;\n s.playbackStarted = true;\n });\n },\n pause: () => {\n set(s => {\n s.isPlaying = false;\n s.controlsVisible = true;\n });\n },\n error: () => {\n set(s => {\n s.isPlaying = false;\n });\n },\n durationChange: payload => {\n set({mediaDuration: payload.duration});\n },\n streamTypeChange: payload => {\n set({streamType: payload.streamType});\n },\n buffered: payload => {\n //\n },\n playbackRateChange: payload => {\n set({playbackRate: payload.rate});\n },\n playbackRates: ({rates}) => {\n set({playbackRates: rates});\n },\n playbackQualities: ({qualities}) => {\n set({playbackQualities: qualities});\n },\n playbackQualityChange: ({quality}) => {\n set({playbackQuality: quality});\n },\n textTracks: ({tracks}) => {\n set({textTracks: tracks});\n },\n currentTextTrackChange: ({trackId}) => {\n set({currentTextTrack: trackId});\n },\n textTrackVisibilityChange: ({isVisible}) => {\n set({textTrackIsVisible: isVisible});\n },\n buffering: ({isBuffering}) => {\n set({isBuffering});\n },\n playbackEnd: async () => {\n const media = get().cuedMedia;\n\n // don't play next or repeat while seeking via seekbar\n if (get().isSeeking) return;\n if (queue.isLast() && options.loadMoreMediaItems) {\n const items = await options.loadMoreMediaItems(media);\n if (items?.length) {\n get().appendToQueue(items);\n }\n }\n get().playNext();\n },\n posterLoaded: ({url}) => {\n set({posterUrl: url});\n },\n providerReady: () => {\n const provider = get().providerApi;\n if (provider) {\n provider.setVolume(get().volume);\n provider.setMuted(get().muted);\n if (options.autoPlay) {\n provider.play();\n }\n set({providerReady: true});\n }\n },\n };\n\n const queue = playerQueue(get);\n\n const keybindsHandler = (e: KeyboardEvent) => {\n handlePlayerKeybinds(e, get);\n };\n\n const initialQueue = initialData.queue || [];\n return {\n options,\n ...createFullscreenSlice(set, get, store, listeners),\n ...createPipSlice(set, get, store, listeners),\n originalQueue: initialQueue,\n shuffledQueue: initialData.state?.shuffling\n ? shuffleArray(initialQueue)\n : initialQueue,\n isPlaying: false,\n isBuffering: false,\n streamType: null,\n playbackStarted: false,\n providerReady: false,\n pauseWhileSeeking: options.pauseWhileSeeking ?? true,\n isSeeking: false,\n setIsSeeking: (isSeeking: boolean) => {\n set({isSeeking});\n },\n controlsVisible: true,\n setControlsVisible: (isVisible: boolean) => {\n set(s => {\n s.controlsVisible = isVisible;\n });\n },\n volume: initialData.state?.volume ?? 30,\n setVolume: value => {\n get().providerApi?.setVolume(value);\n set(s => {\n s.volume = value;\n });\n setInLocalStorage('volume', value);\n },\n muted: initialData.state?.muted ?? false,\n setMuted: isMuted => {\n get().providerApi?.setMuted(isMuted);\n set(s => {\n s.muted = isMuted;\n });\n setInLocalStorage('muted', isMuted);\n },\n playbackRates: [],\n playbackRate: 1,\n setPlaybackRate: speed => {\n get().providerApi?.setPlaybackRate(speed);\n },\n playbackQuality: 'auto',\n setPlaybackQuality: quality => {\n get().providerApi?.setPlaybackQuality?.(quality);\n },\n playbackQualities: [],\n repeat: initialData.state?.repeat ?? 'all',\n toggleRepeatMode: () => {\n let newRepeat: RepeatMode = 'all';\n const currentRepeat = get().repeat;\n if (currentRepeat === 'all') {\n newRepeat = 'one';\n } else if (currentRepeat === 'one') {\n newRepeat = false;\n }\n\n set({repeat: newRepeat});\n setInLocalStorage('repeat', newRepeat);\n },\n shuffling: initialData.state?.shuffling ?? false,\n toggleShuffling: () => {\n let newQueue: MediaItem[] = [];\n\n if (get().shuffling) {\n newQueue = get().originalQueue;\n } else {\n newQueue = shuffleArray([...get().shuffledQueue]);\n }\n\n set(s => {\n s.shuffling = !s.shuffling;\n s.shuffledQueue = newQueue;\n });\n },\n mediaDuration: 0,\n seek: time => {\n const timeStr = `${time}`;\n if (timeStr.startsWith('+')) {\n time = get().getCurrentTime() + Number(time);\n } else if (timeStr.startsWith('-')) {\n time = get().getCurrentTime() - Number(timeStr.replace('-', ''));\n } else {\n time = Number(time);\n }\n get().providerApi?.seek(time);\n get().emit('seek', {time});\n },\n getCurrentTime: () => {\n return get().providerApi?.getCurrentTime() || 0;\n },\n play: async media => {\n // get currently active queue item, if none is provided\n if (media) {\n await get().cue(media);\n } else {\n media = get().cuedMedia || queue.getCurrent();\n }\n // if no media to play, stop player and bail\n if (!media) {\n get().stop();\n return;\n }\n await options.onBeforePlay?.();\n await get().providerApi?.play();\n },\n pause: () => {\n get().providerApi?.pause();\n },\n stop: () => {\n if (!get().isPlaying) return;\n get().pause();\n get().seek(0);\n },\n playNext: async () => {\n get().stop();\n let media = queue.getCurrent();\n\n if (get().repeat === 'all' && queue.isLast()) {\n media = queue.getFirst();\n } else if (get().repeat !== 'one') {\n media = queue.getNext();\n }\n\n if (media) {\n await get().play(media);\n } else {\n get().seek(0);\n get().play();\n }\n },\n playPrevious: async () => {\n get().stop();\n let media = queue.getCurrent();\n\n if (get().repeat === 'all' && queue.getPointer() === 0) {\n media = queue.getLast();\n } else if (get().repeat !== 'one') {\n media = queue.getPrevious();\n }\n\n if (media) {\n await get().play(media);\n } else {\n get().seek(0);\n get().play();\n }\n },\n cue: async media => {\n if (isSameMedia(media, get().cuedMedia)) return;\n\n get().emit('beforeCued', {previous: get().cuedMedia});\n\n return new Promise((resolve, reject) => {\n const previousProvider = get().providerName;\n\n // wait until media is cued on provider or 3 seconds\n const timeoutId = setTimeout(() => {\n unsubscribe();\n resolve();\n }, 3000);\n const unsubscribe = get().subscribe({\n cued: () => {\n clearTimeout(timeoutId);\n unsubscribe();\n resolve();\n },\n error: () => {\n clearTimeout(timeoutId);\n unsubscribe();\n reject();\n },\n });\n\n set({\n cuedMedia: media,\n posterUrl: media.poster,\n providerName: media.provider,\n providerReady: previousProvider === media.provider,\n streamType: 'streamType' in media ? media.streamType : null,\n });\n\n if (media) {\n options.setMediaSessionMetadata?.(media);\n }\n\n if (options.persistQueueInLocalStorage) {\n setInLocalStorage('cuedMediaId', media.id);\n }\n });\n },\n async overrideQueue(\n mediaItems: MediaItem[],\n queuePointer: number = 0\n ): Promise<any> {\n if (!mediaItems?.length) return;\n const items = [...mediaItems];\n set(s => {\n s.shuffledQueue = get().shuffling\n ? shuffleArray(items, true)\n : items;\n s.originalQueue = items;\n });\n if (options.persistQueueInLocalStorage) {\n setInLocalStorage('queue', get().originalQueue.slice(0, 15));\n }\n const media =\n queuePointer > -1 ? mediaItems[queuePointer] : queue.getCurrent();\n if (media) {\n return get().cue(media);\n }\n },\n appendToQueue: (mediaItems, afterCuedMedia = true) => {\n const shuffledNewItems = get().shuffling\n ? shuffleArray([...mediaItems])\n : [...mediaItems];\n const index = afterCuedMedia ? queue.getPointer() : 0;\n set(s => {\n s.shuffledQueue = prependToArrayAtIndex(\n s.shuffledQueue,\n shuffledNewItems,\n index\n );\n s.originalQueue = prependToArrayAtIndex(\n s.originalQueue,\n mediaItems,\n index\n );\n });\n if (options.persistQueueInLocalStorage) {\n setInLocalStorage('queue', get().originalQueue.slice(0, 15));\n }\n },\n removeFromQueue: mediaItems => {\n set(s => {\n s.shuffledQueue = s.shuffledQueue.filter(\n item => !mediaItems.find(m => isSameMedia(m, item))\n );\n s.originalQueue = s.originalQueue.filter(\n item => !mediaItems.find(m => isSameMedia(m, item))\n );\n });\n if (options.persistQueueInLocalStorage) {\n setInLocalStorage('queue', get().originalQueue.slice(0, 15));\n }\n },\n textTracks: [],\n currentTextTrack: -1,\n setCurrentTextTrack: trackId => {\n get().providerApi?.setCurrentTextTrack?.(trackId);\n },\n textTrackIsVisible: false,\n setTextTrackVisibility: isVisible => {\n get().providerApi?.setTextTrackVisibility?.(isVisible);\n },\n destroy: () => {\n get().destroyFullscreen();\n get().destroyPip();\n options?.onDestroy?.();\n resetMediaSession();\n listeners.clear();\n document.removeEventListener('keydown', keybindsHandler);\n },\n init: async () => {\n // add initial and listeners from options, these will be present for the entire lifetime of the player\n get().initFullscreen();\n\n listeners.add(internalListeners);\n if (options.listeners) {\n listeners.add(options.listeners as Partial<ProviderListeners>);\n }\n\n const mediaId =\n initialData.cuedMediaId || initialData.queue?.[0]?.id;\n const mediaToCue = initialData.queue?.find(\n media => media.id === mediaId\n );\n if (mediaToCue) {\n await get().cue(mediaToCue);\n }\n initPlayerMediaSession(get, options);\n document.addEventListener('keydown', keybindsHandler);\n },\n subscribe: newListeners => {\n listeners.add(newListeners);\n return () => listeners.delete(newListeners);\n },\n emit(event, payload?: any) {\n listeners.forEach(l => l[event]?.({state: get(), ...payload}));\n },\n };\n })\n )\n );\n};\n","import {createContext, ReactNode, useState} from 'react';\nimport {createPlayerStore} from '@common/player/state/player-store';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport type {PlayerStoreApi} from '@common/player/state/player-state';\n\nexport const PlayerStoreContext = createContext<PlayerStoreApi>(null!);\n\ninterface PlayerContextProps {\n children: ReactNode;\n id: string | number;\n options: PlayerStoreOptions;\n}\nexport function PlayerContext({children, id, options}: PlayerContextProps) {\n //lazily create store object only once\n const [store] = useState(() => {\n return createPlayerStore(id, options);\n });\n\n return (\n <PlayerStoreContext.Provider value={store}>\n {children}\n </PlayerStoreContext.Provider>\n );\n}\n","import {StoreApi, useStore} from 'zustand';\nimport {useContext} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {PlayerState} from '@common/player/state/player-state';\nimport {FullscreenSlice} from '@common/player/state/fullscreen/fullscreen-slice';\nimport {PipSlice} from '@common/player/state/pip/pip-slice';\n\ntype ExtractState<S> = S extends {\n getState: () => infer T;\n}\n ? T\n : never;\n\ntype UsePlayerStore = {\n (): ExtractState<StoreApi<PlayerState>>;\n <U>(\n selector: (\n state: ExtractState<StoreApi<PlayerState & FullscreenSlice & PipSlice>>\n ) => U,\n equalityFn?: (a: U, b: U) => boolean\n ): U;\n};\n\n// @ts-ignore\nexport const usePlayerStore: UsePlayerStore = (selector, equalityFn) => {\n const store = useContext(PlayerStoreContext);\n return useStore(store, selector, equalityFn);\n};\n","import {useContext, useMemo} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {MediaItem} from '@common/player/media-item';\n\nexport type PlayerActions = ReturnType<typeof usePlayerActions>;\n\nexport function usePlayerActions() {\n const store = useContext(PlayerStoreContext);\n\n return useMemo(() => {\n const s = store.getState();\n\n const overrideQueueAndPlay = async (\n mediaItems: MediaItem[],\n queuePointer?: number\n ) => {\n s.stop();\n await s.overrideQueue(mediaItems, queuePointer);\n return s.play();\n };\n\n return {\n play: s.play,\n playNext: s.playNext,\n playPrevious: s.playPrevious,\n pause: s.pause,\n subscribe: s.subscribe,\n emit: s.emit,\n getCurrentTime: s.getCurrentTime,\n seek: s.seek,\n toggleRepeatMode: s.toggleRepeatMode,\n toggleShuffling: s.toggleShuffling,\n getState: store.getState,\n setVolume: s.setVolume,\n setMuted: s.setMuted,\n appendToQueue: s.appendToQueue,\n removeFromQueue: s.removeFromQueue,\n enterFullscreen: s.enterFullscreen,\n exitFullscreen: s.exitFullscreen,\n toggleFullscreen: s.toggleFullscreen,\n enterPip: s.enterPip,\n exitPip: s.exitPip,\n setTextTrackVisibility: s.setTextTrackVisibility,\n setCurrentTextTrack: s.setCurrentTextTrack,\n setIsSeeking: s.setIsSeeking,\n setControlsVisible: s.setControlsVisible,\n cue: s.cue,\n overrideQueueAndPlay,\n overrideQueue: s.overrideQueue,\n setPlaybackRate: s.setPlaybackRate,\n setPlaybackQuality: s.setPlaybackQuality,\n };\n }, [store]);\n}\n","import {apiClient, queryClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Track} from '@app/web-player/tracks/track';\n\ninterface Response extends BackendResponse {\n tracks: Track[];\n}\n\nexport async function loadMediaItemTracks(\n queueId: string,\n lastTrack?: Track\n): Promise<Response['tracks']> {\n const query = {\n queryKey: ['player/tracks', {queueId, trackId: lastTrack?.id}],\n queryFn: async () => loadTracks(queueId, lastTrack),\n staleTime: Infinity,\n };\n\n try {\n const response =\n queryClient.getQueryData<Response>(query.queryKey) ??\n (await queryClient.fetchQuery(query));\n return response?.tracks || [];\n } catch (e) {\n return [];\n }\n}\n\nfunction loadTracks(queueId: string, lastTrack?: Track): Promise<Response> {\n return apiClient\n .post('player/tracks', {queueId, lastTrack})\n .then(response => response.data);\n}\n","import {MediaItem} from '@common/player/media-item';\n\nconst hlsRegex = /\\.(m3u8)($|\\?)/i;\nconst dashRegex = /\\.(mpd)($|\\?)/i;\nconst audioRegex =\n /\\.(m4a|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\\?)/i;\nconst youtubeUrlRegex =\n /(?:youtu\\.be|youtube|youtube\\.com|youtube-nocookie\\.com)\\/(?:embed\\/|v\\/|watch\\?v=|watch\\?.+&v=|)((?:\\w|-){11})/;\nconst youtubeIdRegex = /^((?:\\w|-){11})$/;\nexport function guessPlayerProvider(src: string): MediaItem['provider'] {\n if (youtubeUrlRegex.test(src) || youtubeIdRegex.test(src)) {\n return 'youtube';\n } else if (audioRegex.test(src)) {\n return 'htmlAudio';\n } else if (hlsRegex.test(src)) {\n return 'hls';\n } else if (dashRegex.test(src)) {\n return 'dash';\n } else {\n return 'htmlVideo';\n }\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {MediaItem} from '@common/player/media-item';\nimport {getTrackImageSrc} from '@app/web-player/tracks/track-image/track-image';\nimport {Album} from '@app/web-player/albums/album';\nimport {guessPlayerProvider} from '@common/player/utils/guess-player-provider';\n\nexport function trackToMediaItem(\n track: Track,\n queueGroupId?: string | number\n): MediaItem<Track> {\n const provider: MediaItem['provider'] = track.src\n ? guessPlayerProvider(track.src)\n : 'youtube';\n\n if (!track.src || provider === 'youtube') {\n return {\n id: track.id,\n provider: 'youtube',\n meta: track,\n src: track.src ? track.src : 'resolve',\n groupId: queueGroupId,\n };\n }\n\n return {\n id: track.id,\n src: track.src,\n provider,\n meta: track,\n poster: getTrackImageSrc(track),\n groupId: queueGroupId,\n };\n}\n\nexport function tracksToMediaItems(\n tracks: Track[],\n queueGroupId?: string,\n album?: Album\n) {\n return tracks.map(track => {\n if (album && !track.album) {\n track = {\n ...track,\n album: {...album, tracks: undefined},\n };\n }\n return trackToMediaItem(track);\n });\n}\n","export default \"__VITE_ASSET__11267b4b__\"","export default \"__VITE_ASSET__2dd5a730__\"","import white from './equalizer-white.gif';\nimport black from './equalizer-black.gif';\nimport clsx from 'clsx';\nimport {useIsDarkMode} from '@common/ui/themes/use-is-dark-mode';\n\ninterface EqualizerImageProps {\n className?: string;\n color?: 'black' | 'white';\n}\nexport function EqualizerImage({className, color}: EqualizerImageProps) {\n const isDarkMode = useIsDarkMode();\n\n if (!color) {\n color = isDarkMode ? 'white' : 'black';\n }\n\n return (\n <div\n className={clsx('flex items-center justify-center w-20 h-20', className)}\n >\n <img\n src={color === 'white' ? white : black}\n alt=\"\"\n className=\"w-12 h-12\"\n aria-hidden\n />\n </div>\n );\n}\n","import {ComponentPropsWithoutRef, useState} from 'react';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {loadMediaItemTracks} from '@app/web-player/requests/load-media-item-tracks';\nimport {trackToMediaItem} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {PauseIcon} from '@common/icons/material/Pause';\nimport {EqualizerImage} from '@app/web-player/tracks/equalizer-image/equalizer-image';\nimport {PlayArrowFilledIcon} from '@app/web-player/tracks/play-arrow-filled';\nimport {\n ButtonColor,\n ButtonVariant,\n} from '@common/ui/buttons/get-shared-button-style';\nimport {Button} from '@common/ui/buttons/button';\nimport {Trans} from '@common/i18n/trans';\nimport {Track} from '@app/web-player/tracks/track';\nimport {ButtonSize} from '@common/ui/buttons/button-size';\n\ninterface PlaybackToggleButtonProps {\n queueId?: string;\n // track that should be cued\n track?: Track;\n // queue should be overwritten with these tracks\n tracks?: Track[];\n radius?: string;\n variant?: ButtonVariant;\n color?: ButtonColor;\n disabled?: boolean;\n className?: string;\n buttonType: 'icon' | 'text';\n equalizerColor?: 'white' | 'black';\n size?: ButtonSize;\n}\nexport function PlaybackToggleButton({\n queueId,\n track,\n tracks,\n radius,\n variant,\n color,\n disabled,\n className,\n buttonType,\n equalizerColor = buttonType === 'text' ? 'white' : 'black',\n size,\n}: PlaybackToggleButtonProps) {\n const [isHover, setIsHover] = useState(false);\n const modelIsQueued = usePlayerStore(s => {\n // specified queue ID is cued\n if (s.cuedMedia && queueId && s.cuedMedia.groupId === queueId) {\n return true;\n }\n // specified track is cued\n if (s.cuedMedia && track && s.cuedMedia.meta.id === track.id) {\n return true;\n }\n return false;\n });\n const isPlaying = usePlayerStore(s => s.isPlaying);\n const modelIsPlaying = isPlaying && modelIsQueued;\n const player = usePlayerActions();\n\n const statusIcon = modelIsPlaying ? (\n isHover ? (\n <PauseIcon />\n ) : (\n <EqualizerImage color={equalizerColor} />\n )\n ) : (\n <PlayArrowFilledIcon />\n );\n\n const sharedProps: ComponentPropsWithoutRef<'button'> = {\n disabled,\n onPointerEnter: () => {\n setIsHover(true);\n },\n onPointerLeave: () => {\n setIsHover(false);\n },\n onClick: async () => {\n if (modelIsPlaying) {\n player.pause();\n } else if (modelIsQueued) {\n await player.play();\n } else {\n let newQueue: Track[] = [];\n let newIndex: number = 0;\n if (tracks) {\n newQueue = [...tracks];\n newIndex = track ? tracks.findIndex(t => t.id === track.id) : 0;\n } else if (track) {\n newQueue = [track];\n } else {\n newQueue = await loadMediaItemTracks(queueId!);\n }\n if (newQueue.length) {\n await player.overrideQueueAndPlay(\n newQueue.map(t => trackToMediaItem(t, queueId)),\n newIndex\n );\n }\n }\n },\n };\n\n if (buttonType === 'icon') {\n return (\n <IconButton\n {...sharedProps}\n variant={variant}\n color={color}\n radius={radius}\n size={size}\n className={className}\n >\n {statusIcon}\n </IconButton>\n );\n }\n\n return (\n <Button\n {...sharedProps}\n variant={variant || 'flat'}\n color={color || 'primary'}\n radius={radius || 'rounded-full'}\n startIcon={statusIcon}\n size={size}\n className={className}\n >\n {modelIsPlaying ? <Trans message=\"Pause\" /> : <Trans message=\"Play\" />}\n </Button>\n );\n}\n","interface MediaItem {\n id: number;\n model_type: string;\n}\n\nexport function queueGroupId(\n model: MediaItem,\n kind: string = '*',\n sortDescriptor?: {orderBy?: string; orderDir?: string}\n): string {\n let base = `${model.model_type}.${model.id}.${kind}`;\n if (sortDescriptor?.orderBy && sortDescriptor?.orderDir) {\n base += `.${sortDescriptor.orderBy.replace('.', '^')}|${\n sortDescriptor.orderDir\n }`;\n }\n return base;\n}\n","import {cloneElement, ReactElement, ReactNode} from 'react';\nimport {IconButton, IconButtonProps} from '@common/ui/buttons/icon-button';\nimport {MoreHorizIcon} from '@common/icons/material/MoreHoriz';\nimport {PlayableModel} from '@app/web-player/playable-item/playable-model';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport clsx from 'clsx';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {Track, TRACK_MODEL} from '@app/web-player/tracks/track';\n\ninterface PlayableGridProps {\n image: ReactElement;\n title: ReactNode;\n subtitle?: ReactNode;\n model: PlayableModel;\n newQueue?: Track[];\n link: string;\n likeButton?: ReactElement<IconButtonProps>;\n contextDialog: ReactElement;\n radius?: string;\n}\nexport function PlayableGridItem({\n image,\n title,\n subtitle,\n model,\n newQueue,\n link,\n likeButton,\n contextDialog,\n radius = 'rounded',\n}: PlayableGridProps) {\n const navigate = useNavigate();\n return (\n <div className=\"snap-start snap-normal\">\n <DialogTrigger\n type=\"popover\"\n placement=\"bottom-start\"\n triggerOnContextMenu\n >\n <div className=\"w-full relative isolate group\">\n <div\n className=\"w-full aspect-square this\"\n onClick={() => navigate(link)}\n >\n {cloneElement(image, {\n size: 'w-full h-full',\n className: `${radius} shadow-md z-10`,\n })}\n </div>\n <div\n key=\"bg-overlay\"\n className={`absolute top-0 left-0 w-full h-full bg-gradient-to-b from-transparent to-black/75 ${radius} z-20 opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none`}\n />\n <div\n className={clsx(\n 'absolute bottom-0 left-0 w-full p-12 z-30 flex items-center gap-14',\n radius === 'rounded-full' &&\n 'justify-center top-0 right-0 pointer-events-none'\n )}\n >\n <PlaybackToggleButton\n size={radius === 'rounded-full' ? 'lg' : 'md'}\n radius=\"rounded-full\"\n className={clsx(\n 'shadow-md pointer-events-auto',\n radius === 'rounded-full' && 'invisible group-hover:visible'\n )}\n variant=\"flat\"\n color=\"white\"\n buttonType=\"icon\"\n track={model.model_type === TRACK_MODEL ? model : undefined}\n tracks={newQueue}\n queueId={queueGroupId(model)}\n />\n\n {radius !== 'rounded-full' && (\n <DialogTrigger type=\"popover\">\n <IconButton\n className=\"invisible md:group-hover:visible\"\n color=\"white\"\n >\n <MoreHorizIcon />\n </IconButton>\n {contextDialog}\n </DialogTrigger>\n )}\n {radius !== 'rounded-full' &&\n likeButton &&\n // 3 buttons won't fit if item is fully rounded\n cloneElement(likeButton, {\n className: 'invisible md:group-hover:visible ml-auto',\n size: 'md',\n color: 'white',\n })}\n </div>\n </div>\n {contextDialog}\n </DialogTrigger>\n <div\n className={clsx(\n radius === 'rounded-full' && 'text-center',\n 'text-sm mt-12'\n )}\n >\n <div className=\"overflow-hidden overflow-ellipsis\">{title}</div>\n <div className=\"text-muted mt-4 whitespace-nowrap overflow-hidden overflow-ellipsis\">\n {subtitle}\n </div>\n </div>\n </div>\n );\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {useAuth} from '@common/auth/use-auth';\n\ninterface GetAuthUserPlaylistsResponse extends BackendResponse {\n playlists: Playlist[];\n}\n\nexport function useAuthUserPlaylists() {\n const {isLoggedIn, user} = useAuth();\n return useQuery(\n ['playlists', 'library', user?.id, 'compact'],\n () => fetchPlaylists(),\n {\n enabled: isLoggedIn,\n initialData: () => {\n return {\n playlists: getBootstrapData().playlists || [],\n };\n },\n }\n );\n}\n\nfunction fetchPlaylists(): Promise<GetAuthUserPlaylistsResponse> {\n return apiClient\n .get('users/me/playlists', {\n params: {perPage: 30, orderBy: 'updated_at', orderDir: 'desc'},\n })\n .then(response => {\n return {playlists: response.data.pagination.data};\n });\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {Track} from '@app/web-player/tracks/track';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface Response extends BackendResponse {\n playlist: Playlist;\n}\n\ninterface Payload {\n playlistId: number;\n tracks: Track[];\n}\n\nexport function useAddTracksToPlaylist() {\n return useMutation((payload: Payload) => addTracks(payload), {\n onSuccess: (response, {tracks}) => {\n toast(\n message('Added [one 1 track|other :count tracks] to playlist', {\n values: {count: tracks.length},\n })\n );\n queryClient.invalidateQueries(['playlists', response.playlist.id]);\n queryClient.invalidateQueries([\n 'tracks',\n 'playlist',\n response.playlist.id,\n ]);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction addTracks(payload: Payload): Promise<Response> {\n const backendPayload = {\n ids: payload.tracks.map(track => track.id),\n };\n return apiClient\n .post(`playlists/${payload.playlistId}/tracks/add`, backendPayload)\n .then(r => r.data);\n}\n","import {MouseEvent, useCallback} from 'react';\nimport {useAuth} from '@common/auth/use-auth';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\n\nexport function useAuthClickCapture() {\n const dialogContext = useDialogContext();\n const {isLoggedIn} = useAuth();\n const navigate = useNavigate();\n\n return useCallback(\n (e: MouseEvent) => {\n if (!isLoggedIn) {\n e.preventDefault();\n e.stopPropagation();\n\n if (dialogContext) {\n dialogContext.close();\n }\n\n navigate('/login');\n }\n },\n [navigate, isLoggedIn, dialogContext]\n );\n}\n","import {useAuthUserPlaylists} from '@app/web-player/playlists/requests/use-auth-user-playlists';\nimport {m} from 'framer-motion';\nimport {Button} from '@common/ui/buttons/button';\nimport {KeyboardBackspaceIcon} from '@common/icons/material/KeyboardBackspace';\nimport {Trans} from '@common/i18n/trans';\nimport {\n ContextMenuButton,\n ContextMenuLayoutState,\n} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {AddIcon} from '@common/icons/material/Add';\nimport {KeyboardArrowRightIcon} from '@common/icons/material/KeyboardArrowRight';\nimport {useContext, useMemo} from 'react';\nimport {useAddTracksToPlaylist} from '@app/web-player/playlists/requests/use-add-tracks-to-playlist';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport {CreatePlaylistDialog} from '@app/web-player/playlists/crupdate-dialog/create-playlist-dialog';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {useAuth} from '@common/auth/use-auth';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\nexport function PlaylistPanel() {\n const {data} = useAuthUserPlaylists();\n const {user} = useAuth();\n const {close: closeMenu} = useDialogContext();\n const {loadTracks, setPlaylistPanelIsActive} = useContext(\n ContextMenuLayoutState\n );\n const addToPlaylist = useAddTracksToPlaylist();\n\n // only show playlists user created or ones that are collaborative\n const playlists = useMemo(() => {\n return data.playlists.filter(\n p => p.owner_id === user?.id || p.collaborative\n );\n }, [data, user]);\n\n return (\n <m.div\n initial={{x: '100%', opacity: 0}}\n animate={{x: 0, opacity: 1}}\n exit={{x: '-100%', opacity: 0}}\n transition={{type: 'tween', duration: 0.14}}\n >\n <div className=\"border-b pb-10 my-10 px-10\">\n <Button\n startIcon={<KeyboardBackspaceIcon />}\n onClick={() => setPlaylistPanelIsActive(false)}\n >\n <Trans message=\"Back\" />\n </Button>\n </div>\n <ul className=\"overflow-y-auto overflow-x-hidden max-h-350\">\n <ContextMenuButton\n startIcon={<AddIcon />}\n onClick={async () => {\n closeMenu();\n const [playlist, tracks] = await Promise.all([\n openDialog(CreatePlaylistDialog),\n loadTracks(),\n ]);\n if (tracks.length && playlist) {\n addToPlaylist.mutate({\n playlistId: playlist.id,\n tracks,\n });\n }\n }}\n className=\"text-primary\"\n >\n <Trans message=\"New playlist\" />\n </ContextMenuButton>\n {playlists.map(playlist => (\n <ContextMenuButton\n key={playlist.id}\n onClick={async () => {\n closeMenu();\n const tracks = await loadTracks();\n if (tracks?.length && !addToPlaylist.isLoading) {\n addToPlaylist.mutate({\n playlistId: playlist.id,\n tracks,\n });\n } else {\n toast(message('This item does not have tracks yet'));\n }\n }}\n >\n {playlist.name}\n </ContextMenuButton>\n ))}\n </ul>\n </m.div>\n );\n}\n\nexport function PlaylistPanelButton() {\n const authHandler = useAuthClickCapture();\n const {playlistPanelIsActive, setPlaylistPanelIsActive} = useContext(\n ContextMenuLayoutState\n );\n return (\n <ContextMenuButton\n endIcon={<KeyboardArrowRightIcon />}\n onClickCapture={authHandler}\n onClick={() => {\n setPlaylistPanelIsActive(!playlistPanelIsActive);\n }}\n >\n <Trans message=\"Add to playlist\" />\n </ContextMenuButton>\n );\n}\n","import {AnimatePresence} from 'framer-motion';\nimport {\n cloneElement,\n ComponentPropsWithRef,\n createContext,\n forwardRef,\n ReactElement,\n ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {SvgIconProps} from '@common/icons/svg-icon';\nimport clsx from 'clsx';\nimport {PlaylistPanel} from '@app/web-player/context-dialog/playlist-panel';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Dialog} from '@common/ui/overlays/dialog/dialog';\nimport {DialogBody} from '@common/ui/overlays/dialog/dialog-body';\nimport {Link, To, useLocation} from 'react-router-dom';\nimport {usePrevious} from '@common/utils/hooks/use-previous';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\n\ninterface ContextMenuLayoutStateValue {\n playlistPanelIsActive: boolean;\n setPlaylistPanelIsActive: (value: boolean) => void;\n loadTracks: () => Promise<Track[]>;\n}\nexport const ContextMenuLayoutState =\n createContext<ContextMenuLayoutStateValue>(null!);\n\nexport interface ContextMenuLayoutProps {\n image?: ReactElement<{className: string}> | null;\n title?: ReactElement | null;\n description?: ReactElement;\n children: ReactNode;\n loadTracks: () => Promise<Track[]>;\n}\nexport function ContextDialogLayout({\n image,\n title,\n description,\n children,\n loadTracks,\n}: ContextMenuLayoutProps) {\n const [playlistPanelIsActive, setPlaylistPanelIsActive] = useState(false);\n const {close} = useDialogContext();\n const contextValue: ContextMenuLayoutStateValue = useMemo(() => {\n return {\n playlistPanelIsActive,\n setPlaylistPanelIsActive,\n loadTracks,\n };\n }, [playlistPanelIsActive, loadTracks]);\n\n const {pathname} = useLocation();\n\n // close dialog on route change\n const previousPathname = usePrevious(pathname);\n useEffect(() => {\n if (previousPathname && previousPathname !== pathname) {\n close();\n }\n }, [pathname, previousPathname, close]);\n\n const header =\n image || title ? (\n <div className=\"flex items-center gap-14 border-b p-14 mb-10\">\n {image && cloneElement(image, {className: 'w-44 h-44 rounded'})}\n <div className=\"whitespace-nowrap overflow-hidden overflow-ellipsis\">\n {title}\n {description && (\n <div className=\"text-xs text-muted\">{description}</div>\n )}\n </div>\n </div>\n ) : null;\n\n return (\n <ContextMenuLayoutState.Provider value={contextValue}>\n <Dialog size=\"xs\">\n <DialogBody\n padding=\"p-0\"\n onContextMenu={e => {\n e.preventDefault();\n e.stopPropagation();\n }}\n >\n <div className=\"pb-10\">\n {header}\n <AnimatePresence initial={false} mode=\"wait\">\n {playlistPanelIsActive ? (\n <PlaylistPanel key=\"playlist-panel\" />\n ) : (\n <ul key=\"menu\" className=\"text-base md:text-sm\">\n {children}\n </ul>\n )}\n </AnimatePresence>\n </div>\n </DialogBody>\n </Dialog>\n </ContextMenuLayoutState.Provider>\n );\n}\n\ninterface ButtonMenuItemProps\n extends Omit<ComponentPropsWithRef<'button'>, 'type'> {\n type?: 'button';\n}\n\ninterface LinkMenuItemProps\n extends Omit<ComponentPropsWithRef<'link'>, 'type'> {\n type?: 'link';\n}\n\ntype ContextMenuListItemProps = (ButtonMenuItemProps | LinkMenuItemProps) & {\n children: ReactNode;\n endIcon?: ReactElement<SvgIconProps>;\n startIcon?: ReactElement<SvgIconProps>;\n className?: string;\n to?: To;\n};\nexport const ContextMenuButton = forwardRef<any, ContextMenuListItemProps>(\n (\n {\n children,\n endIcon,\n startIcon,\n className,\n type = 'button',\n to,\n ...buttonProps\n },\n ref\n ) => {\n const Element = type === 'button' ? 'button' : Link;\n return (\n <li>\n <Element\n {...(buttonProps as any)}\n to={to as any}\n ref={ref}\n className={clsx(\n 'flex items-center gap-12 py-12 px-20 hover:bg-hover cursor-pointer outline-none focus-visible:ring focus-visible:ring-inset w-full text-left',\n className\n )}\n >\n {startIcon}\n <span className=\"mr-auto whitespace-nowrap overflow-hidden overflow-ellipsis min-w-0\">\n {children}\n </span>\n {endIcon}\n </Element>\n </li>\n );\n }\n);\n","import {create} from 'zustand';\nimport {immer} from 'zustand/middleware/immer';\nimport {TRACK_MODEL} from '@app/web-player/tracks/track';\nimport {ALBUM_MODEL} from '@app/web-player/albums/album';\nimport {ARTIST_MODEL} from '@app/web-player/artists/artist';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {Likeable} from '@app/web-player/library/likeable';\n\ninterface State {\n [TRACK_MODEL]: Record<number, boolean>;\n [ALBUM_MODEL]: Record<number, boolean>;\n [ARTIST_MODEL]: Record<number, boolean>;\n has: (item: Likeable | Likeable[]) => boolean;\n add: (items: Likeable[]) => void;\n remove: (items: Likeable[]) => void;\n}\n\nexport function createCountableStore(key: 'likes' | 'reposts') {\n const items = getBootstrapData()[key];\n return create<State>()(\n immer((set, get) => ({\n track: items?.track || {},\n album: items?.album || {},\n artist: (items && 'artist' in items && items?.artist) || {},\n has: item => {\n const items = Array.isArray(item) ? item : [item];\n return items.every(item => {\n return get()[item.model_type][item.id];\n });\n },\n add: items => {\n // will only be adding items with the same\n // type in one call, no need to group by type\n const type = items[0].model_type;\n set(state => {\n items.forEach(item => {\n state[type][item.id] = true;\n });\n });\n },\n remove: items => {\n const type = items[0].model_type;\n set(state => {\n items.forEach(item => {\n delete state[type][item.id];\n });\n });\n },\n }))\n );\n}\n","import {createCountableStore} from '@app/web-player/library/state/create-countable-store';\n\nexport const useLibraryStore = createCountableStore('likes');\n\nexport const userLibrary = useLibraryStore.getState;\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {Likeable} from '@app/web-player/library/likeable';\nimport {userLibrary} from '@app/web-player/library/state/likes-store';\n\ninterface Response extends BackendResponse {}\n\ninterface Payload {\n likeables: Likeable[];\n}\n\nexport function useAddItemsToLibrary() {\n return useMutation((payload: Payload) => addToLibrary(payload), {\n onSuccess: (response, payload) => {\n toast(getMessage(payload.likeables[0]));\n userLibrary().add(payload.likeables);\n // tracks/albums/artists\n queryClient.invalidateQueries([\n `${payload.likeables[0].model_type}s`,\n 'library',\n ]);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction addToLibrary(payload: Payload): Promise<Response> {\n const likeables = payload.likeables\n .filter(likeable => {\n return !userLibrary().has(likeable);\n })\n .map(likeable => {\n return {\n likeable_id: likeable.id,\n likeable_type: likeable.model_type,\n };\n });\n return apiClient\n .post('users/me/add-to-library', {likeables})\n .then(r => r.data);\n}\n\nfunction getMessage(likeable: Likeable) {\n switch (likeable.model_type) {\n case 'artist':\n return message('Added to your artists');\n case 'album':\n return message('Added to your albums');\n case 'track':\n return message('Added to your liked songs');\n }\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {Likeable} from '@app/web-player/library/likeable';\nimport {userLibrary} from '@app/web-player/library/state/likes-store';\n\ninterface Response extends BackendResponse {}\n\ninterface Payload {\n likeables: Likeable[];\n}\n\nexport function useRemoveItemsFromLibrary() {\n return useMutation((payload: Payload) => addToLibrary(payload), {\n onSuccess: (response, payload) => {\n toast(getMessage(payload.likeables[0]));\n userLibrary().remove(payload.likeables);\n // tracks/albums/artists\n queryClient.invalidateQueries([\n `${payload.likeables[0].model_type}s`,\n 'library',\n ]);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction addToLibrary(payload: Payload): Promise<Response> {\n const likeables = payload.likeables\n .filter(likeable => {\n return userLibrary().has(likeable);\n })\n .map(likeable => {\n return {\n likeable_id: likeable.id,\n likeable_type: likeable.model_type,\n };\n });\n return apiClient\n .post('users/me/remove-from-library', {likeables})\n .then(r => r.data);\n}\n\nfunction getMessage(likeable: Likeable) {\n switch (likeable.model_type) {\n case 'artist':\n return message('Removed from your artists');\n case 'album':\n return message('Removed from your albums');\n case 'track':\n return message('Removed from your liked songs');\n }\n}\n","import {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {Trans} from '@common/i18n/trans';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {useAddItemsToLibrary} from '@app/web-player/library/requests/use-add-items-to-library';\nimport {useRemoveItemsFromLibrary} from '@app/web-player/library/requests/use-remove-items-from-library';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport {Likeable} from '@app/web-player/library/likeable';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\ninterface ToggleInLibraryMenuButtonProps {\n items: Likeable[];\n}\nexport function ToggleInLibraryMenuButton({\n items,\n}: ToggleInLibraryMenuButtonProps) {\n const authHandler = useAuthClickCapture();\n const {close: closeMenu} = useDialogContext();\n const addToLibrary = useAddItemsToLibrary();\n const removeFromLibrary = useRemoveItemsFromLibrary();\n const allInLibrary = useLibraryStore(s => s.has(items));\n\n if (allInLibrary) {\n return (\n <ContextMenuButton\n onClickCapture={authHandler}\n onClick={() => {\n closeMenu();\n removeFromLibrary.mutate({likeables: items});\n }}\n >\n <Trans message=\"Remove from your music\" />\n </ContextMenuButton>\n );\n }\n\n return (\n <ContextMenuButton\n onClickCapture={authHandler}\n onClick={() => {\n closeMenu();\n addToLibrary.mutate({likeables: items});\n }}\n >\n <Trans message=\"Add to your music\" />\n </ContextMenuButton>\n );\n}\n","import useCopyClipboard from 'react-use-clipboard';\nimport {getAlbumLink} from '@app/web-player/albums/album-link';\nimport {ReactNode} from 'react';\nimport {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {Trans} from '@common/i18n/trans';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\n\ninterface CopyLinkMenuButtonProps {\n link: string;\n children: ReactNode;\n}\nexport function CopyLinkMenuButton({link, children}: CopyLinkMenuButtonProps) {\n const {close: closeMenu} = useDialogContext();\n const [, copyLink] = useCopyClipboard(link);\n\n return (\n <ContextMenuButton\n onClick={() => {\n copyLink();\n closeMenu();\n toast(message('Copied link to clipboard'));\n }}\n >\n {children}\n </ContextMenuButton>\n );\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {useLocation} from 'react-router-dom';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuth} from '@common/auth/use-auth';\n\ninterface Response extends BackendResponse {}\n\nexport function useDeleteArtist(artistId: number | string) {\n const {pathname} = useLocation();\n const navigate = useNavigate();\n const {getRedirectUri} = useAuth();\n\n return useMutation(() => deleteArtist(artistId), {\n onSuccess: () => {\n toast(message('Artist deleted'));\n // navigate to homepage if we are on this artist page currently\n if (pathname.startsWith(`/artist/${artistId}`)) {\n navigate(getRedirectUri());\n }\n queryClient.invalidateQueries(['tracks']);\n queryClient.invalidateQueries(['albums']);\n queryClient.invalidateQueries(['artists']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction deleteArtist(artistId: number | string): Promise<Response> {\n return apiClient.delete(`artists/${artistId}`).then(r => r.data);\n}\n","import {slugifyString} from '@common/utils/string/slugify-string';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {RadioSeed} from '@app/web-player/radio/requests/use-radio-recommendations';\n\nexport function getRadioLink(\n seed: RadioSeed,\n {absolute}: {absolute?: boolean} = {}\n): string {\n let link = `/radio/${seed.model_type}/${seed.id}/${slugifyString(seed.name)}`;\n if (absolute) {\n link = `${getBootstrapData().settings.base_url}${link}`;\n }\n return link;\n}\n","import {useSettings} from '@common/core/settings/use-settings';\n\nexport function useShouldShowRadioButton(): boolean {\n const {player, artist_provider} = useSettings();\n return !player?.hide_radio_button && artist_provider === 'spotify';\n}\n","import {useTrans} from '@common/i18n/use-trans';\nimport {message} from '@common/i18n/message';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport defaultImage from './../albums/album-image/default-album-image.png';\nimport {getTrackImageSrc} from '@app/web-player/tracks/track-image/track-image';\nimport clsx from 'clsx';\n\ninterface PlaylistImageProps {\n playlist: Playlist;\n className?: string;\n size?: string;\n}\nexport function PlaylistImage({playlist, className, size}: PlaylistImageProps) {\n const {trans} = useTrans();\n return (\n <img\n className={clsx(className, size, 'object-cover bg-fg-base/4')}\n draggable={false}\n loading=\"lazy\"\n src={getPlaylistImageSrc(playlist)}\n alt={trans(message('Image for :name', {values: {name: playlist.name}}))}\n />\n );\n}\n\nexport function getPlaylistImageSrc(playlist: Playlist) {\n if (playlist.image) {\n return playlist.image;\n }\n const firstTrackImage = playlist.tracks?.[0]\n ? getTrackImageSrc(playlist.tracks[0])\n : null;\n if (firstTrackImage) {\n return firstTrackImage;\n }\n return defaultImage;\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {Album} from '@app/web-player/albums/album';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Dialog} from '@common/ui/overlays/dialog/dialog';\nimport {DialogHeader} from '@common/ui/overlays/dialog/dialog-header';\nimport {Trans} from '@common/i18n/trans';\nimport {DialogBody} from '@common/ui/overlays/dialog/dialog-body';\nimport {Tabs} from '@common/ui/tabs/tabs';\nimport {TabList} from '@common/ui/tabs/tab-list';\nimport {Tab} from '@common/ui/tabs/tab';\nimport {TabPanel, TabPanels} from '@common/ui/tabs/tab-panels';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {getAlbumLink} from '@app/web-player/albums/album-link';\nimport {getTrackLink} from '@app/web-player/tracks/track-link';\nimport {Button} from '@common/ui/buttons/button';\nimport {useRef} from 'react';\nimport useCopyClipboard from 'react-use-clipboard';\nimport {ShareMediaButtons} from '@app/web-player/sharing/share-media-buttons';\nimport {DialogFooter} from '@common/ui/overlays/dialog/dialog-footer';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {PlaylistImage} from '@app/web-player/playlists/playlist-image';\nimport {getPlaylistLink} from '@app/web-player/playlists/playlist-link';\n\ninterface Props {\n item: Artist | Album | Track | Playlist;\n}\nexport function ShareMediaDialog({item}: Props) {\n const {close} = useDialogContext();\n return (\n <Dialog size=\"xl\">\n <DialogHeader>\n <Trans message=\"Share :name\" values={{name: item.name}} />\n </DialogHeader>\n <DialogBody>\n {item.model_type === 'artist' || item.model_type === 'playlist' ? (\n <SharePanel item={item} />\n ) : (\n <Tabs>\n <TabList>\n <Tab>\n <Trans message=\"Share\" />\n </Tab>\n <Tab>\n <Trans message=\"Embed\" />\n </Tab>\n </TabList>\n <TabPanels className=\"pt-20\">\n <TabPanel>\n <SharePanel item={item} />\n </TabPanel>\n <TabPanel>\n <EmbedPanel item={item} />\n </TabPanel>\n </TabPanels>\n </Tabs>\n )}\n </DialogBody>\n <DialogFooter>\n <Button onClick={() => close()}>\n <Trans message=\"Close\" />\n </Button>\n </DialogFooter>\n </Dialog>\n );\n}\n\nfunction EmbedPanel({item}: Props) {\n const isMobile = useIsMobileMediaQuery();\n const link = `${getLink(item)}/embed`;\n const height = item.model_type === 'track' ? 174 : 384;\n\n const code = `<iframe width=\"100%\" height=\"${height}\" allow=\"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture\" src=\"${link}\"></iframe>`;\n\n return (\n <div>\n {!isMobile && (\n <iframe\n src={link}\n width=\"100%\"\n height={height}\n allow=\"autoplay; fullscreen; picture-in-picture\"\n allowFullScreen\n />\n )}\n <TextField\n className=\"mt-20\"\n inputElementType=\"textarea\"\n readOnly\n value={code}\n rows={3}\n onClick={e => {\n e.currentTarget.focus();\n e.currentTarget.select();\n }}\n />\n </div>\n );\n}\n\nfunction SharePanel({item}: Props) {\n const link = getLink(item);\n const inputRef = useRef<HTMLInputElement>(null);\n const [copied, copyLink] = useCopyClipboard(link, {successDuration: 600});\n return (\n <div className=\"flex items-center gap-14\">\n <MediaImage\n item={item}\n size=\"w-128 h-128\"\n className=\"rounded object-cover flex-shrink-0 max-md:hidden\"\n />\n <div className=\"flex-auto\">\n <div className=\"text-xl mb-8\">{item.name}</div>\n <TextField\n className=\"mb-8\"\n inputRef={inputRef}\n readOnly\n onClick={e => {\n e.currentTarget.focus();\n e.currentTarget.select();\n }}\n value={link}\n endAppend={\n <Button\n variant=\"flat\"\n color=\"primary\"\n onClick={() => {\n inputRef.current?.select();\n copyLink();\n }}\n >\n {copied ? <Trans message=\"Copied!\" /> : <Trans message=\"Copy\" />}\n </Button>\n }\n />\n <ShareMediaButtons\n link={link}\n image={'image' in item ? item.image : (item as any).image_small}\n name={item.name}\n />\n </div>\n </div>\n );\n}\n\ninterface MediaImageProps {\n item: Props['item'];\n className?: string;\n size?: string;\n}\nfunction MediaImage({item, className, size}: MediaImageProps) {\n switch (item.model_type) {\n case 'artist':\n return (\n <SmallArtistImage\n size={size}\n className={className}\n wrapperClassName=\"max-md:hidden\"\n artist={item}\n />\n );\n case 'album':\n return <AlbumImage size={size} className={className} album={item} />;\n case 'track':\n return <TrackImage size={size} className={className} track={item} />;\n case 'playlist':\n return (\n <PlaylistImage size={size} className={className} playlist={item} />\n );\n }\n}\n\nfunction getLink(item: Props['item']) {\n switch (item.model_type) {\n case 'artist':\n return getArtistLink(item, {absolute: true});\n case 'album':\n return getAlbumLink(item, {absolute: true});\n case 'track':\n return getTrackLink(item, {absolute: true});\n case 'playlist':\n return getPlaylistLink(item, {absolute: true});\n }\n}\n","import {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {Trans} from '@common/i18n/trans';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {Album} from '@app/web-player/albums/album';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport React from 'react';\nimport {ShareMediaDialog} from '@app/web-player/sharing/share-media-dialog';\nimport {Playlist} from '@app/web-player/playlists/playlist';\n\ninterface Props {\n item: Track | Album | Artist | Playlist;\n}\nexport function ShareMediaButton({item}: Props) {\n const {close: closeMenu} = useDialogContext();\n return (\n <ContextMenuButton\n onClick={() => {\n closeMenu();\n openDialog(ShareMediaDialog, {\n item,\n });\n }}\n >\n <Trans message=\"Share\" />\n </ContextMenuButton>\n );\n}\n","import {Trans} from '@common/i18n/trans';\nimport {Track} from '@app/web-player/tracks/track';\nimport {\n ContextDialogLayout,\n ContextMenuButton,\n} from '@app/web-player/context-dialog/context-dialog-layout';\nimport React, {useCallback} from 'react';\nimport {ToggleInLibraryMenuButton} from '@app/web-player/context-dialog/toggle-in-library-menu-button';\nimport {CopyLinkMenuButton} from '@app/web-player/context-dialog/copy-link-menu-button';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {useArtistPermissions} from '@app/web-player/artists/use-artist-permissions';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {ArtistLink, getArtistLink} from '@app/web-player/artists/artist-link';\nimport {useDeleteArtist} from '@app/web-player/artists/requests/use-delete-artist';\nimport {getRadioLink} from '@app/web-player/radio/get-radio-link';\nimport {useShouldShowRadioButton} from '@app/web-player/tracks/context-dialog/use-should-show-radio-button';\nimport {ShareMediaButton} from '@app/web-player/context-dialog/share-media-button';\n\ninterface ArtistContextDialogProps {\n artist: Artist;\n}\nexport function ArtistContextDialog({artist}: ArtistContextDialogProps) {\n const showRadioButton = useShouldShowRadioButton();\n const {canEdit} = useArtistPermissions(artist);\n const loadTracks = useCallback(() => {\n return loadArtistTracks(artist);\n }, [artist]);\n\n return (\n <ContextDialogLayout\n image={<SmallArtistImage artist={artist} />}\n title={<ArtistLink artist={artist} />}\n loadTracks={loadTracks}\n >\n <ToggleInLibraryMenuButton items={[artist]} />\n {showRadioButton && (\n <ContextMenuButton type=\"link\" to={getRadioLink(artist)}>\n <Trans message=\"Go to artist radio\" />\n </ContextMenuButton>\n )}\n <CopyLinkMenuButton link={getArtistLink(artist, {absolute: true})}>\n <Trans message=\"Copy artist link\" />\n </CopyLinkMenuButton>\n <ShareMediaButton item={artist} />\n {canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/artists/${artist.id}/insights`}\n >\n <Trans message=\"Insights\" />\n </ContextMenuButton>\n )}\n {canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/artists/${artist.id}/edit`}\n >\n <Trans message=\"Edit\" />\n </ContextMenuButton>\n )}\n <DeleteButton artist={artist} />\n </ContextDialogLayout>\n );\n}\n\nfunction DeleteButton({artist}: ArtistContextDialogProps) {\n const {close: closeMenu} = useDialogContext();\n const deleteArtist = useDeleteArtist(artist.id);\n const {canDelete} = useArtistPermissions(artist);\n\n if (!canDelete) {\n return null;\n }\n\n return (\n <ContextMenuButton\n disabled={deleteArtist.isLoading}\n onClick={() => {\n closeMenu();\n openDialog(ConfirmationDialog, {\n isDanger: true,\n title: <Trans message=\"Delete artist\" />,\n body: (\n <Trans message=\"Are you sure you want to delete this artist?\" />\n ),\n confirm: <Trans message=\"Delete\" />,\n onConfirm: () => {\n deleteArtist.mutate();\n },\n });\n }}\n >\n <Trans message=\"Delete\" />\n </ContextMenuButton>\n );\n}\n\n// tracks are never used/loaded in artist context dialog\nasync function loadArtistTracks(artist: Artist): Promise<Track[]> {\n return Promise.resolve([]);\n}\n","import {useAddItemsToLibrary} from '@app/web-player/library/requests/use-add-items-to-library';\nimport {useRemoveItemsFromLibrary} from '@app/web-player/library/requests/use-remove-items-from-library';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport {Likeable} from '@app/web-player/library/likeable';\nimport {IconButton, IconButtonProps} from '@common/ui/buttons/icon-button';\nimport {FavoriteIcon} from '@common/icons/material/Favorite';\nimport {FavoriteBorderIcon} from '@common/icons/material/FavoriteBorder';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\ninterface LikeIconButtonProps\n extends Omit<IconButtonProps, 'children' | 'disabled' | 'onClick'> {\n likeable: Likeable;\n}\nexport function LikeIconButton({\n likeable,\n size = 'sm',\n ...buttonProps\n}: LikeIconButtonProps) {\n const authHandler = useAuthClickCapture();\n const addToLibrary = useAddItemsToLibrary();\n const removeFromLibrary = useRemoveItemsFromLibrary();\n const isLiked = useLibraryStore(s => s.has(likeable));\n const isLoading = addToLibrary.isLoading || removeFromLibrary.isLoading;\n\n if (isLiked) {\n return (\n <IconButton\n {...buttonProps}\n size={size}\n color=\"primary\"\n disabled={isLoading}\n onClickCapture={authHandler}\n onClick={e => {\n e.stopPropagation();\n removeFromLibrary.mutate({likeables: [likeable]});\n }}\n >\n <FavoriteIcon />\n </IconButton>\n );\n }\n return (\n <IconButton\n {...buttonProps}\n size={size}\n disabled={isLoading}\n onClickCapture={authHandler}\n onClick={e => {\n e.stopPropagation();\n addToLibrary.mutate({likeables: [likeable]});\n }}\n >\n <FavoriteBorderIcon />\n </IconButton>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {PlayableGridItem} from '@app/web-player/playable-item/playable-grid-item';\nimport {ArtistContextDialog} from '@app/web-player/artists/artist-context-dialog';\nimport {ArtistLink, getArtistLink} from '@app/web-player/artists/artist-link';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\n\ninterface ArtistGridItemProps {\n artist: Artist;\n radius?: string;\n}\nexport function ArtistGridItem({\n artist,\n radius = 'rounded-full',\n}: ArtistGridItemProps) {\n return (\n <PlayableGridItem\n image={<SmallArtistImage artist={artist} />}\n title={<ArtistLink artist={artist} />}\n model={artist}\n link={getArtistLink(artist)}\n likeButton={<LikeIconButton likeable={artist} />}\n contextDialog={<ArtistContextDialog artist={artist} />}\n radius={radius}\n />\n );\n}\n","import {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {Trans} from '@common/i18n/trans';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {tracksToMediaItems} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {Album} from '@app/web-player/albums/album';\n\ntype MediaItem = Track[] | Album | Artist | Playlist;\n\ninterface AddToQueueButtonProps {\n item: MediaItem;\n loadTracks: () => Promise<Track[]>;\n}\nexport function AddToQueueButton({item, loadTracks}: AddToQueueButtonProps) {\n const {close: closeMenu} = useDialogContext();\n const player = usePlayerActions();\n\n return (\n <ContextMenuButton\n onClick={async () => {\n closeMenu();\n const tracks = await loadTracks();\n player.appendToQueue(\n tracksToMediaItems(\n tracks,\n Array.isArray(item) ? undefined : queueGroupId(item)\n )\n );\n }}\n >\n <Trans message=\"Add to queue\" />\n </ContextMenuButton>\n );\n}\n","import {createCountableStore} from '@app/web-player/library/state/create-countable-store';\n\nexport const useRepostsStore = createCountableStore('reposts');\n\nexport const userReposts = useRepostsStore.getState;\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Album} from '@app/web-player/albums/album';\nimport {userReposts} from '@app/web-player/library/state/reposts-store';\n\ninterface Response extends BackendResponse {\n action: 'added' | 'removed';\n}\n\ninterface Payload {\n repostable: Track | Album;\n}\n\nexport function useToggleRepost() {\n return useMutation((payload: Payload) => toggleRepost(payload), {\n onSuccess: (response, {repostable}) => {\n if (response.action === 'added') {\n userReposts().add([repostable]);\n } else {\n userReposts().remove([repostable]);\n }\n queryClient.invalidateQueries(['reposts']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction toggleRepost({repostable}: Payload): Promise<Response> {\n const payload = {\n repostable_id: repostable.id,\n repostable_type: repostable.model_type,\n };\n return apiClient.post('reposts/toggle', payload).then(r => r.data);\n}\n","import {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {Trans} from '@common/i18n/trans';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Album} from '@app/web-player/albums/album';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {useToggleRepost} from '@app/web-player/reposts/use-toggle-repost';\nimport {useRepostsStore} from '@app/web-player/library/state/reposts-store';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\ninterface Props {\n item: Track | Album;\n}\nexport function ToggleRepostMenuButton({item}: Props) {\n const authHandler = useAuthClickCapture();\n const {close: closeMenu} = useDialogContext();\n const {player} = useSettings();\n const toggleRepost = useToggleRepost();\n const isReposted = useRepostsStore(s => s.has(item));\n if (!player?.enable_repost) return null;\n\n return (\n <ContextMenuButton\n onClickCapture={authHandler}\n onClick={() => {\n closeMenu();\n toggleRepost.mutate({repostable: item});\n }}\n >\n {isReposted ? <Trans message=\"Reposted\" /> : <Trans message=\"Repost\" />}\n </ContextMenuButton>\n );\n}\n","import {Album} from '@app/web-player/albums/album';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {AlbumLink, getAlbumLink} from '@app/web-player/albums/album-link';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {Trans} from '@common/i18n/trans';\nimport {loadMediaItemTracks} from '@app/web-player/requests/load-media-item-tracks';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {Track} from '@app/web-player/tracks/track';\nimport {\n ContextDialogLayout,\n ContextMenuButton,\n} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {PlaylistPanelButton} from '@app/web-player/context-dialog/playlist-panel';\nimport {useAlbumPermissions} from '@app/web-player/albums/use-album-permissions';\nimport React, {useCallback} from 'react';\nimport {AddToQueueButton} from '@app/web-player/context-dialog/add-to-queue-menu-button';\nimport {ToggleInLibraryMenuButton} from '@app/web-player/context-dialog/toggle-in-library-menu-button';\nimport {CopyLinkMenuButton} from '@app/web-player/context-dialog/copy-link-menu-button';\nimport {useDeleteAlbum} from '@app/web-player/albums/requests/use-delete-album';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';\nimport {ToggleRepostMenuButton} from '@app/web-player/context-dialog/toggle-repost-menu-button';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {ShareMediaButton} from '@app/web-player/context-dialog/share-media-button';\n\ninterface AlbumContextMenuProps {\n album: Album;\n}\nexport function AlbumContextDialog({album}: AlbumContextMenuProps) {\n const {canEdit} = useAlbumPermissions(album);\n const isMobile = useIsMobileMediaQuery();\n\n const loadTracks = useCallback(() => {\n return loadAlbumTracks(album);\n }, [album]);\n\n return (\n <ContextDialogLayout\n image={<AlbumImage album={album} />}\n title={<AlbumLink album={album} />}\n description={<ArtistLinks artists={album.artists} />}\n loadTracks={loadTracks}\n >\n <AddToQueueButton item={album} loadTracks={loadTracks} />\n <PlaylistPanelButton />\n <ToggleInLibraryMenuButton items={[album]} />\n {isMobile && album.artists?.[0] && (\n <ContextMenuButton type=\"link\" to={getArtistLink(album.artists[0])}>\n <Trans message=\"Go to artist\" />\n </ContextMenuButton>\n )}\n {!isMobile && (\n <CopyLinkMenuButton link={getAlbumLink(album, {absolute: true})}>\n <Trans message=\"Copy album link\" />\n </CopyLinkMenuButton>\n )}\n <ShareMediaButton item={album} />\n <ToggleRepostMenuButton item={album} />\n {canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/albums/${album.id}/insights`}\n >\n <Trans message=\"Insights\" />\n </ContextMenuButton>\n )}\n {canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/albums/${album.id}/edit`}\n >\n <Trans message=\"Edit\" />\n </ContextMenuButton>\n )}\n <DeleteButton album={album} />\n </ContextDialogLayout>\n );\n}\n\nfunction DeleteButton({album}: AlbumContextMenuProps) {\n const {close: closeMenu} = useDialogContext();\n const deleteAlbum = useDeleteAlbum();\n const {canDelete} = useAlbumPermissions(album);\n\n if (!canDelete) {\n return null;\n }\n\n return (\n <ContextMenuButton\n disabled={deleteAlbum.isLoading}\n onClick={() => {\n closeMenu();\n openDialog(ConfirmationDialog, {\n isDanger: true,\n title: <Trans message=\"Delete album\" />,\n body: <Trans message=\"Are you sure you want to delete this album?\" />,\n confirm: <Trans message=\"Delete\" />,\n onConfirm: () => {\n deleteAlbum.mutate({albumId: album.id});\n },\n });\n }}\n >\n <Trans message=\"Delete\" />\n </ContextMenuButton>\n );\n}\n\nasync function loadAlbumTracks(album: Album): Promise<Track[]> {\n // load album tracks if not loaded already\n if (typeof album.tracks === 'undefined') {\n const tracks = await loadMediaItemTracks(queueGroupId(album));\n if (!tracks.length) {\n toast(message('This album has no tracks yet.'));\n }\n return tracks;\n }\n return album.tracks;\n}\n","import {Album} from '@app/web-player/albums/album';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {PlayableGridItem} from '@app/web-player/playable-item/playable-grid-item';\nimport {AlbumLink, getAlbumLink} from '@app/web-player/albums/album-link';\nimport {AlbumContextDialog} from '@app/web-player/albums/album-context-dialog';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\n\ninterface AlbumGridItemProps {\n album: Album;\n}\nexport function AlbumGridItem({album}: AlbumGridItemProps) {\n return (\n <PlayableGridItem\n image={<AlbumImage album={album} />}\n title={<AlbumLink album={album} />}\n subtitle={<ArtistLinks artists={album.artists} />}\n link={getAlbumLink(album)}\n likeButton={<LikeIconButton likeable={album} />}\n model={album}\n contextDialog={<AlbumContextDialog album={album} />}\n />\n );\n}\n","import defaultImage from './../artists/artist-image/artist-default-image-small.jpg';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {message} from '@common/i18n/message';\nimport clsx from 'clsx';\nimport {Genre} from '@app/web-player/genres/genre';\n\ninterface GenreImageProps {\n genre: Genre;\n className?: string;\n size?: string;\n}\nexport function GenreImage({genre, className, size}: GenreImageProps) {\n const {trans} = useTrans();\n return (\n <img\n className={clsx(className, size, 'object-cover bg-fg-base/4')}\n draggable={false}\n loading=\"lazy\"\n src={getGenreImage(genre)}\n alt={trans(message('Image for :name', {values: {name: genre.name}}))}\n />\n );\n}\n\nexport function getGenreImage(genre: Genre): string {\n return genre?.image ? genre.image : defaultImage;\n}\n","import {Genre} from '@app/web-player/genres/genre';\nimport {GenreImage} from '@app/web-player/genres/genre-image';\nimport {Link} from 'react-router-dom';\nimport {getGenreLink} from '@app/web-player/genres/genre-link';\n\ninterface GenreGridItemProps {\n genre: Genre;\n}\nexport function GenreGridItem({genre}: GenreGridItemProps) {\n return (\n <Link\n to={getGenreLink(genre)}\n className=\"block relative h-max after:bg-black/50 after:top-0 after:left-0 after:w-full after:h-full after:absolute rounded overflow-hidden cursor-pointer isolate\"\n >\n <GenreImage genre={genre} className=\"shadow-md w-full aspect-square\" />\n <div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-xl font-semibold capitalize text-white whitespace-nowrap overflow-hidden overflow-ellipsis max-w-[86%] z-20\">\n {genre.display_name || genre.name}\n </div>\n </Link>\n );\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {useLocation} from 'react-router-dom';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuth} from '@common/auth/use-auth';\n\ninterface Response extends BackendResponse {}\n\ninterface Payload {\n trackIds: number[];\n}\n\nexport function useDeleteTracks() {\n const {pathname} = useLocation();\n const navigate = useNavigate();\n const {getRedirectUri} = useAuth();\n\n return useMutation((payload: Payload) => deleteTracks(payload), {\n onSuccess: (response, {trackIds}) => {\n toast(\n message('[one track|other :count tracks] deleted', {\n values: {count: trackIds.length},\n })\n );\n // navigate to homepage if we are on this track page currently\n if (trackIds.some(trackId => pathname.startsWith(`/track/${trackId}`))) {\n navigate(getRedirectUri());\n }\n queryClient.invalidateQueries(['tracks']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction deleteTracks({trackIds}: Payload): Promise<Response> {\n return apiClient.delete(`tracks/${trackIds.join(',')}`).then(r => r.data);\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Lyric} from '@app/web-player/tracks/lyrics/lyric';\n\ninterface Response extends BackendResponse {\n lyric?: Lyric;\n}\n\nexport function useLyrics(track: Track) {\n return useQuery(['lyrics', track.id], () => fetchLyrics(track.id));\n}\n\nfunction fetchLyrics(trackId: number) {\n return apiClient\n .get<Response>(`tracks/${trackId}/lyrics`)\n .then(response => response.data);\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaMicrophoneIcon = createSvgIcon(\n [<path d=\"M22.3257 15.8354C22.1263 15.8695 21.9256 15.7966 21.7826 15.6536L16.347 10.218C16.2039 10.0749 16.1311 9.87422 16.1652 9.67483C16.3448 8.62476 16.84 7.61813 17.6506 6.80752C19.7334 4.72472 23.1103 4.72472 25.193 6.80752C27.2758 8.89032 27.2758 12.2672 25.193 14.35C24.3824 15.1606 23.3758 15.6557 22.3257 15.8354Z\" key=\"0\"/>,<path d=\"M15.3386 12.9809C15.0613 12.7036 14.6058 12.7244 14.3549 13.0257L5.78725 23.3142C5.56666 23.5791 5.58439 23.9685 5.82814 24.2122L7.79205 26.1761C8.03586 26.42 8.42536 26.4376 8.69024 26.2169L18.9754 17.6459C19.2766 17.3949 19.2972 16.9395 19.02 16.6623L15.3386 12.9809Z\" key=\"1\"/>,],\n 'MediaMicrophone',\n '0 0 32 32'\n);\n","import {Dialog} from '@common/ui/overlays/dialog/dialog';\nimport {DialogBody} from '@common/ui/overlays/dialog/dialog-body';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {DialogHeader} from '@common/ui/overlays/dialog/dialog-header';\nimport {Trans} from '@common/i18n/trans';\nimport {useLyrics} from '@app/web-player/tracks/lyrics/requests/use-lyrics';\nimport {Skeleton} from '@common/ui/skeleton/skeleton';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {MediaMicrophoneIcon} from '@common/icons/media/media-microphone';\n\ninterface Props {\n track: Track;\n}\nexport function LyricsDialog({track}: Props) {\n const {data, isLoading} = useLyrics(track);\n\n let content;\n\n if (data?.lyric?.text) {\n content = (\n <m.div\n className=\"text-lg w-full\"\n key=\"lyrics\"\n {...opacityAnimation}\n dangerouslySetInnerHTML={{__html: data?.lyric?.text || ''}}\n />\n );\n } else if (isLoading) {\n content = <LyricSkeleton />;\n } else {\n content = (\n <IllustratedMessage\n image={<MediaMicrophoneIcon size=\"xl\" />}\n imageHeight=\"h-auto\"\n title={<Trans message=\"We do not have lyrics for this song yet\" />}\n description={<Trans message=\"Please try again later\" />}\n />\n );\n }\n\n return (\n <Dialog size=\"fullscreenTakeover\">\n <DialogHeader closeButtonSize=\"lg\">\n <div className=\"sr-only\">\n <Trans message=\"Lyrics\" />\n </div>\n </DialogHeader>\n <DialogBody className=\"flex items-stretch gap-24 h-full\" padding=\"p-0\">\n <div className=\"hidden md:flex-[0.4_1_0%] md:flex items-center justify-end pl-40\">\n <div>\n <TrackImage\n track={track}\n size=\"w-400 max-w-full aspect-square\"\n className=\"flex-shrink-0 shadow-md rounded\"\n />\n <div className=\"mt-14 text-center text-xl\">{track.name}</div>\n <div className=\"mt-4 text-center text-base text-muted\">\n <ArtistLinks artists={track.artists} />\n </div>\n </div>\n </div>\n <div className=\"flex-auto md:flex-[0.6_1_0%] stable-scrollbar overflow-y-auto text-center pl-14 pr-14 md:pl-0 md:pr-40 pb-40\">\n <div className=\"flex items-center justify-center min-h-full w-full max-w-580 mx-auto\">\n <AnimatePresence>{content}</AnimatePresence>\n </div>\n </div>\n </DialogBody>\n </Dialog>\n );\n}\n\nfunction LyricSkeleton() {\n return (\n <m.div key=\"skeleton\" {...opacityAnimation} className=\"w-full\">\n {[...new Array(8).keys()].map(key => (\n <Skeleton key={key} variant=\"text\" className=\"mb-20\" />\n ))}\n </m.div>\n );\n}\n","import {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {Trans} from '@common/i18n/trans';\nimport {Track} from '@app/web-player/tracks/track';\nimport {\n ContextDialogLayout,\n ContextMenuButton,\n ContextMenuLayoutProps,\n} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {PlaylistPanelButton} from '@app/web-player/context-dialog/playlist-panel';\nimport {CopyLinkMenuButton} from '@app/web-player/context-dialog/copy-link-menu-button';\nimport {getTrackLink, TrackLink} from '@app/web-player/tracks/track-link';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {useTrackPermissions} from '@app/web-player/tracks/hooks/use-track-permissions';\nimport {AddToQueueButton} from '@app/web-player/context-dialog/add-to-queue-menu-button';\nimport React, {Fragment, ReactNode, useCallback} from 'react';\nimport {ToggleInLibraryMenuButton} from '@app/web-player/context-dialog/toggle-in-library-menu-button';\nimport {ToggleRepostMenuButton} from '@app/web-player/context-dialog/toggle-repost-menu-button';\nimport {getRadioLink} from '@app/web-player/radio/get-radio-link';\nimport {useShouldShowRadioButton} from '@app/web-player/tracks/context-dialog/use-should-show-radio-button';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';\nimport {useDeleteTracks} from '@app/web-player/tracks/requests/use-delete-tracks';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {getAlbumLink} from '@app/web-player/albums/album-link';\nimport {ShareMediaButton} from '@app/web-player/context-dialog/share-media-button';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {LyricsDialog} from '@app/web-player/tracks/lyrics/lyrics-dialog';\n\nexport interface TrackContextDialogProps {\n tracks: Track[];\n children?: (tracks: Track[]) => ReactNode;\n showAddToQueueButton?: boolean;\n}\nexport function TrackContextDialog({\n children,\n tracks,\n showAddToQueueButton = true,\n}: TrackContextDialogProps) {\n const isMobile = useIsMobileMediaQuery();\n const firstTrack = tracks[0];\n const {canEdit, canDelete} = useTrackPermissions(tracks);\n const shouldShowRadio = useShouldShowRadioButton();\n const {player} = useSettings();\n const {close} = useDialogContext();\n\n const loadTracks = useCallback(() => {\n return Promise.resolve(tracks);\n }, [tracks]);\n\n const headerProps: Partial<ContextMenuLayoutProps> =\n tracks.length === 1\n ? {\n image: <TrackImage track={firstTrack} />,\n title: <TrackLink track={firstTrack} />,\n description: <ArtistLinks artists={firstTrack.artists} />,\n }\n : {};\n\n return (\n <ContextDialogLayout {...headerProps} loadTracks={loadTracks}>\n {showAddToQueueButton && (\n <AddToQueueButton item={tracks} loadTracks={loadTracks} />\n )}\n <ToggleInLibraryMenuButton items={tracks} />\n {children?.(tracks)}\n <PlaylistPanelButton />\n {tracks.length === 1 ? (\n <Fragment>\n {shouldShowRadio && (\n <ContextMenuButton type=\"link\" to={getRadioLink(firstTrack)}>\n <Trans message=\"Go to song radio\" />\n </ContextMenuButton>\n )}\n {isMobile && (\n <Fragment>\n {firstTrack.artists?.[0] && (\n <ContextMenuButton\n type=\"link\"\n to={getArtistLink(firstTrack.artists[0])}\n >\n <Trans message=\"Go to artist\" />\n </ContextMenuButton>\n )}\n {firstTrack.album && (\n <ContextMenuButton\n type=\"link\"\n to={getAlbumLink(firstTrack.album)}\n >\n <Trans message=\"Go to album\" />\n </ContextMenuButton>\n )}\n <ContextMenuButton type=\"link\" to={getTrackLink(firstTrack)}>\n <Trans message=\"Go to track\" />\n </ContextMenuButton>\n </Fragment>\n )}\n {!player?.hide_lyrics && tracks.length === 1 && (\n <ContextMenuButton\n onClick={() => {\n close();\n openDialog(LyricsDialog, {track: firstTrack});\n }}\n >\n <Trans message=\"View lyrics\" />\n </ContextMenuButton>\n )}\n {!isMobile && (\n <CopyLinkMenuButton\n link={getTrackLink(firstTrack, {absolute: true})}\n >\n <Trans message=\"Copy song link\" />\n </CopyLinkMenuButton>\n )}\n {tracks.length === 1 && <ShareMediaButton item={firstTrack} />}\n {tracks.length === 1 ? (\n <ToggleRepostMenuButton item={tracks[0]} />\n ) : null}\n {tracks.length === 1 && canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/tracks/${firstTrack.id}/insights`}\n >\n <Trans message=\"Insights\" />\n </ContextMenuButton>\n )}\n {tracks.length === 1 && canEdit && (\n <ContextMenuButton\n type=\"link\"\n to={`/backstage/tracks/${firstTrack.id}/edit`}\n >\n <Trans message=\"Edit\" />\n </ContextMenuButton>\n )}\n </Fragment>\n ) : null}\n {canDelete && !isMobile && <DeleteButton tracks={tracks} />}\n </ContextDialogLayout>\n );\n}\n\nfunction DeleteButton({tracks}: TrackContextDialogProps) {\n const {close: closeMenu} = useDialogContext();\n const deleteTracks = useDeleteTracks();\n const {canDelete} = useTrackPermissions(tracks);\n\n if (!canDelete) {\n return null;\n }\n\n return (\n <ContextMenuButton\n disabled={deleteTracks.isLoading}\n onClick={() => {\n closeMenu();\n openDialog(ConfirmationDialog, {\n isDanger: true,\n title: <Trans message=\"Delete tracks\" />,\n body: (\n <Trans message=\"Are you sure you want to delete selected tracks?\" />\n ),\n confirm: <Trans message=\"Delete\" />,\n onConfirm: () => {\n deleteTracks.mutate({trackIds: tracks.map(t => t.id)});\n },\n });\n }}\n >\n <Trans message=\"Delete\" />\n </ContextMenuButton>\n );\n}\n","import {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {PlayableGridItem} from '@app/web-player/playable-item/playable-grid-item';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {getTrackLink, TrackLink} from '@app/web-player/tracks/track-link';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\n\ninterface TrackGridItemProps {\n track: Track;\n newQueue?: Track[];\n}\nexport function TrackGridItem({track, newQueue}: TrackGridItemProps) {\n return (\n <PlayableGridItem\n image={<TrackImage track={track} />}\n title={<TrackLink track={track} />}\n subtitle={<ArtistLinks artists={track.artists} />}\n link={getTrackLink(track)}\n likeButton={<LikeIconButton likeable={track} />}\n model={track}\n newQueue={newQueue}\n contextDialog={<TrackContextDialog tracks={[track]} />}\n />\n );\n}\n","import {Playlist} from '@app/web-player/playlists/playlist';\nimport {useAuth} from '@common/auth/use-auth';\n\nexport function usePlaylistPermissions(playlist: Playlist) {\n const {user} = useAuth();\n const isCreator: boolean = !!(user?.id && user.id === playlist.owner_id);\n return {canEdit: isCreator, canDelete: isCreator, isCreator};\n}\n","import {useAuthUserPlaylists} from '@app/web-player/playlists/requests/use-auth-user-playlists';\nimport {useAuth} from '@common/auth/use-auth';\n\nexport function useIsFollowingPlaylist(playlistId: number): boolean {\n const {data} = useAuthUserPlaylists();\n const {user} = useAuth();\n // if user is playlist creator, then he is not following it\n const playlist = data.playlists.find(p => p.id === +playlistId);\n if (playlist && user && user.id !== playlist.owner_id) {\n return true;\n }\n return false;\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {useLocation} from 'react-router-dom';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuth} from '@common/auth/use-auth';\n\ninterface Response extends BackendResponse {}\n\nexport function useDeletePlaylist(playlistId: number | string) {\n const {pathname} = useLocation();\n const navigate = useNavigate();\n const {getRedirectUri} = useAuth();\n\n return useMutation(() => deletePlaylist(playlistId), {\n onSuccess: () => {\n toast(message('Playlist deleted'));\n queryClient.invalidateQueries(['playlists']);\n // navigate to homepage if we are on this playlist page currently\n if (pathname.startsWith(`/playlist/${playlistId}`)) {\n navigate(getRedirectUri());\n }\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction deletePlaylist(playlistId: number | string): Promise<Response> {\n return apiClient.delete(`playlists/${playlistId}`).then(r => r.data);\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface Response extends BackendResponse {\n playlist: Playlist;\n}\n\nexport function useFollowPlaylist(playlist: Playlist) {\n return useMutation(() => followPlaylist(playlist.id), {\n onSuccess: () => {\n toast(message('Following :name', {values: {name: playlist.name}}));\n queryClient.invalidateQueries(['playlists']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction followPlaylist(playlistId: number | string): Promise<Response> {\n return apiClient.post(`playlists/${playlistId}/follow`).then(r => r.data);\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface Response extends BackendResponse {\n playlist: Playlist;\n}\n\nexport function useUnfollowPlaylist(playlist: Playlist) {\n return useMutation(() => unfollowPlaylist(playlist.id), {\n onSuccess: () => {\n toast(\n message('Stopped following :name', {values: {name: playlist.name}})\n );\n queryClient.invalidateQueries(['playlists']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction unfollowPlaylist(playlistId: number | string): Promise<Response> {\n return apiClient.post(`playlists/${playlistId}/unfollow`).then(r => r.data);\n}\n","import {Trans} from '@common/i18n/trans';\nimport {loadMediaItemTracks} from '@app/web-player/requests/load-media-item-tracks';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {Track} from '@app/web-player/tracks/track';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {\n ContextDialogLayout,\n ContextMenuButton,\n} from '@app/web-player/context-dialog/context-dialog-layout';\nimport useCopyClipboard from 'react-use-clipboard';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {\n getPlaylistLink,\n PlaylistLink,\n} from '@app/web-player/playlists/playlist-link';\nimport {usePlaylistPermissions} from '@app/web-player/playlists/hooks/use-playlist-permissions';\nimport {PlaylistImage} from '@app/web-player/playlists/playlist-image';\nimport React, {Fragment, useCallback} from 'react';\nimport {useIsFollowingPlaylist} from '@app/web-player/playlists/hooks/use-is-following-playlist';\nimport {openDialog} from '@common/ui/overlays/store/dialog-store';\nimport {UpdatePlaylistDialog} from '@app/web-player/playlists/crupdate-dialog/update-playlist-dialog';\nimport {useUpdatePlaylist} from '@app/web-player/playlists/requests/use-update-playlist';\nimport {CheckIcon} from '@common/icons/material/Check';\nimport {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';\nimport {useDeletePlaylist} from '@app/web-player/playlists/requests/use-delete-playlist';\nimport {useFollowPlaylist} from '@app/web-player/playlists/requests/use-follow-playlist';\nimport {useUnfollowPlaylist} from '@app/web-player/playlists/requests/use-unfollow-playlist';\nimport {AddToQueueButton} from '@app/web-player/context-dialog/add-to-queue-menu-button';\nimport {PlaylistOwnerName} from '@app/web-player/playlists/playlist-grid-item';\nimport {ShareMediaButton} from '@app/web-player/context-dialog/share-media-button';\n\ninterface PlaylistContextDialogProps {\n playlist: Playlist;\n}\nexport function PlaylistContextDialog({playlist}: PlaylistContextDialogProps) {\n const {close: closeMenu} = useDialogContext();\n const [, copyAlbumLink] = useCopyClipboard(\n getPlaylistLink(playlist, {absolute: true})\n );\n const {canEdit} = usePlaylistPermissions(playlist);\n\n const loadTracks = useCallback(() => {\n return loadPlaylistTracks(playlist);\n }, [playlist]);\n\n return (\n <ContextDialogLayout\n image={<PlaylistImage playlist={playlist} />}\n title={<PlaylistLink playlist={playlist} />}\n description={<PlaylistOwnerName playlist={playlist} />}\n loadTracks={loadTracks}\n >\n <AddToQueueButton item={playlist} loadTracks={loadTracks} />\n <TogglePublicButton playlist={playlist} />\n <ToggleCollaborativeButton playlist={playlist} />\n <FollowButtons playlist={playlist} />\n <ContextMenuButton\n onClick={() => {\n copyAlbumLink();\n closeMenu();\n toast(message('Copied link to clipboard'));\n }}\n >\n <Trans message=\"Copy playlist link\" />\n </ContextMenuButton>\n {playlist.public && <ShareMediaButton item={playlist} />}\n {canEdit && (\n <ContextMenuButton\n onClick={() => {\n closeMenu();\n openDialog(UpdatePlaylistDialog, {playlist});\n }}\n >\n <Trans message=\"Edit\" />\n </ContextMenuButton>\n )}\n <DeleteButton playlist={playlist} />\n </ContextDialogLayout>\n );\n}\n\ninterface FollowButtonsProps {\n playlist: Playlist;\n}\nfunction FollowButtons({playlist}: FollowButtonsProps) {\n const isFollowing = useIsFollowingPlaylist(playlist.id);\n const {close: closeMenu} = useDialogContext();\n const followPlaylist = useFollowPlaylist(playlist);\n const unFollowPlaylist = useUnfollowPlaylist(playlist);\n const {isCreator} = usePlaylistPermissions(playlist);\n\n // if user has created this playlist, bail\n if (isCreator) {\n return null;\n }\n\n return (\n <Fragment>\n {!isFollowing ? (\n <ContextMenuButton\n onClick={() => {\n closeMenu();\n followPlaylist.mutate();\n }}\n >\n <Trans message=\"Follow\" />\n </ContextMenuButton>\n ) : (\n <ContextMenuButton\n onClick={() => {\n closeMenu();\n unFollowPlaylist.mutate();\n }}\n >\n <Trans message=\"Unfollow\" />\n </ContextMenuButton>\n )}\n </Fragment>\n );\n}\n\nfunction TogglePublicButton({playlist}: FollowButtonsProps) {\n const {close: closeMenu} = useDialogContext();\n const updatePlaylist = useUpdatePlaylist({playlistId: playlist.id});\n const {isCreator} = usePlaylistPermissions(playlist);\n\n if (!isCreator) {\n return null;\n }\n\n const togglePublic = () => {\n closeMenu();\n updatePlaylist.mutate({public: !playlist.public});\n };\n\n return (\n <ContextMenuButton\n disabled={updatePlaylist.isLoading}\n onClick={() => togglePublic()}\n >\n {playlist.public ? (\n <Trans message=\"Make private\" />\n ) : (\n <Trans message=\"Make public\" />\n )}\n </ContextMenuButton>\n );\n}\n\nfunction ToggleCollaborativeButton({playlist}: FollowButtonsProps) {\n const {close: closeMenu} = useDialogContext();\n const updatePlaylist = useUpdatePlaylist({playlistId: playlist.id});\n const {isCreator} = usePlaylistPermissions(playlist);\n\n if (!isCreator) {\n return null;\n }\n\n const toggleCollaborative = () => {\n closeMenu();\n updatePlaylist.mutate({collaborative: !playlist.collaborative});\n };\n\n return (\n <ContextMenuButton\n disabled={updatePlaylist.isLoading}\n startIcon={playlist.collaborative ? <CheckIcon /> : undefined}\n onClick={() => toggleCollaborative()}\n >\n <Trans message=\"Collaborative\" />\n </ContextMenuButton>\n );\n}\n\nfunction DeleteButton({playlist}: FollowButtonsProps) {\n const {close: closeMenu} = useDialogContext();\n const deletePlaylist = useDeletePlaylist(playlist.id);\n const {canDelete} = usePlaylistPermissions(playlist);\n\n if (!canDelete) {\n return null;\n }\n\n return (\n <ContextMenuButton\n disabled={deletePlaylist.isLoading}\n onClick={() => {\n closeMenu();\n openDialog(ConfirmationDialog, {\n isDanger: true,\n title: <Trans message=\"Delete playlist\" />,\n body: (\n <Trans message=\"Are you sure you want to delete this playlist?\" />\n ),\n confirm: <Trans message=\"Delete\" />,\n onConfirm: () => {\n deletePlaylist.mutate();\n },\n });\n }}\n >\n <Trans message=\"Delete\" />\n </ContextMenuButton>\n );\n}\n\nasync function loadPlaylistTracks(playlist: Playlist): Promise<Track[]> {\n // load playlist tracks if not loaded already\n if (typeof playlist.tracks === 'undefined') {\n const tracks = await loadMediaItemTracks(queueGroupId(playlist));\n if (!tracks.length) {\n toast(message('This playlist has no tracks yet.'));\n }\n return tracks;\n }\n return playlist.tracks;\n}\n","import {FavoriteIcon} from '@common/icons/material/Favorite';\nimport {FavoriteBorderIcon} from '@common/icons/material/FavoriteBorder';\nimport {Button} from '@common/ui/buttons/button';\nimport {Trans} from '@common/i18n/trans';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {useFollowPlaylist} from '@app/web-player/playlists/requests/use-follow-playlist';\nimport {useUnfollowPlaylist} from '@app/web-player/playlists/requests/use-unfollow-playlist';\nimport {useIsFollowingPlaylist} from '@app/web-player/playlists/hooks/use-is-following-playlist';\nimport {usePlaylistPermissions} from '@app/web-player/playlists/hooks/use-playlist-permissions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonSize} from '@common/ui/buttons/button-size';\n\ninterface FollowPlaylistButtonProps {\n buttonType: 'icon' | 'text';\n className?: string;\n size?: ButtonSize;\n playlist: Playlist;\n radius?: string;\n}\nexport function FollowPlaylistButton({\n playlist,\n size = 'sm',\n className,\n buttonType = 'text',\n radius,\n}: FollowPlaylistButtonProps) {\n const {isCreator} = usePlaylistPermissions(playlist);\n const follow = useFollowPlaylist(playlist);\n const unfollow = useUnfollowPlaylist(playlist);\n const isFollowing = useIsFollowingPlaylist(playlist.id);\n const isLoading = follow.isLoading || unfollow.isLoading;\n\n if (isCreator) {\n return null;\n }\n\n if (buttonType === 'icon') {\n if (isFollowing) {\n return (\n <IconButton\n size={size}\n radius={radius}\n color=\"primary\"\n className={className}\n disabled={isLoading}\n onClick={() => unfollow.mutate()}\n >\n <FavoriteIcon />\n </IconButton>\n );\n }\n return (\n <IconButton\n size={size}\n radius={radius}\n disabled={isLoading}\n className={className}\n onClick={() => follow.mutate()}\n >\n <FavoriteBorderIcon />\n </IconButton>\n );\n }\n\n if (isFollowing) {\n return (\n <Button\n size={size}\n variant=\"outline\"\n radius={radius || 'rounded-full'}\n startIcon={<FavoriteIcon className=\"text-primary\" />}\n disabled={isLoading}\n className={className}\n onClick={() => unfollow.mutate()}\n >\n <Trans message=\"Following\" />\n </Button>\n );\n }\n return (\n <Button\n size={size}\n variant=\"outline\"\n radius={radius || 'rounded-full'}\n startIcon={<FavoriteBorderIcon />}\n disabled={isLoading}\n className={className}\n onClick={() => follow.mutate()}\n >\n <Trans message=\"Follow\" />\n </Button>\n );\n}\n","import {PlayableGridItem} from '@app/web-player/playable-item/playable-grid-item';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {PlaylistImage} from '@app/web-player/playlists/playlist-image';\nimport {\n getPlaylistLink,\n PlaylistLink,\n} from '@app/web-player/playlists/playlist-link';\nimport {PlaylistContextDialog} from '@app/web-player/playlists/playlist-context-dialog';\nimport {Trans} from '@common/i18n/trans';\nimport {UserProfileLink} from '@app/web-player/users/user-profile-link';\nimport React from 'react';\nimport {FollowPlaylistButton} from '@app/web-player/playlists/playlist-page/follow-playlist-button';\n\ninterface PlaylistGridItemProps {\n playlist: Playlist;\n}\nexport function PlaylistGridItem({playlist}: PlaylistGridItemProps) {\n return (\n <PlayableGridItem\n image={<PlaylistImage playlist={playlist} />}\n title={<PlaylistLink playlist={playlist} />}\n subtitle={<PlaylistOwnerName playlist={playlist} />}\n link={getPlaylistLink(playlist)}\n likeButton={\n <FollowPlaylistButton buttonType=\"icon\" size=\"md\" playlist={playlist} />\n }\n model={playlist}\n contextDialog={<PlaylistContextDialog playlist={playlist} />}\n />\n );\n}\n\nexport function PlaylistOwnerName({playlist}: PlaylistGridItemProps) {\n const owner = playlist.owner || playlist.editors?.[0];\n if (!owner) {\n return null;\n }\n return (\n <Trans\n message=\"By :name\"\n values={{\n name: <UserProfileLink user={owner} />,\n }}\n />\n );\n}\n","export default \"__VITE_ASSET__6d84205f__\"","import {useTrans} from '@common/i18n/use-trans';\nimport {message} from '@common/i18n/message';\nimport {User} from '@common/auth/user';\nimport clsx from 'clsx';\nimport {Trans} from '@common/i18n/trans';\nimport {StarIcon} from '@common/icons/material/Star';\nimport userDefaultImage from './user-default.svg';\n\ninterface UserImageProps {\n user: User;\n className?: string;\n size?: string;\n showProBadge?: boolean;\n}\nexport function UserImage({\n user,\n className,\n size,\n showProBadge,\n}: UserImageProps) {\n const {trans} = useTrans();\n const showBadge = showProBadge && user.subscriptions?.find(s => s.valid);\n return (\n <div\n className={clsx(\n 'relative flex-shrink-0 isolate overflow-hidden',\n size,\n className\n )}\n >\n <img\n className=\"object-cover bg-fg-base/4 w-full h-full\"\n draggable={false}\n src={getUserImage(user)}\n alt={trans(\n message('Avatar for :name', {values: {name: user.display_name}})\n )}\n />\n {showBadge && (\n <div\n className=\"absolute bottom-12 text-sm left-0 right-0 w-max max-w-full mx-auto flex items-center gap-6 bg-black/60 text-white rounded-full py-4 px-8\"\n color=\"positive\"\n >\n <div className=\"bg-primary rounded-full p-1\">\n <StarIcon className=\"text-white\" size=\"sm\" />\n </div>\n <Trans message=\"PRO user\" />\n </div>\n )}\n </div>\n );\n}\n\nexport function getUserImage(user: User): string {\n return user.avatar || userDefaultImage;\n}\n","import {Link} from 'react-router-dom';\nimport {getUserProfileLink} from '@app/web-player/users/user-profile-link';\nimport {UserImage} from '@app/web-player/users/user-image';\nimport {User} from '@common/auth/user';\nimport {Trans} from '@common/i18n/trans';\n\ninterface UserGridItemProps {\n user: User;\n}\nexport function UserGridItem({user}: UserGridItemProps) {\n return (\n <div>\n <Link to={getUserProfileLink(user)}>\n <UserImage\n user={user}\n className=\"shadow-md w-full aspect-square rounded\"\n />\n </Link>\n <div className=\"text-sm mt-12\">\n <div className=\"overflow-hidden overflow-ellipsis\">\n <Link to={getUserProfileLink(user)}>{user.display_name}</Link>\n </div>\n {user.followers_count ? (\n <div className=\"text-muted mt-4 whitespace-nowrap overflow-hidden overflow-ellipsis\">\n <Trans\n message=\":count followers\"\n values={{count: user.followers_count}}\n />\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n","import {ChannelContentItem} from '@app/web-player/channels/channel';\nimport {ARTIST_MODEL} from '@app/web-player/artists/artist';\nimport {ArtistGridItem} from '@app/web-player/artists/artist-grid-item';\nimport {ALBUM_MODEL} from '@app/web-player/albums/album';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\nimport {GENRE_MODEL} from '@app/web-player/genres/genre';\nimport {GenreGridItem} from '@app/web-player/genres/genre-grid-item';\nimport React from 'react';\nimport {Track, TRACK_MODEL} from '@app/web-player/tracks/track';\nimport {TrackGridItem} from '@app/web-player/tracks/track-grid-item';\nimport {PLAYLIST_MODEL} from '@app/web-player/playlists/playlist';\nimport {PlaylistGridItem} from '@app/web-player/playlists/playlist-grid-item';\nimport {USER_MODEL} from '@common/auth/user';\nimport {UserGridItem} from '@app/web-player/users/user-grid-item';\n\ninterface Props {\n item: ChannelContentItem;\n items?: ChannelContentItem[];\n}\nexport function ChannelContentGridItem({item, items}: Props) {\n switch (item.model_type) {\n case ARTIST_MODEL:\n return <ArtistGridItem artist={item} />;\n case ALBUM_MODEL:\n return <AlbumGridItem album={item} />;\n case GENRE_MODEL:\n return <GenreGridItem genre={item} />;\n case TRACK_MODEL:\n return <TrackGridItem track={item} newQueue={items as Track[]} />;\n case PLAYLIST_MODEL:\n return <PlaylistGridItem playlist={item} />;\n case USER_MODEL:\n return <UserGridItem user={item} />;\n default:\n return null;\n }\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const AntennaIcon = createSvgIcon(\n <path d=\"M12 7.5c.69 0 1.27.23 1.76.7s.74 1.07.74 1.8c0 1.05-.5 1.81-1.5 2.28V21h-2v-8.72c-1-.47-1.5-1.23-1.5-2.28 0-.73.26-1.33.74-1.8s1.07-.7 1.76-.7m4.69-2.2c1.25 1.25 1.92 2.81 2.01 4.7 0 1.8-.67 3.38-2.01 4.72L15.5 13.5c1-.91 1.5-2.08 1.5-3.5 0-1.33-.5-2.5-1.5-3.5l1.19-1.2M6.09 4.08C4.5 5.67 3.7 7.64 3.7 10s.8 4.3 2.39 5.89l-1.17 1.22C3 15.08 2 12.7 2 10s1-5.06 2.92-7.09l1.17 1.17m12.99-1.17C21 4.94 22 7.3 22 10c0 2.8-1 5.17-2.92 7.11l-1.17-1.22C19.5 14.3 20.3 12.33 20.3 10s-.8-4.33-2.39-5.92l1.17-1.17M7.31 5.3L8.5 6.5C7.5 7.42 7 8.58 7 10c0 1.33.5 2.5 1.5 3.5l-1.19 1.22C5.97 13.38 5.3 11.8 5.3 10c0-1.8.67-3.36 2.01-4.7z\"></path>,\n 'Radio'\n);\n","import React from 'react';\nimport {Channel} from '@app/web-player/channels/channel';\nimport {Link, useParams} from 'react-router-dom';\nimport {KeyboardArrowRightIcon} from '@common/icons/material/KeyboardArrowRight';\nimport clsx from 'clsx';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\nimport {AntennaIcon} from '@app/web-player/channels/antenna-icon';\nimport {useShouldShowRadioButton} from '@app/web-player/tracks/context-dialog/use-should-show-radio-button';\nimport {getRadioLink} from '@app/web-player/radio/get-radio-link';\n\ninterface ChannelHeadingProps {\n channel: Channel;\n margin?: string;\n isNested?: boolean;\n}\nexport function ChannelHeading({\n channel,\n isNested,\n margin = isNested ? 'mb-16 md:mb-20' : 'mb-20 md:mb-40',\n}: ChannelHeadingProps) {\n const shouldShowRadio = useShouldShowRadioButton();\n if (channel.config.hideTitle) {\n return null;\n }\n if (!isNested) {\n if (shouldShowRadio && channel.genre) {\n return (\n <div\n className={clsx('flex gap-24 items-center justify-between', margin)}\n >\n <h1 className=\"text-3xl flex-auto\">\n <Trans message={channel.name} />\n </h1>\n <Tooltip label={<Trans message=\"Genre radio\" />}>\n <IconButton\n className=\"flex-shrink-0\"\n elementType={Link}\n to={getRadioLink(channel.genre)}\n >\n <AntennaIcon />\n </IconButton>\n </Tooltip>\n </div>\n );\n }\n return (\n <h1 className={clsx('text-3xl', margin)}>\n <Trans message={channel.name} />\n </h1>\n );\n }\n\n return (\n <div className={clsx('text-xl flex items-center gap-4', margin)}>\n <NestedChannelLink channel={channel} />\n <KeyboardArrowRightIcon className=\"mt-4\" />\n </div>\n );\n}\n\ninterface ChannelLinkProps {\n channel: Channel;\n}\nfunction NestedChannelLink({channel}: ChannelLinkProps) {\n const {filter: genreName} = useParams();\n return (\n <Link\n className=\"hover:underline outline-none focus-visible:underline\"\n to={\n channel.config.connectToGenreViaUrl && genreName\n ? `/channel/${channel.slug}/${genreName}`\n : `/channel/${channel.slug}`\n }\n >\n <Trans message={channel.name} />\n </Link>\n );\n}\n","import {usePaginatedChannelContent} from '@app/web-player/channels/requests/use-paginated-channel-content';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport React, {Fragment} from 'react';\nimport {ChannelContentProps} from '@app/web-player/channels/channel-content';\nimport {ChannelContentGridItem} from '@app/web-player/channels/channel-content-grid-item';\nimport {ChannelHeading} from '@app/web-player/channels/channel-heading';\nimport {Channel, ChannelContentItem} from '@app/web-player/channels/channel';\n\nexport function ChannelContentGrid(props: ChannelContentProps) {\n return (\n <Fragment>\n <ChannelHeading {...props} />\n {props.isNested || props.channel.config.contentType !== 'listAll' ? (\n <SimpleGrid {...props} />\n ) : (\n <PaginatedGrid {...props} />\n )}\n </Fragment>\n );\n}\n\nfunction SimpleGrid({channel}: ChannelContentProps) {\n const content = (channel.content?.data || []) as Exclude<\n ChannelContentItem,\n Channel\n >[];\n return (\n <ContentGrid>\n {content.map(item => (\n <ChannelContentGridItem\n key={`${item.id}-${item.model_type}`}\n item={item}\n items={content}\n />\n ))}\n </ContentGrid>\n );\n}\n\nfunction PaginatedGrid({channel}: ChannelContentProps) {\n const query = usePaginatedChannelContent(channel);\n const content = (query.items || []) as Exclude<ChannelContentItem, Channel>[];\n return (\n <div>\n <ContentGrid>\n {content.map(item => (\n <ChannelContentGridItem\n key={`${item.id}-${item.model_type}`}\n item={item}\n items={content}\n />\n ))}\n </ContentGrid>\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {useContext} from 'react';\nimport {TableContext} from '@common/ui/tables/table-context';\n\nexport interface TrackTableMeta {\n queueGroupId?: string | number;\n hideTrackImage?: boolean;\n}\n\nconst stableObj = {};\n\nexport function useTrackTableMeta() {\n const {meta} = useContext(TableContext);\n return (meta || stableObj) as TrackTableMeta;\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\n\nexport function useIsTrackCued(\n trackId: number,\n groupId?: string | number\n): boolean {\n return usePlayerStore(s => {\n if (!s.cuedMedia?.meta.id || s.cuedMedia.meta.id !== trackId) {\n return false;\n }\n\n if (!s.cuedMedia?.groupId && !groupId) {\n return true;\n }\n\n if (groupId && s.cuedMedia.groupId === groupId) {\n return true;\n }\n\n return false;\n });\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useIsTrackCued} from '@app/web-player/tracks/hooks/use-is-track-cued';\n\nexport function useIsTrackPlaying(\n trackId: number,\n groupId?: string | number\n): boolean {\n const isCued = useIsTrackCued(trackId, groupId);\n const isPlaying = usePlayerStore(s => s.isPlaying);\n return isCued && isPlaying;\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {useTrans} from '@common/i18n/use-trans';\nimport React, {useContext, useState} from 'react';\nimport {TableContext} from '@common/ui/tables/table-context';\nimport {trackToMediaItem} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {message} from '@common/i18n/message';\nimport {PauseIcon} from '@common/icons/material/Pause';\nimport {PlayArrowFilledIcon} from '@app/web-player/tracks/play-arrow-filled';\nimport clsx from 'clsx';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {useTrackTableMeta} from '@app/web-player/tracks/track-table/use-track-table-meta';\nimport {EqualizerImage} from '@app/web-player/tracks/equalizer-image/equalizer-image';\nimport {useIsTrackPlaying} from '@app/web-player/tracks/hooks/use-is-track-playing';\nimport {useIsTrackCued} from '@app/web-player/tracks/hooks/use-is-track-cued';\n\ninterface TogglePlaybackColumnProps {\n track: Track;\n rowIndex: number;\n isHovered: boolean;\n}\nexport function TogglePlaybackColumn({\n track,\n rowIndex,\n isHovered,\n}: TogglePlaybackColumnProps) {\n const {queueGroupId} = useTrackTableMeta();\n const isPlaying = useIsTrackPlaying(track.id, queueGroupId);\n const isCued = useIsTrackCued(track.id, queueGroupId);\n\n return (\n <div className=\"w-24 h-24 text-center\">\n {isHovered || isPlaying ? (\n <TogglePlaybackButton\n track={track}\n trackIndex={rowIndex}\n isPlaying={isPlaying}\n />\n ) : (\n <span className={clsx(isCued ? 'text-primary' : 'text-muted')}>\n {rowIndex + 1}\n </span>\n )}\n </div>\n );\n}\n\ninterface TogglePlaybackButtonProps {\n track: Track;\n trackIndex: number;\n isPlaying: boolean;\n}\nfunction TogglePlaybackButton({\n track,\n trackIndex,\n isPlaying,\n}: TogglePlaybackButtonProps) {\n const {trans} = useTrans();\n const player = usePlayerActions();\n const {data} = useContext(TableContext);\n const {queueGroupId} = useTrackTableMeta();\n const [isHover, setHover] = useState(false);\n\n if (isPlaying) {\n return (\n <button\n onPointerEnter={() => setHover(true)}\n onPointerLeave={() => setHover(false)}\n aria-label={trans(message('Pause :name', {values: {name: track.name}}))}\n tabIndex={0}\n onClick={e => {\n e.stopPropagation();\n player.pause();\n }}\n >\n {isHover ? <PauseIcon /> : <EqualizerImage />}\n </button>\n );\n }\n\n return (\n <button\n aria-label={trans(message('Play :name', {values: {name: track.name}}))}\n tabIndex={0}\n onClick={async e => {\n e.stopPropagation();\n const newQueue = data.map(d =>\n trackToMediaItem(d as Track, queueGroupId)\n );\n player.overrideQueueAndPlay(newQueue, trackIndex);\n }}\n >\n <PlayArrowFilledIcon />\n </button>\n );\n}\n","import {NameWithAvatar} from '@common/datatable/column-templates/name-with-avatar';\nimport React from 'react';\nimport {Track} from '@app/web-player/tracks/track';\nimport clsx from 'clsx';\nimport {useTrackTableMeta} from '@app/web-player/tracks/track-table/use-track-table-meta';\nimport {getTrackImageSrc} from '@app/web-player/tracks/track-image/track-image';\nimport {useIsTrackCued} from '@app/web-player/tracks/hooks/use-is-track-cued';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\n\ninterface TrackNameColumnProps {\n track: Track;\n}\nexport function TrackNameColumn({track}: TrackNameColumnProps) {\n const isMobile = useIsMobileMediaQuery();\n const {hideTrackImage, queueGroupId} = useTrackTableMeta();\n const isCued = useIsTrackCued(track.id, queueGroupId);\n\n return (\n <NameWithAvatar\n image={!hideTrackImage ? getTrackImageSrc(track) : undefined}\n label={track.name}\n avatarSize={isMobile ? 'lg' : 'md'}\n description={\n isMobile ? track.artists?.map(a => a.name).join(', ') : undefined\n }\n labelClassName={clsx(\n isCued && 'text-primary',\n isMobile && 'text-[15px] leading-6'\n )}\n />\n );\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {useContext, useMemo} from 'react';\nimport {TableContext} from '@common/ui/tables/table-context';\nimport {\n TrackContextDialog,\n TrackContextDialogProps,\n} from '@app/web-player/tracks/context-dialog/track-context-dialog';\n\ninterface TableTrackContextDialogProps\n extends Omit<TrackContextDialogProps, 'tracks'> {}\nexport function TableTrackContextDialog({\n children,\n ...props\n}: TableTrackContextDialogProps) {\n const {selectedRows, data} = useContext(TableContext);\n const tracks = useMemo(() => {\n return selectedRows\n .map(trackId => data.find(track => track.id === trackId))\n .filter(t => !!t) as Track[];\n }, [selectedRows, data]);\n return (\n <TrackContextDialog {...props} tracks={tracks}>\n {children}\n </TrackContextDialog>\n );\n}\n","import React, {Fragment} from 'react';\nimport {Track} from '@app/web-player/tracks/track';\nimport clsx from 'clsx';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {MoreHorizIcon} from '@common/icons/material/MoreHoriz';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\nimport {MoreVertIcon} from '@common/icons/material/MoreVert';\n\ninterface Props {\n track: Track;\n isHovered: boolean;\n}\nexport function TrackOptionsColumn({track, isHovered}: Props) {\n const isMobile = useIsMobileMediaQuery();\n\n return (\n <Fragment>\n <DialogTrigger type=\"popover\">\n <IconButton\n size={isMobile ? 'sm' : 'md'}\n className={clsx(\n isMobile ? 'text-muted' : 'mr-8',\n !isMobile && !isHovered && 'invisible'\n )}\n >\n {isMobile ? <MoreVertIcon /> : <MoreHorizIcon />}\n </IconButton>\n <TrackContextDialog tracks={[track]} />\n </DialogTrigger>\n {!isMobile && <LikeIconButton size=\"xs\" likeable={track} />}\n </Fragment>\n );\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {Table, TableProps} from '@common/ui/tables/table';\nimport {ColumnConfig} from '@common/datatable/column-config';\nimport {Trans} from '@common/i18n/trans';\nimport React, {useMemo} from 'react';\nimport {AlbumLink} from '@app/web-player/albums/album-link';\nimport {ScheduleIcon} from '@common/icons/material/Schedule';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {TogglePlaybackColumn} from '@app/web-player/tracks/track-table/toggle-playback-column';\nimport {TrackNameColumn} from '@app/web-player/tracks/track-table/track-name-column';\nimport {TrackTableMeta} from '@app/web-player/tracks/track-table/use-track-table-meta';\nimport {Skeleton} from '@common/ui/skeleton/skeleton';\nimport {NameWithAvatarPlaceholder} from '@common/datatable/column-templates/name-with-avatar';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {RowElementProps} from '@common/ui/tables/table-row';\nimport {TableTrackContextDialog} from '@app/web-player/tracks/context-dialog/table-track-context-dialog';\nimport {TrendingUpIcon} from '@common/icons/material/TrendingUp';\nimport {FormattedRelativeTime} from '@common/i18n/formatted-relative-time';\nimport {trackToMediaItem} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {TrackOptionsColumn} from '@app/web-player/tracks/track-table/track-options-column';\nimport {TableDataItem} from '@common/ui/tables/types/table-data-item';\n\nconst columnConfig: ColumnConfig<Track>[] = [\n {\n key: 'index',\n header: () => <span>#</span>,\n align: 'center',\n width: 'w-24 flex-shrink-0',\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton size=\"w-20 h-20\" variant=\"rect\" />;\n }\n return (\n <TogglePlaybackColumn\n track={track}\n rowIndex={row.index}\n isHovered={row.isHovered}\n />\n );\n },\n },\n {\n key: 'name',\n allowsSorting: true,\n width: 'flex-3 min-w-224',\n visibleInMode: 'all',\n header: () => <Trans message=\"Title\" />,\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <NameWithAvatarPlaceholder showDescription={false} />;\n }\n return <TrackNameColumn track={track} />;\n },\n },\n {\n key: 'artist',\n header: () => <Trans message=\"Artist\" />,\n width: 'flex-2',\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton className=\"leading-3 max-w-4/5\" />;\n }\n return <ArtistLinks artists={track.artists} />;\n },\n },\n {\n key: 'album_name',\n allowsSorting: true,\n width: 'flex-2',\n header: () => <Trans message=\"Album\" />,\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton className=\"leading-3 max-w-4/5\" />;\n }\n return track.album ? <AlbumLink album={track.album} /> : null;\n },\n },\n {\n key: 'added_at',\n sortingKey: 'likes.created_at',\n allowsSorting: true,\n maxWidth: 'max-w-112',\n header: () => <Trans message=\"Date added\" />,\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton className=\"leading-3 max-w-4/5\" />;\n }\n return <FormattedRelativeTime date={track.added_at} />;\n },\n },\n {\n key: 'options',\n align: 'end',\n width: 'w-36 md:w-84',\n header: () => <Trans message=\"Options\" />,\n hideHeader: true,\n visibleInMode: 'all',\n body: (track, row) => {\n if (row.isPlaceholder) {\n return (\n <div className=\"flex justify-end\">\n <Skeleton size=\"w-20 h-20\" variant=\"rect\" />\n </div>\n );\n }\n return <TrackOptionsColumn track={track} isHovered={row.isHovered} />;\n },\n },\n {\n key: 'duration',\n allowsSorting: true,\n className: 'text-muted',\n maxWidth: 'max-w-48',\n align: 'end',\n header: () => <ScheduleIcon />,\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton className=\"leading-3\" />;\n }\n return track.duration ? <FormattedDuration ms={track.duration} /> : null;\n },\n },\n {\n key: 'popularity',\n allowsSorting: true,\n className: 'text-muted',\n maxWidth: 'max-w-54',\n header: () => <TrendingUpIcon />,\n body: (track, row) => {\n if (row.isPlaceholder) {\n return <Skeleton className=\"leading-3\" />;\n }\n return (\n <div className=\"h-6 w-full relative bg-chip\">\n <div\n style={{width: `${track.popularity || 50}%`}}\n className=\"h-full w-0 absolute top-0 left-0 bg-black/30 dark:bg-white/30\"\n />\n </div>\n );\n },\n },\n];\n\nexport interface TrackTableProps {\n tracks: Track[] | TableDataItem[]; // might be passing in placeholder items for skeletons\n hideArtist?: boolean;\n hideAlbum?: boolean;\n hideTrackImage?: boolean;\n hidePopularity?: boolean;\n hideAddedAtColumn?: boolean;\n hideHeaderRow?: boolean;\n queueGroupId?: string | number;\n renderRowAs?: TableProps<Track>['renderRowAs'];\n sortDescriptor?: TableProps<Track>['sortDescriptor'];\n onSortChange?: TableProps<Track>['onSortChange'];\n enableSorting?: TableProps<Track>['enableSorting'];\n tableBody?: TableProps<Track>['tableBody'];\n className?: string;\n}\nexport function TrackTable({\n tracks,\n hideArtist = false,\n hideAlbum = false,\n hideHeaderRow = false,\n hideTrackImage = false,\n hidePopularity = true,\n hideAddedAtColumn = true,\n queueGroupId,\n renderRowAs,\n ...tableProps\n}: TrackTableProps) {\n const player = usePlayerActions();\n const isMobile = useIsMobileMediaQuery();\n hideHeaderRow = hideHeaderRow || !!isMobile;\n\n const filteredColumns = useMemo(() => {\n return columnConfig.filter(col => {\n if (col.key === 'artist' && hideArtist) {\n return false;\n }\n if (col.key === 'album_name' && hideAlbum) {\n return false;\n }\n if (col.key === 'popularity' && hidePopularity) {\n return false;\n }\n if (col.key === 'added_at' && hideAddedAtColumn) {\n return false;\n }\n return true;\n });\n }, [hideArtist, hideAlbum, hidePopularity, hideAddedAtColumn]);\n\n const meta: TrackTableMeta = useMemo(() => {\n return {queueGroupId: queueGroupId, hideTrackImage};\n }, [queueGroupId, hideTrackImage]);\n\n return (\n <Table\n closeOnInteractOutside\n hideHeaderRow={hideHeaderRow}\n selectionStyle=\"highlight\"\n selectRowOnContextMenu\n renderRowAs={renderRowAs || TrackTableRowWithContextMenu}\n columns={filteredColumns}\n data={tracks as Track[]}\n meta={meta}\n hideBorder={!!isMobile}\n onAction={(track, index) => {\n const newQueue = tracks.map(d =>\n trackToMediaItem(d as Track, queueGroupId)\n );\n player.overrideQueueAndPlay(newQueue, index);\n }}\n {...tableProps}\n />\n );\n}\n\nfunction TrackTableRowWithContextMenu({\n item,\n children,\n ...domProps\n}: RowElementProps<Track>) {\n const row = <div {...domProps}>{children}</div>;\n if (item.isPlaceholder) {\n return row;\n }\n return (\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"bottom-start\">\n {row}\n <TableTrackContextDialog />\n </DialogTrigger>\n );\n}\n","import {observeElementOffset, useVirtualizer} from '@tanstack/react-virtual';\nimport React, {Fragment, useContext, useEffect, useRef} from 'react';\nimport {TableRow} from '@common/ui/tables/table-row';\nimport {TableBodyProps} from '@common/ui/tables/table';\nimport {getScrollParent} from '@react-aria/utils';\nimport {TableContext} from '@common/ui/tables/table-context';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {UseInfiniteQueryResult} from '@tanstack/react-query/src/types';\n\ninterface VirtualTableBodyProps extends TableBodyProps {\n totalItems?: number;\n query: UseInfiniteQueryResult;\n}\nexport function VirtualTableBody({\n renderRowAs,\n totalItems = 0,\n query,\n}: VirtualTableBodyProps) {\n const {data} = useContext(TableContext);\n\n // make sure we are not rendering more placeholder rows than\n // there are items left to lazy load and at most 10 placeholders.\n // If total items is unknown, we will render 10 placeholders.\n const placeholderRowCount =\n totalItems <= 0 ? 10 : Math.min(totalItems - data.length, 10);\n\n // only use virtualizer if playlist has more than 3 pages\n return totalItems < 91 ? (\n <Body\n placeholderRowCount={placeholderRowCount}\n renderRowAs={renderRowAs}\n query={query}\n />\n ) : (\n <VirtualizedBody\n placeholderRowCount={placeholderRowCount}\n renderRowAs={renderRowAs}\n query={query}\n />\n );\n}\n\ninterface BodyProps extends TableBodyProps {\n placeholderRowCount: number;\n query: UseInfiniteQueryResult;\n}\nfunction Body({renderRowAs, placeholderRowCount, query}: BodyProps) {\n const {data} = useContext(TableContext);\n return (\n <Fragment>\n {data.map((track, index) => (\n <TableRow\n item={track}\n index={index}\n key={track.id}\n renderAs={renderRowAs}\n />\n ))}\n <Sentinel\n dataCount={data.length}\n placeholderRowCount={placeholderRowCount}\n query={query}\n />\n </Fragment>\n );\n}\n\nfunction VirtualizedBody({renderRowAs, placeholderRowCount, query}: BodyProps) {\n const {data} = useContext(TableContext);\n const bodyRef = useRef<HTMLTableSectionElement>(null);\n const scrollableRef = useRef<Element>(null!);\n const scrollOffset = useRef(0);\n\n useEffect(() => {\n if (bodyRef.current) {\n scrollableRef.current = getScrollParent(bodyRef.current);\n scrollOffset.current =\n bodyRef.current.getBoundingClientRect().top +\n scrollableRef.current.scrollTop;\n }\n }, [bodyRef]);\n\n const virtualizer = useVirtualizer({\n overscan: 10,\n count: data.length,\n getScrollElement: () => scrollableRef.current,\n estimateSize: () => 48,\n observeElementOffset: (instance, cb) => {\n return observeElementOffset(instance, offset => {\n cb(offset - scrollOffset.current);\n });\n },\n });\n\n const virtualRows = virtualizer.getVirtualItems();\n const virtualHeight = `${\n virtualizer.getTotalSize() +\n // if showing placeholder rows, extended height of virtual list to show them\n (query.isFetchingNextPage ? placeholderRowCount * 48 : 0)\n }px`;\n\n return (\n <div\n ref={bodyRef}\n role=\"presentation\"\n className=\"w-full relative\"\n style={{\n height: virtualHeight,\n }}\n >\n {virtualRows.map(virtualItem => {\n const item = data[virtualItem.index];\n return (\n <TableRow\n item={item}\n index={virtualItem.index}\n key={item.id}\n renderAs={renderRowAs}\n className=\"absolute top-0 left-0 w-full\"\n style={{\n height: `${virtualItem.size}px`,\n transform: `translateY(${virtualItem.start}px)`,\n }}\n />\n );\n })}\n <Sentinel\n dataCount={virtualizer.range.endIndex}\n placeholderRowCount={placeholderRowCount}\n query={query}\n style={{\n top: `${virtualizer.getTotalSize()}px`,\n }}\n />\n </div>\n );\n}\n\ninterface SentinelProps extends BodyProps {\n dataCount: number;\n query: UseInfiniteQueryResult;\n style?: React.CSSProperties;\n}\nfunction Sentinel({\n dataCount,\n placeholderRowCount,\n renderRowAs,\n query,\n style,\n}: SentinelProps) {\n // show at least one placeholder row always\n return (\n <InfiniteScrollSentinel\n query={query}\n style={style}\n loaderMarginTop=\"mt-0\"\n className=\"absolute left-0\"\n >\n {[...new Array(Math.max(placeholderRowCount, 1)).keys()].map(\n (key, index) => {\n const id = `placeholder-${key}`;\n return (\n <TableRow\n item={{id, isPlaceholder: true}}\n index={dataCount + index}\n key={id}\n renderAs={renderRowAs}\n />\n );\n }\n )}\n </InfiniteScrollSentinel>\n );\n}\n","import {usePaginatedChannelContent} from '@app/web-player/channels/requests/use-paginated-channel-content';\nimport React, {Fragment} from 'react';\nimport {ChannelContentProps} from '@app/web-player/channels/channel-content';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {Track} from '@app/web-player/tracks/track';\nimport {VirtualTableBody} from '@app/web-player/playlists/virtual-table-body';\nimport {ChannelHeading} from '@app/web-player/channels/channel-heading';\n\nexport function ChannelTrackTable(props: ChannelContentProps<Track>) {\n return (\n <Fragment>\n <ChannelHeading {...props} />\n {props.isNested ? (\n <SimpleTable {...props} />\n ) : (\n <PaginatedTable {...props} />\n )}\n </Fragment>\n );\n}\n\nfunction SimpleTable({channel}: ChannelContentProps<Track>) {\n return (\n <TrackTable tracks={channel.content?.data || []} enableSorting={false} />\n );\n}\n\nfunction PaginatedTable({channel}: ChannelContentProps<Track>) {\n const query = usePaginatedChannelContent(channel);\n\n const totalItems =\n channel.content && 'total' in channel.content\n ? channel.content.total\n : undefined;\n\n return (\n <TrackTable\n enableSorting={false}\n tracks={query.items}\n tableBody={<VirtualTableBody query={query} totalItems={totalItems} />}\n />\n );\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Comment} from '@common/comments/comment';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface WaveDataResponse extends BackendResponse {\n waveData: number[][];\n comments: Comment[];\n}\n\nfunction queryKey(trackId: number | string) {\n return ['tracks', +trackId, 'wave-data'];\n}\n\nexport function invalidateWaveData(trackId: number | string) {\n queryClient.invalidateQueries(queryKey(trackId));\n}\n\nexport function useTrackWaveData(\n trackId: number | string,\n {enabled}: {enabled?: boolean} = {}\n) {\n return useQuery(queryKey(trackId), () => fetchWaveData(trackId), {\n onError: err => showHttpErrorToast(err),\n enabled,\n });\n}\n\nfunction fetchWaveData(trackId: number | string) {\n return apiClient\n .get<WaveDataResponse>(`tracks/${trackId}/wave`)\n .then(response => response.data);\n}\n","export function drawWaveform(\n waveData: number[][],\n canvas: HTMLCanvasElement,\n color: string\n) {\n const context = canvas.getContext('2d');\n if (!context) return;\n context.clearRect(0, 0, canvas.width, canvas.height);\n\n // mirror\n context.fillStyle = color;\n context.globalAlpha = 0.5;\n waveData.forEach(lineData => {\n const height = (55 / 100) * lineData[3];\n context.fillRect(\n lineData[0],\n lineData[1] + lineData[3] + 1,\n lineData[2],\n height\n );\n });\n\n // main\n context.fillStyle = color;\n context.globalAlpha = 1;\n waveData.forEach(lineData => {\n context.fillRect(lineData[0], lineData[1], lineData[2], lineData[3]);\n });\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {\n tracksToMediaItems,\n trackToMediaItem,\n} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {flushSync} from 'react-dom';\nimport {useEffect, useState} from 'react';\n\nexport function useTrackSeekbar(track: Track, queue?: Track[]) {\n const player = usePlayerActions();\n const cuedMedia = usePlayerStore(s => s.cuedMedia);\n\n // either use exact duration from provider if this track is cued, or use duration from track props\n const playerDuration = usePlayerStore(s => s.mediaDuration);\n const duration =\n cuedMedia?.id === track.id && playerDuration\n ? playerDuration\n : (track.duration || 0) / 1000;\n\n const [currentTime, setCurrentTime] = useState(\n track.id === player.getState().cuedMedia?.id ? player.getCurrentTime() : 0\n );\n\n useEffect(() => {\n return player.subscribe({\n progress: ({currentTime}) => {\n setCurrentTime(\n track.id === player.getState().cuedMedia?.id ? currentTime : 0\n );\n },\n });\n }, [player, track]);\n\n return {\n duration,\n minValue: 0,\n maxValue: duration,\n value: currentTime,\n onPointerDown: () => {\n player.setIsSeeking(true);\n player.pause();\n\n // flush so provider src is changed immediately. Without this seeking\n // will not work when clicking on a different track the first time\n if (player.getState().cuedMedia?.id !== track.id) {\n flushSync(() => {\n if (queue?.length) {\n const pointer = queue?.findIndex(t => t.id === track.id);\n player.overrideQueue(tracksToMediaItems(queue), pointer);\n } else {\n player.cue(trackToMediaItem(track));\n }\n });\n }\n },\n onChange: (value: number) => {\n player.getState().emit('progress', {currentTime: value});\n player.seek(value);\n },\n onChangeEnd: () => {\n player.setIsSeeking(false);\n player.play();\n },\n };\n}\n","import {\n createContext,\n MutableRefObject,\n RefObject,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\ninterface CommentBarContextValue {\n newCommentInputRef: RefObject<HTMLInputElement>;\n newCommentPositionRef: MutableRefObject<number>;\n markerIsVisible: boolean;\n setMarkerIsVisible: (value: boolean) => void;\n disableCommenting: boolean;\n}\n\nexport const CommentBarContext = createContext<CommentBarContextValue>(null!);\n\ninterface CommentBarContextProps {\n children: any;\n disableCommenting?: boolean;\n}\nexport function CommentBarContextProvider({\n children,\n disableCommenting = false,\n}: CommentBarContextProps) {\n const [markerIsVisible, setMarkerIsVisible] = useState(false);\n const newCommentInputRef = useRef<HTMLInputElement>(null);\n const newCommentPositionRef = useRef<number>(0);\n const value: CommentBarContextValue = useMemo(() => {\n return {\n newCommentInputRef,\n newCommentPositionRef,\n markerIsVisible,\n setMarkerIsVisible,\n disableCommenting,\n };\n }, [markerIsVisible, disableCommenting]);\n return (\n <CommentBarContext.Provider value={value}>\n {children}\n </CommentBarContext.Provider>\n );\n}\n","import {getUserImage} from '@app/web-player/users/user-image';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {Dialog} from '@common/ui/overlays/dialog/dialog';\nimport {DialogBody} from '@common/ui/overlays/dialog/dialog-body';\nimport {useSlider} from '@common/ui/forms/slider/use-slider';\nimport {useAuth} from '@common/auth/use-auth';\nimport {useContext} from 'react';\nimport {Avatar} from '@common/ui/images/avatar';\nimport clsx from 'clsx';\nimport {useInteractOutside} from '@react-aria/interactions';\nimport {CommentBarContext} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport {Comment} from '@common/comments/comment';\nimport {Track} from '@app/web-player/tracks/track';\n\ninterface CommentBarProps {\n comments: Comment[];\n track: Track;\n}\nexport function CommentBar({comments, track}: CommentBarProps) {\n const {user, hasPermission} = useAuth();\n const {\n newCommentInputRef,\n newCommentPositionRef,\n markerIsVisible,\n setMarkerIsVisible,\n ...commentBarContext\n } = useContext(CommentBarContext);\n\n const disableCommenting =\n commentBarContext.disableCommenting || !hasPermission('comments.create');\n\n const {domProps, groupId, trackRef, getThumbPercent} = useSlider({\n onChange: () => {\n setMarkerIsVisible(true);\n newCommentPositionRef.current = getThumbPercent(0) * 100;\n },\n onChangeEnd: () => {\n newCommentInputRef.current?.focus();\n },\n });\n\n useInteractOutside({\n ref: trackRef,\n onInteractOutside: e => {\n if (!newCommentInputRef.current?.contains(e.target as HTMLElement)) {\n setMarkerIsVisible(false);\n }\n },\n });\n\n return (\n <div\n className={clsx(\n 'absolute top-48 left-0 h-26 w-full isolate',\n !disableCommenting && 'cursor-pointer'\n )}\n ref={trackRef}\n {...(disableCommenting ? {} : domProps)}\n id={groupId}\n >\n {markerIsVisible ? (\n <div\n className=\"absolute top-0 left-0 z-20 overflow-hidden w-26 h-26 shadow-md -translate-x-1/2 cursor-move\"\n style={{left: `${getThumbPercent(0) * 100}%`}}\n >\n <Avatar src={user?.avatar} size=\"w-full h-full\" />\n </div>\n ) : null}\n {comments.map(comment => {\n if (!comment.user) return null;\n return (\n <DialogTrigger key={comment.id} type=\"popover\" triggerOnHover>\n <div\n style={{left: `${Math.min(99, comment.position || 0)}%`}}\n className={clsx(\n 'transition-opacity duration-300 ease-in-out absolute top-0 -translate-x-1/2 cursor-pointer',\n markerIsVisible ? 'opacity-40' : 'opacity-100'\n )}\n >\n <div\n className=\"bg-cover w-16 h-16 rounded shadow bg-chip\"\n style={{backgroundImage: `url(${getUserImage(comment.user)})`}}\n />\n </div>\n <CommentDialog comment={comment} />\n </DialogTrigger>\n );\n })}\n </div>\n );\n}\n\ninterface CommentDialogProps {\n comment: Comment;\n}\nfunction CommentDialog({comment}: CommentDialogProps) {\n return (\n <Dialog size=\"w-auto\">\n <DialogBody padding=\"p-8\">\n <div className=\"flex items-center gap-10\">\n {comment.user && (\n <div className=\"text-primary\">{comment.user.display_name}</div>\n )}\n <div>{comment.content}</div>\n </div>\n </DialogBody>\n </Dialog>\n );\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {useEffect, useRef, useState} from 'react';\nimport {useTrackWaveData} from '@app/web-player/tracks/requests/use-track-wave-data';\nimport {\n WAVE_HEIGHT,\n WAVE_WIDTH,\n} from '@app/web-player/tracks/waveform/generate-waveform-data';\nimport clsx from 'clsx';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {useSlider} from '@common/ui/forms/slider/use-slider';\nimport {useThemeSelector} from '@common/ui/themes/theme-selector-context';\nimport {themeValueToHex} from '@common/ui/themes/utils/theme-value-to-hex';\nimport {AnimatePresence} from 'framer-motion';\nimport {drawWaveform} from '@app/web-player/tracks/waveform/draw-waveform';\nimport {useTrackSeekbar} from '@app/web-player/player-controls/seekbar/use-track-seekbar';\nimport {CommentBar} from '@app/web-player/tracks/waveform/comment-bar';\n\nconst durationClassName =\n 'text-[11px] absolute bottom-32 p-3 rounded text-white font-semibold z-30 pointer-events-none bg-black/80';\n\ninterface WaveformProps {\n track: Track;\n queue?: Track[];\n className?: string;\n}\nexport function Waveform({track, queue, className}: WaveformProps) {\n const ref = useRef<HTMLDivElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const progressCanvasRef = useRef<HTMLCanvasElement>(null);\n // when wave is scrolled into view\n const [isInView, setIsInView] = useState(false);\n // after wave is drawn into canvas and fade in animation should start running\n const [isVisible, setIsVisible] = useState(false);\n const {data} = useTrackWaveData(track.id, {enabled: isInView});\n const themeSelector = useThemeSelector();\n\n useEffect(() => {\n const observer = new IntersectionObserver(\n (entries: IntersectionObserverEntry[]) => {\n entries.forEach(entry => {\n if (entry.isIntersecting && entry.target === ref.current) {\n setIsInView(true);\n observer.disconnect();\n }\n });\n },\n {root: document.body}\n );\n if (ref.current) {\n observer.observe(ref.current);\n }\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (canvasRef.current && data?.waveData && progressCanvasRef.current) {\n drawWaveform(data.waveData, canvasRef.current, '#666');\n drawWaveform(\n data.waveData,\n progressCanvasRef.current,\n themeValueToHex(themeSelector.selectedTheme.colors['--be-primary'])\n );\n setIsVisible(true);\n }\n }, [data, themeSelector.selectedTheme]);\n\n const {value, onChange, onChangeEnd, duration, ...sliderProps} =\n useTrackSeekbar(track, queue);\n const {domProps, groupId, thumbIds, trackRef, getThumbPercent} = useSlider({\n ...sliderProps,\n value: [value],\n onChange: ([newValue]: number[]) => onChange(newValue),\n onChangeEnd: () => onChangeEnd(),\n });\n\n return (\n <AnimatePresence mode=\"wait\">\n <section className=\"relative max-w-full\">\n <div\n id={groupId}\n role=\"group\"\n ref={ref}\n className={clsx(\n 'relative isolate h-70 cursor-pointer overflow-hidden transition-opacity duration-200 ease-in',\n isVisible ? 'opacity-100' : 'opacity-0',\n className\n )}\n >\n <output\n className={clsx(durationClassName, 'left-0')}\n htmlFor={thumbIds[0]}\n aria-live=\"off\"\n >\n {value ? <FormattedDuration seconds={value} /> : '0:00'}\n </output>\n <div key=\"wave\" {...domProps} ref={trackRef}>\n <canvas\n ref={canvasRef}\n width={WAVE_WIDTH}\n height={WAVE_HEIGHT + 25}\n />\n <div\n className=\"absolute top-0 left-0 z-20 overflow-hidden w-0\"\n style={{width: `${getThumbPercent(0) * 100}%`}}\n >\n <canvas\n ref={progressCanvasRef}\n width={WAVE_WIDTH}\n height={WAVE_HEIGHT + 25}\n />\n </div>\n </div>\n <div className={clsx(durationClassName, 'right-0')}>\n <FormattedDuration seconds={duration} />\n </div>\n </div>\n {data?.comments && (\n <CommentBar comments={data.comments} track={track} />\n )}\n </section>\n </AnimatePresence>\n );\n}\n","import {Slider} from '@common/ui/forms/slider/slider';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {useTrackSeekbar} from '@app/web-player/player-controls/seekbar/use-track-seekbar';\nimport {Track} from '@app/web-player/tracks/track';\nimport clsx from 'clsx';\n\ninterface TrackSeekbarProps {\n track: Track;\n queue?: Track[];\n className?: string;\n}\nexport function TrackSeekbar({track, queue, className}: TrackSeekbarProps) {\n const {duration, ...sliderProps} = useTrackSeekbar(track, queue);\n\n return (\n <div className={clsx('flex items-center gap-12', className)}>\n <div className=\"text-xs text-muted flex-shrink-0 min-w-40 text-right\">\n {sliderProps.value ? (\n <FormattedDuration seconds={sliderProps.value} />\n ) : (\n '0:00'\n )}\n </div>\n <Slider\n trackColor=\"neutral\"\n thumbSize=\"w-14 h-14\"\n showThumbOnHoverOnly={true}\n className=\"flex-auto\"\n width=\"w-auto\"\n {...sliderProps}\n />\n <div className=\"text-xs text-muted flex-shrink-0 min-w-40\">\n <FormattedDuration seconds={duration} />\n </div>\n </div>\n );\n}\n","import {Track} from '@app/web-player/tracks/track';\n\nexport function trackIsLocallyUploaded(track: Track): boolean {\n return (\n track?.src != null &&\n (track.src.startsWith('storage') ||\n track.src.includes('storage/track_media'))\n );\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {Commentable} from '@common/comments/commentable';\nimport {Comment} from '@common/comments/comment';\n\ninterface Response extends BackendResponse {\n //\n}\n\nexport interface CreateCommentPayload {\n commentable: Commentable;\n content: string;\n inReplyTo?: Comment;\n}\n\nexport function useCreateComment() {\n return useMutation((props: CreateCommentPayload) => createComment(props), {\n onSuccess: (response, props) => {\n toast(message('Comment posted'));\n queryClient.invalidateQueries([\n 'comment',\n `${props.commentable.id}-${props.commentable.model_type}`,\n ]);\n },\n onError: err => showHttpErrorToast(err),\n });\n}\n\nfunction createComment({\n commentable,\n content,\n inReplyTo,\n ...other\n}: CreateCommentPayload): Promise<Response> {\n const payload = {\n commentable_id: commentable.id,\n commentable_type: commentable.model_type,\n content,\n inReplyTo,\n ...other,\n };\n return apiClient.post('comment', payload).then(r => r.data);\n}\n","import {Commentable} from '@common/comments/commentable';\nimport {Comment} from '@common/comments/comment';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {useAuth} from '@common/auth/use-auth';\nimport {useCreateComment} from '@common/comments/requests/use-create-comment';\nimport {RefObject, useState} from 'react';\nimport clsx from 'clsx';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {Avatar} from '@common/ui/images/avatar';\nimport {message} from '@common/i18n/message';\nimport {Trans} from '@common/i18n/trans';\nimport {useObjectRef} from '@react-aria/utils';\nimport {Button} from '@common/ui/buttons/button';\n\nexport interface NewCommentFormProps {\n commentable: Commentable;\n inReplyTo?: Comment;\n onSuccess?: () => void;\n className?: string;\n autoFocus?: boolean;\n inputRef?: RefObject<HTMLInputElement>;\n // additional data that should be sent to backend when creating comments\n payload?: Record<string, number | string>;\n}\nexport function NewCommentForm({\n commentable,\n inReplyTo,\n onSuccess,\n className,\n autoFocus,\n payload,\n ...props\n}: NewCommentFormProps) {\n const {trans} = useTrans();\n const {user} = useAuth();\n const createComment = useCreateComment();\n const inputRef = useObjectRef<HTMLInputElement>(props.inputRef);\n const [inputIsExpanded, setInputIsExpanded] = useState(false);\n const [inputValue, setInputValue] = useState('');\n\n const clearInput = () => {\n setInputIsExpanded(false);\n if (inputRef.current) {\n inputRef.current.blur();\n setInputValue('');\n }\n };\n\n return (\n <form\n className={clsx('py-6 flex gap-24', className)}\n onSubmit={e => {\n e.preventDefault();\n if (inputValue && !createComment.isLoading) {\n createComment.mutate(\n {\n ...payload,\n commentable,\n content: inputValue,\n inReplyTo,\n },\n {\n onSuccess: () => {\n clearInput();\n onSuccess?.();\n },\n }\n );\n }\n }}\n >\n <Avatar size=\"xl\" circle src={user?.avatar} label={user?.display_name} />\n <div className=\"flex-auto\">\n <div className=\"text-xs text-muted mb-10\">\n <Trans\n message=\"Comment as :name\"\n values={{\n name: (\n <span className=\"font-medium text\">{user?.display_name}</span>\n ),\n }}\n />\n </div>\n <TextField\n inputRef={inputRef}\n autoFocus={autoFocus}\n inputElementType=\"textarea\"\n inputClassName=\"resize-none\"\n value={inputValue}\n onChange={e => setInputValue(e.target.value)}\n onFocus={() => setInputIsExpanded(true)}\n onBlur={() => {\n if (!inputValue) {\n setInputIsExpanded(false);\n }\n }}\n minLength={3}\n rows={inputIsExpanded ? 3 : 1}\n placeholder={\n inReplyTo\n ? trans(message('Write a reply'))\n : trans(message('Leave a comment'))\n }\n />\n {inputIsExpanded && (\n <div className=\"flex items-center gap-12 justify-end mt-12\">\n <Button variant=\"outline\" onClick={() => clearInput()}>\n <Trans message=\"Cancel\" />\n </Button>\n <Button\n variant=\"outline\"\n color=\"primary\"\n type=\"submit\"\n disabled={createComment.isLoading || inputValue.length < 3}\n >\n <Trans message=\"Comment\" />\n </Button>\n </div>\n )}\n </div>\n </form>\n );\n}\n","import {\n NewCommentForm,\n NewCommentFormProps,\n} from '@common/comments/new-comment-form';\nimport React, {useContext} from 'react';\nimport {CommentBarContext} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport {invalidateWaveData} from '@app/web-player/tracks/requests/use-track-wave-data';\nimport {useAuth} from '@common/auth/use-auth';\n\nexport function CommentBarNewCommentForm({\n commentable,\n className,\n}: NewCommentFormProps) {\n const {isLoggedIn} = useAuth();\n const {newCommentInputRef, newCommentPositionRef, setMarkerIsVisible} =\n useContext(CommentBarContext);\n\n if (!isLoggedIn) return null;\n\n return (\n <NewCommentForm\n inputRef={newCommentInputRef}\n className={className}\n commentable={commentable}\n payload={{position: newCommentPositionRef.current}}\n onSuccess={() => {\n setMarkerIsVisible(false);\n invalidateWaveData(commentable.id);\n }}\n />\n );\n}\n","import {useAddItemsToLibrary} from '@app/web-player/library/requests/use-add-items-to-library';\nimport {useRemoveItemsFromLibrary} from '@app/web-player/library/requests/use-remove-items-from-library';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport {Likeable} from '@app/web-player/library/likeable';\nimport {FavoriteIcon} from '@common/icons/material/Favorite';\nimport {FavoriteBorderIcon} from '@common/icons/material/FavoriteBorder';\nimport {Button, ButtonProps} from '@common/ui/buttons/button';\nimport {message} from '@common/i18n/message';\nimport {Trans} from '@common/i18n/trans';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\ninterface LikeButtonProps extends Omit<ButtonProps, 'children' | 'onClick'> {\n likeable: Likeable;\n}\nexport function LikeButton({\n likeable,\n radius = 'rounded-full',\n disabled,\n ...buttonProps\n}: LikeButtonProps) {\n const authHandler = useAuthClickCapture();\n const addToLibrary = useAddItemsToLibrary();\n const removeFromLibrary = useRemoveItemsFromLibrary();\n const isLiked = useLibraryStore(s => s.has(likeable));\n const isLoading = addToLibrary.isLoading || removeFromLibrary.isLoading;\n\n const labels = getLabels(likeable);\n\n if (isLiked) {\n return (\n <Button\n {...buttonProps}\n variant=\"outline\"\n radius={radius}\n startIcon={<FavoriteIcon className=\"text-primary\" />}\n disabled={disabled || isLoading}\n onClickCapture={authHandler}\n onClick={() => {\n removeFromLibrary.mutate({likeables: [likeable]});\n }}\n >\n <Trans {...labels.removeLike} />\n </Button>\n );\n }\n return (\n <Button\n {...buttonProps}\n variant=\"outline\"\n radius={radius}\n startIcon={<FavoriteBorderIcon />}\n disabled={disabled || isLoading}\n onClickCapture={authHandler}\n onClick={() => {\n addToLibrary.mutate({likeables: [likeable]});\n }}\n >\n <Trans {...labels.like} />\n </Button>\n );\n}\n\nfunction getLabels(likeable: Likeable) {\n switch (likeable.model_type) {\n case 'artist':\n return {like: message('Follow'), removeLike: message('Following')};\n default:\n return {like: message('Like'), removeLike: message('Liked')};\n }\n}\n","import {Track} from '@app/web-player/tracks/track';\nimport {Album} from '@app/web-player/albums/album';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {useToggleRepost} from '@app/web-player/reposts/use-toggle-repost';\nimport {useRepostsStore} from '@app/web-player/library/state/reposts-store';\nimport {Button} from '@common/ui/buttons/button';\nimport {RepeatIcon} from '@common/icons/material/Repeat';\nimport clsx from 'clsx';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {ButtonSize} from '@common/ui/buttons/button-size';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\ninterface RepostButtonProps {\n item: Track | Album;\n className?: string;\n size?: ButtonSize;\n radius?: string;\n disabled?: boolean;\n}\nexport function RepostButton({\n item,\n className,\n size = 'xs',\n radius,\n disabled,\n}: RepostButtonProps) {\n const authHandler = useAuthClickCapture();\n const {player} = useSettings();\n const toggleRepost = useToggleRepost();\n const isReposted = useRepostsStore(s => s.has(item));\n if (!player?.enable_repost) return null;\n\n return (\n <Button\n className={className}\n variant=\"outline\"\n size={size}\n radius={radius}\n startIcon={<RepeatIcon className={clsx(isReposted && 'text-primary')} />}\n disabled={disabled || toggleRepost.isLoading}\n onClickCapture={authHandler}\n onClick={() => toggleRepost.mutate({repostable: item})}\n >\n {isReposted ? <Trans message=\"Reposted\" /> : <Trans message=\"Repost\" />}\n </Button>\n );\n}\n","import React from 'react';\nimport clsx from 'clsx';\nimport {Track} from '@app/web-player/tracks/track';\nimport {PlayArrowFilledIcon} from '@app/web-player/tracks/play-arrow-filled';\nimport {FormattedNumber} from '@common/i18n/formatted-number';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\nimport {FavoriteIcon} from '@common/icons/material/Favorite';\nimport {RepeatIcon} from '@common/icons/material/Repeat';\nimport {Album} from '@app/web-player/albums/album';\nimport {Artist} from '@app/web-player/artists/artist';\n\ninterface Props {\n item: Track | Album | Artist;\n className?: string;\n showPlays?: boolean;\n}\nexport function MediaItemStats({item, className, showPlays = true}: Props) {\n return (\n <div\n className={clsx('flex items-center gap-20 text-sm text-muted', className)}\n >\n {showPlays && <PlayCount item={item} />}\n <LikesCount item={item} />\n {item.model_type !== 'artist' && <RepostsCount item={item} />}\n </div>\n );\n}\n\ninterface PlayCountProps {\n item: Track | Album | Artist;\n}\nfunction PlayCount({item}: PlayCountProps) {\n if (!item.plays) return null;\n\n const count = (\n <FormattedNumber\n compactDisplay=\"short\"\n notation=\"compact\"\n value={item.plays}\n />\n );\n\n return (\n <Tooltip label={<Trans message=\":count plays\" values={{count}} />}>\n <div>\n <PlayArrowFilledIcon size=\"xs\" className=\"mr-4\" />\n {count}\n </div>\n </Tooltip>\n );\n}\n\ninterface LikesCountProps {\n item: Track | Album | Artist;\n}\nfunction LikesCount({item}: LikesCountProps) {\n if (!item.likes_count) return null;\n\n const count = <FormattedNumber value={item.likes_count} />;\n\n return (\n <Tooltip label={<Trans message=\":count likes\" values={{count}} />}>\n <div>\n <FavoriteIcon size=\"xs\" className=\"mr-4\" />\n {count}\n </div>\n </Tooltip>\n );\n}\n\ninterface RepostsCountProps {\n item: Track | Album;\n}\nfunction RepostsCount({item}: RepostsCountProps) {\n if (!item.reposts_count) return null;\n\n const count = <FormattedNumber value={item.reposts_count} />;\n\n return (\n <Tooltip label={<Trans message=\":count reposts\" values={{count}} />}>\n <div className=\"hidden @[566px]:block\">\n <RepeatIcon size=\"xs\" className=\"mr-4\" />\n {count}\n </div>\n </Tooltip>\n );\n}\n","import React, {Fragment, ReactNode} from 'react';\nimport {LikeButton} from '@app/web-player/library/like-button';\nimport {RepostButton} from '@app/web-player/reposts/repost-button';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {Button} from '@common/ui/buttons/button';\nimport {ShareIcon} from '@common/icons/material/Share';\nimport {Trans} from '@common/i18n/trans';\nimport {MoreHorizIcon} from '@common/icons/material/MoreHoriz';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {MediaItemStats} from '@app/web-player/tracks/media-item-stats';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Album} from '@app/web-player/albums/album';\nimport {AlbumContextDialog} from '@app/web-player/albums/album-context-dialog';\nimport clsx from 'clsx';\nimport {ButtonSize} from '@common/ui/buttons/button-size';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {ShareMediaDialog} from '@app/web-player/sharing/share-media-dialog';\n\ninterface Props {\n item: Track | Album;\n managesItem: boolean;\n buttonClassName?: string;\n buttonGap?: string;\n buttonSize?: ButtonSize;\n buttonRadius?: string;\n children?: ReactNode;\n className?: string;\n}\nexport function TrackActionsBar({\n item,\n managesItem,\n buttonClassName,\n buttonGap = 'mr-8',\n buttonSize = 'xs',\n buttonRadius = 'rounded',\n children,\n className,\n}: Props) {\n const isMobile = useIsMobileMediaQuery();\n return (\n <div\n className={clsx(\n 'flex items-center gap-24 justify-center md:justify-between overflow-hidden @container',\n className\n )}\n >\n <div>\n {children}\n {!isMobile && (\n <Fragment>\n <LikeButton\n size={buttonSize}\n likeable={item}\n className={clsx(buttonGap, buttonClassName)}\n radius={buttonRadius}\n disabled={managesItem}\n />\n <RepostButton\n item={item}\n size={buttonSize}\n radius={buttonRadius}\n disabled={managesItem}\n className={clsx(\n buttonGap,\n buttonClassName,\n 'hidden @[840px]:inline-flex'\n )}\n />\n </Fragment>\n )}\n {!isMobile && (\n <DialogTrigger type=\"modal\">\n <Button\n size={buttonSize}\n variant=\"outline\"\n startIcon={<ShareIcon />}\n className={clsx(\n buttonGap,\n buttonClassName,\n 'hidden @[660px]:inline-flex'\n )}\n radius={buttonRadius}\n >\n <Trans message=\"Share\" />\n </Button>\n <ShareMediaDialog item={item} />\n </DialogTrigger>\n )}\n <DialogTrigger type=\"popover\">\n <Button\n variant=\"outline\"\n size={buttonSize}\n startIcon={<MoreHorizIcon />}\n className={clsx(buttonGap, buttonClassName)}\n radius={buttonRadius}\n >\n <Trans message=\"More\" />\n </Button>\n <MoreDialog item={item} />\n </DialogTrigger>\n </div>\n {!isMobile && <MediaItemStats item={item} />}\n </div>\n );\n}\n\ninterface MoreDialogProps {\n item: Track | Album;\n}\nfunction MoreDialog({item}: MoreDialogProps) {\n if (item.model_type === 'track') {\n return <TrackContextDialog tracks={[item]} />;\n }\n return <AlbumContextDialog album={item} />;\n}\n","import {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {Waveform} from '@app/web-player/tracks/waveform/waveform';\nimport {Track} from '@app/web-player/tracks/track';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {TrackSeekbar} from '@app/web-player/player-controls/seekbar/track-seekbar';\nimport {trackIsLocallyUploaded} from '@app/web-player/tracks/utils/track-is-locally-uploaded';\nimport {FormattedRelativeTime} from '@common/i18n/formatted-relative-time';\nimport {\n CommentBarContext,\n CommentBarContextProvider,\n} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport {CommentBarNewCommentForm} from '@app/web-player/tracks/waveform/comment-bar-new-comment-form';\nimport React, {Fragment, memo, useContext} from 'react';\nimport {AnimatePresence} from 'framer-motion';\nimport {Chip} from '@common/ui/forms/input-field/chip-field/chip';\nimport {GenreLink} from '@app/web-player/genres/genre-link';\nimport {RepeatIcon} from '@common/icons/material/Repeat';\nimport {TrackLink} from '@app/web-player/tracks/track-link';\nimport {useTrackPermissions} from '@app/web-player/tracks/hooks/use-track-permissions';\nimport {User} from '@common/auth/user';\nimport {UserProfileLink} from '@app/web-player/users/user-profile-link';\nimport {TrackActionsBar} from '@app/web-player/tracks/track-actions-bar';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport clsx from 'clsx';\n\ninterface TrackListItemProps {\n track: Track;\n queue?: Track[];\n reposter?: User;\n className?: string;\n hideArtwork?: boolean;\n hideActions?: boolean;\n linksInNewTab?: boolean;\n}\nexport const TrackListItem = memo(\n ({\n track,\n queue,\n reposter,\n className,\n hideArtwork = false,\n hideActions = false,\n linksInNewTab = false,\n }: TrackListItemProps) => {\n const {player} = useSettings();\n const isMobile = useIsMobileMediaQuery();\n hideArtwork = hideArtwork || !!isMobile;\n const {managesTrack} = useTrackPermissions([track]);\n\n const showWave =\n player?.seekbar_type === 'waveform' && trackIsLocallyUploaded(track);\n\n return (\n <div\n className={clsx(\n 'overflow-hidden',\n !hideArtwork && 'flex gap-24',\n className\n )}\n >\n {!hideArtwork && (\n <TrackImage\n track={track}\n className=\"flex-shrink-0 rounded\"\n size=\"w-184 h-184\"\n />\n )}\n <div className=\"flex-auto min-w-0\">\n <div className=\"flex items-center gap-14\">\n <PlaybackToggleButton\n track={track}\n tracks={queue}\n buttonType=\"icon\"\n color=\"primary\"\n variant=\"flat\"\n radius=\"rounded-full\"\n equalizerColor=\"white\"\n />\n <div>\n <div className=\"text-sm text-muted flex items-center gap-6\">\n <ArtistLinks\n artists={track.artists}\n target={linksInNewTab ? '_blank' : undefined}\n />\n {reposter && (\n <Fragment>\n <RepeatIcon size=\"xs\" />\n <UserProfileLink\n user={reposter}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </Fragment>\n )}\n </div>\n <div>\n <TrackLink\n track={track}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </div>\n </div>\n <div className=\"ml-auto text-sm\">\n <FormattedRelativeTime date={track.created_at} />\n {track.genres?.length ? (\n <Chip className=\"mt-6 w-max\" size=\"xs\">\n <GenreLink\n genre={track.genres[0]}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </Chip>\n ) : null}\n </div>\n </div>\n <div className=\"mt-20\">\n {showWave ? (\n <CommentBarContextProvider disableCommenting={hideActions}>\n <WaveformWithComments track={track} queue={queue} />\n </CommentBarContextProvider>\n ) : (\n <TrackSeekbar track={track} queue={queue} />\n )}\n </div>\n {!hideActions && (\n <TrackActionsBar\n item={track}\n managesItem={managesTrack}\n className=\"mt-20\"\n />\n )}\n </div>\n </div>\n );\n }\n);\n\ninterface WaveformWithCommentsProps {\n track: Track;\n queue?: Track[];\n}\nexport function WaveformWithComments({\n track,\n queue,\n}: WaveformWithCommentsProps) {\n const {markerIsVisible} = useContext(CommentBarContext);\n return (\n <Fragment>\n <Waveform track={track} queue={queue} />\n <AnimatePresence mode=\"wait\">\n {markerIsVisible && (\n <CommentBarNewCommentForm\n className=\"mt-28 mb-8\"\n commentable={track}\n />\n )}\n </AnimatePresence>\n </Fragment>\n );\n}\n","import {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {TrackListItem} from '@app/web-player/tracks/track-list/track-list-item';\nimport React from 'react';\nimport {Track} from '@app/web-player/tracks/track';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {VirtualTableBody} from '@app/web-player/playlists/virtual-table-body';\nimport {UseInfiniteDataResult} from '@common/ui/infinite-scroll/use-infinite-data';\n\ninterface Props {\n tracks?: Track[];\n query?: UseInfiniteDataResult<Track>;\n}\nexport function TrackList({tracks, query}: Props) {\n const isMobile = useIsMobileMediaQuery();\n\n if (!tracks) {\n tracks = query ? query.items : [];\n }\n\n if (isMobile) {\n if (!query) {\n return <TrackTable tracks={tracks} />;\n }\n return (\n <TrackTable\n tracks={tracks}\n tableBody={<VirtualTableBody query={query} />}\n />\n );\n }\n\n return (\n <div>\n {tracks.map(track => (\n <TrackListItem\n queue={tracks}\n key={track.id}\n track={track}\n className=\"mb-40\"\n />\n ))}\n {query && <InfiniteScrollSentinel query={query} />}\n </div>\n );\n}\n","import {usePaginatedChannelContent} from '@app/web-player/channels/requests/use-paginated-channel-content';\nimport React, {Fragment} from 'react';\nimport {ChannelContentProps} from '@app/web-player/channels/channel-content';\nimport {Track} from '@app/web-player/tracks/track';\nimport {ChannelHeading} from '@app/web-player/channels/channel-heading';\nimport {TrackList} from '@app/web-player/tracks/track-list/track-list';\n\nexport function ChannelTrackList(props: ChannelContentProps<Track>) {\n return (\n <Fragment>\n <ChannelHeading {...props} />\n {props.isNested ? (\n <TrackList tracks={props.channel.content?.data} />\n ) : (\n <PaginatedList {...props} />\n )}\n </Fragment>\n );\n}\n\nfunction PaginatedList({channel}: ChannelContentProps<Track>) {\n const query = usePaginatedChannelContent<Track>(channel);\n return <TrackList query={query} />;\n}\n","var functionDebounce = debounce;\n\nfunction debounce(fn, wait, callFirst) {\n var timeout = null;\n var debouncedFn = null;\n\n var clear = function() {\n if (timeout) {\n clearTimeout(timeout);\n\n debouncedFn = null;\n timeout = null;\n }\n };\n\n var flush = function() {\n var call = debouncedFn;\n clear();\n\n if (call) {\n call();\n }\n };\n\n var debounceWrapper = function() {\n if (!wait) {\n return fn.apply(this, arguments);\n }\n\n var context = this;\n var args = arguments;\n var callNow = callFirst && !timeout;\n clear();\n\n debouncedFn = function() {\n fn.apply(context, args);\n };\n\n timeout = setTimeout(function() {\n timeout = null;\n\n if (!callNow) {\n var call = debouncedFn;\n debouncedFn = null;\n\n return call();\n }\n }, wait);\n\n if (callNow) {\n return debouncedFn();\n }\n };\n\n debounceWrapper.cancel = clear;\n debounceWrapper.flush = flush;\n\n return debounceWrapper;\n}\n\nexport {functionDebounce as default};\n","import React, {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {KeyboardArrowRightIcon} from '@common/icons/material/KeyboardArrowRight';\nimport {KeyboardArrowLeftIcon} from '@common/icons/material/KeyboardArrowLeft';\nimport {ChannelContentProps} from '@app/web-player/channels/channel-content';\nimport {ChannelContentGridItem} from '@app/web-player/channels/channel-content-grid-item';\nimport {ChannelHeading} from '@app/web-player/channels/channel-heading';\nimport debounce from 'just-debounce-it';\n\nexport function ChannelContentCarousel(props: ChannelContentProps) {\n const {channel} = props;\n const ref = useRef<HTMLDivElement>(null);\n const itemWidth = useRef<number>(0);\n\n const [enablePrev, setEnablePrev] = useState(false);\n const [enableNext, setEnableNext] = useState(true);\n\n const updateNavStatus = useCallback(() => {\n const el = ref.current;\n if (el && itemWidth.current) {\n setEnablePrev(el.scrollLeft > 0);\n setEnableNext(el.scrollWidth - el.scrollLeft !== el.clientWidth);\n }\n }, []);\n\n // enable/disable navigation buttons based on element scroll offset\n useEffect(() => {\n const el = ref.current;\n const handleScroll = debounce(() => updateNavStatus(), 100);\n if (el) {\n el.addEventListener('scroll', handleScroll);\n }\n return () => el?.removeEventListener('scroll', handleScroll);\n }, [updateNavStatus]);\n\n // get width for first grid item\n useLayoutEffect(() => {\n const el = ref.current;\n if (el) {\n const firstGridItem = el.children.item(0);\n const observer = new ResizeObserver(entries => {\n itemWidth.current = entries[0].contentRect.width;\n updateNavStatus();\n });\n if (firstGridItem) {\n observer.observe(firstGridItem);\n }\n return () => observer.unobserve(el);\n }\n }, [updateNavStatus]);\n\n const scrollAmount = () => {\n return itemWidth.current * (3 - 1);\n };\n\n return (\n <div>\n <div className=\"flex items-center justify-between gap-24 mb-14\">\n <ChannelHeading {...props} margin=\"mb-4\" />\n <div>\n <IconButton\n disabled={!enablePrev}\n onClick={() => {\n if (ref.current) {\n ref.current.scrollBy({left: -scrollAmount()});\n }\n }}\n >\n <KeyboardArrowLeftIcon />\n </IconButton>\n <IconButton\n disabled={!enableNext}\n onClick={() => {\n if (ref.current) {\n ref.current.scrollBy({left: scrollAmount()});\n }\n }}\n >\n <KeyboardArrowRightIcon />\n </IconButton>\n </div>\n </div>\n <div\n ref={ref}\n className=\"content-carousel content-grid relative w-full grid grid-flow-col grid-rows-[auto] overflow-x-auto overflow-y-hidden gap-24 snap-always snap-x snap-mandatory hidden-scrollbar scroll-smooth\"\n >\n {channel.content?.data.map(item => (\n <ChannelContentGridItem\n key={`${item.id}-${item.model_type}`}\n item={item}\n items={channel.content?.data}\n />\n ))}\n </div>\n </div>\n );\n}\n","import {\n Channel,\n CHANNEL_MODEL,\n ChannelContentItem,\n} from '@app/web-player/channels/channel';\nimport {Track, TRACK_MODEL} from '@app/web-player/tracks/track';\nimport React, {Fragment} from 'react';\nimport {ChannelContentGrid} from '@app/web-player/channels/channel-content-grid';\nimport {ChannelTrackTable} from '@app/web-player/channels/channel-track-table';\nimport {ChannelTrackList} from '@app/web-player/channels/channel-track-list';\nimport {ChannelContentCarousel} from '@app/web-player/channels/channel-content-carousel';\nimport {ChannelHeading} from '@app/web-player/channels/channel-heading';\n\nexport interface ChannelContentProps<\n T extends ChannelContentItem = ChannelContentItem\n> {\n channel: Channel<T>;\n isNested?: boolean;\n}\nexport function ChannelContent(props: ChannelContentProps) {\n const {channel, isNested} = props;\n const contentModel = channel.config.contentModel;\n const layout = channel.config.layout;\n if (!channel.content) {\n return null;\n }\n\n if (contentModel === TRACK_MODEL && layout === 'trackList') {\n return <ChannelTrackList {...(props as ChannelContentProps<Track>)} />;\n } else if (contentModel === TRACK_MODEL && layout === 'trackTable') {\n return <ChannelTrackTable {...(props as ChannelContentProps<Track>)} />;\n }\n\n if (contentModel === CHANNEL_MODEL) {\n return <NestedChannels {...(props as ChannelContentProps<Channel>)} />;\n } else {\n return channel.config.carouselWhenNested && isNested ? (\n <ChannelContentCarousel {...props} />\n ) : (\n <ChannelContentGrid {...props} />\n );\n }\n}\n\nfunction NestedChannels({channel}: ChannelContentProps<Channel>) {\n return (\n <Fragment>\n <ChannelHeading channel={channel} />\n {channel.content?.data.map(nestedChannel => (\n <div key={nestedChannel.id} className=\"mb-50\">\n <ChannelContent channel={nestedChannel} isNested />\n </div>\n ))}\n </Fragment>\n );\n}\n","import {useAuth} from '../../auth/use-auth';\nimport {memo, useEffect, useId, useMemo, useRef} from 'react';\nimport lazyLoader from '../../utils/http/lazy-loader';\nimport clsx from 'clsx';\nimport {useSettings} from '../../core/settings/use-settings';\nimport dot from 'dot-object';\nimport {Settings} from '@common/core/settings/settings';\n\ninterface AdHostProps {\n slot: keyof Omit<NonNullable<Settings['ads']>, 'disable'>;\n className?: string;\n}\nexport function AdHost({slot, className}: AdHostProps) {\n const settings = useSettings();\n const {isSubscribed} = useAuth();\n const adCode = useMemo(() => {\n return dot.pick(`ads.${slot}`, settings);\n }, [slot, settings]);\n\n if (settings.ads?.disable || isSubscribed || !adCode) return null;\n\n return <InvariantAd className={className} slot={slot} adCode={adCode} />;\n}\n\ninterface InvariantAdProps {\n slot: string;\n adCode: string;\n className?: string;\n}\nconst InvariantAd = memo(\n ({slot, adCode, className}: InvariantAdProps) => {\n const ref = useRef<HTMLDivElement>(null);\n\n const id = useId();\n\n useEffect(() => {\n if (ref.current) {\n loadAdScripts(adCode, ref.current).then(() => {\n executeAdJavascript(adCode, id);\n });\n }\n return () => {\n // @ts-ignore\n delete window['google_ad_modifications'];\n };\n }, [adCode, id]);\n\n return (\n <div\n ref={ref}\n id={id}\n className={clsx(\n 'ad-host flex items-center justify-center w-full max-w-full overflow-hidden min-h-90 max-h-[600px]',\n `${slot.replace(/\\./g, '-')}-host`,\n className\n )}\n dangerouslySetInnerHTML={{__html: getAdHtml(adCode)}}\n ></div>\n );\n },\n () => {\n // never re-render\n return false;\n }\n);\n\nfunction getAdHtml(adCode: string) {\n // strip out all script tags from ad code and leave only html\n return adCode\n ?.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '')\n .trim();\n}\n\n// Load any external scripts needed by ad.\nfunction loadAdScripts(adCode: string, parentEl: HTMLDivElement): Promise<any> {\n const promises = [];\n\n // load ad code script\n const pattern = /<script.*?src=['\"](.*?)['\"]/g;\n let match;\n\n while ((match = pattern.exec(adCode))) {\n if (match[1]) {\n promises.push(lazyLoader.loadAsset(match[1], {type: 'js', parentEl}));\n }\n }\n\n return Promise.all(promises);\n}\n\n// Execute ad code javascript and replace document.write if needed.\nfunction executeAdJavascript(adCode: string, id: string) {\n // find any ad code javascript that needs to be executed\n const pattern = /<script\\b[^>]*>([\\s\\S]*?)<\\/script>/g;\n let content;\n\n while ((content = pattern.exec(adCode))) {\n if (content[1]) {\n const r = `var d = document.createElement('div'); d.innerHTML = $1; document.getElementById('${id}').appendChild(d.firstChild);`;\n const toEval = content[1].replace(/document.write\\((.+?)\\);/, r);\n eval(toEval);\n }\n }\n}\n","import {useChannel} from '@app/web-player/channels/requests/use-channel';\nimport React from 'react';\nimport {Helmet} from '@common/seo/helmet';\nimport {ChannelContent} from '@app/web-player/channels/channel-content';\nimport {PageStatus} from '@common/http/page-status';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\ninterface ChannelPageProps {\n slugOrId?: string | number;\n}\nexport function ChannelPage({slugOrId}: ChannelPageProps) {\n const query = useChannel(slugOrId);\n\n if (query.data) {\n return (\n <div>\n <Helmet tags={query.data.seo} />\n <div className=\"pb-24\">\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <ChannelContent\n channel={query.data.channel}\n // set key to force re-render when channel changes\n key={query.data.channel.id}\n />\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n </div>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n","import {apiClient, queryClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Track} from '@app/web-player/tracks/track';\nimport {CancelTokenSource} from 'axios';\n\ninterface Response extends BackendResponse {\n results: {title: string; id: string}[];\n}\n\nconst endpoint = (track: Track) => {\n const artistName =\n track.artists?.[0]?.name || track.album?.artists?.[0]?.name;\n return `search/audio/${track.id}/${doubleEncode(artistName!)}/${doubleEncode(\n track.name\n )}`;\n};\n\nexport let isSearchingForYoutubeVideo = false;\n\nexport async function findYoutubeVideosForTrack(\n track: Track,\n cancelToken?: CancelTokenSource\n): Promise<Response['results']> {\n const query = {\n queryKey: [endpoint(track)],\n queryFn: async () => findMatch(track, cancelToken),\n staleTime: Infinity,\n };\n\n const response =\n queryClient.getQueryData<Response>(query.queryKey) ??\n (await queryClient.fetchQuery(query));\n\n isSearchingForYoutubeVideo = false;\n\n return response?.results || [];\n}\n\nfunction findMatch(\n track: Track,\n cancelToken?: CancelTokenSource\n): Promise<Response> {\n isSearchingForYoutubeVideo = true;\n return apiClient\n .get(endpoint(track), {cancelToken: cancelToken?.token})\n .then(response => response.data);\n}\n\nfunction doubleEncode(value: string) {\n return encodeURIComponent(encodeURIComponent(value));\n}\n","import {create} from 'zustand';\nimport {immer} from 'zustand/middleware/immer';\n\ninterface OverlayState {\n isMaximized: boolean;\n isQueueOpen: boolean;\n open: () => void;\n toggle: () => void;\n toggleQueue: () => void;\n}\n\nexport const usePlayerOverlayStore = create<OverlayState>()(\n immer((set, get) => ({\n isMaximized: false,\n isQueueOpen: false,\n open: () => {\n set(state => {\n state.isMaximized = true;\n state.isQueueOpen = false;\n });\n },\n toggle: () => {\n set(state => {\n state.isMaximized = !state.isMaximized;\n state.isQueueOpen = false;\n });\n },\n toggleQueue: () => {\n set(state => {\n state.isQueueOpen = !state.isQueueOpen;\n });\n },\n }))\n);\n\nexport const playerOverlayState = usePlayerOverlayStore.getState();\n","/**\n * @see https://developers.google.com/youtube/iframe_api_reference#Playback_controls\n */\nexport const enum YoutubeCommand {\n Play = 'playVideo',\n Pause = 'pauseVideo',\n Stop = 'stopVideo',\n Seek = 'seekTo',\n // this will cue video without playing it, \"loadVideoById\" will cue it and start playback\n Load = 'cueVideoById',\n Mute = 'mute',\n Unmute = 'unMute',\n SetVolume = 'setVolume',\n SetPlaybackRate = 'setPlaybackRate',\n SetPlaybackQuality = 'setPlaybackQuality',\n}\n\nexport interface YouTubeCommandArg {\n [YoutubeCommand.Play]: void;\n [YoutubeCommand.Pause]: void;\n [YoutubeCommand.Stop]: void;\n [YoutubeCommand.Seek]: number;\n [YoutubeCommand.Load]: string;\n [YoutubeCommand.Mute]: void;\n [YoutubeCommand.Unmute]: void;\n [YoutubeCommand.SetVolume]: number;\n [YoutubeCommand.SetPlaybackRate]: number;\n [YoutubeCommand.SetPlaybackQuality]: string;\n}\n\n/**\n * @see https://developers.google.com/youtube/iframe_api_reference#onStateChange\n */\nexport const enum YouTubePlayerState {\n Unstarted = -1,\n Ended = 0,\n Playing = 1,\n Paused = 2,\n Buffering = 3,\n Cued = 5,\n}\n\nexport interface YoutubeInternalState {\n duration: number;\n currentTime: number;\n videoId?: string;\n lastTimeUpdate: number;\n playbackRate: number;\n playbackReady: boolean;\n buffered: number;\n state: YouTubePlayerState;\n firedPlaybackEnd: boolean;\n}\n\nexport const enum YouTubePlaybackQuality {\n Unknown = 'unknown',\n Tiny = 'tiny',\n Small = 'small',\n Medium = 'medium',\n Large = 'large',\n Hd720 = 'hd720',\n Hd1080 = 'hd1080',\n Highres = 'highres',\n Max = 'max',\n}\n\nexport interface YouTubeMessage {\n channel: string;\n event: 'initialDelivery' | 'onReady' | 'infoDelivery' | 'apiInfoDelivery';\n info?: YoutubeMessageInfo;\n}\n\nexport interface YoutubeMessageInfo {\n availablePlaybackRates?: number[];\n availableQualityLevels?: YouTubePlaybackQuality[];\n currentTime?: number;\n currentTimeLastUpdated?: number;\n videoLoadedFraction?: number;\n volume?: number;\n videoUrl?: string;\n videoData?: {\n author: string;\n title: string;\n video_id: string;\n errorCode?: string;\n };\n duration?: number;\n muted?: boolean;\n playbackQuality?: YouTubePlaybackQuality;\n playbackRate?: number;\n playerState?: YouTubePlayerState;\n}\n\nexport interface YoutubeProviderError {\n code?: string;\n videoId?: string;\n}\n\nexport interface YoutubeProviderInternalApi {\n loadVideoById: (videoId: string) => void;\n}\n","import {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {findYoutubeVideosForTrack} from '@app/web-player/tracks/requests/find-youtube-videos-for-track';\nimport {MediaItem, YoutubeMediaItem} from '@common/player/media-item';\nimport {apiClient} from '@common/http/query-client';\nimport {Track} from '@app/web-player/tracks/track';\nimport {playerOverlayState} from '@app/web-player/state/player-overlay-store';\nimport {loadMediaItemTracks} from '@app/web-player/requests/load-media-item-tracks';\nimport {tracksToMediaItems} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport {\n YouTubePlayerState,\n YoutubeProviderError,\n YoutubeProviderInternalApi,\n} from '@common/player/providers/youtube/youtube-types';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\n\n// used to track play history for logging plays on backend (prevents logging play twice, unless track is fully played)\nconst trackPlays = new Set<number>();\n\n// this is needed in order to stop YouTube embed from trying to\n// cue a video that will error out while valid video is already playing\nconst failedVideoId = ' ';\n\n// list of video Ids for which YouTube embed errored out\nconst failedVideoIds = new Set<string>();\nlet tracksSkippedDueToError = 0;\n\nasync function resolveSrc(\n media: YoutubeMediaItem<Track>\n): Promise<YoutubeMediaItem> {\n const results = await findYoutubeVideosForTrack(media.meta!);\n // Find first video ID that did not error out yet\n const match = results?.find(r => !failedVideoIds.has(`${r.id}`))?.id;\n return {\n ...media,\n src: match || failedVideoId,\n };\n}\n\nfunction setMediaSessionMetadata(media: MediaItem<Track>) {\n if ('mediaSession' in navigator) {\n const track = media.meta;\n if (!track) return;\n const image = track.image || track.album?.image;\n navigator.mediaSession.metadata = new MediaMetadata({\n title: track.name,\n artist: track.artists?.[0]?.name,\n album: track.album?.name,\n artwork: image\n ? [\n {\n src: image,\n sizes: '300x300',\n type: 'image/jpg',\n },\n ]\n : undefined,\n });\n }\n}\n\nexport const playerStoreOptions: Partial<PlayerStoreOptions> = {\n persistQueueInLocalStorage: true,\n defaultVolume: getBootstrapData().settings.player?.default_volume,\n setMediaSessionMetadata,\n youtube: {\n srcResolver: resolveSrc,\n onStateChange: state => {\n if (state === YouTubePlayerState.Playing) {\n tracksSkippedDueToError = 0;\n }\n },\n },\n onBeforePlay: () => {\n const player = getBootstrapData().settings.player;\n // on mobile, YouTube embed playback needs to be started via user gesture\n // on YouTube embed itself, starting it with custom play button will not work\n if (\n player?.mobile?.auto_open_overlay &&\n // check if mobile\n window.matchMedia('(max-width: 768px)').matches\n ) {\n playerOverlayState.open();\n // wait for overlay animation to complete\n return new Promise<void>(resolve => setTimeout(() => resolve(), 151));\n }\n },\n loadMoreMediaItems: async media => {\n if (media?.groupId) {\n const tracks = await loadMediaItemTracks(\n media.groupId as string,\n media.meta\n );\n return tracksToMediaItems(tracks);\n }\n },\n listeners: {\n // change document title to currently cued track name\n cued: ({state: {cuedMedia}}) => {\n if (!cuedMedia) return;\n const site_name = getBootstrapData().settings.branding.site_name;\n let title = `${cuedMedia.meta.name}`;\n const artistName = cuedMedia.meta.artists?.[0].name;\n\n if (artistName) {\n title = `${title} - ${artistName} - ${site_name}`;\n } else {\n title = `${title} - ${site_name}`;\n }\n\n document.title = title;\n },\n play: ({state: {cuedMedia, pause}}) => {\n // prevent playback if user does not have permission to play music\n const hasPermission = userHasPlayPermission();\n if (!hasPermission) {\n toast.danger(\n message('Your current plan does not allow music playback.')\n );\n pause();\n return;\n }\n // log track play\n if (cuedMedia && !trackPlays.has(cuedMedia.meta.id)) {\n trackPlays.add(cuedMedia.meta.id);\n apiClient.post(`tracks/plays/${cuedMedia.meta.id}/log`, {\n queueId: cuedMedia.groupId,\n });\n }\n },\n playbackEnd: ({state: {cuedMedia}}) => {\n // clear track play\n if (cuedMedia) {\n trackPlays.delete(cuedMedia.meta.id);\n }\n },\n error: async ({\n sourceEvent,\n state: {cuedMedia, providerApi, providerName, emit},\n }) => {\n const e = sourceEvent as YoutubeProviderError;\n if (providerName === 'youtube' && providerApi) {\n //const provider = state.provider as YoutubeProvider;\n logYoutubeError(e);\n\n if (e.videoId) {\n failedVideoIds.add(`${e.videoId}`);\n }\n\n const media = cuedMedia\n ? await resolveSrc(cuedMedia as YoutubeMediaItem)\n : null;\n\n // try to play alternative videos we fetched\n if (media?.src && media?.src !== failedVideoId) {\n await (\n providerApi.internalProviderApi as YoutubeProviderInternalApi\n ).loadVideoById(media.src);\n providerApi.play();\n\n // there are no more alternative videos to try, we can error out\n } else {\n tracksSkippedDueToError++;\n\n // try to play up to two next queued tracks if we can't play\n // a video for this one. If we can't play 3 tracks in a row\n // we can assume there's an issue with YouTube API and bail\n if (tracksSkippedDueToError <= 2) {\n emit('playbackEnd');\n }\n }\n } else {\n tracksSkippedDueToError = 0;\n }\n },\n },\n onDestroy: () => {\n tracksSkippedDueToError = 0;\n },\n};\n\nfunction logYoutubeError(e: YoutubeProviderError) {\n const code = e?.code;\n if (!e || !e.videoId) return;\n apiClient.post('youtube/log-client-error', {\n code,\n videoUrl: e.videoId,\n });\n}\n\nfunction userHasPlayPermission(): boolean {\n const user = getBootstrapData().user;\n const guest_role = getBootstrapData().guest_role;\n const permissions = user?.permissions || guest_role?.permissions;\n return permissions?.find(p => p.name === 'music.play') != null;\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {Link, NavLink} from 'react-router-dom';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {useIsDarkMode} from '@common/ui/themes/use-is-dark-mode';\nimport {CustomMenu} from '@common/menus/custom-menu';\nimport {Trans} from '@common/i18n/trans';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {PlaylistAddIcon} from '@common/icons/material/PlaylistAdd';\nimport {ReactNode} from 'react';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {CreatePlaylistDialog} from '@app/web-player/playlists/crupdate-dialog/create-playlist-dialog';\nimport {useAuthUserPlaylists} from '@app/web-player/playlists/requests/use-auth-user-playlists';\nimport {getPlaylistLink} from '@app/web-player/playlists/playlist-link';\nimport clsx from 'clsx';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\n\nconst menuItemClassName = (isActive: boolean): string => {\n return clsx(\n 'h-44 px-12 mx-12 hover:bg-hover rounded-lg',\n isActive && 'text-primary'\n );\n};\n\ninterface Props {\n className?: string;\n}\nexport function Sidenav({className}: Props) {\n return (\n <div className={clsx('border-r py-12 bg-alt overflow-y-auto', className)}>\n <Logo />\n <CustomMenu\n className=\"mt-24 items-stretch\"\n menu=\"sidebar-primary\"\n orientation=\"vertical\"\n gap=\"gap-none\"\n iconClassName=\"text-muted\"\n itemClassName={({isActive}) => menuItemClassName(isActive)}\n />\n <div className=\"mt-48\">\n <SectionTitle>\n <Trans message=\"Your Music\" />\n </SectionTitle>\n <CustomMenu\n className=\"mt-12 text-sm items-stretch\"\n menu=\"sidebar-secondary\"\n orientation=\"vertical\"\n gap=\"gap-none\"\n iconClassName=\"text-muted\"\n itemClassName={({isActive}) => menuItemClassName(isActive)}\n />\n <PlaylistSection />\n </div>\n </div>\n );\n}\n\ninterface SectionTitleProps {\n children?: ReactNode;\n}\nfunction SectionTitle({children}: SectionTitleProps) {\n return (\n <div className=\"uppercase text-xs font-semibold text-muted mb-8 mx-24\">\n {children}\n </div>\n );\n}\n\nfunction Logo() {\n const {branding} = useSettings();\n const {trans} = useTrans();\n const isDarkMode = useIsDarkMode();\n const logoUrl = isDarkMode ? branding.logo_light : branding.logo_dark;\n\n return (\n <Link\n to=\"/\"\n className=\"block flex-shrink-0 mx-18\"\n aria-label={trans({message: 'Go to homepage'})}\n >\n <img\n className=\"block w-auto h-56 max-w-[188px] object-contain\"\n src={logoUrl}\n alt={trans({message: 'Site logo'})}\n />\n </Link>\n );\n}\n\nfunction PlaylistSection() {\n const {data} = useAuthUserPlaylists();\n const navigate = useNavigate();\n const authHandler = useAuthClickCapture();\n\n return (\n <div className=\"mt-40\">\n <div className=\"flex items-center justify-between mr-24\">\n <SectionTitle>\n <Trans message=\"Playlists\" />\n </SectionTitle>\n <DialogTrigger\n type=\"modal\"\n onClose={newPlaylist => {\n if (newPlaylist) {\n navigate(getPlaylistLink(newPlaylist));\n }\n }}\n >\n <IconButton\n className=\"flex-shrink-0 text-muted\"\n onClickCapture={authHandler}\n >\n <PlaylistAddIcon />\n </IconButton>\n <CreatePlaylistDialog />\n </DialogTrigger>\n </div>\n {data?.playlists?.map(playlist => (\n <NavLink\n to={getPlaylistLink(playlist)}\n key={playlist.id}\n className={({isActive}) =>\n clsx(menuItemClassName(isActive), 'flex items-center text-sm')\n }\n >\n <div className=\"overflow-hidden overflow-ellipsis\">\n {playlist.name}\n </div>\n </NavLink>\n ))}\n </div>\n );\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\n\nexport function useIsMediaPlaying(\n mediaId: string | number,\n groupId?: string | number\n): boolean {\n return usePlayerStore(s => {\n return (\n s.isPlaying &&\n s.cuedMedia?.id === mediaId &&\n (!groupId || groupId === s.cuedMedia.groupId)\n );\n });\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\n\nexport function useMiniPlayerIsHidden() {\n const {player} = useSettings();\n const mediaIsCued = usePlayerStore(s => s.cuedMedia != null);\n const isAudioProvider = usePlayerStore(s => s.providerName === 'htmlAudio');\n const isMobile = useIsMobileMediaQuery();\n return player?.hide_video || !mediaIsCued || isMobile || isAudioProvider;\n}\n","import {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport React from 'react';\nimport {MediaItem} from '@common/player/media-item';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {Trans} from '@common/i18n/trans';\n\ninterface Props {\n queueItems: MediaItem[];\n}\nexport function QueueTrackContextDialog({queueItems}: Props) {\n return (\n <TrackContextDialog\n tracks={queueItems.map(item => item.meta)}\n showAddToQueueButton={false}\n >\n {() => <RemoveFromQueueContextButton queueItems={queueItems} />}\n </TrackContextDialog>\n );\n}\n\ninterface RemoveFromQueueContextButton {\n queueItems: MediaItem[];\n}\nfunction RemoveFromQueueContextButton({\n queueItems,\n}: RemoveFromQueueContextButton) {\n const {close: closeMenu} = useDialogContext();\n const player = usePlayerActions();\n\n return (\n <ContextMenuButton\n onClick={async () => {\n closeMenu();\n player.removeFromQueue(queueItems);\n }}\n >\n <Trans message=\"Remove from queue\" />\n </ContextMenuButton>\n );\n}\n","import {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {MediaItem} from '@common/player/media-item';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport clsx from 'clsx';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport React, {ReactElement, useState} from 'react';\nimport {message} from '@common/i18n/message';\nimport {PauseIcon} from '@common/icons/material/Pause';\nimport {EqualizerImage} from '@app/web-player/tracks/equalizer-image/equalizer-image';\nimport {PlayArrowFilledIcon} from '@app/web-player/tracks/play-arrow-filled';\nimport {useIsMediaPlaying} from '@common/player/hooks/use-is-media-playing';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {useMiniPlayerIsHidden} from '@app/web-player/overlay/use-mini-player-is-hidden';\nimport {QueueTrackContextDialog} from '@app/web-player/layout/queue/queue-track-context-dialog';\n\nexport function QueueSidenav() {\n const queue = usePlayerStore(s => s.shuffledQueue);\n const miniPlayerIsHidden = useMiniPlayerIsHidden();\n return (\n <div className=\"border-l bg h-full\">\n <div\n className={clsx(\n 'overflow-y-auto overflow-x-hidden',\n miniPlayerIsHidden ? 'h-full' : 'h-[calc(100%-213px)]'\n )}\n >\n {queue.map((media: MediaItem<Track>, index) => (\n // same media.id might be multiple times in the queue, use index as well to avoid errors\n <QueueItem key={`${media.id}-${index}`} media={media} />\n ))}\n </div>\n </div>\n );\n}\n\ninterface QueueItemProps {\n media: MediaItem<Track>;\n}\nfunction QueueItem({media}: QueueItemProps) {\n const isCued = usePlayerStore(s => s.cuedMedia?.id === media.id);\n const isPlaying = useIsMediaPlaying(media.id);\n const [isHover, setHover] = useState(false);\n\n if (!media.meta) {\n return null;\n }\n\n return (\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"bottom-start\">\n <div\n onPointerEnter={() => setHover(true)}\n onPointerLeave={() => setHover(false)}\n className={clsx(\n 'flex items-center gap-10 p-8 border-b',\n isCued && 'bg-primary/80 text-white'\n )}\n >\n <div className=\"relative overflow-hidden\">\n <TrackImage\n className=\"w-34 h-34 flex-shrink-0 rounded object-cover\"\n track={media.meta}\n />\n {(isHover || isPlaying) && (\n <TogglePlaybackOverlay media={media} isHover={isHover} />\n )}\n </div>\n <div className=\"flex-auto max-w-180 whitespace-nowrap\">\n <div className=\"text-sm overflow-hidden overflow-ellipsis\">\n {media.meta.name}\n </div>\n <ArtistLinks\n className=\"text-xs overflow-hidden overflow-ellipsis\"\n linkClassName={isCued ? 'text-inherit' : 'text-muted'}\n artists={media.meta.artists}\n />\n </div>\n </div>\n <QueueTrackContextDialog queueItems={[media]} />\n </DialogTrigger>\n );\n}\n\ninterface TogglePlaybackOverlayProps {\n media: MediaItem<Track>;\n isHover: boolean;\n}\nfunction TogglePlaybackOverlay({media, isHover}: TogglePlaybackOverlayProps) {\n const isPlaying = useIsMediaPlaying(media.id);\n const {trans} = useTrans();\n const player = usePlayerActions();\n\n if (!media.meta) {\n return null;\n }\n\n let button: ReactElement;\n\n if (isPlaying) {\n button = (\n <button\n aria-label={trans(\n message('Pause :name', {values: {name: media.meta.name}})\n )}\n tabIndex={0}\n onClick={() => player.pause()}\n >\n {isHover ? <PauseIcon /> : <EqualizerImage color=\"white\" />}\n </button>\n );\n } else {\n button = (\n <button\n aria-label={trans(\n message('Play :name', {values: {name: media.meta.name}})\n )}\n tabIndex={0}\n onClick={() => player.play(media)}\n >\n <PlayArrowFilledIcon />\n </button>\n );\n }\n\n return (\n <div className=\"absolute top-0 left-0 w-full h-full bg-black/50 rounded flex items-center justify-center text-white\">\n {button}\n </div>\n );\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {Track} from '@app/web-player/tracks/track';\n\nexport function useCuedTrack(): Track | undefined {\n const media = usePlayerStore(s => s.cuedMedia);\n if (!media) return;\n return media.meta as Track;\n}\n","import {useEffect, useState} from 'react';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\n\nexport function useCurrentTime() {\n const {subscribe, getCurrentTime} = usePlayerActions();\n const providerKey = usePlayerStore(s =>\n s.providerName && s.cuedMedia?.id\n ? `${s.providerName}+${s.cuedMedia.id}`\n : null\n );\n\n const [currentTime, setCurrentTime] = useState(() => getCurrentTime());\n\n useEffect(() => {\n return subscribe({\n progress: ({currentTime}) => setCurrentTime(currentTime),\n });\n }, [subscribe]);\n\n // update current time when media or provider changes\n useEffect(() => {\n if (providerKey) {\n setCurrentTime(getCurrentTime());\n }\n }, [providerKey, getCurrentTime]);\n\n return currentTime;\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaPlayIcon = createSvgIcon(\n <path d=\"M10.6667 6.6548C10.6667 6.10764 11.2894 5.79346 11.7295 6.11862L24.377 15.4634C24.7377 15.7298 24.7377 16.2692 24.3771 16.5357L11.7295 25.8813C11.2895 26.2065 10.6667 25.8923 10.6667 25.3451L10.6667 6.6548Z\"/>,\n 'MediaPlay',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaPauseIcon = createSvgIcon(\n [<path d=\"M8.66667 6.66667C8.29848 6.66667 8 6.96514 8 7.33333V24.6667C8 25.0349 8.29848 25.3333 8.66667 25.3333H12.6667C13.0349 25.3333 13.3333 25.0349 13.3333 24.6667V7.33333C13.3333 6.96514 13.0349 6.66667 12.6667 6.66667H8.66667Z\" key=\"0\"/>,<path d=\"M19.3333 6.66667C18.9651 6.66667 18.6667 6.96514 18.6667 7.33333V24.6667C18.6667 25.0349 18.9651 25.3333 19.3333 25.3333H23.3333C23.7015 25.3333 24 25.0349 24 24.6667V7.33333C24 6.96514 23.7015 6.66667 23.3333 6.66667H19.3333Z\" key=\"1\"/>,],\n 'MediaPause',\n '0 0 32 32'\n);\n","import {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {MediaPlayIcon} from '@common/icons/media/media-play';\nimport {MediaPauseIcon} from '@common/icons/media/media-pause';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\n\ninterface Props {\n color?: ButtonProps['color'];\n size?: ButtonProps['size'];\n iconSize?: ButtonProps['size'];\n className?: string;\n stopPropagation?: boolean;\n}\nexport function PlayButton({\n size = 'md',\n iconSize = 'xl',\n color,\n stopPropagation,\n}: Props) {\n const isPlaying = usePlayerStore(s => s.isPlaying);\n const playerReady = usePlayerStore(s => s.providerReady);\n const player = usePlayerActions();\n\n const label = isPlaying ? (\n <Trans message=\"Pause (k)\" />\n ) : (\n <Trans message=\"Play (k)\" />\n );\n\n return (\n <Tooltip label={label}>\n <IconButton\n color={color}\n size={size}\n iconSize={iconSize}\n disabled={!playerReady}\n onClick={e => {\n if (stopPropagation) {\n e.stopPropagation();\n }\n if (isPlaying) {\n player.pause();\n } else {\n player.play();\n }\n }}\n >\n {isPlaying ? <MediaPauseIcon /> : <MediaPlayIcon />}\n </IconButton>\n </Tooltip>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaPreviousIcon = createSvgIcon(\n [<path d=\"M25.1377 6.78532C25.5778 6.46017 26.2005 6.77434 26.2005 7.32151V24.6785C26.2005 25.2257 25.5777 25.5398 25.1377 25.2147L13.3924 16.5358C13.0317 16.2693 13.0317 15.7299 13.3924 15.4634L25.1377 6.78532Z\" key=\"0\"/>,<path d=\"M8 6.6667C8.36819 6.6667 8.66667 6.96518 8.66667 7.33337V24.6667C8.66667 25.0349 8.36819 25.3334 8 25.3334H6C5.63181 25.3334 5.33333 25.0349 5.33333 24.6667V7.33337C5.33333 6.96518 5.63181 6.6667 6 6.6667H8Z\" key=\"1\"/>,],\n 'MediaPrevious',\n '0 0 32 32'\n);\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {MediaPreviousIcon} from '@common/icons/media/media-previous';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\n\ninterface Props {\n color?: ButtonProps['color'];\n size?: ButtonProps['size'];\n iconSize?: ButtonProps['size'];\n className?: string;\n stopPropagation?: boolean;\n}\nexport function PreviousButton({\n size = 'md',\n iconSize,\n color,\n className,\n stopPropagation,\n}: Props) {\n const player = usePlayerActions();\n const playerReady = usePlayerStore(s => s.providerReady);\n\n return (\n <Tooltip label={<Trans message=\"Previous\" />}>\n <IconButton\n disabled={!playerReady}\n size={size}\n color={color}\n iconSize={iconSize}\n className={className}\n onClick={e => {\n if (stopPropagation) {\n e.stopPropagation();\n }\n player.playPrevious();\n }}\n >\n <MediaPreviousIcon />\n </IconButton>\n </Tooltip>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaNextIcon = createSvgIcon(\n [<path d=\"M6.39617 6.78532C5.9561 6.46017 5.33334 6.77434 5.33334 7.32151V24.6785C5.33334 25.2257 5.95612 25.5398 6.39619 25.2147L18.1415 16.5358C18.5021 16.2693 18.5021 15.7299 18.1415 15.4634L6.39617 6.78532Z\" key=\"0\"/>,<path d=\"M23.5339 6.6667C23.1657 6.6667 22.8672 6.96518 22.8672 7.33337V24.6667C22.8672 25.0349 23.1657 25.3334 23.5339 25.3334H25.5339C25.902 25.3334 26.2005 25.0349 26.2005 24.6667V7.33337C26.2005 6.96518 25.902 6.6667 25.5339 6.6667H23.5339Z\" key=\"1\"/>,],\n 'MediaNext',\n '0 0 32 32'\n);\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {MediaNextIcon} from '@common/icons/media/media-next';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\n\ninterface Props {\n color?: ButtonProps['color'];\n size?: ButtonProps['size'];\n iconSize?: ButtonProps['size'];\n className?: string;\n stopPropagation?: boolean;\n}\nexport function NextButton({\n size = 'md',\n iconSize,\n color,\n className,\n stopPropagation,\n}: Props) {\n const player = usePlayerActions();\n const playerReady = usePlayerStore(s => s.providerReady);\n\n return (\n <Tooltip label={<Trans message=\"Next\" />}>\n <IconButton\n disabled={!playerReady}\n size={size}\n color={color}\n iconSize={iconSize}\n className={className}\n onClick={e => {\n if (stopPropagation) {\n e.stopPropagation();\n }\n player.playNext();\n }}\n >\n <MediaNextIcon />\n </IconButton>\n </Tooltip>\n );\n}\n","import clsx from 'clsx';\nimport {useContext, useEffect, useState} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {isSearchingForYoutubeVideo} from '@app/web-player/tracks/requests/find-youtube-videos-for-track';\n\nexport function BufferingIndicator() {\n const store = useContext(PlayerStoreContext);\n\n const [isVisible, setIsVisible] = useState(false);\n const [animationActive, setAnimationActive] = useState(false);\n\n useEffect(() => {\n return store.subscribe(\n s => s.isBuffering,\n isBuffering => {\n const isLoading = isBuffering || isSearchingForYoutubeVideo;\n if (isLoading) {\n // make loader visible only after animation is running\n setAnimationActive(true);\n setTimeout(() => {\n setIsVisible(true);\n });\n } else {\n setIsVisible(false);\n }\n }\n );\n }, [store]);\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"48\"\n height=\"48\"\n fill=\"none\"\n className={clsx(\n 'absolute -top-3 -left-3 z-10 transition-opacity duration-300 pointer-events-none',\n isVisible ? 'opacity-100' : 'opacity-0',\n animationActive && 'animate-spin'\n )}\n onTransitionEnd={() => {\n // stop animation only after opacity transition is done to avoid flickering\n if (!isVisible) {\n setAnimationActive(false);\n }\n }}\n >\n <g clipPath=\"url(#a)\">\n <path\n stroke=\"url(#b)\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeMiterlimit=\"10\"\n d=\"M45.72 31.644c-1.016 3.036-2.777 5.84-5.116 8.301-8.846 9.161-23.386 9.5-32.547.654-9.16-8.845-9.416-23.44-.654-32.546\"\n />\n </g>\n <defs>\n <linearGradient\n id=\"b\"\n x1=\"7.863\"\n x2=\"45.527\"\n y1=\"7.178\"\n y2=\"31.53\"\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop stopColor=\"currentColor\" />\n <stop offset=\"1\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n <clipPath>\n <path fill=\"currentColor\" d=\"M0 0h48v48H0z\" />\n </clipPath>\n </defs>\n </svg>\n );\n}\n","import {useCuedTrack} from '@app/web-player/player-controls/use-cued-track';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport React, {useMemo} from 'react';\nimport {ProgressBar} from '@common/ui/progress/progress-bar';\nimport {CustomMenuItem} from '@common/menus/custom-menu';\nimport clsx from 'clsx';\nimport {useCustomMenu} from '@common/menus/use-custom-menu';\nimport {Trans} from '@common/i18n/trans';\nimport {NavbarAuthMenu} from '@common/ui/navigation/navbar/navbar-auth-menu';\nimport {PersonIcon} from '@common/icons/material/Person';\nimport {Badge} from '@common/ui/badge/badge';\nimport {useAuth} from '@common/auth/use-auth';\nimport {\n Menu,\n MenuItem,\n MenuTrigger,\n} from '@common/ui/navigation/menu/menu-trigger';\nimport {Item} from '@common/ui/forms/listbox/item';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {playerOverlayState} from '@app/web-player/state/player-overlay-store';\nimport {usePrimaryArtistForCurrentUser} from '@app/web-player/backstage/use-primary-artist-for-current-user';\nimport {MicIcon} from '@common/icons/material/Mic';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {useCurrentTime} from '@common/player/hooks/use-current-time';\nimport {PlayButton} from '@common/player/ui/controls/play-button';\nimport {PreviousButton} from '@common/player/ui/controls/previous-button';\nimport {NextButton} from '@common/player/ui/controls/next-button';\nimport {BufferingIndicator} from '@app/web-player/player-controls/buffering-indicator';\n\nexport function MobilePlayerControls() {\n return (\n <div className=\"fixed bottom-0 left-0 right-0 w-[calc(100%-20px)] mx-auto bg-background/95\">\n <PlayerControls />\n <MobileNavbar />\n </div>\n );\n}\n\nfunction PlayerControls() {\n const mediaIsCued = usePlayerStore(s => s.cuedMedia != null);\n if (!mediaIsCued) return null;\n\n return (\n <div\n className=\"bg-chip rounded p-6 flex items-center gap-24 justify-between shadow relative\"\n onClick={() => {\n playerOverlayState.toggle();\n }}\n >\n <QueuedTrack />\n <PlaybackButtons />\n <PlayerProgressBar />\n </div>\n );\n}\n\nfunction QueuedTrack() {\n const track = useCuedTrack();\n\n if (!track) {\n return null;\n }\n\n return (\n <div className=\"flex items-center gap-10 min-w-0 flex-auto\">\n <TrackImage className=\"rounded w-36 h-36 object-cover\" track={track} />\n <div className=\"flex-auto whitespace-nowrap overflow-hidden\">\n <div className=\"text-sm font-medium overflow-hidden overflow-ellipsis\">\n {track.name}\n </div>\n <div className=\"text-xs text-muted overflow-hidden overflow-ellipsis\">\n {track.artists?.map(a => a.name).join(', ')}\n </div>\n </div>\n </div>\n );\n}\n\nfunction PlaybackButtons() {\n return (\n <div className=\"flex items-center justify-center\">\n <PreviousButton stopPropagation />\n <div className=\"relative\">\n <BufferingIndicator />\n <PlayButton size=\"md\" iconSize=\"lg\" stopPropagation />\n </div>\n <NextButton stopPropagation />\n </div>\n );\n}\n\nfunction PlayerProgressBar() {\n const duration = usePlayerStore(s => s.mediaDuration);\n const currentTime = useCurrentTime();\n return (\n <ProgressBar\n size=\"xs\"\n className=\"absolute left-0 right-0 bottom-0\"\n progressColor=\"bg-white\"\n trackColor=\"bg-white/10\"\n trackHeight=\"h-2\"\n radius=\"rounded-none\"\n minValue={0}\n maxValue={duration}\n value={currentTime}\n />\n );\n}\n\nfunction MobileNavbar() {\n const menu = useCustomMenu('mobile-bottom');\n if (!menu) return null;\n\n return (\n <div className=\"flex items-center justify-center gap-30 my-12\">\n {menu.items.map(item => (\n <CustomMenuItem\n unstyled\n iconClassName=\"block mx-auto mb-6\"\n iconSize=\"md\"\n className={({isActive}) =>\n clsx(\n 'text-xs whitespace-nowrap overflow-hidden',\n isActive && 'font-bold'\n )\n }\n key={item.id}\n item={item}\n />\n ))}\n <AccountButton />\n </div>\n );\n}\n\nfunction AccountButton() {\n const {user} = useAuth();\n const hasUnreadNotif = !!user?.unread_notifications_count;\n const navigate = useNavigate();\n const {registration} = useSettings();\n\n const primaryArtist = usePrimaryArtistForCurrentUser();\n const {player} = useSettings();\n const menuItems = useMemo(() => {\n if (primaryArtist) {\n return [\n <MenuItem\n value=\"author\"\n key=\"author\"\n startIcon={<MicIcon />}\n onSelected={() => {\n navigate(getArtistLink(primaryArtist));\n }}\n >\n <Trans message=\"Artist profile\" />\n </MenuItem>,\n ];\n }\n if (player?.show_become_artist_btn) {\n return [\n <MenuItem\n value=\"author\"\n key=\"author\"\n startIcon={<MicIcon />}\n onSelected={() => {\n navigate('/backstage/requests');\n }}\n >\n <Trans message=\"Become an author\" />\n </MenuItem>,\n ];\n }\n\n return [];\n }, [primaryArtist, navigate, player?.show_become_artist_btn]);\n\n const button = (\n <button className=\"text-xs\">\n <Badge\n badgeClassName=\"mb-6\"\n badgeLabel={user?.unread_notifications_count}\n badgeIsVisible={hasUnreadNotif}\n >\n <PersonIcon size=\"md\" />\n </Badge>\n <div className=\"text-xs\">\n <Trans message=\"Account\" />\n </div>\n </button>\n );\n\n if (!user) {\n return (\n <MenuTrigger>\n {button}\n <Menu>\n <Item value=\"login\" onSelected={() => navigate('/login')}>\n <Trans message=\"Login\" />\n </Item>\n {!registration.disable && (\n <Item value=\"register\" onSelected={() => navigate('/register')}>\n <Trans message=\"Register\" />\n </Item>\n )}\n </Menu>\n </MenuTrigger>\n );\n }\n\n return <NavbarAuthMenu items={menuItems}>{button}</NavbarAuthMenu>;\n}\n","import {Slider} from '@common/ui/forms/slider/slider';\nimport {UseSliderProps} from '@common/ui/forms/slider/use-slider';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useCurrentTime} from '@common/player/hooks/use-current-time';\nimport {useRef} from 'react';\n\ninterface Props {\n trackColor?: UseSliderProps['trackColor'];\n fillColor?: UseSliderProps['fillColor'];\n className?: string;\n}\nexport function Seekbar({trackColor, fillColor, className}: Props) {\n const {pause, seek, setIsSeeking, play, getState} = usePlayerActions();\n const duration = usePlayerStore(s => s.mediaDuration);\n const playerReady = usePlayerStore(s => s.providerReady);\n const pauseWhileSeeking = usePlayerStore(s => s.pauseWhileSeeking);\n\n const currentTime = useCurrentTime();\n\n const wasPlayingBeforeDragging = useRef(false);\n\n return (\n <Slider\n fillColor={fillColor}\n trackColor={trackColor}\n thumbSize=\"w-14 h-14\"\n showThumbOnHoverOnly\n className={className}\n width=\"w-auto\"\n isDisabled={!playerReady}\n value={currentTime}\n minValue={0}\n maxValue={duration}\n onPointerDown={() => {\n setIsSeeking(true);\n if (pauseWhileSeeking) {\n wasPlayingBeforeDragging.current =\n getState().isPlaying || getState().isBuffering;\n pause();\n }\n }}\n onChange={value => {\n getState().emit('progress', {currentTime: value});\n seek(value);\n }}\n onChangeEnd={() => {\n setIsSeeking(false);\n if (pauseWhileSeeking && wasPlayingBeforeDragging.current) {\n play();\n wasPlayingBeforeDragging.current = false;\n }\n }}\n />\n );\n}\n","import {useCurrentTime} from '@common/player/hooks/use-current-time';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\n\ninterface Props {\n className?: string;\n}\nexport function FormattedCurrentTime({className}: Props) {\n const duration = usePlayerStore(s => s.mediaDuration);\n const currentTime = useCurrentTime();\n return (\n <span className={className}>\n <FormattedDuration\n seconds={currentTime}\n addZeroToFirstUnit={duration >= 600}\n />\n </span>\n );\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\n\ninterface Props {\n className?: string;\n}\nexport function FormattedPlayerDuration({className}: Props) {\n const duration = usePlayerStore(s => s.mediaDuration);\n return (\n <span className={className}>\n <FormattedDuration\n seconds={duration}\n addZeroToFirstUnit={duration >= 600}\n />\n </span>\n );\n}\n","import {Fragment} from 'react';\nimport {Seekbar} from '@common/player/ui/controls/seeking/seekbar';\nimport {FormattedCurrentTime} from '@common/player/ui/controls/formatted-current-time';\nimport {FormattedPlayerDuration} from '@common/player/ui/controls/formatted-player-duration';\n\nexport function MainSeekbar() {\n return (\n <Fragment>\n <div className=\"flex items-center gap-12\">\n <div className=\"text-xs text-muted flex-shrink-0 min-w-40 text-right\">\n <FormattedCurrentTime />\n </div>\n <Seekbar className=\"flex-auto\" trackColor=\"neutral\" />\n <div className=\"text-xs text-muted flex-shrink-0 min-w-40\">\n <FormattedPlayerDuration />\n </div>\n </div>\n </Fragment>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaShuffleIcon = createSvgIcon(\n <path d=\"M23.7295 5.65252C23.2894 5.32737 22.6667 5.64155 22.6667 6.18871V7.86672C22.6667 7.94036 22.607 8.00005 22.5333 8.00005H21.3333C18.6228 8.00005 16.2268 9.34843 14.7798 11.411C14.7251 11.489 14.6083 11.489 14.5536 11.411C13.1065 9.34843 10.7106 8.00005 8.00001 8.00005H6.00001C5.63182 8.00005 5.33334 8.29853 5.33334 8.66672V10.3998C5.33334 10.768 5.63182 11.0665 6.00001 11.0665H8.00001C10.724 11.0665 12.9336 13.2748 12.9336 16.0001C12.9336 18.7253 10.724 20.9336 8.00001 20.9336H6.00001C5.63182 20.9336 5.33334 21.2321 5.33334 21.6003V23.3334C5.33334 23.7016 5.63182 24.0001 6.00001 24.0001H8.00001C10.7106 24.0001 13.1065 22.6517 14.5536 20.5891C14.6083 20.5111 14.7251 20.5111 14.7798 20.5891C16.2268 22.6517 18.6228 24.0001 21.3333 24.0001H22.5333C22.607 24.0001 22.6667 24.0597 22.6667 24.1334V25.8113C22.6667 26.3585 23.2895 26.6727 23.7295 26.3475L28.2568 23.0022C28.6175 22.7357 28.6174 22.1963 28.2568 21.9298L23.7295 18.5848C23.2894 18.2597 22.6667 18.5738 22.6667 19.121V20.8003C22.6667 20.874 22.607 20.9336 22.5333 20.9336H21.3333C18.6094 20.9336 16.3997 18.7253 16.3997 16.0001C16.3997 13.2748 18.6094 11.0665 21.3333 11.0665H22.5333C22.607 11.0665 22.6667 11.1262 22.6667 11.1998V12.879C22.6667 13.4262 23.2895 13.7404 23.7295 13.4152L28.2568 10.0699C28.6175 9.8034 28.6174 9.26401 28.2568 8.99753L23.7295 5.65252Z\"/>,\n 'MediaShuffle',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaShuffleOnIcon = createSvgIcon(\n [<path d=\"M22.6666 6.18871C22.6666 5.64155 23.2894 5.32737 23.7295 5.65252L28.2567 8.99753C28.6174 9.26401 28.6174 9.8034 28.2568 10.0699L23.7295 13.4152C23.2894 13.7404 22.6666 13.4262 22.6666 12.879V11.1998C22.6666 11.1262 22.607 11.0665 22.5333 11.0665H21.3333C18.6094 11.0665 16.3997 13.2748 16.3997 16.0001C16.3997 18.7253 18.6094 20.9336 21.3333 20.9336H22.5333C22.607 20.9336 22.6666 20.874 22.6666 20.8003V19.121C22.6666 18.5738 23.2894 18.2597 23.7295 18.5848L28.2567 21.9298C28.6174 22.1963 28.6174 22.7357 28.2568 23.0022L23.7295 26.3475C23.2894 26.6727 22.6666 26.3585 22.6666 25.8113V24.1334C22.6666 24.0597 22.607 24.0001 22.5333 24.0001H21.3333C18.6227 24.0001 16.2268 22.6517 14.7798 20.5891C14.725 20.5111 14.6082 20.5111 14.5535 20.5891C13.1065 22.6517 10.7106 24.0001 7.99998 24.0001H5.99998C5.63179 24.0001 5.33331 23.7016 5.33331 23.3334V21.6003C5.33331 21.2321 5.63179 20.9336 5.99998 20.9336H7.99998C10.7239 20.9336 12.9336 18.7253 12.9336 16.0001C12.9336 13.2748 10.7239 11.0665 7.99998 11.0665H5.99998C5.63179 11.0665 5.33331 10.768 5.33331 10.3998V8.66672C5.33331 8.29853 5.63179 8.00005 5.99998 8.00005H7.99998C10.7106 8.00005 13.1065 9.34843 14.5535 11.411C14.6082 11.489 14.725 11.489 14.7798 11.411C16.2268 9.34843 18.6227 8.00005 21.3333 8.00005H22.5333C22.607 8.00005 22.6666 7.94036 22.6666 7.86672V6.18871Z\" key=\"0\"/>,<path d=\"M28.6666 18.0001C29.7712 18.0001 30.6666 17.1046 30.6666 16.0001C30.6666 14.8955 29.7712 14.0001 28.6666 14.0001C27.5621 14.0001 26.6666 14.8955 26.6666 16.0001C26.6666 17.1046 27.5621 18.0001 28.6666 18.0001Z\" key=\"1\"/>,],\n 'MediaShuffleOn',\n '0 0 32 32'\n);\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {MediaShuffleIcon} from '@common/icons/media/media-shuffle';\nimport {MediaShuffleOnIcon} from '@common/icons/media/media-shuffle-on';\nimport {Trans} from '@common/i18n/trans';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\n\ninterface Props {\n color?: ButtonProps['color'];\n activeColor?: ButtonProps['color'];\n size?: ButtonProps['size'];\n iconSize?: ButtonProps['size'];\n className?: string;\n}\nexport function ShuffleButton({\n size = 'md',\n iconSize,\n color,\n activeColor = 'primary',\n className,\n}: Props) {\n const playerReady = usePlayerStore(s => s.providerReady);\n const isShuffling = usePlayerStore(s => s.shuffling);\n const player = usePlayerActions();\n\n const label = isShuffling ? (\n <Trans message=\"Disable shuffle\" />\n ) : (\n <Trans message=\"Enable shuffle\" />\n );\n\n return (\n <Tooltip label={label}>\n <IconButton\n disabled={!playerReady}\n size={size}\n color={isShuffling ? activeColor : color}\n iconSize={iconSize}\n className={className}\n onClick={() => {\n player.toggleShuffling();\n }}\n >\n {isShuffling ? <MediaShuffleOnIcon /> : <MediaShuffleIcon />}\n </IconButton>\n </Tooltip>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaRepeatIcon = createSvgIcon(\n [<path d=\"M22.1969 4.98846C21.7569 4.66331 21.1341 4.97748 21.1341 5.52465V7.20266C21.1341 7.27629 21.0744 7.33599 21.0008 7.33599H11.1341C8.18859 7.33599 5.80078 9.72381 5.80078 12.6693V14.6693C5.80078 15.0375 6.09925 15.336 6.46744 15.336H8.20078C8.56897 15.336 8.86744 15.0375 8.86744 14.6693V13.0691C8.86744 11.5963 10.0613 10.4024 11.5341 10.4024H21.0008C21.0744 10.4024 21.1341 10.4621 21.1341 10.5357V12.215C21.1341 12.7621 21.7569 13.0763 22.197 12.7511L26.7242 9.40583C27.0849 9.13934 27.0849 8.59995 26.7242 8.33347L22.1969 4.98846Z\" key=\"0\"/>,<path d=\"M10.8652 24.7975C10.8652 24.7238 10.9249 24.6641 10.9986 24.6641H20.8652C23.8108 24.6641 26.1986 22.2763 26.1986 19.3308V17.3308C26.1986 16.9626 25.9001 16.6641 25.5319 16.6641H23.7986C23.4304 16.6641 23.1319 16.9626 23.1319 17.3308V18.931C23.1319 20.4038 21.938 21.5977 20.4652 21.5977H10.9986C10.9249 21.5977 10.8652 21.538 10.8652 21.4644V19.7851C10.8652 19.238 10.2425 18.9238 9.80239 19.249L5.27512 22.5943C4.91447 22.8608 4.91448 23.4002 5.27514 23.6666L9.80241 27.0116C10.2425 27.3368 10.8652 27.0226 10.8652 26.4755V24.7975Z\" key=\"1\"/>,],\n 'MediaRepeat',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaRepeatOnIcon = createSvgIcon(\n [<path d=\"M22.1969 4.98846C21.7569 4.66331 21.1341 4.97748 21.1341 5.52465V7.20266C21.1341 7.27629 21.0744 7.33599 21.0008 7.33599H11.1341C8.18859 7.33599 5.80078 9.72381 5.80078 12.6693V14.6693C5.80078 15.0375 6.09925 15.336 6.46744 15.336H8.20078C8.56897 15.336 8.86744 15.0375 8.86744 14.6693V13.0691C8.86744 11.5963 10.0613 10.4024 11.5341 10.4024H21.0008C21.0744 10.4024 21.1341 10.4621 21.1341 10.5357V12.215C21.1341 12.7621 21.7569 13.0763 22.197 12.7511L26.7242 9.40583C27.0849 9.13934 27.0849 8.59995 26.7242 8.33347L22.1969 4.98846Z\" key=\"0\"/>,<path d=\"M16 18.0001C17.1046 18.0001 18 17.1046 18 16.0001C18 14.8955 17.1046 14.0001 16 14.0001C14.8954 14.0001 14 14.8955 14 16.0001C14 17.1046 14.8954 18.0001 16 18.0001Z\" key=\"1\"/>,<path d=\"M20.8652 24.6641H10.9986C10.9249 24.6641 10.8652 24.7238 10.8652 24.7975V26.4755C10.8652 27.0226 10.2425 27.3368 9.80241 27.0116L5.27514 23.6666C4.91448 23.4002 4.91447 22.8608 5.27512 22.5943L9.80239 19.249C10.2425 18.9238 10.8652 19.238 10.8652 19.7851V21.4644C10.8652 21.538 10.9249 21.5977 10.9986 21.5977H20.4652C21.938 21.5977 23.1319 20.4038 23.1319 18.931V17.3308C23.1319 16.9626 23.4304 16.6641 23.7986 16.6641H25.5319C25.9001 16.6641 26.1986 16.9626 26.1986 17.3308V19.3308C26.1986 22.2763 23.8108 24.6641 20.8652 24.6641Z\" key=\"2\"/>,],\n 'MediaRepeatOn',\n '0 0 32 32'\n);\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {MediaRepeatIcon} from '@common/icons/media/media-repeat';\nimport {MediaRepeatOnIcon} from '@common/icons/media/media-repeat-on';\nimport {Trans} from '@common/i18n/trans';\nimport {ReactElement} from 'react';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\n\ninterface Props {\n color?: ButtonProps['color'];\n activeColor?: ButtonProps['color'];\n size?: ButtonProps['size'];\n iconSize?: ButtonProps['size'];\n className?: string;\n}\nexport function RepeatButton({\n size = 'md',\n iconSize,\n color,\n activeColor = 'primary',\n className,\n}: Props) {\n const playerReady = usePlayerStore(s => s.providerReady);\n const repeating = usePlayerStore(s => s.repeat);\n const player = usePlayerActions();\n\n let label: ReactElement;\n if (repeating === 'all') {\n label = <Trans message=\"Enable repeat one\" />;\n } else if (repeating === 'one') {\n label = <Trans message=\"Disable repeat\" />;\n } else {\n label = <Trans message=\"Enable repeat\" />;\n }\n\n return (\n <Tooltip label={label}>\n <IconButton\n disabled={!playerReady}\n size={size}\n color={repeating ? activeColor : color}\n iconSize={iconSize}\n className={className}\n onClick={() => {\n player.toggleRepeatMode();\n }}\n >\n {repeating === 'one' ? <MediaRepeatOnIcon /> : <MediaRepeatIcon />}\n </IconButton>\n </Tooltip>\n );\n}\n","import {MainSeekbar} from '@app/web-player/player-controls/seekbar/main-seekbar';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport clsx from 'clsx';\nimport {PlayButton} from '@common/player/ui/controls/play-button';\nimport {NextButton} from '@common/player/ui/controls/next-button';\nimport {PreviousButton} from '@common/player/ui/controls/previous-button';\nimport {ShuffleButton} from '@common/player/ui/controls/shuffle-button';\nimport {RepeatButton} from '@common/player/ui/controls/repeat-button';\nimport {BufferingIndicator} from '@app/web-player/player-controls/buffering-indicator';\n\ninterface Props {\n className?: string;\n}\nexport function PlaybackControls({className}: Props) {\n return (\n <div className={className}>\n <PlaybackButtons />\n <MainSeekbar />\n </div>\n );\n}\n\nfunction PlaybackButtons() {\n const isMobile = useIsMobileMediaQuery();\n\n // need to add a gap on mobile between buttons and seekbar, otherwise seekbar will be impossible to tap\n return (\n <div\n className={clsx(\n 'flex items-center justify-center gap-6',\n isMobile && 'mb-20'\n )}\n >\n <ShuffleButton iconSize={isMobile ? 'md' : 'sm'} />\n <PreviousButton size=\"md\" />\n <div className=\"relative\">\n <BufferingIndicator />\n <PlayButton size=\"md\" iconSize=\"xl\" />\n </div>\n <NextButton size=\"md\" />\n <RepeatButton iconSize={isMobile ? 'md' : 'sm'} />\n </div>\n );\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {useCuedTrack} from '@app/web-player/player-controls/use-cued-track';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {LyricsDialog} from '@app/web-player/tracks/lyrics/lyrics-dialog';\nimport {MediaMicrophoneIcon} from '@common/icons/media/media-microphone';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\n\nexport function LyricsButton() {\n const {player} = useSettings();\n const track = useCuedTrack();\n\n if (!track || player?.hide_lyrics) {\n return null;\n }\n\n return (\n <DialogTrigger type=\"modal\">\n <Tooltip label={<Trans message=\"Lyrics\" />}>\n <IconButton>\n <MediaMicrophoneIcon />\n </IconButton>\n </Tooltip>\n <LyricsDialog track={track} />\n </DialogTrigger>\n );\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {useCuedTrack} from '@app/web-player/player-controls/use-cued-track';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {trackIsLocallyUploaded} from '@app/web-player/tracks/utils/track-is-locally-uploaded';\nimport {DownloadIcon} from '@common/icons/material/Download';\nimport {downloadFileFromUrl} from '@common/uploads/utils/download-file-from-url';\nimport {useAuth} from '@common/auth/use-auth';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\n\nexport function DownloadTrackButton() {\n const {player, base_url} = useSettings();\n const track = useCuedTrack();\n const {hasPermission} = useAuth();\n\n if (\n !player?.enable_download ||\n !track ||\n !trackIsLocallyUploaded(track) ||\n !hasPermission('music.download')\n ) {\n return null;\n }\n\n return (\n <Tooltip label={<Trans message=\"Download\" />}>\n <IconButton\n onClick={() => {\n downloadFileFromUrl(`${base_url}/api/v1/tracks/${track.id}/download`);\n }}\n >\n <DownloadIcon />\n </IconButton>\n </Tooltip>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaQueueListIcon = createSvgIcon(\n [<path fillRule=\"evenodd\" clipRule=\"evenodd\" d=\"M7.33335 6C6.96516 6 6.66669 6.29848 6.66669 6.66667V13.3333C6.66669 13.7015 6.96516 14 7.33335 14H24.6667C25.0349 14 25.3334 13.7015 25.3334 13.3333V6.66667C25.3334 6.29848 25.0349 6 24.6667 6H7.33335ZM9.46669 8.66667C9.39305 8.66667 9.33335 8.72636 9.33335 8.8V11.2C9.33335 11.2736 9.39305 11.3333 9.46669 11.3333H22.5334C22.607 11.3333 22.6667 11.2736 22.6667 11.2V8.8C22.6667 8.72636 22.607 8.66667 22.5334 8.66667H9.46669Z\" key=\"0\"/>,<path d=\"M6.66669 18C6.66669 17.6318 6.96516 17.3333 7.33335 17.3333H24.6667C25.0349 17.3333 25.3334 17.6318 25.3334 18V19.3333C25.3334 19.7015 25.0349 20 24.6667 20H7.33335C6.96516 20 6.66669 19.7015 6.66669 19.3333V18Z\" key=\"1\"/>,<path d=\"M6.66669 24C6.66669 23.6318 6.96516 23.3333 7.33335 23.3333H24.6667C25.0349 23.3333 25.3334 23.6318 25.3334 24V25.3333C25.3334 25.7015 25.0349 26 24.6667 26H7.33335C6.96516 26 6.66669 25.7015 6.66669 25.3333V24Z\" key=\"2\"/>,],\n 'MediaQueueList',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaMuteIcon = createSvgIcon(\n [<path d=\"M17.5091 24.6594C17.5091 25.2066 16.8864 25.5208 16.4463 25.1956L9.44847 20.0252C9.42553 20.0083 9.39776 19.9991 9.36923 19.9991H4.66667C4.29848 19.9991 4 19.7006 4 19.3325V12.6658C4 12.2976 4.29848 11.9991 4.66667 11.9991H9.37115C9.39967 11.9991 9.42745 11.99 9.45039 11.973L16.4463 6.8036C16.8863 6.47842 17.5091 6.79259 17.5091 7.33977L17.5091 24.6594Z\" key=\"0\"/>,<path d=\"M28.8621 13.6422C29.1225 13.3818 29.1225 12.9597 28.8621 12.6994L27.9193 11.7566C27.659 11.4962 27.2368 11.4962 26.9765 11.7566L24.7134 14.0197C24.6613 14.0717 24.5769 14.0717 24.5248 14.0197L22.262 11.7568C22.0016 11.4964 21.5795 11.4964 21.3191 11.7568L20.3763 12.6996C20.116 12.9599 20.116 13.382 20.3763 13.6424L22.6392 15.9053C22.6913 15.9573 22.6913 16.0418 22.6392 16.0938L20.3768 18.3562C20.1165 18.6166 20.1165 19.0387 20.3768 19.299L21.3196 20.2419C21.58 20.5022 22.0021 20.5022 22.2624 20.2418L24.5248 17.9795C24.5769 17.9274 24.6613 17.9274 24.7134 17.9795L26.976 20.2421C27.2363 20.5024 27.6585 20.5024 27.9188 20.2421L28.8616 19.2992C29.122 19.0389 29.122 18.6168 28.8616 18.3564L26.599 16.0938C26.547 16.0418 26.547 15.9573 26.599 15.9053L28.8621 13.6422Z\" key=\"1\"/>,],\n 'MediaMute',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaVolumeLowIcon = createSvgIcon(\n [<path d=\"M17.5091 24.6594C17.5091 25.2066 16.8864 25.5207 16.4463 25.1956L9.44847 20.0252C9.42553 20.0083 9.39776 19.9991 9.36923 19.9991H4.66667C4.29848 19.9991 4 19.7006 4 19.3324V12.6658C4 12.2976 4.29848 11.9991 4.66667 11.9991H9.37115C9.39967 11.9991 9.42745 11.99 9.45039 11.973L16.4463 6.80358C16.8863 6.4784 17.5091 6.79258 17.5091 7.33975L17.5091 24.6594Z\" key=\"0\"/>,<path d=\"M22.8424 12.6667C22.8424 12.2985 22.544 12 22.1758 12H20.8424C20.4743 12 20.1758 12.2985 20.1758 12.6667V19.3333C20.1758 19.7015 20.4743 20 20.8424 20H22.1758C22.544 20 22.8424 19.7015 22.8424 19.3333V12.6667Z\" key=\"1\"/>,],\n 'MediaVolumeLow',\n '0 0 32 32'\n);\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaVolumeHighIcon = createSvgIcon(\n [<path d=\"M17.5091 24.6595C17.5091 25.2066 16.8864 25.5208 16.4463 25.1956L9.44847 20.0252C9.42553 20.0083 9.39776 19.9992 9.36923 19.9992H4.66667C4.29848 19.9992 4 19.7007 4 19.3325V12.6658C4 12.2976 4.29848 11.9992 4.66667 11.9992H9.37115C9.39967 11.9992 9.42745 11.99 9.45039 11.9731L16.4463 6.80363C16.8863 6.47845 17.5091 6.79262 17.5091 7.3398L17.5091 24.6595Z\" key=\"0\"/>,<path d=\"M27.5091 9.33336C27.8773 9.33336 28.1758 9.63184 28.1758 10V22C28.1758 22.3682 27.8773 22.6667 27.5091 22.6667H26.1758C25.8076 22.6667 25.5091 22.3682 25.5091 22V10C25.5091 9.63184 25.8076 9.33336 26.1758 9.33336L27.5091 9.33336Z\" key=\"1\"/>,<path d=\"M22.1758 12C22.544 12 22.8424 12.2985 22.8424 12.6667V19.3334C22.8424 19.7016 22.544 20 22.1758 20H20.8424C20.4743 20 20.1758 19.7016 20.1758 19.3334V12.6667C20.1758 12.2985 20.4743 12 20.8424 12H22.1758Z\" key=\"2\"/>,],\n 'MediaVolumeHigh',\n '0 0 32 32'\n);\n","import {Slider} from '@common/ui/forms/slider/slider';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {BaseSliderProps} from '@common/ui/forms/slider/base-slider';\nimport {ButtonProps} from '@common/ui/buttons/button';\nimport {MediaMuteIcon} from '@common/icons/media/media-mute';\nimport {MediaVolumeLowIcon} from '@common/icons/media/media-volume-low';\nimport {MediaVolumeHighIcon} from '@common/icons/media/media-volume-high';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\n\ninterface Props {\n trackColor?: BaseSliderProps['trackColor'];\n fillColor?: BaseSliderProps['fillColor'];\n buttonColor?: ButtonProps['color'];\n}\nexport function VolumeControls({trackColor, fillColor, buttonColor}: Props) {\n const volume = usePlayerStore(s => s.volume);\n const player = usePlayerActions();\n const playerReady = usePlayerStore(s => s.providerReady);\n\n return (\n <div className=\"flex w-min items-center gap-4\">\n <ToggleMuteButton color={buttonColor} />\n <Slider\n isDisabled={!playerReady}\n showThumbOnHoverOnly\n thumbSize=\"w-14 h-14\"\n trackColor={trackColor}\n fillColor={fillColor}\n minValue={0}\n maxValue={100}\n className=\"flex-auto\"\n width=\"w-96\"\n value={volume}\n onChange={value => {\n player.setVolume(value);\n }}\n />\n </div>\n );\n}\n\ninterface ToggleMuteButtonProps {\n color?: ButtonProps['color'];\n}\nfunction ToggleMuteButton({color}: ToggleMuteButtonProps) {\n const isMuted = usePlayerStore(s => s.muted);\n const volume = usePlayerStore(s => s.volume);\n const player = usePlayerActions();\n const playerReady = usePlayerStore(s => s.providerReady);\n\n if (isMuted) {\n return (\n <Tooltip label={<Trans message=\"Unmute\" />}>\n <IconButton\n disabled={!playerReady}\n color={color}\n size=\"sm\"\n iconSize=\"md\"\n onClick={() => player.setMuted(false)}\n >\n <MediaMuteIcon />\n </IconButton>\n </Tooltip>\n );\n }\n return (\n <Tooltip label={<Trans message=\"Mute\" />}>\n <IconButton\n disabled={!playerReady}\n color={color}\n size=\"sm\"\n iconSize=\"md\"\n onClick={() => player.setMuted(true)}\n >\n {volume < 40 ? <MediaVolumeLowIcon /> : <MediaVolumeHighIcon />}\n </IconButton>\n </Tooltip>\n );\n}\n","import {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {ReactNode, useContext} from 'react';\nimport {useCuedTrack} from '@app/web-player/player-controls/use-cued-track';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {PlaybackControls} from '@app/web-player/player-controls/playback-controls';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\nimport {DashboardLayoutContext} from '@common/ui/layout/dashboard-layout-context';\nimport {\n playerOverlayState,\n usePlayerOverlayStore,\n} from '@app/web-player/state/player-overlay-store';\nimport {KeyboardArrowDownIcon} from '@common/icons/material/KeyboardArrowDown';\nimport {KeyboardArrowUpIcon} from '@common/icons/material/KeyboardArrowUp';\nimport {LyricsButton} from '@app/web-player/player-controls/lyrics-button';\nimport {DownloadTrackButton} from '@app/web-player/player-controls/download-track-button';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {getTrackLink, TrackLink} from '@app/web-player/tracks/track-link';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {Link} from 'react-router-dom';\nimport {ArtistContextDialog} from '@app/web-player/artists/artist-context-dialog';\nimport {MediaQueueListIcon} from '@common/icons/media/media-queue-list';\nimport {VolumeControls} from '@common/player/ui/controls/volume-controls';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {Trans} from '@common/i18n/trans';\n\nexport function DesktopPlayerControls() {\n const mediaIsCued = usePlayerStore(s => s.cuedMedia != null);\n if (!mediaIsCued) return null;\n\n return (\n <div className=\"h-96 px-16 flex items-center justify-between border-t bg dashboard-grid-footer z-30\">\n <QueuedTrack />\n <PlaybackControls className=\"w-2/5 max-w-[722px]\" />\n <SecondaryControls />\n </div>\n );\n}\n\nfunction QueuedTrack() {\n const track = useCuedTrack();\n let content: ReactNode;\n\n if (track) {\n content = (\n <div className=\"flex items-center gap-14\">\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"top\">\n <Link to={getTrackLink(track)} className=\"flex-shrink-0\">\n <TrackImage\n className=\"rounded w-56 h-56 object-cover\"\n track={track}\n />\n </Link>\n <TrackContextDialog tracks={[track]} />\n </DialogTrigger>\n <div className=\"min-w-0 overflow-hidden overflow-ellipsis\">\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"top\">\n <TrackLink\n track={track}\n className=\"text-sm whitespace-nowrap min-w-0 max-w-full\"\n />\n <TrackContextDialog tracks={[track]} />\n </DialogTrigger>\n {track.artists?.length ? (\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"top\">\n <div className=\"text-xs text-muted\">\n <ArtistLinks\n artists={track.artists}\n className=\"whitespace-nowrap\"\n />\n </div>\n <ArtistContextDialog artist={track.artists[0]} />\n </DialogTrigger>\n ) : null}\n </div>\n <LikeIconButton likeable={track} />\n </div>\n );\n } else {\n content = null;\n }\n\n return <div className=\"min-w-180 w-[30%]\">{content}</div>;\n}\n\nfunction SecondaryControls() {\n const {rightSidenavStatus, setRightSidenavStatus} = useContext(\n DashboardLayoutContext\n );\n return (\n <div className=\"flex items-center justify-end min-w-180 w-[30%]\">\n <LyricsButton />\n <DownloadTrackButton />\n <Tooltip label={<Trans message=\"Queue\" />}>\n <IconButton\n className=\"flex-shrink-0\"\n onClick={() => {\n setRightSidenavStatus(\n rightSidenavStatus === 'closed' ? 'open' : 'closed'\n );\n }}\n >\n <MediaQueueListIcon />\n </IconButton>\n </Tooltip>\n <VolumeControls trackColor=\"neutral\" />\n <OverlayButton />\n </div>\n );\n}\n\nfunction OverlayButton() {\n const isActive = usePlayerOverlayStore(s => s.isMaximized);\n const playerReady = usePlayerStore(s => s.providerReady);\n const {player} = useSettings();\n\n if (player?.hide_video_button) {\n return null;\n }\n\n return (\n <Tooltip label={<Trans message=\"Expand\" />}>\n <IconButton\n className=\"flex-shrink-0 ml-26\"\n color=\"chip\"\n variant=\"flat\"\n radius=\"rounded\"\n size=\"xs\"\n iconSize=\"sm\"\n disabled={!playerReady}\n onClick={() => {\n playerOverlayState.toggle();\n }}\n >\n {isActive ? <KeyboardArrowDownIcon /> : <KeyboardArrowUpIcon />}\n </IconButton>\n </Tooltip>\n );\n}\n","export function isNumber(value: any): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n","/**\n * Load image avoiding xhr/fetch CORS issues. Server status can't be obtained this way\n * unfortunately, so this uses \"naturalWidth\" to determine if the image has been loaded. By\n * default, it checks if it is at least 1px.\n */\nexport const loadImage = (\n src: string,\n minWidth = 1\n): Promise<HTMLImageElement> =>\n new Promise((resolve, reject) => {\n const image = new Image();\n const handler = () => {\n // @ts-expect-error\n delete image.onload;\n // @ts-expect-error\n delete image.onerror;\n if (image.naturalWidth >= minWidth) {\n resolve(image);\n } else {\n reject(image);\n }\n };\n Object.assign(image, {onload: handler, onerror: handler, src});\n });\n","import {loadImage} from '@common/utils/http/load-image';\n\nconst posterCache = new Map<string, string>();\n\nexport async function loadYoutubePoster(\n videoId: string\n): Promise<string | undefined> {\n if (!videoId) return;\n if (posterCache.has(videoId)) {\n return posterCache.get(videoId);\n }\n\n const posterURL = (quality: string) =>\n `https://i.ytimg.com/vi/${videoId}/${quality}.jpg`;\n\n /**\n * We are testing that the image has a min-width of 121px because if the thumbnail does not\n * exist YouTube returns a blank/error image that is 120px wide.\n */\n return loadImage(posterURL('maxresdefault'), 121) // 1080p (no padding)\n .catch(() => loadImage(posterURL('sddefault'), 121)) // 640p (padded 4:3)\n .catch(() => loadImage(posterURL('hqdefault'), 121)) // 480p (padded 4:3)\n .then(img => {\n const poster = img.src;\n posterCache.set(videoId, poster);\n return poster;\n });\n}\n","import {\n YoutubeInternalState,\n YouTubeMessage,\n YoutubeMessageInfo,\n YouTubePlayerState,\n YoutubeProviderError,\n} from '@common/player/providers/youtube/youtube-types';\nimport {MutableRefObject, RefObject} from 'react';\nimport {PlayerStoreApi} from '@common/player/state/player-state';\nimport {isNumber} from '@common/utils/number/is-number';\nimport {loadYoutubePoster} from '@common/player/providers/youtube/load-youtube-poster';\n\nexport function handleYoutubeEmbedMessage(\n e: MessageEvent,\n internalStateRef: MutableRefObject<YoutubeInternalState>,\n iframeRef: RefObject<HTMLIFrameElement>,\n store: PlayerStoreApi\n) {\n const data = JSON.parse(e.data) as YouTubeMessage;\n const info = data.info;\n const internalState = internalStateRef.current;\n const emit = store.getState().emit;\n if (!info) return;\n\n if (info.videoData?.video_id) {\n internalState.videoId = info.videoData.video_id;\n }\n\n if (info.videoData?.errorCode) {\n const event: YoutubeProviderError = {\n code: info.videoData.errorCode,\n videoId: internalState.videoId,\n };\n emit('error', {sourceEvent: event});\n }\n\n if (isNumber(info.duration) && info.duration !== internalState.duration) {\n internalState.duration = info.duration;\n emit('durationChange', {duration: internalState.duration});\n }\n\n if (\n isNumber(info.currentTime) &&\n info.currentTime !== internalState.currentTime\n ) {\n internalState.currentTime = info.currentTime;\n // don't fire progress events while seeking via seekbar\n if (!store.getState().isSeeking) {\n emit('progress', {currentTime: internalState.currentTime});\n }\n }\n\n if (isNumber(info.currentTimeLastUpdated)) {\n internalState.lastTimeUpdate = info.currentTimeLastUpdated;\n }\n\n if (isNumber(info.playbackRate)) {\n if (internalState.playbackRate !== info.playbackRate) {\n emit('playbackRateChange', {rate: info.playbackRate});\n }\n internalState.playbackRate = info.playbackRate;\n }\n\n if (isNumber(info.videoLoadedFraction)) {\n const buffered = info.videoLoadedFraction * internalState.duration;\n if (internalState.buffered !== buffered) {\n emit('buffered', {\n seconds: info.videoLoadedFraction * internalState.duration,\n });\n }\n internalState.buffered = buffered;\n }\n\n if (Array.isArray(info.availablePlaybackRates)) {\n emit('playbackRates', {rates: info.availablePlaybackRates});\n }\n\n if (isNumber(info.playerState)) {\n onYoutubeStateChange(info, internalStateRef, iframeRef, store);\n internalState.state = info.playerState;\n }\n}\n\nfunction onYoutubeStateChange(\n info: YoutubeMessageInfo,\n internalStateRef: MutableRefObject<YoutubeInternalState>,\n iframeRef: RefObject<HTMLIFrameElement>,\n store: PlayerStoreApi\n) {\n const emit = store.getState().emit;\n const state = info.playerState!;\n\n const onCued = async () => {\n // load poster, if needed\n if (info.videoData?.video_id && !store.getState().cuedMedia?.poster) {\n const url = await loadYoutubePoster(info.videoData.video_id);\n if (url) {\n store.getState().emit('posterLoaded', {url});\n }\n }\n\n // mark provider as ready\n if (!internalStateRef.current.playbackReady) {\n emit('providerReady', {el: iframeRef.current!});\n internalStateRef.current.playbackReady = true;\n }\n emit('cued');\n };\n\n emit('youtubeStateChange', {state});\n emit('buffering', {isBuffering: state === YouTubePlayerState.Buffering});\n\n if (state !== YouTubePlayerState.Ended) {\n internalStateRef.current.firedPlaybackEnd = false;\n }\n\n switch (state) {\n case YouTubePlayerState.Unstarted:\n // When using autoplay, but autoplay fails, player will get \"unstarted\" event\n onCued();\n break;\n case YouTubePlayerState.Ended:\n // will sometimes fire twice without this, if player starts buffering as a result of seek to the end\n if (!internalStateRef.current.firedPlaybackEnd) {\n emit('playbackEnd');\n internalStateRef.current.firedPlaybackEnd = true;\n }\n break;\n case YouTubePlayerState.Playing:\n // When using autoplay, \"cued\" event is never fired, handle \"cued\" here instead\n onCued();\n emit('play');\n break;\n case YouTubePlayerState.Paused:\n emit('pause');\n break;\n case YouTubePlayerState.Cued:\n onCued();\n break;\n }\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useCallback, useEffect, useState} from 'react';\nimport {YoutubeMediaItem} from '@common/player/media-item';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\n\nconst queryString =\n '&controls=0&disablekb=1&enablejsapi=1&iv_load_policy=3&modestbranding=1&playsinline=1&rel=0&showinfo=0';\n\nexport function useYoutubeProviderSrc(\n loadVideoById: (videoId: string) => void\n) {\n const {getState, emit} = usePlayerActions();\n const options = usePlayerStore(s => s.options);\n const media = usePlayerStore(s => s.cuedMedia) as\n | YoutubeMediaItem\n | undefined;\n\n const origin = options.youtube?.useCookies\n ? 'https://www.youtube.com'\n : 'https://www.youtube-nocookie.com';\n\n const [initialVideoId, setInitialVideoId] = useState(() => {\n if (media?.src && media.src !== 'resolve') {\n return youtubeIdFromSrc(media.src);\n }\n });\n\n const updateVideoIds = useCallback(\n (src: string) => {\n const videoId = youtubeIdFromSrc(src);\n if (!videoId) return;\n\n // use setState callback, so we don't need to use \"initialVideoId\" in the dependency array\n setInitialVideoId(prevId => {\n if (!prevId) {\n return videoId;\n } else {\n // changing src of iframe will cause it to fully reload, use \"loadVideoById\" api method instead\n loadVideoById(videoId);\n return prevId;\n }\n });\n },\n [loadVideoById]\n );\n\n useEffect(() => {\n if (media?.src && media.src !== 'resolve') {\n updateVideoIds(media.src);\n } else if (media) {\n emit('buffering', {isBuffering: true});\n options.youtube?.srcResolver?.(media).then(item => {\n // check if resolved media matches the one currently in the store to prevent race conditions.\n // check against current value in store, because this callback will close over old value\n if (item?.src && getState().cuedMedia?.id === item.id) {\n updateVideoIds(item.src);\n }\n });\n }\n // only update when media id changes to prevent infinite loops\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options, updateVideoIds, media?.id]);\n\n return {\n initialVideoUrl: initialVideoId\n ? `${origin}/embed/${initialVideoId}?${queryString}&autoplay=${\n options.autoPlay ? '1' : '0'\n }&mute=${getState().muted ? '1' : '0'}&start=${media?.initialTime ?? 0}`\n : undefined,\n origin,\n };\n}\n\nfunction youtubeIdFromSrc(src: string) {\n return src.match(/((?:\\w|-){11})/)?.[0];\n}\n","import {useGlobalListeners} from '@react-aria/utils';\nimport {useCallback, useContext, useEffect, useRef} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {\n YoutubeCommand,\n YouTubeCommandArg,\n YoutubeInternalState,\n YoutubeProviderInternalApi,\n} from '@common/player/providers/youtube/youtube-types';\nimport {handleYoutubeEmbedMessage} from '@common/player/providers/youtube/handle-youtube-embed-message';\nimport {useYoutubeProviderSrc} from '@common/player/providers/youtube/use-youtube-provider-src';\n\nexport function YoutubeProvider() {\n const {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n const youtubeApi = useCallback(\n <T extends keyof YouTubeCommandArg>(\n command: T,\n arg?: YouTubeCommandArg[T]\n ) =>\n iframeRef.current?.contentWindow?.postMessage(\n JSON.stringify({\n event: 'command',\n func: command,\n args: arg ? [arg] : undefined,\n }),\n '*'\n ),\n []\n );\n\n const loadVideoById = useCallback(\n (videoId: string) => {\n youtubeApi(YoutubeCommand.Load, videoId);\n },\n [youtubeApi]\n );\n\n const {initialVideoUrl, origin} = useYoutubeProviderSrc(loadVideoById);\n const store = useContext(PlayerStoreContext);\n\n const internalStateRef = useRef<YoutubeInternalState>({\n duration: 0,\n currentTime: 0,\n lastTimeUpdate: 0,\n playbackRate: 1,\n state: -1,\n playbackReady: false,\n buffered: 0,\n firedPlaybackEnd: false,\n });\n\n const registerApi = useCallback(() => {\n const internalProviderApi: YoutubeProviderInternalApi = {\n loadVideoById,\n };\n store.setState({\n providerApi: {\n play: () => {\n youtubeApi(YoutubeCommand.Play);\n },\n pause: () => {\n youtubeApi(YoutubeCommand.Pause);\n },\n stop: () => {\n youtubeApi(YoutubeCommand.Stop);\n },\n seek: (time: number) => {\n if (time !== internalStateRef.current.currentTime) {\n youtubeApi(YoutubeCommand.Seek, time);\n }\n },\n setVolume: (volume: number) => {\n youtubeApi(YoutubeCommand.SetVolume, volume);\n },\n setMuted: (muted: boolean) => {\n if (muted) {\n youtubeApi(YoutubeCommand.Mute);\n } else {\n youtubeApi(YoutubeCommand.Unmute);\n }\n },\n setPlaybackRate: (value: number) => {\n youtubeApi(YoutubeCommand.SetPlaybackRate, value);\n },\n setPlaybackQuality: (value: string) => {\n youtubeApi(YoutubeCommand.SetPlaybackQuality, value);\n },\n getCurrentTime: () => {\n return internalStateRef.current.currentTime;\n },\n getSrc: () => {\n return internalStateRef.current.videoId;\n },\n internalProviderApi,\n },\n });\n }, [store, loadVideoById, youtubeApi]);\n\n useEffect(() => {\n addGlobalListener(window, 'message', event => {\n const e = event as MessageEvent;\n if (\n e.origin === origin &&\n e.source === iframeRef.current?.contentWindow\n ) {\n handleYoutubeEmbedMessage(e, internalStateRef, iframeRef, store);\n }\n });\n\n registerApi();\n\n return () => {\n removeAllGlobalListeners();\n };\n }, [addGlobalListener, removeAllGlobalListeners, store, origin, registerApi]);\n\n if (!initialVideoUrl) {\n return null;\n }\n\n return (\n <iframe\n className=\"w-full h-full\"\n ref={iframeRef}\n src={initialVideoUrl}\n allowFullScreen\n allow=\"autoplay; encrypted-media; picture-in-picture;\"\n onLoad={() => {\n // window does not receive \"message\" events on safari without waiting a small amount of time for some reason\n setTimeout(() => {\n iframeRef.current?.contentWindow?.postMessage(\n JSON.stringify({event: 'listening'}),\n '*'\n );\n registerApi();\n });\n }}\n />\n );\n}\n","export function createRafLoop(callback: () => void) {\n let id: number | undefined;\n\n function start() {\n // Time updates are already in progress.\n if (!isUndefined(id)) return;\n loop();\n }\n\n function loop() {\n id = window.requestAnimationFrame(function rafLoop() {\n if (isUndefined(id)) return;\n callback();\n loop();\n });\n }\n\n function stop() {\n if (isNumber(id)) window.cancelAnimationFrame(id);\n id = undefined;\n }\n\n return {\n start,\n stop,\n };\n}\n\nfunction isUndefined(value: unknown): value is undefined {\n return typeof value === 'undefined';\n}\n\nfunction isNumber(value: any): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n","import {\n MutableRefObject,\n RefObject,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from 'react';\nimport {createRafLoop} from '@common/utils/dom/create-ref-loop';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\n\nexport interface HtmlMediaInternalStateReturn {\n ref: RefObject<HTMLMediaElement>;\n updateCurrentTime: () => void;\n updateBuffered: () => void;\n toggleTextTrackModes: (newTrackId: number, isVisible: boolean) => void;\n internalState: MutableRefObject<{\n currentTime: number;\n playbackReady: boolean;\n timeRafLoop: ReturnType<typeof createRafLoop>;\n }>;\n}\n\nexport function useHtmlMediaInternalState(\n ref: RefObject<HTMLMediaElement>\n): HtmlMediaInternalStateReturn {\n const store = useContext(PlayerStoreContext);\n const cuedMedia = usePlayerStore(s => s.cuedMedia);\n\n const internalState = useRef({\n currentTime: 0,\n buffered: 0,\n isMediaWaiting: false,\n playbackReady: false,\n /**\n * The `timeupdate` event fires surprisingly infrequently during playback, meaning your progress\n * bar (or whatever else is synced to the currentTime) moves in a choppy fashion. This helps\n * resolve that by retrieving time updates in a request animation frame loop.\n */\n timeRafLoop: createRafLoop(() => {\n updateCurrentTime();\n updateBuffered();\n }),\n });\n\n const updateBuffered = useCallback(() => {\n const timeRange = ref.current?.buffered;\n const seconds =\n !timeRange || timeRange.length === 0\n ? 0\n : timeRange.end(timeRange.length - 1);\n\n if (internalState.current.buffered !== seconds) {\n store.getState().emit('buffered', {seconds});\n internalState.current.buffered = seconds;\n }\n }, [ref, store]);\n\n const updateCurrentTime = useCallback(() => {\n const newTime = ref.current?.currentTime || 0;\n if (\n internalState.current.currentTime !== newTime &&\n !store.getState().isSeeking\n ) {\n store.getState().emit('progress', {currentTime: newTime});\n internalState.current.currentTime = newTime;\n }\n }, [internalState, store, ref]);\n\n const toggleTextTrackModes = useCallback(\n (newTrackId: number, isVisible: boolean) => {\n if (!ref.current) return;\n const {textTracks} = ref.current;\n\n if (newTrackId === -1) {\n Array.from(textTracks).forEach(track => {\n track.mode = 'disabled';\n });\n } else {\n const oldTrack = textTracks[store.getState().currentTextTrack];\n if (oldTrack) oldTrack.mode = 'disabled';\n }\n\n const nextTrack = textTracks[newTrackId];\n\n if (nextTrack) {\n nextTrack.mode = isVisible ? 'showing' : 'hidden';\n }\n\n store.getState().emit('currentTextTrackChange', {\n trackId: !isVisible ? -1 : newTrackId,\n });\n store\n .getState()\n .emit('textTrackVisibilityChange', {isVisible: isVisible});\n },\n [ref, store]\n );\n\n // stop current time loop on unmount\n useEffect(() => {\n const timeRafLoop = internalState.current.timeRafLoop;\n return () => {\n timeRafLoop.stop();\n };\n }, []);\n\n // reload metadata when new media is cued\n useEffect(() => {\n ref.current?.load();\n }, [cuedMedia?.src, ref]);\n\n return {\n ref,\n internalState,\n updateCurrentTime,\n toggleTextTrackModes,\n updateBuffered,\n };\n}\n","import {\n HTMLAttributes,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {HtmlMediaInternalStateReturn} from '@common/player/providers/html-media/use-html-media-internal-state';\n\nconst defaultPlaybackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];\n\nexport function useHtmlMediaEvents({\n ref,\n updateCurrentTime,\n updateBuffered,\n internalState,\n}: HtmlMediaInternalStateReturn): HTMLAttributes<HTMLMediaElement> {\n const store = useContext(PlayerStoreContext);\n\n const onTextTracksChange = useCallback(() => {\n if (!ref.current) return;\n const tracks = Array.from(ref.current.textTracks).filter(\n t => t.label && (t.kind === 'subtitles' || t.kind === 'captions')\n );\n\n let trackId = -1;\n for (let id = 0; id < tracks.length; id += 1) {\n if (tracks[id].mode === 'hidden') {\n // Do not break in case there is a following track with showing.\n trackId = id;\n } else if (tracks[id].mode === 'showing') {\n trackId = id;\n break;\n }\n }\n\n const isVisible = trackId !== -1 && tracks[trackId].mode === 'showing';\n store.getState().emit('currentTextTrackChange', {trackId});\n store.getState().emit('textTrackVisibilityChange', {isVisible});\n store.getState().emit('textTracks', {tracks});\n }, [ref, store]);\n\n useEffect(() => {\n const el = ref.current;\n return () => {\n el?.textTracks.removeEventListener('change', onTextTracksChange);\n };\n }, [ref, onTextTracksChange]);\n\n return useMemo(() => {\n const emit = store.getState().emit;\n return {\n // set some common props used on audio/video/hls/dash providers\n autoPlay: false,\n onContextMenu: e => e.preventDefault(),\n controlsList: 'nodownload',\n preload: 'metadata',\n 'x-webkit-airplay': 'allow',\n onEnded: () => {\n emit('playbackEnd');\n updateCurrentTime();\n internalState.current.timeRafLoop.stop();\n },\n onStalled: e => {\n if (e.currentTarget.readyState < 3) {\n emit('buffering', {isBuffering: true});\n }\n },\n onWaiting: () => {\n emit('buffering', {isBuffering: true});\n },\n onPlaying: () => {\n emit('play');\n emit('buffering', {isBuffering: false});\n },\n onPause: e => {\n emit('pause');\n emit('buffering', {isBuffering: false});\n internalState.current.timeRafLoop.stop();\n },\n onSuspend: () => {\n emit('buffering', {isBuffering: false});\n },\n onSeeking: () => {\n updateCurrentTime();\n },\n onSeeked: () => {\n updateCurrentTime();\n },\n onTimeUpdate: () => {\n updateCurrentTime();\n },\n onError: e => {\n emit('error', {sourceEvent: e});\n },\n onDurationChange: e => {\n updateCurrentTime();\n emit('durationChange', {duration: e.currentTarget.duration});\n },\n onRateChange: e => {\n emit('playbackRateChange', {rate: e.currentTarget.playbackRate});\n },\n onLoadedMetadata: e => {\n if (!internalState.current.playbackReady) {\n emit('providerReady', {el: e.currentTarget});\n internalState.current.playbackReady = true;\n updateBuffered();\n onTextTracksChange();\n e.currentTarget.textTracks.addEventListener('change', () => {\n onTextTracksChange();\n });\n }\n emit('cued');\n emit('playbackRates', {rates: defaultPlaybackRates});\n },\n };\n }, [\n internalState,\n store,\n updateCurrentTime,\n onTextTracksChange,\n updateBuffered,\n ]);\n}\n","import {HtmlMediaInternalStateReturn} from '@common/player/providers/html-media/use-html-media-internal-state';\nimport {useContext, useMemo} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {PlayerProviderApi} from '@common/player/state/player-provider-api';\n\nexport function useHtmlMediaApi({\n ref,\n internalState,\n toggleTextTrackModes,\n}: HtmlMediaInternalStateReturn): PlayerProviderApi {\n const store = useContext(PlayerStoreContext);\n return useMemo(\n () => ({\n play: async () => {\n try {\n await ref.current?.play();\n } catch (e) {\n store.getState().emit('error', {sourceEvent: e});\n }\n internalState.current.timeRafLoop.start();\n },\n pause: () => {\n ref.current?.pause();\n internalState.current.timeRafLoop.stop();\n },\n stop: () => {\n if (ref.current) {\n ref.current.pause();\n ref.current.currentTime = 0;\n }\n },\n seek: (time: number) => {\n if (time !== internalState.current.currentTime && ref.current) {\n ref.current.currentTime = time;\n }\n },\n setVolume: (volume: number) => {\n if (ref.current) {\n ref.current.volume = volume / 100;\n }\n },\n setMuted: (muted: boolean) => {\n if (ref.current) {\n ref.current.muted = muted;\n }\n },\n setPlaybackRate: (value: number) => {\n if (ref.current) {\n ref.current.playbackRate = value;\n }\n },\n setTextTrackVisibility: isVisible => {\n toggleTextTrackModes(store.getState().currentTextTrack, isVisible);\n },\n setCurrentTextTrack: newTrackId => {\n toggleTextTrackModes(newTrackId, store.getState().textTrackIsVisible);\n },\n getCurrentTime: () => {\n return internalState.current.currentTime;\n },\n getSrc: () => {\n return ref.current?.src;\n },\n }),\n [ref, store, internalState, toggleTextTrackModes]\n );\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useContext, useEffect, useRef} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {useHtmlMediaInternalState} from '@common/player/providers/html-media/use-html-media-internal-state';\nimport {useHtmlMediaEvents} from '@common/player/providers/html-media/use-html-media-events';\nimport {useHtmlMediaApi} from '@common/player/providers/html-media/use-html-media-api';\n\nexport function HtmlVideoProvider() {\n const ref = useRef<HTMLVideoElement>(null);\n\n const autoPlay = usePlayerStore(s => s.options.autoPlay);\n const muted = usePlayerStore(s => s.muted);\n const cuedMedia = usePlayerStore(s => s.cuedMedia);\n const store = useContext(PlayerStoreContext);\n\n const state = useHtmlMediaInternalState(ref);\n const events = useHtmlMediaEvents(state);\n const providerApi = useHtmlMediaApi(state);\n\n useEffect(() => {\n store.setState({\n providerApi,\n });\n }, [store, providerApi]);\n\n let src = cuedMedia?.src;\n if (src && cuedMedia?.initialTime) {\n src = `${src}#t=${cuedMedia.initialTime}`;\n }\n\n return (\n <video\n className=\"w-full h-full\"\n ref={ref}\n src={src}\n playsInline\n poster={cuedMedia?.poster}\n autoPlay={autoPlay}\n muted={muted}\n {...events}\n >\n {cuedMedia?.captions?.map((caption, index) => (\n <track\n key={caption.id}\n label={caption.label}\n kind=\"subtitles\"\n srcLang={caption.language || 'en'}\n src={caption.src}\n default={index === 0}\n />\n ))}\n </video>\n );\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useContext, useEffect, useRef} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {useHtmlMediaInternalState} from '@common/player/providers/html-media/use-html-media-internal-state';\nimport {useHtmlMediaEvents} from '@common/player/providers/html-media/use-html-media-events';\nimport {useHtmlMediaApi} from '@common/player/providers/html-media/use-html-media-api';\n\nexport function HtmlAudioProvider() {\n const ref = useRef<HTMLAudioElement>(null);\n\n const autoPlay = usePlayerStore(s => s.options.autoPlay);\n const muted = usePlayerStore(s => s.muted);\n const cuedMedia = usePlayerStore(s => s.cuedMedia);\n const store = useContext(PlayerStoreContext);\n\n const state = useHtmlMediaInternalState(ref);\n const events = useHtmlMediaEvents(state);\n const providerApi = useHtmlMediaApi(state);\n\n useEffect(() => {\n store.setState({\n providerApi,\n });\n }, [store, providerApi]);\n\n let src = cuedMedia?.src;\n if (src && cuedMedia?.initialTime) {\n src = `${src}#t=${cuedMedia.initialTime}`;\n }\n\n return (\n <audio\n className=\"w-full h-full\"\n ref={ref}\n src={src}\n autoPlay={autoPlay}\n muted={muted}\n {...events}\n />\n );\n}\n","import React, {memo, Suspense, useContext, useEffect} from 'react';\nimport {PlayerStoreContext} from '@common/player/player-context';\nimport {YoutubeProvider} from '@common/player/providers/youtube/youtube-provider';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {HtmlVideoProvider} from '@common/player/providers/html-video-provider';\nimport {HtmlAudioProvider} from '@common/player/providers/html-audio-provider';\n\nconst HlsProvider = React.lazy(\n () => import('@common/player/providers/hls-provider')\n);\nconst DashProvider = React.lazy(\n () => import('@common/player/providers/dash-provider')\n);\n\ninterface Props {\n className?: string;\n}\nexport const PlayerOutlet = memo(({className}: Props) => {\n const {getState} = useContext(PlayerStoreContext);\n\n useEffect(() => {\n getState().init();\n return getState().destroy;\n }, [getState]);\n\n return (\n <div className={className}>\n <Provider />\n </div>\n );\n});\n\nfunction Provider() {\n const provider = usePlayerStore(s => s.providerName);\n switch (provider) {\n case 'youtube':\n return <YoutubeProvider />;\n case 'htmlVideo':\n return <HtmlVideoProvider />;\n case 'htmlAudio':\n return <HtmlAudioProvider />;\n case 'hls':\n return (\n <Suspense>\n <HlsProvider />\n </Suspense>\n );\n case 'dash':\n return (\n <Suspense>\n <DashProvider />\n </Suspense>\n );\n default:\n return null;\n }\n}\n","import {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport clsx from 'clsx';\nimport {HTMLAttributes} from 'react';\n\ninterface Props extends HTMLAttributes<HTMLDivElement> {\n hideDuringPlayback?: boolean;\n}\nexport function PlayerPoster({\n className,\n hideDuringPlayback = true,\n ...domProps\n}: Props) {\n const posterUrl = usePlayerStore(s => s.posterUrl);\n const shouldHidePoster = usePlayerStore(\n s =>\n hideDuringPlayback && s.playbackStarted && s.providerName !== 'htmlAudio'\n );\n if (!posterUrl) return null;\n return (\n <div\n {...domProps}\n className={clsx(\n 'transition-opacity pointer-events-none flex items-center justify-center bg-black w-full max-h-full',\n shouldHidePoster ? 'opacity-0' : 'opacity-100',\n className\n )}\n >\n <img\n loading=\"lazy\"\n src={posterUrl}\n alt=\"\"\n className=\"w-full max-h-full object-cover flex-shrink-0\"\n />\n </div>\n );\n}\n","import {createSvgIcon} from '@common/icons/create-svg-icon';\n\nexport const MediaFullscreenIcon = createSvgIcon(\n [<path d=\"M25.3299 7.26517C25.2958 6.929 25.0119 6.66666 24.6667 6.66666H19.3334C18.9652 6.66666 18.6667 6.96514 18.6667 7.33333V9.33333C18.6667 9.70152 18.9652 10 19.3334 10L21.8667 10C21.9403 10 22 10.0597 22 10.1333V12.6667C22 13.0349 22.2985 13.3333 22.6667 13.3333H24.6667C25.0349 13.3333 25.3334 13.0349 25.3334 12.6667V7.33333C25.3334 7.31032 25.3322 7.28758 25.3299 7.26517Z\" key=\"0\"/>,<path d=\"M22 21.8667C22 21.9403 21.9403 22 21.8667 22L19.3334 22C18.9652 22 18.6667 22.2985 18.6667 22.6667V24.6667C18.6667 25.0349 18.9652 25.3333 19.3334 25.3333L24.6667 25.3333C25.0349 25.3333 25.3334 25.0349 25.3334 24.6667V19.3333C25.3334 18.9651 25.0349 18.6667 24.6667 18.6667H22.6667C22.2985 18.6667 22 18.9651 22 19.3333V21.8667Z\" key=\"1\"/>,<path d=\"M12.6667 22H10.1334C10.0597 22 10 21.9403 10 21.8667V19.3333C10 18.9651 9.70154 18.6667 9.33335 18.6667H7.33335C6.96516 18.6667 6.66669 18.9651 6.66669 19.3333V24.6667C6.66669 25.0349 6.96516 25.3333 7.33335 25.3333H12.6667C13.0349 25.3333 13.3334 25.0349 13.3334 24.6667V22.6667C13.3334 22.2985 13.0349 22 12.6667 22Z\" key=\"2\"/>,<path d=\"M10 12.6667V10.1333C10 10.0597 10.0597 10 10.1334 10L12.6667 10C13.0349 10 13.3334 9.70152 13.3334 9.33333V7.33333C13.3334 6.96514 13.0349 6.66666 12.6667 6.66666H7.33335C6.96516 6.66666 6.66669 6.96514 6.66669 7.33333V12.6667C6.66669 13.0349 6.96516 13.3333 7.33335 13.3333H9.33335C9.70154 13.3333 10 13.0349 10 12.6667Z\" key=\"3\"/>,],\n 'MediaFullscreen',\n '0 0 32 32'\n);\n","import {useCallback, useRef} from 'react';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\n\nexport function usePlayerClickHandler() {\n const clickRef = useRef(0);\n const player = usePlayerActions();\n\n const togglePlay = useCallback(() => {\n if (player.getState().isPlaying) {\n player.pause();\n } else {\n player.play();\n }\n }, [player]);\n\n return useCallback(() => {\n if (!player.getState().providerReady) return;\n clickRef.current += 1;\n togglePlay();\n if (clickRef.current === 1) {\n setTimeout(() => {\n if (clickRef.current > 1) {\n player.toggleFullscreen();\n }\n clickRef.current = 0;\n }, 300);\n }\n }, [player, togglePlay]);\n}\n","import React, {\n Fragment,\n MutableRefObject,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport clsx from 'clsx';\nimport {\n playerOverlayState,\n usePlayerOverlayStore,\n} from '@app/web-player/state/player-overlay-store';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {KeyboardArrowDownIcon} from '@common/icons/material/KeyboardArrowDown';\nimport {PlaybackControls} from '@app/web-player/player-controls/playback-controls';\nimport {useCuedTrack} from '@app/web-player/player-controls/use-cued-track';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {LikeIconButton} from '@app/web-player/library/like-icon-button';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {MoreVertIcon} from '@common/icons/material/MoreVert';\nimport fscreen from 'fscreen';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {LyricsButton} from '@app/web-player/player-controls/lyrics-button';\nimport {useMediaQuery} from '@common/utils/hooks/use-media-query';\nimport {DownloadTrackButton} from '@app/web-player/player-controls/download-track-button';\nimport {TrackLink} from '@app/web-player/tracks/track-link';\nimport {useLocation} from 'react-router-dom';\nimport {usePrevious} from '@common/utils/hooks/use-previous';\nimport {PlayerOutlet} from '@common/player/ui/player-outlet';\nimport {PlayerPoster} from '@common/player/ui/controls/player-poster';\nimport {MediaFullscreenIcon} from '@common/icons/media/media-fullscreen';\nimport {MediaQueueListIcon} from '@common/icons/media/media-queue-list';\nimport {useMiniPlayerIsHidden} from '@app/web-player/overlay/use-mini-player-is-hidden';\nimport {usePlayerClickHandler} from '@common/player/hooks/use-player-click-handler';\nimport {QueueTrackContextDialog} from '@app/web-player/layout/queue/queue-track-context-dialog';\nimport {RowElementProps} from '@common/ui/tables/table-row';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TableContext} from '@common/ui/tables/table-context';\nimport {MediaItem} from '@common/player/media-item';\n\nexport function PlayerOverlay() {\n const isMobile = useMediaQuery('(max-width: 1024px)');\n const isMaximized = usePlayerOverlayStore(s => s.isMaximized);\n const isQueueOpen = usePlayerOverlayStore(s => s.isQueueOpen);\n const isFullscreen = usePlayerStore(s => s.isFullscreen);\n const miniPlayerIsHidden = useMiniPlayerIsHidden();\n const overlayRef = useRef<HTMLDivElement>(null);\n const {pathname} = useLocation();\n const playerClickHandler = usePlayerClickHandler();\n const haveVideo = usePlayerStore(\n s => s.providerApi != null && s.providerName !== 'htmlAudio'\n );\n const previousPathname = usePrevious(pathname);\n\n // close overlay when route changes\n useEffect(() => {\n if (isMaximized && previousPathname && pathname !== previousPathname) {\n playerOverlayState.toggle();\n }\n }, [pathname, previousPathname, isMaximized]);\n\n useEffect(() => {\n if (!isMaximized) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n playerOverlayState.toggle();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isMaximized]);\n\n return (\n <div\n ref={overlayRef}\n className={clsx(\n 'fixed bg right-0 transition-all outline-none',\n miniPlayerIsHidden && !isMaximized && 'hidden',\n isMaximized\n ? 'bottom-0 w-full h-full flex flex-col pb-50 player-overlay-bg'\n : 'bottom-96 right-0 w-256 h-[213px]'\n )}\n >\n {isMaximized && (\n <div className=\"flex items-center flex-shrink-0 p-10 mb-10\">\n <IconButton\n iconSize=\"lg\"\n className=\"mr-auto\"\n onClick={() => playerOverlayState.toggle()}\n >\n <KeyboardArrowDownIcon />\n </IconButton>\n {isMobile && <LyricsButton />}\n {isMobile && <DownloadTrackButton />}\n <IconButton\n onClick={() => playerOverlayState.toggleQueue()}\n color={isQueueOpen ? 'primary' : undefined}\n >\n <MediaQueueListIcon />\n </IconButton>\n <FullscreenButton overlayRef={overlayRef} />\n </div>\n )}\n <div\n onClick={() => {\n // native video will be put into fullscreen, it will already handle click and double click events\n if (!isFullscreen) {\n playerClickHandler();\n }\n }}\n className={clsx(\n 'min-h-0 max-w-full flex-auto relative',\n isMaximized ? 'mx-auto px-14 mt-auto' : 'w-full h-full',\n isMaximized && haveVideo ? 'aspect-video' : 'aspect-square max-h-400'\n )}\n >\n <PlayerPoster className=\"absolute inset-0\" />\n <div\n className={haveVideo ? 'w-full h-full flex-auto bg-black' : undefined}\n >\n <PlayerOutlet className=\"w-full h-full\" />\n </div>\n </div>\n {isMaximized && (\n <Fragment>\n <QueuedTrack />\n <PlaybackControls className=\"container mx-auto px-14 flex-shrink-0 mb-auto\" />\n </Fragment>\n )}\n {isMaximized && isQueueOpen && <PlayerQueue />}\n </div>\n );\n}\n\ninterface FullscreenButtonProps {\n overlayRef: MutableRefObject<HTMLDivElement | null>;\n}\nfunction FullscreenButton({overlayRef}: FullscreenButtonProps) {\n const playerReady = usePlayerStore(s => s.providerReady);\n const isMobile = useIsMobileMediaQuery();\n if (!fscreen.fullscreenEnabled || isMobile) {\n return null;\n }\n\n return (\n <IconButton\n className=\"flex-shrink-0 ml-12\"\n disabled={!playerReady}\n onClick={() => {\n if (!overlayRef.current) return;\n if (fscreen.fullscreenElement) {\n fscreen.exitFullscreen();\n } else {\n fscreen.requestFullscreen(overlayRef.current);\n }\n }}\n >\n <MediaFullscreenIcon />\n </IconButton>\n );\n}\n\nfunction QueuedTrack() {\n const track = useCuedTrack();\n const isMobile = useIsMobileMediaQuery();\n\n if (!track) {\n return null;\n }\n\n return (\n <div\n className={clsx(\n 'container mx-auto px-14 flex-shrink-0 flex items-center justify-center gap-34',\n isMobile ? 'my-40' : 'my-60'\n )}\n >\n <LikeIconButton likeable={track} />\n <div className=\"text-center min-w-0\">\n <div className=\"text-base whitespace-nowrap overflow-hidden overflow-ellipsis\">\n <TrackLink track={track} />\n </div>\n <div className=\"text-sm text-muted\">\n <ArtistLinks artists={track.artists} />\n </div>\n </div>\n <DialogTrigger type=\"popover\">\n <IconButton>\n <MoreVertIcon />\n </IconButton>\n <TrackContextDialog tracks={[track]} />\n </DialogTrigger>\n </div>\n );\n}\n\nfunction PlayerQueue() {\n const queue = usePlayerStore(s => s.shuffledQueue);\n const tracks = queue.map(item => item.meta);\n return (\n <div className=\"bg-inherit fixed top-70 left-0 right-0 bottom-0 px-14 md:px-50 overflow-y-auto\">\n <TrackTable\n tracks={tracks}\n queueGroupId={queue[0]?.groupId}\n renderRowAs={PlayerQueueRow}\n />\n </div>\n );\n}\n\nfunction PlayerQueueRow({item, children, ...domProps}: RowElementProps<Track>) {\n const queue = usePlayerStore(s => s.shuffledQueue);\n const {selectedRows} = useContext(TableContext);\n const queueItems = useMemo(() => {\n return selectedRows\n .map(trackId => queue.find(item => item.meta.id === trackId))\n .filter(t => !!t) as MediaItem[];\n }, [queue, selectedRows]);\n\n const row = <div {...domProps}>{children}</div>;\n if (item.isPlaceholder) {\n return row;\n }\n\n return (\n <DialogTrigger type=\"popover\" triggerOnContextMenu placement=\"bottom-start\">\n {row}\n <QueueTrackContextDialog queueItems={queueItems} />\n </DialogTrigger>\n );\n}\n","import {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {Item} from '@common/ui/forms/listbox/item';\nimport {ComboBox} from '@common/ui/forms/combobox/combobox';\nimport React, {cloneElement, ReactElement, useState} from 'react';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {useSearchResults} from '@app/web-player/search/requests/use-search-results';\nimport {ARTIST_MODEL} from '@app/web-player/artists/artist';\nimport {ALBUM_MODEL} from '@app/web-player/albums/album';\nimport {TRACK_MODEL} from '@app/web-player/tracks/track';\nimport {USER_MODEL} from '@common/auth/user';\nimport {PLAYLIST_MODEL} from '@app/web-player/playlists/playlist';\nimport {Section} from '@common/ui/forms/listbox/section';\nimport {Trans} from '@common/i18n/trans';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {\n getUserProfileLink,\n UserProfileLink,\n} from '@app/web-player/users/user-profile-link';\nimport {AlbumLink, getAlbumLink} from '@app/web-player/albums/album-link';\nimport {ArtistLink, getArtistLink} from '@app/web-player/artists/artist-link';\nimport {getTrackLink, TrackLink} from '@app/web-player/tracks/track-link';\nimport {UserImage} from '@app/web-player/users/user-image';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {PlayableModel} from '@app/web-player/playable-item/playable-model';\nimport clsx from 'clsx';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {\n getPlaylistLink,\n PlaylistLink,\n} from '@app/web-player/playlists/playlist-link';\nimport {PlaylistImage} from '@app/web-player/playlists/playlist-image';\nimport {PlaylistOwnerName} from '@app/web-player/playlists/playlist-grid-item';\nimport {useListboxContext} from '@common/ui/forms/listbox/listbox-context';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {useParams} from 'react-router-dom';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {ArtistContextDialog} from '@app/web-player/artists/artist-context-dialog';\nimport {AlbumContextDialog} from '@app/web-player/albums/album-context-dialog';\nimport {TrackContextDialog} from '@app/web-player/tracks/context-dialog/track-context-dialog';\nimport {PlaylistContextDialog} from '@app/web-player/playlists/playlist-context-dialog';\n\nexport const mainSearchModels = [\n ARTIST_MODEL,\n ALBUM_MODEL,\n TRACK_MODEL,\n USER_MODEL,\n PLAYLIST_MODEL,\n];\n\ninterface SearchAutocompleteProps {\n className?: string;\n}\nexport function SearchAutocomplete({className}: SearchAutocompleteProps) {\n const {searchQuery} = useParams();\n const {trans} = useTrans();\n const navigate = useNavigate();\n const [query, setQuery] = useState(searchQuery || '');\n const [isOpen, setIsOpen] = useState(false);\n const {isFetching, data} = useSearchResults({\n query,\n types: mainSearchModels,\n limit: 3,\n });\n\n return (\n <form\n onSubmit={e => {\n e.preventDefault();\n if (query.trim().length) {\n setIsOpen(false);\n navigate(`/search/${query.trim()}`);\n }\n }}\n className={clsx('flex items-center gap-14 flex-auto', className)}\n >\n <button type=\"submit\" aria-label={trans(message('Search'))}>\n <SearchIcon className=\"text-muted flex-shrink-0\" />\n </button>\n <ComboBox\n unstyled\n className=\"w-full max-w-780 flex-auto\"\n offset={12}\n inputClassName=\"w-full outline-none bg-transparent h-42 placeholder:text-muted\"\n hideEndAdornment\n inputBorder=\"border-none\"\n isAsync\n placeholder={trans(message('Search'))}\n isLoading={isFetching}\n inputValue={query}\n onInputValueChange={setQuery}\n clearInputOnItemSelection\n blurReferenceOnItemSelection\n selectionMode=\"none\"\n openMenuOnFocus\n floatingMaxHeight={670}\n isOpen={isOpen}\n onOpenChange={setIsOpen}\n >\n {Object.entries(data?.results || {}).map(([groupName, results]) => (\n <Section key={groupName} label={<Trans message={groupName} />}>\n {results.map(result => {\n const key = `${groupName}-${result.id}`;\n switch (result.model_type) {\n case ARTIST_MODEL:\n return (\n <Item\n key={key}\n value={key}\n onSelected={() => {\n navigate(getArtistLink(result));\n }}\n startIcon={\n <PlayableImage\n model={result}\n className=\"rounded-full\"\n value={key}\n >\n <SmallArtistImage artist={result} />\n </PlayableImage>\n }\n description={<Trans message=\"Artist\" />}\n textLabel={result.name}\n >\n <DialogTrigger type=\"popover\" triggerOnContextMenu>\n <div>\n <ArtistLink artist={result} />\n </div>\n <ArtistContextDialog artist={result} />\n </DialogTrigger>\n </Item>\n );\n case ALBUM_MODEL:\n return (\n <Item\n key={key}\n value={key}\n onSelected={() => {\n navigate(getAlbumLink(result));\n }}\n startIcon={\n <PlayableImage model={result} value={key}>\n <AlbumImage album={result} />\n </PlayableImage>\n }\n description={<ArtistLinks artists={result.artists} />}\n textLabel={result.name}\n >\n <DialogTrigger type=\"popover\" triggerOnContextMenu>\n <div>\n <AlbumLink album={result} />\n </div>\n <AlbumContextDialog album={result} />\n </DialogTrigger>\n </Item>\n );\n case TRACK_MODEL:\n return (\n <Item\n key={key}\n value={key}\n onSelected={() => {\n navigate(getTrackLink(result));\n }}\n startIcon={\n <PlayableImage model={result} value={key}>\n <TrackImage track={result} />\n </PlayableImage>\n }\n description={<ArtistLinks artists={result.artists} />}\n textLabel={result.name}\n >\n <DialogTrigger type=\"popover\" triggerOnContextMenu>\n <div>\n <TrackLink track={result} />\n </div>\n <TrackContextDialog tracks={[result]} />\n </DialogTrigger>\n </Item>\n );\n case USER_MODEL:\n return (\n <Item\n key={key}\n value={key}\n onSelected={() => {\n navigate(getUserProfileLink(result));\n }}\n startIcon={\n <UserImage className=\"w-48 h-48\" user={result} />\n }\n description={\n result.followers_count ? (\n <Trans\n message=\":count followers\"\n values={{count: result.followers_count}}\n />\n ) : null\n }\n textLabel={result.display_name}\n >\n <UserProfileLink user={result} />\n </Item>\n );\n case PLAYLIST_MODEL:\n return (\n <Item\n key={key}\n value={key}\n onSelected={() => {\n navigate(getPlaylistLink(result));\n }}\n startIcon={\n <PlayableImage model={result} value={key}>\n <PlaylistImage playlist={result} />\n </PlayableImage>\n }\n description={<PlaylistOwnerName playlist={result} />}\n textLabel={result.name}\n >\n <DialogTrigger type=\"popover\" triggerOnContextMenu>\n <div>\n <PlaylistLink playlist={result} />\n </div>\n <PlaylistContextDialog playlist={result} />\n </DialogTrigger>\n </Item>\n );\n }\n })}\n </Section>\n ))}\n </ComboBox>\n </form>\n );\n}\n\ninterface PlayableImageProps {\n children: ReactElement<{size: string; className?: string}>;\n model: PlayableModel;\n className?: string;\n value: string;\n}\nfunction PlayableImage({\n children,\n model,\n className,\n value,\n}: PlayableImageProps) {\n const {\n collection,\n state: {activeIndex},\n } = useListboxContext();\n const index = collection.get(value)?.index;\n const isActive = activeIndex === index;\n\n const queueId = queueGroupId(model);\n const isPlaying = usePlayerStore(\n s => s.isPlaying && s.originalQueue[0]?.groupId === queueId\n );\n\n return (\n <div\n className={clsx(className, 'relative w-48 h-48 overflow-hidden')}\n onClick={e => {\n e.preventDefault();\n e.stopPropagation();\n }}\n >\n {cloneElement(children, {\n size: 'w-full h-full',\n })}\n <AnimatePresence>\n {isActive || isPlaying ? (\n <m.div\n key=\"play-overlay\"\n {...opacityAnimation}\n transition={{duration: 0.24}}\n className=\"absolute w-full h-full inset-0 bg-black/60 m-auto flex items-center justify-center\"\n >\n <PlaybackToggleButton\n buttonType=\"icon\"\n color=\"white\"\n equalizerColor=\"white\"\n track={model.model_type === TRACK_MODEL ? model : undefined}\n queueId={queueId}\n />\n </m.div>\n ) : null}\n </AnimatePresence>\n </div>\n );\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {useAuth} from '@common/auth/use-auth';\nimport React, {Fragment, useMemo} from 'react';\nimport {Button} from '@common/ui/buttons/button';\nimport {Link} from 'react-router-dom';\nimport {Trans} from '@common/i18n/trans';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {usePrimaryArtistForCurrentUser} from '@app/web-player/backstage/use-primary-artist-for-current-user';\nimport {MenuItem} from '@common/ui/navigation/menu/menu-trigger';\nimport {MicIcon} from '@common/icons/material/Mic';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {Navbar} from '@common/ui/navigation/navbar/navbar';\nimport {SearchAutocomplete} from '@app/web-player/search/search-autocomplete';\n\nexport function PlayerNavbar() {\n const navigate = useNavigate();\n const primaryArtist = usePrimaryArtistForCurrentUser();\n const {player} = useSettings();\n const menuItems = useMemo(() => {\n if (primaryArtist) {\n return [\n <MenuItem\n value=\"author\"\n key=\"author\"\n startIcon={<MicIcon />}\n onSelected={() => {\n navigate(getArtistLink(primaryArtist));\n }}\n >\n <Trans message=\"Artist profile\" />\n </MenuItem>,\n ];\n }\n if (player?.show_become_artist_btn) {\n return [\n <MenuItem\n value=\"author\"\n key=\"author\"\n startIcon={<MicIcon />}\n onSelected={() => {\n navigate('/backstage/requests');\n }}\n >\n <Trans message=\"Become an author\" />\n </MenuItem>,\n ];\n }\n\n return [];\n }, [primaryArtist, navigate, player?.show_become_artist_btn]);\n\n return (\n <Navbar\n hideLogo\n color=\"bg\"\n darkModeColor=\"bg\"\n size=\"sm\"\n authMenuItems={menuItems}\n className=\"dashboard-grid-header\"\n >\n <SearchAutocomplete />\n <ActionButtons />\n </Navbar>\n );\n}\n\nfunction ActionButtons() {\n const {player, billing} = useSettings();\n const {isLoggedIn, hasPermission, isSubscribed} = useAuth();\n\n const showUploadButton =\n player?.show_upload_btn && isLoggedIn && hasPermission('music.create');\n const showTryProButton =\n billing?.enable && hasPermission('plans.view') && !isSubscribed;\n\n return (\n <Fragment>\n {showTryProButton ? (\n <Button\n variant=\"outline\"\n size=\"xs\"\n color=\"primary\"\n elementType={Link}\n to=\"/pricing\"\n >\n <Trans message=\"Try Pro\" />\n </Button>\n ) : null}\n {showUploadButton ? (\n <Button\n variant={showTryProButton ? 'text' : 'outline'}\n size=\"xs\"\n color={showTryProButton ? undefined : 'primary'}\n elementType={Link}\n to=\"/backstage/upload\"\n >\n <Trans message=\"Upload\" />\n </Button>\n ) : null}\n </Fragment>\n );\n}\n","import {Outlet} from 'react-router-dom';\nimport {PlayerContext} from '@common/player/player-context';\nimport {playerStoreOptions} from '@app/web-player/state/player-store-options';\nimport React, {useContext} from 'react';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {DashboardLayout} from '@common/ui/layout/dashboard-layout';\nimport {DashboardSidenav} from '@common/ui/layout/dashboard-sidenav';\nimport {Sidenav} from '@app/web-player/layout/sidenav';\nimport {DashboardContent} from '@common/ui/layout/dashboard-content';\nimport {QueueSidenav} from '@app/web-player/layout/queue/queue-sidenav';\nimport clsx from 'clsx';\nimport {useMediaQuery} from '@common/utils/hooks/use-media-query';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {MobilePlayerControls} from '@app/web-player/player-controls/mobile-player-controls';\nimport {DesktopPlayerControls} from '@app/web-player/player-controls/desktop-player-controls';\nimport {PlayerOverlay} from '@app/web-player/overlay/player-overlay';\nimport {DashboardLayoutContext} from '@common/ui/layout/dashboard-layout-context';\nimport {PlayerNavbar} from '@app/web-player/layout/player-navbar';\n\nexport function WebPlayerLayout() {\n const {player} = useSettings();\n const isMobile = useIsMobileMediaQuery();\n\n return (\n <PlayerContext id=\"web-player\" options={playerStoreOptions}>\n <DashboardLayout\n name=\"web-player\"\n initialRightSidenavStatus={player?.hide_queue ? 'closed' : 'open'}\n >\n {!isMobile && <PlayerNavbar />}\n {!isMobile && (\n <DashboardSidenav position=\"left\" display=\"block\">\n <Sidenav />\n </DashboardSidenav>\n )}\n <DashboardContent>\n <Main />\n </DashboardContent>\n {!isMobile && <RightSidenav />}\n <PlayerControlsBar />\n </DashboardLayout>\n <PlayerOverlay />\n </PlayerContext>\n );\n}\n\nfunction PlayerControlsBar() {\n const {isMobileMode} = useContext(DashboardLayoutContext);\n if (isMobileMode) {\n return <MobilePlayerControls />;\n }\n return <DesktopPlayerControls />;\n}\n\ninterface MainProps {\n className?: string;\n}\nfunction Main({className}: MainProps) {\n const isMobile = useIsMobileMediaQuery();\n return (\n <main\n className={clsx(\n 'overflow-x-hidden relative stable-scrollbar',\n className,\n // mobile player controls are fixed to bottom of screen,\n // make sure we can scroll to the bottom of the page\n isMobile && 'pb-124'\n )}\n >\n <div className=\"web-player-container @container min-h-full mx-auto p-16 md:p-30\">\n <Outlet />\n </div>\n </main>\n );\n}\n\nfunction RightSidenav() {\n const isOverlay = useMediaQuery('(max-width: 1280px)');\n const hideQueue = usePlayerStore(s => !s.shuffledQueue.length);\n return (\n <DashboardSidenav\n position=\"right\"\n size=\"w-256\"\n mode={isOverlay ? 'overlay' : undefined}\n overlayPosition=\"absolute\"\n display=\"block\"\n forceClosed={hideQueue}\n >\n <QueueSidenav />\n </DashboardSidenav>\n );\n}\n","import React, {cloneElement, ReactElement, ReactNode} from 'react';\nimport clsx from 'clsx';\n\ninterface MediaPageHeaderLayoutProps {\n className?: string;\n image: ReactElement<{size: string; className?: string}>;\n title: ReactNode;\n subtitle?: ReactNode;\n description?: ReactNode;\n actionButtons?: ReactNode;\n centerItems?: boolean;\n footer?: ReactNode;\n}\nexport function MediaPageHeaderLayout({\n className,\n image,\n title,\n subtitle,\n description,\n actionButtons,\n footer,\n centerItems = false,\n}: MediaPageHeaderLayoutProps) {\n return (\n <header\n className={clsx(\n 'flex flex-col md:flex-row gap-24 md:gap-34',\n centerItems && 'items-center',\n className\n )}\n >\n {cloneElement(image, {\n size: image.props.size || 'w-256 h-256',\n className: clsx(image.props.className, 'mx-auto flex-shrink-0'),\n })}\n <div className=\"flex-auto min-w-0\">\n <h1 className=\"text-2xl md:text-4xl font-semibold mb-14 text-center md:text-start\">\n {title}\n </h1>\n {subtitle && <div className=\"w-max mx-auto md:mx-0\">{subtitle}</div>}\n {description ? (\n <div className=\"text-muted mt-18 md:mt-26 text-sm w-max mx-auto md:mx-0\">\n {description}\n </div>\n ) : null}\n <div className=\"mt-30\">{actionButtons}</div>\n {footer ? <div className=\"mt-30\">{footer}</div> : null}\n </div>\n </header>\n );\n}\n\ninterface ActionButtonClassNameProps {\n isFirst?: boolean;\n}\nexport function actionButtonClassName({\n isFirst,\n}: ActionButtonClassNameProps = {}) {\n return clsx('min-h-40', isFirst ? 'min-w-128 mr-20' : 'mr-10 min-w-100');\n}\n","import {isAbsoluteUrl} from '../utils/urls/is-absolute-url';\nimport memoize from 'nano-memoize';\nimport clsx from 'clsx';\n\ninterface RemoteFaviconProps {\n url: string;\n className?: string;\n size?: string;\n alt?: string;\n}\nexport function RemoteFavicon({\n url,\n className,\n size = 'w-16 h-16',\n alt,\n}: RemoteFaviconProps) {\n if (!url) {\n return null;\n }\n\n const src = getFaviconSrc(url);\n\n return (\n <img\n className={clsx(size, className)}\n src={getFaviconSrc(url)}\n alt={alt || `${src} favicon`}\n />\n );\n}\n\nconst getFaviconSrc = memoize((url: string): string => {\n if (url.includes('youtube')) {\n return 'https://www.youtube.com/s/desktop/ca54e1bd/img/favicon.ico';\n }\n\n // relative url to current site\n if (!isAbsoluteUrl(url)) {\n url = `${window.location.protocol}//${window.location.host}`;\n }\n const domain = new URL(url).origin;\n return 'https://www.google.com/s2/favicons?domain=' + domain;\n});\n","import {UserLink} from '@app/web-player/user-profile/user-link';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {RemoteFavicon} from '@common/ui/remote-favicon';\nimport {IconButton} from '@common/ui/buttons/icon-button';\n\ninterface ProfileLinksProps {\n links?: UserLink[];\n}\nexport function ProfileLinks({links}: ProfileLinksProps) {\n if (!links?.length) return null;\n return (\n <div className=\"flex items-center\">\n {links.map(link => (\n <Tooltip label={link.title} key={link.url}>\n <IconButton\n size=\"xs\"\n elementType=\"a\"\n href={link.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <RemoteFavicon url={link.url} alt={link.title} />\n </IconButton>\n </Tooltip>\n ))}\n </div>\n );\n}\n","import {UserProfile} from '@app/web-player/user-profile/user-profile';\nimport {UserLink} from '@app/web-player/user-profile/user-link';\nimport {ProfileLinks} from '@app/web-player/user-profile/profile-links';\n\ninterface Props {\n profile?: UserProfile;\n links?: UserLink[];\n shortDescription?: boolean;\n}\nexport function ProfileDescription({profile, links, shortDescription}: Props) {\n if (!profile) return null;\n return (\n <div className=\"text-sm\">\n {profile.description && (\n <div\n className=\"p-10 rounded bg-alt/80 dark:bg text-secondary max-w-720\"\n dangerouslySetInnerHTML={{\n __html: shortDescription\n ? profile.description.slice(0, 300)\n : profile.description,\n }}\n />\n )}\n {profile.city || profile.country || links?.length ? (\n <div className=\"flex items-center gap-24 justify-between mt-20\">\n {(profile.city || profile.country) && (\n <div className=\"p-10 rounded bg-alt/80 dark:bg text-secondary w-max\">\n {profile.city}\n {profile.city && ','} {profile.country}\n </div>\n )}\n <ProfileLinks links={links} />\n </div>\n ) : null}\n </div>\n );\n}\n","import {Genre} from '@app/web-player/genres/genre';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {Button} from '@common/ui/buttons/button';\nimport {Trans} from '@common/i18n/trans';\nimport {ArrowDropDownIcon} from '@common/icons/material/ArrowDropDown';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {LikeButton} from '@app/web-player/library/like-button';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {GenreLink} from '@app/web-player/genres/genre-link';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {ArtistContextDialog} from '@app/web-player/artists/artist-context-dialog';\nimport {ProfileDescription} from '@app/web-player/user-profile/profile-description';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {MediaItemStats} from '@app/web-player/tracks/media-item-stats';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\n\ninterface ArtistPageHeaderProps {\n artist: Artist;\n}\nexport function ArtistPageHeader({artist}: ArtistPageHeaderProps) {\n const {artistPage} = useSettings();\n const isMobile = useIsMobileMediaQuery();\n return (\n <MediaPageHeaderLayout\n centerItems\n image={\n <SmallArtistImage\n showVerifiedBadge\n artist={artist}\n className=\"rounded-full shadow-lg object-cover\"\n />\n }\n title={artist.name}\n subtitle={<GenreList genres={artist.genres} />}\n actionButtons={\n <div className=\"flex items-center gap-24 justify-center md:justify-between\">\n <ActionButtons artist={artist} />\n {!isMobile && <MediaItemStats item={artist} />}\n </div>\n }\n footer={\n artistPage.showDescription && (\n <ProfileDescription\n profile={artist.profile}\n links={artist.links}\n shortDescription\n />\n )\n }\n />\n );\n}\n\ninterface GenreListProps {\n genres?: Genre[];\n}\nfunction GenreList({genres}: GenreListProps) {\n const isMobile = useIsMobileMediaQuery();\n if (isMobile) {\n return null;\n }\n return (\n <ul className=\"flex items-center justify-start gap-14 text-muted text-sm max-w-620 overflow-hidden overflow-ellipsis whitespace-nowrap\">\n {genres?.slice(0, 5).map(genre => (\n <li key={genre.id}>\n <GenreLink genre={genre} />\n </li>\n ))}\n </ul>\n );\n}\n\ninterface ActionButtonsProps {\n artist: Artist;\n}\nfunction ActionButtons({artist}: ActionButtonsProps) {\n const isMobile = useIsMobileMediaQuery();\n return (\n <div>\n <PlaybackToggleButton\n queueId={queueGroupId(artist)}\n buttonType=\"text\"\n className={actionButtonClassName({isFirst: true})}\n />\n {!isMobile && (\n <LikeButton likeable={artist} className={actionButtonClassName()} />\n )}\n <DialogTrigger type=\"popover\">\n <Button\n variant=\"outline\"\n radius=\"rounded-full\"\n endIcon={<ArrowDropDownIcon />}\n className={actionButtonClassName()}\n >\n <Trans message=\"More\" />\n </Button>\n <ArtistContextDialog artist={artist} />\n </DialogTrigger>\n </div>\n );\n}\n","import {useMemo, useState} from 'react';\nimport {Trans} from '@common/i18n/trans';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {Button} from '@common/ui/buttons/button';\nimport {Track} from '@app/web-player/tracks/track';\n\ninterface TopTracksTableProps {\n tracks?: Track[];\n}\nexport function TopTracksTable({tracks: initialTracks}: TopTracksTableProps) {\n const [showingAll, setShowingAll] = useState(false);\n\n const topTracks = useMemo(() => {\n return {\n all: initialTracks || [],\n sliced: initialTracks?.slice(0, 5) || [],\n };\n }, [initialTracks]);\n\n return (\n <div className=\"flex-auto\">\n <h2 className=\"text-muted text-base my-16\">\n <Trans message=\"Popular songs\" />\n </h2>\n <TrackTable\n tracks={showingAll ? topTracks.all : topTracks.sliced}\n hideArtist\n hideAlbum\n hideHeaderRow\n />\n <Button\n radius=\"rounded-full\"\n className=\"mt-20\"\n variant=\"outline\"\n onClick={() => {\n setShowingAll(!showingAll);\n }}\n >\n {showingAll ? (\n <Trans message=\"Show less\" />\n ) : (\n <Trans message=\"Show more\" />\n )}\n </Button>\n </div>\n );\n}\n","import {useParams} from 'react-router-dom';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Album} from '@app/web-player/albums/album';\nimport {assignAlbumToTracks} from '@app/web-player/albums/assign-album-to-tracks';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\n\nexport type AlbumViewMode = 'list' | 'grid';\n\nexport const albumListViewPerPage = 5;\nexport const albumGridViewPerPage = 25;\n\nexport function useArtistAlbums(\n initialPage: PaginationResponse<Album> | null,\n viewMode: AlbumViewMode\n) {\n const {artistId} = useParams();\n\n return useInfiniteData<Album>({\n endpoint: `artists/${artistId}/albums`,\n queryKey: ['artists', +artistId!, 'albums', viewMode],\n paginate: 'simple',\n initialPage,\n transformResponse: response => {\n response.pagination.data = response.pagination.data.map(album =>\n assignAlbumToTracks(album)\n );\n return response;\n },\n });\n}\n","import {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {AlbumIcon} from '@common/icons/material/Album';\nimport {Trans} from '@common/i18n/trans';\n\nexport function NoDiscographyMessage() {\n return (\n <IllustratedMessage\n className=\"my-80\"\n imageHeight=\"h-auto\"\n image={<AlbumIcon size=\"xl\" className=\"text-muted\" />}\n title={<Trans message=\"We do not have discography for this artist yet\" />}\n />\n );\n}\n","import {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Album} from '@app/web-player/albums/album';\nimport {useArtistAlbums} from '@app/web-player/artists/requests/use-artist-albums';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {AlbumLink} from '@app/web-player/albums/album-link';\nimport {FormattedDate} from '@common/i18n/formatted-date';\nimport {Button} from '@common/ui/buttons/button';\nimport {ArrowDropDownIcon} from '@common/icons/material/ArrowDropDown';\nimport {Trans} from '@common/i18n/trans';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {NoDiscographyMessage} from '@app/web-player/artists/artist-page/discography-panel/no-discography-message';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {AlbumContextDialog} from '@app/web-player/albums/album-context-dialog';\nimport {useSortableTableData} from '@common/ui/tables/use-sortable-table-data';\n\ninterface ArtistAlbumsListProps {\n artist: Artist;\n initialAlbums: PaginationResponse<Album> | null;\n}\nexport function ArtistAlbumsList({initialAlbums}: ArtistAlbumsListProps) {\n const query = useArtistAlbums(initialAlbums, 'list');\n const {isInitialLoading, items} = query;\n\n if (!isInitialLoading && !items.length) {\n return <NoDiscographyMessage />;\n }\n\n return (\n <section>\n {items.map(album => (\n <div key={album.id} className=\"mb-40\">\n <div className=\"flex items-center gap-14 mb-20\">\n <AlbumImage\n album={album}\n size=\"w-110 h-110\"\n className=\"rounded object-cover flex-shrink-0\"\n />\n <div className=\"flex-auto\">\n <h4 className=\"font-semibold text-lg whitespace-nowrap min-w-0 overflow-hidden overflow-ellipsis\">\n <AlbumLink album={album} />\n </h4>\n {album.release_date && (\n <div className=\"text-muted text-sm mt-2 mb-18\">\n <FormattedDate date={album.release_date} />\n </div>\n )}\n <DialogTrigger type=\"popover\" offset={10}>\n <Button\n variant=\"outline\"\n size=\"xs\"\n radius=\"rounded-full\"\n endIcon={<ArrowDropDownIcon />}\n >\n <Trans message=\"More\" />\n </Button>\n <AlbumContextDialog album={album} />\n </DialogTrigger>\n </div>\n </div>\n <AlbumTrackTable album={album} />\n </div>\n ))}\n <InfiniteScrollSentinel query={query} />\n </section>\n );\n}\n\ninterface AlbumTrackTableProps {\n album: Album;\n}\nfunction AlbumTrackTable({album}: AlbumTrackTableProps) {\n const {data, sortDescriptor, onSortChange} = useSortableTableData(\n album.tracks\n );\n return (\n <TrackTable\n tracks={data}\n hideArtist\n hideAlbum\n hideTrackImage\n sortDescriptor={sortDescriptor}\n onSortChange={onSortChange}\n queueGroupId={queueGroupId(album, '*', sortDescriptor)}\n />\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Album} from '@app/web-player/albums/album';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\nimport {useArtistAlbums} from '@app/web-player/artists/requests/use-artist-albums';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {NoDiscographyMessage} from '@app/web-player/artists/artist-page/discography-panel/no-discography-message';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\n\ninterface ArtistAlbumsGridProps {\n artist: Artist;\n initialAlbums: PaginationResponse<Album> | null;\n}\nexport function ArtistAlbumsGrid({initialAlbums}: ArtistAlbumsGridProps) {\n const query = useArtistAlbums(initialAlbums, 'grid');\n\n if (!query.isInitialLoading && !query.items.length) {\n return <NoDiscographyMessage />;\n }\n\n return (\n <ContentGrid>\n {query.items.map(album => (\n <AlbumGridItem key={album.id} album={album} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </ContentGrid>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {Trans} from '@common/i18n/trans';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {Link} from 'react-router-dom';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {TopTracksTable} from '@app/web-player/artists/artist-page/discography-panel/top-tracks-table';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Album} from '@app/web-player/albums/album';\nimport {ArtistAlbumsList} from '@app/web-player/artists/artist-page/discography-panel/artist-albums-list';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {ViewAgendaIcon} from '@common/icons/material/ViewAgenda';\nimport {GridViewIcon} from '@common/icons/material/GridView';\nimport {useLocalStorage} from '@common/utils/hooks/local-storage';\nimport {ArtistAlbumsGrid} from '@app/web-player/artists/artist-page/discography-panel/artist-albums-grid';\nimport {Tooltip} from '@common/ui/tooltip/tooltip';\nimport {\n albumGridViewPerPage,\n albumListViewPerPage,\n AlbumViewMode,\n} from '@app/web-player/artists/requests/use-artist-albums';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {AdHost} from '@common/admin/ads/ad-host';\nimport React from 'react';\n\ninterface DiscographyTabProps {\n artist: Artist;\n initialAlbums?: PaginationResponse<Album>;\n}\nexport function DiscographyTab({artist, initialAlbums}: DiscographyTabProps) {\n const {player} = useSettings();\n const [viewMode, setViewMode] = useLocalStorage<AlbumViewMode>(\n 'artistPage.albumLayout',\n player?.default_artist_view || 'list'\n );\n return (\n <div>\n <Header artist={artist} />\n <AdHost slot=\"artist_bottom\" className=\"mt-34\" />\n <div className=\"mt-44\">\n <div className=\"flex items-center border-b pb-4 mb-30 text-muted\">\n <h2 className=\"text-base mr-auto\">\n <Trans message=\"Albums\" />\n </h2>\n <Tooltip label={<Trans message=\"List view\" />}>\n <IconButton\n className=\"ml-24 flex-shrink-0\"\n color={viewMode === 'list' ? 'primary' : undefined}\n onClick={() => setViewMode('list')}\n >\n <ViewAgendaIcon />\n </IconButton>\n </Tooltip>\n <Tooltip label={<Trans message=\"Grid view\" />}>\n <IconButton\n className=\"flex-shrink-0\"\n color={viewMode === 'grid' ? 'primary' : undefined}\n onClick={() => setViewMode('grid')}\n >\n <GridViewIcon />\n </IconButton>\n </Tooltip>\n </div>\n {viewMode === 'list' ? (\n <ArtistAlbumsList\n artist={artist}\n initialAlbums={\n initialAlbums?.per_page === albumListViewPerPage\n ? initialAlbums\n : null\n }\n />\n ) : (\n <ArtistAlbumsGrid\n artist={artist}\n initialAlbums={\n initialAlbums?.per_page === albumGridViewPerPage\n ? initialAlbums\n : null\n }\n />\n )}\n </div>\n </div>\n );\n}\n\ninterface HeaderProps {\n artist: Artist;\n}\nfunction Header({artist}: HeaderProps) {\n const isMobile = useIsMobileMediaQuery();\n if (!artist.top_tracks?.length) return null;\n const similarArtists = artist.similar?.slice(0, 4) || [];\n\n return (\n <div className=\"flex items-start gap-30\">\n <TopTracksTable tracks={artist.top_tracks} />\n {!isMobile && (\n <div className=\"w-1/3 max-w-320\">\n <h2 className=\"text-muted text-base my-16\">\n <Trans message=\"Similar artists\" />\n </h2>\n <div>\n {similarArtists.map(similar => (\n <Link\n key={similar.id}\n to={getArtistLink(similar)}\n className=\"flex items-center gap-14 block p-4 mb-4 rounded hover:bg-hover cursor-pointer\"\n >\n <SmallArtistImage\n artist={similar}\n className=\"w-44 h-44 object-cover rounded-full\"\n />\n <div className=\"text-sm\">{similar.name}</div>\n </Link>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {ArtistGridItem} from '@app/web-player/artists/artist-grid-item';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\n\ninterface SimilarArtistsTabProps {\n artist: Artist;\n}\nexport function SimilarArtistsPanel({artist}: SimilarArtistsTabProps) {\n return (\n <ContentGrid>\n {artist.similar?.map(similar => (\n <ArtistGridItem key={similar.id} artist={similar} />\n ))}\n </ContentGrid>\n );\n}\n","import { Options, tokenize } from 'linkifyjs';\n\n/**\n\tConvert strings of text into linkable HTML text\n*/\nfunction escapeText(text) {\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\nfunction escapeAttr(href) {\n return href.replace(/\"/g, '"');\n}\nfunction attributesToString(attributes) {\n const result = [];\n for (const attr in attributes) {\n let val = attributes[attr] + '';\n result.push(`${attr}=\"${escapeAttr(val)}\"`);\n }\n return result.join(' ');\n}\nfunction defaultRender(_ref) {\n let {\n tagName,\n attributes,\n content\n } = _ref;\n return `<${tagName} ${attributesToString(attributes)}>${escapeText(content)}</${tagName}>`;\n}\n\n/**\n * Convert a plan text string to an HTML string with links. Expects that the\n * given strings does not contain any HTML entities. Use the linkify-html\n * interface if you need to parse HTML entities.\n *\n * @param {string} str string to linkify\n * @param {import('linkifyjs').Opts} [opts] overridable options\n * @returns {string}\n */\nfunction linkifyStr(str, opts) {\n if (opts === void 0) {\n opts = {};\n }\n opts = new Options(opts, defaultRender);\n const tokens = tokenize(str);\n const result = [];\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (token.t === 'nl' && opts.get('nl2br')) {\n result.push('<br>\\n');\n } else if (!token.isLink || !opts.check(token)) {\n result.push(escapeText(token.toString()));\n } else {\n result.push(opts.render(token));\n }\n }\n return result.join('');\n}\nif (!String.prototype.linkify) {\n Object.defineProperty(String.prototype, 'linkify', {\n writable: false,\n value: function linkify(options) {\n return linkifyStr(this, options);\n }\n });\n}\n\nexport { linkifyStr as default };\n","import {useMemo} from 'react';\nimport linkifyStr from 'linkify-string';\n\nexport function useLinkifiedString(text: string | null | undefined) {\n return useMemo(() => {\n if (!text) {\n return text;\n }\n return linkifyStr(text, {\n nl2br: true,\n attributes: {rel: 'nofollow'},\n });\n }, [text]);\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {ImageZoomDialog} from '@common/ui/overlays/dialog/image-zoom-dialog';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {useLinkifiedString} from '@common/utils/hooks/use-linkified-string';\nimport {useMemo} from 'react';\n\ninterface ArtistAboutTabProps {\n artist: Artist;\n}\nexport function ArtistAboutPanel({artist}: ArtistAboutTabProps) {\n const description = useLinkifiedString(artist.profile?.description);\n\n const images = useMemo(() => {\n return artist.profile_images?.map(img => img.url) || [];\n }, [artist.profile_images]);\n\n return (\n <div className=\"\">\n <div className=\"grid grid-cols-3 lg:grid-cols-4 gap-24\">\n {images.map((src, index) => (\n <DialogTrigger key={src} type=\"modal\">\n <button\n type=\"button\"\n className=\"outline-none focus-visible:ring cursor-zoom-in rounded overflow-hidden hover:scale-105 transition\"\n >\n <img\n className=\"aspect-video object-cover rounded shadow cursor-zoom-in\"\n src={src}\n alt=\"\"\n />\n </button>\n <ImageZoomDialog images={images} defaultActiveIndex={index} />\n </DialogTrigger>\n ))}\n </div>\n <div\n className=\"py-24 text-sm whitespace-pre-wrap\"\n dangerouslySetInnerHTML={{__html: description || ''}}\n />\n </div>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Track} from '@app/web-player/tracks/track';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {AudiotrackIcon} from '@common/icons/material/Audiotrack';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {TrackList} from '@app/web-player/tracks/track-list/track-list';\n\ninterface Props {\n artist: Artist;\n initialTracks?: PaginationResponse<Track>;\n}\nexport function ArtistTracksPanel({artist, initialTracks}: Props) {\n const query = useInfiniteData<Track>({\n queryKey: ['tracks', artist.id],\n endpoint: `artists/${artist.id}/tracks`,\n initialPage: initialTracks,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AudiotrackIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No tracks yet\" />}\n description={\n <Trans\n message=\"Follow :artist for updates on their latest releases.\"\n values={{artist: artist.name}}\n />\n }\n />\n );\n }\n\n return <TrackList query={query} />;\n}\n","import {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {ArtistLinks} from '@app/web-player/artists/artist-links';\nimport {Track} from '@app/web-player/tracks/track';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {TrackSeekbar} from '@app/web-player/player-controls/seekbar/track-seekbar';\nimport {trackIsLocallyUploaded} from '@app/web-player/tracks/utils/track-is-locally-uploaded';\nimport {FormattedRelativeTime} from '@common/i18n/formatted-relative-time';\nimport {CommentBarContextProvider} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport React, {Fragment, memo} from 'react';\nimport {Chip} from '@common/ui/forms/input-field/chip-field/chip';\nimport {GenreLink} from '@app/web-player/genres/genre-link';\nimport {Album} from '@app/web-player/albums/album';\nimport {RepeatIcon} from '@common/icons/material/Repeat';\nimport clsx from 'clsx';\nimport {User} from '@common/auth/user';\nimport {UserProfileLink} from '@app/web-player/users/user-profile-link';\nimport {useAlbumPermissions} from '@app/web-player/albums/use-album-permissions';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {AlbumLink} from '@app/web-player/albums/album-link';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {FormattedNumber} from '@common/i18n/formatted-number';\nimport {PlayArrowFilledIcon} from '@app/web-player/tracks/play-arrow-filled';\nimport {usePlayerStore} from '@common/player/hooks/use-player-store';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {usePlayerActions} from '@common/player/hooks/use-player-actions';\nimport {tracksToMediaItems} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {WaveformWithComments} from '@app/web-player/tracks/track-list/track-list-item';\nimport {TrackActionsBar} from '@app/web-player/tracks/track-actions-bar';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\n\ninterface Props {\n album: Album;\n reposter?: User;\n className?: string;\n hideArtwork?: boolean;\n hideActions?: boolean;\n linksInNewTab?: boolean;\n maxHeight?: string;\n}\nexport const AlbumListItem = memo(\n ({\n album,\n reposter,\n className,\n hideArtwork,\n hideActions,\n linksInNewTab,\n maxHeight,\n }: Props) => {\n const queueId = queueGroupId(album);\n const {player} = useSettings();\n const isMobile = useIsMobileMediaQuery();\n hideArtwork = hideArtwork || !!isMobile;\n const {managesAlbum} = useAlbumPermissions(album);\n const tracks = album?.tracks || [];\n\n const media = usePlayerStore(s => s.cuedMedia);\n const activeTrack = tracks.find(t => t.id === media?.meta.id) || tracks[0];\n\n const showWave =\n player?.seekbar_type === 'waveform' &&\n trackIsLocallyUploaded(activeTrack);\n\n return (\n <div\n key={album.id}\n className={clsx(\n 'overflow-hidden',\n !hideArtwork && 'flex gap-24',\n className,\n maxHeight\n )}\n >\n {!hideArtwork && (\n <AlbumImage\n album={album}\n className=\"flex-shrink-0 rounded\"\n size=\"w-184 h-184\"\n />\n )}\n <div\n className={clsx(\n 'flex-auto min-w-0',\n maxHeight && 'flex flex-col h-full'\n )}\n >\n <div className=\"flex-shrink-0\">\n <div className=\"flex items-center gap-14\">\n <PlaybackToggleButton\n queueId={queueId}\n track={activeTrack}\n tracks={album.tracks}\n buttonType=\"icon\"\n color=\"primary\"\n variant=\"flat\"\n radius=\"rounded-full\"\n equalizerColor=\"white\"\n />\n <div>\n <div className=\"text-sm text-muted flex items-center gap-6\">\n <ArtistLinks\n artists={album.artists}\n target={linksInNewTab ? '_blank' : undefined}\n />\n {reposter && (\n <Fragment>\n <RepeatIcon size=\"xs\" />\n <UserProfileLink\n user={reposter}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </Fragment>\n )}\n </div>\n <div>\n <AlbumLink\n album={album}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </div>\n </div>\n <div className=\"ml-auto text-sm\">\n <FormattedRelativeTime date={album.created_at} />\n {album.genres?.length ? (\n <Chip className=\"mt-6 w-max\" size=\"xs\">\n <GenreLink\n genre={album.genres[0]}\n target={linksInNewTab ? '_blank' : undefined}\n />\n </Chip>\n ) : null}\n </div>\n </div>\n <div className=\"my-20\">\n {showWave ? (\n <CommentBarContextProvider disableCommenting={hideActions}>\n <WaveformWithComments\n track={activeTrack}\n queue={album.tracks}\n />\n </CommentBarContextProvider>\n ) : (\n <TrackSeekbar track={activeTrack} queue={album.tracks} />\n )}\n </div>\n </div>\n <div className=\"flex-auto overflow-y-auto\">\n {tracks.map((track, index) => {\n const isLast = index - 1 === album.tracks?.length;\n const isActive = activeTrack?.id === track.id;\n return (\n <TrackItem\n key={track.id}\n track={track}\n album={album}\n index={index}\n isLast={isLast}\n isActive={isActive}\n />\n );\n })}\n </div>\n {!hideActions && (\n <TrackActionsBar\n className=\"mt-20\"\n item={album}\n managesItem={managesAlbum}\n />\n )}\n </div>\n </div>\n );\n }\n);\n\ninterface TrackItemProps {\n track: Track;\n album: Album;\n index: number;\n isLast: boolean;\n isActive: boolean;\n}\nfunction TrackItem({track, index, isLast, isActive, album}: TrackItemProps) {\n const playerActions = usePlayerActions();\n return (\n <div\n key={track.id}\n className={clsx(\n 'flex items-center text-[13px] gap-8 p-8 cursor-pointer hover:bg-hover',\n !isLast && 'border-b',\n isActive && 'text-primary'\n )}\n onClick={() => {\n if (album.tracks?.length) {\n playerActions.overrideQueueAndPlay(\n tracksToMediaItems(album.tracks),\n index\n );\n }\n }}\n >\n <TrackImage track={track} size=\"w-20 h-20\" className=\"rounded\" />\n <div>{index + 1}</div>\n <div className=\"mx-10 flex-auto\">{track.name}</div>\n {track.plays && track.plays > 0 ? (\n <Fragment>\n <PlayArrowFilledIcon size=\"xs\" className=\"text-muted ml-auto\" />\n <div className=\"text-muted\">\n <FormattedNumber value={track.plays} />\n </div>\n </Fragment>\n ) : null}\n </div>\n );\n}\n","import {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport React from 'react';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {UseInfiniteDataResult} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Album} from '@app/web-player/albums/album';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\nimport {AlbumListItem} from '@app/web-player/albums/album-list/album-list-item';\n\ninterface Props {\n albums?: Album[];\n query?: UseInfiniteDataResult<Album>;\n}\nexport function AlbumList({albums, query}: Props) {\n const isMobile = useIsMobileMediaQuery();\n if (!albums && query) {\n albums = query.items;\n } else {\n albums = [];\n }\n\n if (isMobile) {\n return (\n <div>\n <ContentGrid>\n {albums.map(album => (\n <AlbumGridItem album={album} key={album.id} />\n ))}\n </ContentGrid>\n {query && <InfiniteScrollSentinel query={query} />}\n </div>\n );\n }\n\n return (\n <div>\n {albums.map(album => (\n <AlbumListItem key={album.id} album={album} className=\"mb-40\" />\n ))}\n {query && <InfiniteScrollSentinel query={query} />}\n </div>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {Album} from '@app/web-player/albums/album';\nimport {AlbumIcon} from '@common/icons/material/Album';\nimport {AlbumList} from '@app/web-player/albums/album-list/album-list';\n\ninterface Props {\n artist: Artist;\n}\nexport function ArtistAlbumsPanel({artist}: Props) {\n const query = useInfiniteData<Album>({\n queryKey: ['albums', artist.id],\n endpoint: `artists/${artist.id}/albums`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AlbumIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No albums yet\" />}\n description={\n <Trans\n message=\"Follow :artist for updates on their latest releases.\"\n values={{artist: artist.name}}\n />\n }\n />\n );\n }\n\n return <AlbumList query={query} />;\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {useSearchParams} from 'react-router-dom';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {useMemo} from 'react';\nimport {artistPageTabs} from '@app/web-player/artists/artist-page-tabs';\n\nexport function useArtistPageTabs(artist: Artist) {\n const [searchParams] = useSearchParams();\n const {artistPage} = useSettings();\n\n return useMemo(() => {\n const haveSimilar = artist.similar?.length;\n const haveBio =\n artist.profile_images?.length || artist.profile?.description;\n const activeTabs = artistPage?.tabs?.filter(tab => {\n if (!tab.active) {\n return false;\n }\n if (tab.id === artistPageTabs.similar && !haveSimilar) {\n return false;\n }\n if (tab.id === artistPageTabs.about && !haveBio) {\n return false;\n }\n return true;\n });\n const selectedTabId =\n artistPageTabs[searchParams.get('tab') as keyof typeof artistPageTabs];\n const i = activeTabs?.findIndex(t => t.id === selectedTabId);\n const selectedIndex = i > -1 ? i : 0;\n return {\n selectedIndex,\n activeTabs,\n };\n }, [artist, artistPage.tabs, searchParams]);\n}\n","import {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {create} from 'zustand';\nimport {immer} from 'zustand/middleware/immer';\n\ninterface State {\n followedUsers: number[];\n isFollowing: (id: number) => boolean;\n add: (id: number) => void;\n remove: (id: number) => void;\n}\n\nexport const userFollowsStore = create<State>()(\n immer((set, get) => ({\n followedUsers:\n getBootstrapData().user?.followed_users?.map(u => u.id) || [],\n isFollowing: (id: number) => get().followedUsers.includes(id),\n add: (id: number) => {\n set(draft => {\n draft.followedUsers.push(id);\n });\n },\n remove: (id: number) => {\n set(draft => {\n draft.followedUsers = draft.followedUsers.filter(i => i !== id);\n });\n },\n }))\n);\n\nexport const userFollows = userFollowsStore.getState;\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {User} from '@common/auth/user';\nimport {userFollows} from '@app/web-player/users/user-follows-store';\n\ninterface Response extends BackendResponse {}\n\ninterface Payload {\n user: User;\n}\n\nexport function useFollowUser() {\n return useMutation((payload: Payload) => followUser(payload), {\n onSuccess: (response, {user}) => {\n userFollows().add(user.id);\n toast(message('Following :name', {values: {name: user.display_name}}));\n queryClient.invalidateQueries(['users']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction followUser({user}: Payload): Promise<Response> {\n return apiClient.post(`users/${user.id}/follow`).then(r => r.data);\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {User} from '@common/auth/user';\nimport {userFollows} from '@app/web-player/users/user-follows-store';\n\ninterface Response extends BackendResponse {}\n\ninterface Payload {\n user: User;\n}\n\nexport function useUnfollowUser() {\n return useMutation((payload: Payload) => unfollowUser(payload), {\n onSuccess: (response, {user}) => {\n userFollows().remove(user.id);\n toast(\n message('Stopped following :name', {values: {name: user.display_name}})\n );\n queryClient.invalidateQueries(['users']);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction unfollowUser({user}: Payload): Promise<Response> {\n return apiClient.post(`users/${user.id}/unfollow`).then(r => r.data);\n}\n","import {User} from '@common/auth/user';\nimport {userFollowsStore} from '@app/web-player/users/user-follows-store';\nimport {UserImage} from '@app/web-player/users/user-image';\nimport {UserProfileLink} from '@app/web-player/users/user-profile-link';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {useFollowUser} from '@app/web-player/users/use-follow-user';\nimport {useAuth} from '@common/auth/use-auth';\nimport {Button} from '@common/ui/buttons/button';\nimport {useUnfollowUser} from '@app/web-player/users/use-unfollow-user';\n\ninterface Props {\n follower: User;\n}\nexport function FollowerListItem({follower}: Props) {\n const isFollowing = userFollowsStore(s => s.isFollowing(follower.id));\n return (\n <div\n key={follower.id}\n className=\"flex items-center gap-16 mb-16 pb-16 border-b\"\n >\n <UserImage user={follower} className=\"w-64 h-64 rounded\" />\n <div className=\"text-sm\">\n <UserProfileLink user={follower} />\n {follower.followers_count && follower.followers_count > 0 ? (\n <div className=\"text-xs text-muted\">\n <Trans\n message=\"[one 1 followers|other :count followers]\"\n values={{count: follower.followers_count}}\n />\n </div>\n ) : null}\n </div>\n {isFollowing ? (\n <UnfollowUserButton user={follower} />\n ) : (\n <FollowUserButton user={follower} />\n )}\n </div>\n );\n}\n\ninterface FollowUserButtonProps {\n user: User;\n}\nfunction FollowUserButton({user}: FollowUserButtonProps) {\n const followUser = useFollowUser();\n const {user: currentUser} = useAuth();\n if (currentUser?.id === user.id) return null;\n return (\n <Button\n variant=\"outline\"\n radius=\"rounded-full\"\n className=\"flex-shrink-0 ml-auto\"\n onClick={() => followUser.mutate({user})}\n disabled={followUser.isLoading}\n >\n <Trans message=\"Follow\" />\n </Button>\n );\n}\n\nfunction UnfollowUserButton({user}: FollowUserButtonProps) {\n const unfollowUser = useUnfollowUser();\n const {user: currentUser} = useAuth();\n if (currentUser?.id === user.id) return null;\n return (\n <Button\n variant=\"outline\"\n radius=\"rounded-full\"\n className=\"flex-shrink-0 ml-auto\"\n onClick={() => unfollowUser.mutate({user})}\n disabled={unfollowUser.isLoading}\n >\n <Trans message=\"Unfollow\" />\n </Button>\n );\n}\n","import {Artist} from '@app/web-player/artists/artist';\nimport {Trans} from '@common/i18n/trans';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {User} from '@common/auth/user';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport React from 'react';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {BookmarkBorderIcon} from '@common/icons/material/BookmarkBorder';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {FollowerListItem} from '@app/web-player/artists/artist-page/followers-panel/follower-list-item';\n\ninterface Props {\n artist: Artist;\n}\nexport function ArtistFollowersPanel({artist}: Props) {\n const query = useInfiniteData<User>({\n queryKey: ['artists', artist.id, 'followers'],\n endpoint: `artists/${artist.id}/followers`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<BookmarkBorderIcon size=\"lg\" className=\"text-muted\" />}\n description={\n <Trans\n message=\"Seems like no one is following :name yet.\"\n values={{name: artist.name}}\n />\n }\n />\n );\n }\n\n return (\n <div>\n {query.items.map(follower => (\n <FollowerListItem key={follower.id} follower={follower} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {Link} from 'react-router-dom';\nimport {artistPageTabs} from '@app/web-player/artists/artist-page-tabs';\nimport {Tabs} from '@common/ui/tabs/tabs';\nimport {TabList} from '@common/ui/tabs/tab-list';\nimport {Tab} from '@common/ui/tabs/tab';\nimport {Trans} from '@common/i18n/trans';\nimport {TabPanel, TabPanels} from '@common/ui/tabs/tab-panels';\nimport {DiscographyTab} from '@app/web-player/artists/artist-page/discography-panel/discography-tab';\nimport {SimilarArtistsPanel} from '@app/web-player/artists/artist-page/similar-artists-panel';\nimport {ArtistAboutPanel} from '@app/web-player/artists/artist-page/artist-about-panel';\nimport {ArtistTracksPanel} from '@app/web-player/artists/artist-page/artist-tracks-panel';\nimport {ArtistAlbumsPanel} from '@app/web-player/artists/artist-page/artist-albums-panel';\nimport React from 'react';\nimport {UseArtistResponse} from '@app/web-player/artists/requests/use-artist';\nimport {useArtistPageTabs} from '@app/web-player/artists/artist-page/use-artist-page-tabs';\nimport {ArtistFollowersPanel} from '@app/web-player/artists/artist-page/artist-followers-panel';\n\ninterface Props {\n data: UseArtistResponse;\n}\nexport function ArtistPageTabs({data}: Props) {\n const {selectedIndex, activeTabs} = useArtistPageTabs(data.artist);\n return (\n <Tabs className=\"mt-24 md:mt-48\" selectedTab={selectedIndex} isLazy>\n <TabList>\n {activeTabs.map(tab => {\n switch (tab.id) {\n case artistPageTabs.discography:\n return (\n <Tab elementType={Link} key={artistPageTabs.discography}>\n <Trans message=\"Discography\" />\n </Tab>\n );\n case artistPageTabs.similar:\n return (\n <Tab\n elementType={Link}\n to={{search: '?tab=similar'}}\n key={artistPageTabs.similar}\n >\n <Trans message=\"Similar artists\" />\n </Tab>\n );\n case artistPageTabs.about:\n return (\n <Tab\n elementType={Link}\n to={{search: '?tab=about'}}\n key={artistPageTabs.about}\n >\n <Trans message=\"About\" />\n </Tab>\n );\n case artistPageTabs.tracks:\n return (\n <Tab\n elementType={Link}\n to={{search: '?tab=tracks'}}\n key={artistPageTabs.tracks}\n >\n <Trans message=\"Tracks\" />\n </Tab>\n );\n case artistPageTabs.albums:\n return (\n <Tab\n elementType={Link}\n to={{search: '?tab=albums'}}\n key={artistPageTabs.albums}\n >\n <Trans message=\"Albums\" />\n </Tab>\n );\n case artistPageTabs.followers:\n return (\n <Tab\n elementType={Link}\n to={{search: '?tab=followers'}}\n key={artistPageTabs.followers}\n >\n <Trans message=\"Followers\" />\n </Tab>\n );\n }\n })}\n </TabList>\n <TabPanels className=\"mt-12 md:mt-24\">\n {activeTabs.map(tab => {\n switch (tab.id) {\n case artistPageTabs.discography:\n return (\n <TabPanel key={artistPageTabs.discography}>\n <DiscographyTab\n artist={data.artist}\n initialAlbums={data.albums}\n />\n </TabPanel>\n );\n case artistPageTabs.similar:\n return (\n <TabPanel key={artistPageTabs.similar}>\n <SimilarArtistsPanel artist={data.artist} />\n </TabPanel>\n );\n case artistPageTabs.about:\n return (\n <TabPanel key={artistPageTabs.about}>\n <ArtistAboutPanel artist={data.artist} />\n </TabPanel>\n );\n case artistPageTabs.tracks:\n return (\n <TabPanel key={artistPageTabs.tracks}>\n <ArtistTracksPanel\n artist={data.artist}\n initialTracks={data.tracks}\n />\n </TabPanel>\n );\n case artistPageTabs.albums:\n return (\n <TabPanel key={artistPageTabs.albums}>\n <ArtistAlbumsPanel artist={data.artist} />\n </TabPanel>\n );\n case artistPageTabs.followers:\n return (\n <TabPanel key={artistPageTabs.followers}>\n <ArtistFollowersPanel artist={data.artist} />\n </TabPanel>\n );\n }\n })}\n </TabPanels>\n </Tabs>\n );\n}\n","import {\n albumLayoutKey,\n useArtist,\n UseArtistParams,\n} from '@app/web-player/artists/requests/use-artist';\nimport {ArtistPageHeader} from '@app/web-player/artists/artist-page/artist-page-header';\nimport {PageMetaTags} from '@common/http/page-meta-tags';\nimport {PageStatus} from '@common/http/page-status';\nimport {getFromLocalStorage} from '@common/utils/hooks/local-storage';\nimport React from 'react';\nimport {ArtistPageTabs} from '@app/web-player/artists/artist-page/artist-page-tabs';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {artistPageTabs} from '@app/web-player/artists/artist-page-tabs';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nexport function ArtistPage() {\n const isListView = getFromLocalStorage(albumLayoutKey, 'list') === 'list';\n const {artistPage} = useSettings();\n const tabIds = artistPage.tabs.filter(tab => tab.active).map(tab => tab.id);\n\n let load = ['similar', 'genres', 'profile'];\n if (tabIds.includes(artistPageTabs.tracks)) {\n load.push('tracks');\n }\n if (tabIds.includes(artistPageTabs.discography)) {\n load = [...load, 'albums', 'topTracks'];\n }\n const params: UseArtistParams = {\n with: load,\n withCount: 'likes',\n autoUpdate: true,\n loadAlbumTracks: isListView,\n albumsPerPage: isListView ? 5 : 25,\n paginate: 'simple',\n };\n const query = useArtist(params);\n\n if (query.data) {\n return (\n <div>\n <PageMetaTags query={query} />\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <ArtistPageHeader artist={query.data.artist} />\n <AdHost slot=\"artist_top\" className=\"mt-14\" />\n <ArtistPageTabs data={query.data} />\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useParams} from 'react-router-dom';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Playlist} from '@app/web-player/playlists/playlist';\n\ninterface GetPlaylistResponse extends BackendResponse {\n playlist: Playlist;\n tracks: PaginationResponse<Track>;\n totalDuration: number;\n}\n\nexport function usePlaylist() {\n const {playlistId} = useParams();\n return useQuery(['playlists', +playlistId!], () =>\n fetchPlaylist(playlistId!)\n );\n}\n\nfunction fetchPlaylist(\n playlistId: number | string\n): Promise<GetPlaylistResponse> {\n return apiClient\n .get(`playlists/${playlistId}`)\n .then(response => response.data);\n}\n","import React, {Children, Fragment, ReactElement, ReactNode} from 'react';\nimport {AvatarProps} from '@common/ui/images/avatar';\nimport clsx from 'clsx';\nimport {Trans} from '@common/i18n/trans';\nimport {Link} from 'react-router-dom';\n\ninterface AvatarGroupProps {\n children: ReactNode;\n className?: string;\n}\nexport function AvatarGroup(props: AvatarGroupProps) {\n const children = Children.toArray(\n props.children\n ) as ReactElement<AvatarProps>[];\n\n if (!children.length) return null;\n\n const firstLink = children[0].props.link;\n const label = children[0].props.label;\n\n return (\n <div className={clsx('pl-10 flex isolate items-center', props.className)}>\n <Fragment>\n {children.map((avatar, index) => (\n <div\n key={index}\n style={{zIndex: 5 - index}}\n className={clsx(\n 'relative border-2 border-bg-alt bg-alt rounded-full -ml-10 overflow-hidden flex-shrink-0'\n )}\n >\n {avatar}\n </div>\n ))}\n </Fragment>\n <div className=\"text-sm whitespace-nowrap ml-10\">\n {firstLink && label ? (\n <Link to={firstLink} className=\"hover:underline\">\n {label}\n </Link>\n ) : null}\n {children.length > 1 && (\n <span>\n {' '}\n <Trans\n message=\"+ :count more\"\n values={{count: children.length - 1}}\n />\n </span>\n )}\n </div>\n </div>\n );\n}\n","import React, {Children, Fragment, ReactNode} from 'react';\nimport clsx from 'clsx';\n\ninterface BulletSeparatedItemsProps {\n children: ReactNode;\n className?: string;\n}\n\nexport function BulletSeparatedItems({\n children,\n className,\n}: BulletSeparatedItemsProps) {\n const items = Children.toArray(children);\n return (\n <div className={clsx('flex items-center gap-4', className)}>\n {items.map((child, index) => (\n <Fragment key={index}>\n <div>{child}</div>\n {index < items.length - 1 ? <div>•</div> : null}\n </Fragment>\n ))}\n </div>\n );\n}\n","import {Playlist} from '@app/web-player/playlists/playlist';\nimport {\n getPlaylistImageSrc,\n PlaylistImage,\n} from '@app/web-player/playlists/playlist-image';\nimport {Trans} from '@common/i18n/trans';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport React, {Fragment} from 'react';\nimport {FileUploadProvider} from '@common/uploads/uploader/file-upload-provider';\nimport {ImageSelector} from '@common/ui/images/image-selector';\nimport {ImageIcon} from '@common/icons/material/Image';\nimport {useUpdatePlaylist} from '@app/web-player/playlists/requests/use-update-playlist';\nimport {usePlaylistPermissions} from '@app/web-player/playlists/hooks/use-playlist-permissions';\nimport {Button} from '@common/ui/buttons/button';\nimport {ArrowDropDownIcon} from '@common/icons/material/ArrowDropDown';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {PlaylistContextDialog} from '@app/web-player/playlists/playlist-context-dialog';\nimport {FollowPlaylistButton} from '@app/web-player/playlists/playlist-page/follow-playlist-button';\nimport {AvatarGroup} from '@common/ui/images/avatar-group';\nimport {Avatar} from '@common/ui/images/avatar';\nimport {getUserProfileLink} from '@app/web-player/users/user-profile-link';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {BulletSeparatedItems} from '@app/web-player/layout/bullet-separated-items';\n\ninterface PlaylistPageHeaderProps {\n playlist: Playlist;\n totalDuration: number;\n queueId: string;\n}\nexport function PlaylistPageHeader({\n playlist,\n totalDuration,\n queueId,\n}: PlaylistPageHeaderProps) {\n return (\n <Fragment>\n <MediaPageHeaderLayout\n image={<EditableImage playlist={playlist} />}\n title={playlist.name}\n subtitle={\n <AvatarGroup>\n {playlist.editors?.map(editor => (\n <Avatar\n key={editor.id}\n circle\n src={editor.avatar}\n label={editor.display_name}\n link={getUserProfileLink(editor)}\n />\n ))}\n </AvatarGroup>\n }\n description={\n <Fragment>\n {playlist.description}\n {playlist.tracks_count ? (\n <BulletSeparatedItems className=\"mt-14 text-sm text-muted\">\n <Trans\n message=\"[one 1 track|other :count tracks]\"\n values={{count: playlist.tracks_count}}\n />\n <FormattedDuration ms={totalDuration} verbose />\n {playlist.collaborative && <Trans message=\"Collaborative\" />}\n </BulletSeparatedItems>\n ) : null}\n </Fragment>\n }\n actionButtons={\n <ActionButtons\n playlist={playlist}\n hasTracks={totalDuration > 0}\n queueId={queueId}\n />\n }\n />\n </Fragment>\n );\n}\n\ninterface ImageContainerProps {\n playlist: Playlist;\n size?: string;\n className?: string;\n}\nfunction EditableImage({playlist, size, className}: ImageContainerProps) {\n const updatePlaylist = useUpdatePlaylist();\n const {canEdit} = usePlaylistPermissions(playlist);\n\n if (!canEdit) {\n return (\n <PlaylistImage\n className={`${size} ${className} object-cover rounded`}\n playlist={playlist}\n />\n );\n }\n\n return (\n <FileUploadProvider>\n <ImageSelector\n showEditButtonOnHover\n diskPrefix=\"playlist_media\"\n variant=\"square\"\n previewSize={size}\n className={className}\n value={getPlaylistImageSrc(playlist)}\n onChange={newValue => {\n updatePlaylist.mutate({image: newValue});\n }}\n placeholderIcon={<ImageIcon />}\n stretchPreview\n />\n </FileUploadProvider>\n );\n}\n\ninterface ActionButtonsProps {\n playlist: Playlist;\n hasTracks: boolean;\n queueId: string;\n}\nfunction ActionButtons({playlist, hasTracks, queueId}: ActionButtonsProps) {\n return (\n <div className=\"text-center md:text-start\">\n <PlaybackToggleButton\n disabled={!hasTracks}\n buttonType=\"text\"\n queueId={queueId}\n className={actionButtonClassName({isFirst: true})}\n />\n <FollowPlaylistButton\n buttonType=\"text\"\n playlist={playlist}\n className={actionButtonClassName()}\n />\n <DialogTrigger type=\"popover\">\n <Button\n variant=\"outline\"\n radius=\"rounded-full\"\n endIcon={<ArrowDropDownIcon />}\n className={actionButtonClassName()}\n >\n <Trans message=\"More\" />\n </Button>\n <PlaylistContextDialog playlist={playlist} />\n </DialogTrigger>\n </div>\n );\n}\n","export function moveMultipleItemsInArray<T>(\n array: T[],\n indexOrIndexes: number | number[],\n newIndex: number\n) {\n const indexes = Array.isArray(indexOrIndexes)\n ? indexOrIndexes\n : [indexOrIndexes];\n const insertBefore = array[newIndex + (newIndex < indexes[0] ? 0 : 1)];\n const itemsToBeMoved = indexes.map(i => array[i]);\n\n // in original sequence order, check for presence in the removal\n // list, *and* remove them from the original array\n const moved = [];\n for (let i = 0; i < array.length; ) {\n const value = array[i];\n if (itemsToBeMoved.indexOf(value) >= 0) {\n moved.push(value);\n array.splice(i, 1);\n } else {\n ++i;\n }\n }\n\n // find the new index of the insertion point\n let insertionIndex = array.indexOf(insertBefore);\n if (insertionIndex < 0) {\n insertionIndex = array.length;\n }\n\n // and add the elements back in\n array.splice(insertionIndex, 0, ...moved);\n\n return array;\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useMutation} from '@tanstack/react-query';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {Track} from '@app/web-player/tracks/track';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {useParams} from 'react-router-dom';\nimport {moveMultipleItemsInArray} from '@common/utils/array/move-multiple-items-in-array';\n\ninterface Response extends BackendResponse {\n //\n}\n\ninterface Payload {\n tracks: Track[];\n oldIndexes: number | number[];\n newIndex: number;\n}\n\nexport function useReorderPlaylistTracks() {\n const {playlistId} = useParams();\n return useMutation(\n (payload: Payload) => reorderTracks(playlistId!, payload),\n {\n onSuccess: () => {\n queryClient.invalidateQueries(['tracks', 'playlist', +playlistId!]);\n },\n onError: err => showHttpErrorToast(err),\n }\n );\n}\n\nfunction reorderTracks(\n playlistId: number | string,\n {tracks, oldIndexes, newIndex}: Payload\n): Promise<Response> {\n const ids = tracks.map(t => t.id);\n moveMultipleItemsInArray(ids, oldIndexes, newIndex);\n return apiClient\n .post(`playlists/${playlistId}/tracks/order`, {ids})\n .then(r => r.data);\n}\n","import {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {useMutation} from '@tanstack/react-query';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {Track} from '@app/web-player/tracks/track';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface Response extends BackendResponse {\n playlist: Playlist;\n}\n\ninterface Payload {\n playlistId: number;\n tracks: Track[];\n}\n\nexport function useRemoveTracksFromPlaylist() {\n return useMutation((payload: Payload) => removeTracks(payload), {\n onSuccess: (response, {tracks}) => {\n toast(\n message('Removed [one 1 track|other :count tracks] from playlist', {\n values: {count: tracks.length},\n })\n );\n queryClient.invalidateQueries(['playlists', response.playlist.id]);\n queryClient.invalidateQueries([\n 'tracks',\n 'playlist',\n response.playlist.id,\n ]);\n },\n onError: r => showHttpErrorToast(r),\n });\n}\n\nfunction removeTracks(payload: Payload): Promise<Response> {\n const backendPayload = {\n ids: payload.tracks.map(track => track.id),\n };\n return apiClient\n .post(`playlists/${payload.playlistId}/tracks/remove`, backendPayload)\n .then(r => r.data);\n}\n","import {Playlist} from '@app/web-player/playlists/playlist';\nimport {Trans} from '@common/i18n/trans';\nimport {ContextMenuButton} from '@app/web-player/context-dialog/context-dialog-layout';\nimport {useRemoveTracksFromPlaylist} from '@app/web-player/playlists/requests/use-remove-tracks-from-playlist';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {TableTrackContextDialog} from '@app/web-player/tracks/context-dialog/table-track-context-dialog';\nimport {useAuth} from '@common/auth/use-auth';\n\ninterface PlaylistTrackContextDialogProps {\n playlist: Playlist;\n}\nexport function PlaylistTrackContextDialog({\n playlist,\n ...props\n}: PlaylistTrackContextDialogProps) {\n const {user} = useAuth();\n const {close: closeMenu} = useDialogContext();\n const removeTracks = useRemoveTracksFromPlaylist();\n\n const canRemove = playlist.owner_id === user?.id || playlist.collaborative;\n\n return (\n <TableTrackContextDialog {...props}>\n {tracks => {\n return canRemove ? (\n <ContextMenuButton\n onClick={() => {\n if (!removeTracks.isLoading) {\n removeTracks.mutate({playlistId: playlist.id, tracks});\n closeMenu();\n }\n }}\n >\n <Trans message=\"Remove from this playlist\" />\n </ContextMenuButton>\n ) : null;\n }}\n </TableTrackContextDialog>\n );\n}\n","import {RowElementProps} from '@common/ui/tables/table-row';\nimport {Track} from '@app/web-player/tracks/track';\nimport {useIsTouchDevice} from '@common/utils/hooks/is-touch-device';\nimport React, {Fragment, useContext, useRef} from 'react';\nimport {TableContext} from '@common/ui/tables/table-context';\nimport {DragPreviewRenderer} from '@common/ui/interactions/dnd/use-draggable';\nimport {useReorderPlaylistTracks} from '@app/web-player/playlists/requests/use-reorder-playlist-tracks';\nimport {useSortable} from '@common/ui/interactions/dnd/use-sortable';\nimport {usePlaylist} from '@app/web-player/playlists/requests/use-playlist';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {mergeProps} from '@react-aria/utils';\nimport {PlaylistTrackContextDialog} from '@app/web-player/playlists/playlist-page/playlist-track-context-dialog';\nimport {Trans} from '@common/i18n/trans';\nimport {DragPreview} from '@common/ui/interactions/dnd/drag-preview';\n\nexport function PlaylistTableRow({\n item,\n children,\n className,\n ...domProps\n}: RowElementProps<Track>) {\n const isTouchDevice = useIsTouchDevice();\n const {\n data: tracks,\n selectRow,\n selectedRows,\n sortDescriptor,\n } = useContext(TableContext);\n const domRef = useRef<HTMLTableRowElement>(null);\n const previewRef = useRef<DragPreviewRenderer>(null);\n const reorderTracks = useReorderPlaylistTracks();\n const {data} = usePlaylist();\n\n const {sortableProps} = useSortable({\n ref: domRef,\n disabled:\n (isTouchDevice ?? false) ||\n reorderTracks.isLoading ||\n // disable drag and drop if table is sorted via header\n sortDescriptor?.orderBy !== 'position',\n item: item,\n items: tracks,\n type: 'playlistTrack',\n preview: previewRef,\n previewVariant: 'line',\n onDragEnd: () => {\n selectRow(null);\n },\n onSortStart: () => {\n // if dragging a row that is already selected, do nothing,\n // otherwise deselect all other rows and select this one\n if (!selectedRows.includes(item.id)) {\n selectRow(item);\n }\n },\n onSortEnd: (oldIndex, newIndex) => {\n reorderTracks.mutate({\n tracks: tracks as Track[],\n oldIndexes:\n selectedRows.length > 1\n ? selectedRows.map(id => tracks.findIndex(t => t.id === id))\n : oldIndex,\n newIndex,\n });\n },\n });\n\n return (\n <Fragment>\n <DialogTrigger\n type=\"popover\"\n triggerOnContextMenu\n placement=\"bottom-start\"\n >\n <div\n className={className}\n ref={domRef}\n {...mergeProps(sortableProps, domProps)}\n >\n {children}\n </div>\n <PlaylistTrackContextDialog playlist={data!.playlist} />\n </DialogTrigger>\n {!item.isPlaceholder && <RowDragPreview track={item} ref={previewRef} />}\n </Fragment>\n );\n}\n\ninterface RowDragPreviewProps {\n track: Track;\n}\nconst RowDragPreview = React.forwardRef<\n DragPreviewRenderer,\n RowDragPreviewProps\n>(({track}, ref) => {\n const {selectedRows} = useContext(TableContext);\n\n const content =\n selectedRows.length > 1 ? (\n <Trans message=\":count tracks\" values={{count: selectedRows.length}} />\n ) : (\n `${track.name} - ${track.artists?.[0]?.name}`\n );\n\n return (\n <DragPreview ref={ref}>\n {() => (\n <div\n className=\"p-8 rounded shadow bg-chip text-base\"\n role=\"presentation\"\n >\n {content}\n </div>\n )}\n </DragPreview>\n );\n});\n","import {Trans} from '@common/i18n/trans';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport React, {ReactElement} from 'react';\n\ninterface MediaPageNoResultsMessage {\n description: ReactElement;\n searchQuery?: string;\n className?: string;\n}\nexport function MediaPageNoResultsMessage({\n description,\n searchQuery,\n className,\n}: MediaPageNoResultsMessage) {\n if (searchQuery) {\n return (\n <IllustratedMessage\n className={className}\n title={<Trans message=\"No results found\" />}\n description={\n <Trans message=\"Try another search query or different filters\" />\n }\n />\n );\n }\n return (\n <IllustratedMessage\n className={className}\n title={<Trans message=\"Nothing to display\" />}\n description={description}\n />\n );\n}\n","import {usePlaylist} from '@app/web-player/playlists/requests/use-playlist';\nimport {Trans} from '@common/i18n/trans';\nimport {PaginationResponse} from '@common/http/backend-response/pagination-response';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport React from 'react';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {message} from '@common/i18n/message';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {VirtualTableBody} from '@app/web-player/playlists/virtual-table-body';\nimport {PlaylistPageHeader} from '@app/web-player/playlists/playlist-page/playlist-page-header';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {PlaylistTableRow} from '@app/web-player/playlists/playlist-page/playlist-table-row';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {PageMetaTags} from '@common/http/page-meta-tags';\nimport {PageStatus} from '@common/http/page-status';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nexport function PlaylistPage() {\n const query = usePlaylist();\n\n if (query.data) {\n return (\n <div>\n <PageMetaTags query={query} />\n <PageContent\n initialTracks={query.data.tracks}\n playlist={query.data.playlist}\n totalDuration={query.data.totalDuration}\n />\n </div>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\ninterface PageContentProps {\n initialTracks: PaginationResponse<Track>;\n playlist: Playlist;\n totalDuration: number;\n}\nfunction PageContent({\n initialTracks,\n playlist,\n totalDuration,\n}: PageContentProps) {\n const {trans} = useTrans();\n const query = useInfiniteData({\n initialPage: initialTracks,\n queryKey: ['tracks', 'playlist', playlist.id],\n endpoint: `playlists/${playlist.id}/tracks`,\n defaultOrderBy: 'position',\n defaultOrderDir: 'asc',\n paginate: 'simple',\n willSortOrFilter: true,\n });\n const {\n isInitialLoading,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n items,\n } = query;\n const totalItems = playlist.tracks_count || 0;\n const queueId = queueGroupId(playlist, '*', sortDescriptor);\n\n return (\n <div>\n <AdHost slot=\"general_top\" className=\"mb-44\" />\n <PlaylistPageHeader\n playlist={playlist}\n totalDuration={totalDuration}\n queueId={queueId}\n />\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 mt-28 mb-44 md:mb-24\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within playlist'))}\n />\n <TrackTable\n queueGroupId={queueId}\n tracks={items}\n sortDescriptor={sortDescriptor}\n onSortChange={setSortDescriptor}\n renderRowAs={PlaylistTableRow}\n tableBody={<VirtualTableBody query={query} totalItems={totalItems} />}\n />\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={\n <Trans message=\"This playlist does not have any tracks yet\" />\n }\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-44\" />\n </div>\n );\n}\n","import {Commentable} from '@common/comments/commentable';\nimport {Comment} from '@common/comments/comment';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\n\nexport function commentsQueryKey(commentable: Commentable) {\n return ['comment', `${commentable.id}-${commentable.model_type}`];\n}\n\nexport function useComments(commentable: Commentable) {\n return useInfiniteData<Comment>({\n queryKey: commentsQueryKey(commentable),\n endpoint: 'commentable/comments',\n //paginate: 'cursor',\n queryParams: {\n commentable_type: commentable.model_type,\n commentable_id: commentable.id,\n },\n });\n}\n","import {useMutation} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {VotableModel} from '@common/votes/votable-model';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\n\ninterface Response extends BackendResponse {\n model: VotableModel;\n}\n\ninterface Payload {\n voteType: 'upvote' | 'downvote';\n}\n\nexport function useStoreVote(model: VotableModel) {\n return useMutation((payload: Payload) => changeVote(model, payload), {\n onSuccess: response => {\n //\n },\n onError: err => showHttpErrorToast(err),\n });\n}\n\nfunction changeVote(model: VotableModel, payload: Payload) {\n return apiClient\n .post<Response>('vote', {\n vote_type: payload.voteType,\n model_id: model.id,\n model_type: model.model_type,\n })\n .then(r => r.data);\n}\n","import {ThumbUpIcon} from '@common/icons/material/ThumbUp';\nimport {ThumbDownIcon} from '@common/icons/material/ThumbDown';\nimport {VotableModel} from '@common/votes/votable-model';\nimport {Button} from '@common/ui/buttons/button';\nimport {useStoreVote} from '@common/votes/requests/use-store-vote';\nimport {useState} from 'react';\nimport {FormattedNumber} from '@common/i18n/formatted-number';\n\ninterface Props {\n model: VotableModel;\n className?: string;\n showUpvotesOnly?: boolean;\n}\nexport function ThumbButtons({model, className, showUpvotesOnly}: Props) {\n const changeVote = useStoreVote(model);\n\n const [upvotes, setUpvotes] = useState(model.upvotes || 0);\n const [downvotes, setDownvotes] = useState(model.downvotes || 0);\n const [currentVote, setCurrentVote] = useState(model.current_vote);\n\n const syncLocalState = (model: VotableModel) => {\n setUpvotes(model.upvotes);\n setDownvotes(model.downvotes);\n setCurrentVote(model.current_vote);\n };\n\n return (\n <div className={className}>\n <Button\n className=\"gap-6\"\n sizeClassName=\"px-8 py-4\"\n color={currentVote === 'upvote' ? 'primary' : undefined}\n disabled={changeVote.isLoading}\n onClick={() => {\n changeVote.mutate(\n {voteType: 'upvote'},\n {\n onSuccess: response => syncLocalState(response.model),\n }\n );\n }}\n >\n <ThumbUpIcon />\n <div>\n <FormattedNumber value={upvotes} />\n </div>\n </Button>\n {!showUpvotesOnly && (\n <Button\n className=\"gap-6\"\n sizeClassName=\"px-8 py-4\"\n color={currentVote === 'downvote' ? 'primary' : undefined}\n disabled={changeVote.isLoading}\n onClick={() => {\n changeVote.mutate(\n {voteType: 'downvote'},\n {\n onSuccess: response => syncLocalState(response.model),\n }\n );\n }}\n >\n <ThumbDownIcon />\n <div>\n <FormattedNumber value={downvotes} />\n </div>\n </Button>\n )}\n </div>\n );\n}\n","import {useMutation} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {showHttpErrorToast} from '@common/utils/http/show-http-error-toast';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {Reportable} from '@common/reports/Reportable';\n\ninterface Response extends BackendResponse {\n model: Reportable;\n}\n\ninterface Payload {\n reason?: string;\n}\n\nexport function useSubmitReport(model: Reportable) {\n return useMutation((payload: Payload) => submitReport(model, payload), {\n onSuccess: () => {\n toast(message('Thanks for reporting. We will review this content.'));\n },\n onError: err => showHttpErrorToast(err),\n });\n}\n\nfunction submitReport(model: Reportable, payload: Payload) {\n return apiClient\n .post<Response>('report', {\n reason: payload.reason,\n model_id: model.id,\n model_type: model.model_type,\n })\n .then(r => r.data);\n}\n","import React, {Fragment, memo, useContext, useState} from 'react';\nimport {SiteConfigContext} from '@common/core/settings/site-config-context';\nimport {Link} from 'react-router-dom';\nimport {Comment} from '@common/comments/comment';\nimport {useAuth} from '@common/auth/use-auth';\nimport {UserAvatar} from '@common/ui/images/user-avatar';\nimport {Button} from '@common/ui/buttons/button';\nimport {Trans} from '@common/i18n/trans';\nimport {NewCommentForm} from '@common/comments/new-comment-form';\nimport {User} from '@common/auth/user';\nimport {Commentable} from '@common/comments/commentable';\nimport {useDeleteComments} from '@common/comments/requests/use-delete-comments';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {queryClient} from '@common/http/query-client';\nimport {ConfirmationDialog} from '@common/ui/overlays/dialog/confirmation-dialog';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {ThumbButtons} from '@common/votes/thumb-buttons';\nimport {ReplyIcon} from '@common/icons/material/Reply';\nimport {MoreVertIcon} from '@common/icons/material/MoreVert';\nimport {\n Menu,\n MenuItem,\n MenuTrigger,\n} from '@common/ui/navigation/menu/menu-trigger';\nimport {FormattedRelativeTime} from '@common/i18n/formatted-relative-time';\nimport {useSubmitReport} from '@common/reports/requests/use-submit-report';\n\ninterface CommentListItemProps {\n comment: Comment;\n commentable: Commentable;\n canDelete?: boolean;\n}\nexport function CommentListItem({\n comment,\n commentable,\n // user can delete comment if they have created it, or they have relevant permissions on commentable\n canDelete,\n}: CommentListItemProps) {\n const isMobile = useIsMobileMediaQuery();\n const {user, hasPermission} = useAuth();\n const [replyFormVisible, setReplyFormVisible] = useState(false);\n const showReplyButton =\n user != null &&\n !comment.deleted &&\n !isMobile &&\n comment.depth < 5 &&\n hasPermission('comments.create');\n\n return (\n <div\n style={{paddingLeft: `${comment.depth * 20}px`}}\n onClick={() => {\n if (isMobile) {\n setReplyFormVisible(!replyFormVisible);\n }\n }}\n >\n <div className=\"flex items-start gap-24 py-18 min-h-70 group\">\n <UserAvatar user={comment.user} size=\"xl\" circle />\n <div className=\"text-sm flex-auto\">\n <div className=\"flex items-center gap-8 mb-4\">\n {comment.user && <UserDisplayName user={comment.user} />}\n <time className=\"text-muted text-xs\">\n <FormattedRelativeTime date={comment.created_at} />\n </time>\n {comment.position ? (\n <Position commentable={commentable} position={comment.position} />\n ) : null}\n </div>\n <div>\n {comment.deleted ? (\n <span className=\"text-muted italic\">\n <Trans message=\"[COMMENT DELETED]\" />\n </span>\n ) : (\n comment.content\n )}\n </div>\n {!comment.deleted && (\n <div className=\"flex items-center gap-8 mt-10 -ml-8\">\n {showReplyButton && (\n <Button\n sizeClassName=\"text-sm px-8 py-4\"\n startIcon={<ReplyIcon />}\n onClick={() => setReplyFormVisible(!replyFormVisible)}\n >\n <Trans message=\"Reply\" />\n </Button>\n )}\n <ThumbButtons model={comment} showUpvotesOnly />\n <CommentOptionsTrigger\n comment={comment}\n canDelete={canDelete}\n user={user}\n />\n </div>\n )}\n </div>\n </div>\n {replyFormVisible ? (\n <NewCommentForm\n className={!comment?.depth ? 'pl-20' : undefined}\n commentable={commentable}\n inReplyTo={comment}\n autoFocus\n onSuccess={() => {\n setReplyFormVisible(false);\n }}\n />\n ) : null}\n </div>\n );\n}\n\ninterface PositionProps {\n commentable: Commentable;\n position: number;\n}\nconst Position = memo(({commentable, position}: PositionProps) => {\n if (!commentable.duration) return null;\n const seconds = (position / 100) * (commentable.duration / 1000);\n return (\n <span className=\"text-muted text-xs\">\n <Trans\n message=\"at :position\"\n values={{\n position: <FormattedDuration seconds={seconds} />,\n }}\n />\n </span>\n );\n});\n\ninterface DeleteCommentsButtonProps {\n comment: Comment;\n canDelete?: boolean;\n user: User | null;\n}\nexport function CommentOptionsTrigger({\n comment,\n canDelete,\n user,\n}: DeleteCommentsButtonProps) {\n const deleteComments = useDeleteComments();\n const reportComment = useSubmitReport(comment);\n\n const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);\n const showDeleteButton =\n (comment.user_id === user?.id || canDelete) && !comment.deleted;\n\n const handleReport = () => {\n reportComment.mutate({});\n };\n\n const handleDelete = (isConfirmed: boolean) => {\n setIsDeleteDialogOpen(false);\n if (isConfirmed) {\n deleteComments.mutate(\n {commentIds: [comment.id]},\n {\n onSuccess: () => {\n queryClient.invalidateQueries(['comment']);\n },\n }\n );\n }\n };\n\n return (\n <Fragment>\n <MenuTrigger>\n <Button startIcon={<MoreVertIcon />} sizeClassName=\"text-sm px-8 py-4\">\n <Trans message=\"More\" />\n </Button>\n <Menu>\n <MenuItem value=\"report\" onSelected={() => handleReport()}>\n <Trans message=\"Report comment\" />\n </MenuItem>\n {showDeleteButton && (\n <MenuItem\n value=\"delete\"\n onSelected={() => setIsDeleteDialogOpen(true)}\n >\n <Trans message=\"Delete\" />\n </MenuItem>\n )}\n </Menu>\n </MenuTrigger>\n <DialogTrigger\n type=\"modal\"\n isOpen={isDeleteDialogOpen}\n onClose={isConfirmed => handleDelete(isConfirmed)}\n >\n <ConfirmationDialog\n isDanger\n title={<Trans message=\"Delete comment?\" />}\n body={\n <Trans message=\"Are you sure you want to delete this comment?\" />\n }\n confirm={<Trans message=\"Delete\" />}\n />\n </DialogTrigger>\n </Fragment>\n );\n}\n\ninterface UserDisplayNameProps {\n user: User;\n}\nfunction UserDisplayName({user}: UserDisplayNameProps) {\n const {auth} = useContext(SiteConfigContext);\n if (auth.getUserProfileLink) {\n return (\n <Link\n to={auth.getUserProfileLink(user)}\n className=\"hover:underline text-base font-medium\"\n >\n {user.display_name}\n </Link>\n );\n }\n return <div className=\"text-base font-medium\">{user.display_name}</div>;\n}\n","import {useAuth} from '@common/auth/use-auth';\nimport {Trans} from '@common/i18n/trans';\nimport {Link} from 'react-router-dom';\nimport {LinkStyle} from '@common/ui/buttons/external-link';\nimport {MessageDescriptor} from '@common/i18n/message-descriptor';\n\ninterface Props {\n message: MessageDescriptor;\n}\nexport function AccountRequiredCard({message}: Props) {\n const {user} = useAuth();\n if (user) return null;\n return (\n <div className=\"border border-dashed py-30 px-20 my-40 mx-auto text-center max-w-850 rounded\">\n <div className=\"text-xl font-semibold mb-8\">\n <Trans message=\"Account required\" />\n </div>\n <div className=\"text-muted text-base\">\n <Trans\n {...message}\n values={{\n l: parts => (\n <Link className={LinkStyle} to=\"/login\">\n {parts}\n </Link>\n ),\n r: parts => (\n <Link className={LinkStyle} to=\"/register\">\n {parts}\n </Link>\n ),\n }}\n />\n </div>\n </div>\n );\n}\n","import {Comment} from '@common/comments/comment';\nimport {Trans} from '@common/i18n/trans';\nimport {CommentIcon} from '@common/icons/material/Comment';\nimport {Commentable} from '@common/comments/commentable';\nimport {useComments} from '@common/comments/requests/use-comments';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {FormattedNumber} from '@common/i18n/formatted-number';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {CommentListItem} from '@common/comments/comment-list/comment-list-item';\nimport {Skeleton} from '@common/ui/skeleton/skeleton';\nimport {ReactNode} from 'react';\nimport {AccountRequiredCard} from '@common/comments/comment-list/account-required-card';\nimport {message} from '@common/i18n/message';\n\nconst accountRequiredMessage = message(\n 'Please <l>login</l> or <r>create account</r> to comment'\n);\n\ninterface CommentListProps {\n commentable: Commentable;\n canDeleteAllComments?: boolean;\n className?: string;\n children?: ReactNode;\n}\nexport function CommentList({\n className,\n commentable,\n canDeleteAllComments = false,\n children,\n}: CommentListProps) {\n const {items, totalItems, ...query} = useComments(commentable);\n\n if (query.isError) {\n return null;\n }\n\n return (\n <div className={className}>\n <div className=\"mb-8 pb-8 border-b flex items-center gap-8\">\n <CommentIcon size=\"sm\" className=\"text-muted\" />\n {query.isInitialLoading ? (\n <Trans message=\"Loading comments...\" />\n ) : (\n <Trans\n message=\":count comments\"\n values={{count: <FormattedNumber value={totalItems || 0} />}}\n />\n )}\n </div>\n {children}\n <AccountRequiredCard message={accountRequiredMessage} />\n <AnimatePresence initial={false} mode=\"wait\">\n {query.isInitialLoading ? (\n <CommentSkeletons count={4} />\n ) : (\n <CommentListItems\n comments={items}\n canDeleteAllComments={canDeleteAllComments}\n commentable={commentable}\n />\n )}\n </AnimatePresence>\n <InfiniteScrollSentinel query={query} variant=\"loadMore\" />\n </div>\n );\n}\n\ninterface CommentListItemsProps {\n comments: Comment[];\n canDeleteAllComments: boolean;\n commentable: Commentable;\n}\nfunction CommentListItems({\n comments,\n commentable,\n canDeleteAllComments,\n}: CommentListItemsProps) {\n if (!comments.length) {\n return (\n <IllustratedMessage\n className=\"mt-24\"\n size=\"sm\"\n title={<Trans message=\"Seems a little quiet over here\" />}\n description={<Trans message=\"Be the first to comment\" />}\n />\n );\n }\n\n return (\n <m.div key=\"comments\" {...opacityAnimation}>\n {comments.map(comment => (\n <CommentListItem\n key={comment.id}\n comment={comment}\n commentable={commentable}\n canDelete={canDeleteAllComments}\n />\n ))}\n </m.div>\n );\n}\n\ninterface CommentSkeletonsProps {\n count: number;\n}\nfunction CommentSkeletons({count}: CommentSkeletonsProps) {\n return (\n <m.div key=\"loading-skeleton\" {...opacityAnimation}>\n {[...new Array(count).keys()].map(index => (\n <div\n key={index}\n className=\"flex items-start gap-24 py-18 min-h-70 group\"\n >\n <Skeleton variant=\"avatar\" radius=\"rounded-full\" size=\"w-60 h-60\" />\n <div className=\"text-sm flex-auto\">\n <Skeleton className=\"text-base max-w-184 mb-4\" />\n <Skeleton className=\"text-sm\" />\n <div className=\"flex items-center gap-8 mt-10\">\n <Skeleton className=\"text-sm max-w-70\" />\n <Skeleton className=\"text-sm max-w-40\" />\n <Skeleton className=\"text-sm max-w-60\" />\n </div>\n </div>\n </div>\n ))}\n </m.div>\n );\n}\n","import {useLinkifiedString} from '@common/utils/hooks/use-linkified-string';\nimport {Fragment, useLayoutEffect, useRef, useState} from 'react';\nimport {Button} from '@common/ui/buttons/button';\nimport {Trans} from '@common/i18n/trans';\nimport clsx from 'clsx';\n\ninterface TruncatedDescriptionProps {\n description?: string;\n className?: string;\n}\n\nexport function TruncatedDescription({\n description,\n className,\n}: TruncatedDescriptionProps) {\n const linkifiedDescription = useLinkifiedString(description);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const [isOverflowing, setIsOverflowing] = useState(false);\n const [isShowingAll, setIsShowingAll] = useState(false);\n\n useLayoutEffect(() => {\n const wrapperHeight =\n wrapperRef.current?.getBoundingClientRect().height || 0;\n const contentHeight = wrapperRef.current?.scrollHeight || 0;\n if (contentHeight > wrapperHeight) {\n setIsOverflowing(true);\n }\n }, []);\n\n if (!linkifiedDescription) return null;\n\n return (\n <Fragment>\n <div\n ref={wrapperRef}\n className={clsx(\n 'relative',\n className,\n !isShowingAll && 'max-h-160 overflow-hidden',\n !isShowingAll &&\n isOverflowing &&\n 'after:absolute after:bottom-0 after:left-0 after:w-full after:h-20 after:bg-gradient-to-b after:from-transparent after:to-background'\n )}\n >\n <div\n ref={contentRef}\n dangerouslySetInnerHTML={{__html: linkifiedDescription}}\n />\n </div>\n {isOverflowing && (\n <Button\n size=\"xs\"\n className=\"mt-20\"\n variant=\"outline\"\n onClick={() => setIsShowingAll(!isShowingAll)}\n >\n {isShowingAll ? (\n <Trans message=\"Show less\" />\n ) : (\n <Trans message=\"Show more\" />\n )}\n </Button>\n )}\n </Fragment>\n );\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {useAuth} from '@common/auth/use-auth';\n\nexport function useCommentPermissions() {\n const {player} = useSettings();\n const {hasPermission} = useAuth();\n const canView = player?.track_comments && hasPermission('comments.view');\n return {canView, canCreate: canView && hasPermission('comments.create')};\n}\n","import {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport React, {Fragment} from 'react';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {useAlbum} from '@app/web-player/albums/requests/use-album';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {AvatarGroup} from '@common/ui/images/avatar-group';\nimport {Avatar} from '@common/ui/images/avatar';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {Album} from '@app/web-player/albums/album';\nimport {getSmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {FormattedDate} from '@common/i18n/formatted-date';\nimport {useSortableTableData} from '@common/ui/tables/use-sortable-table-data';\nimport {BulletSeparatedItems} from '@app/web-player/layout/bullet-separated-items';\nimport {CommentList} from '@common/comments/comment-list/comment-list';\nimport {useAlbumPermissions} from '@app/web-player/albums/use-album-permissions';\nimport {PageStatus} from '@common/http/page-status';\nimport {PageMetaTags} from '@common/http/page-meta-tags';\nimport {TrackActionsBar} from '@app/web-player/tracks/track-actions-bar';\nimport {FocusScope} from '@react-aria/focus';\nimport {ChipList} from '@common/ui/forms/input-field/chip-field/chip-list';\nimport {Chip} from '@common/ui/forms/input-field/chip-field/chip';\nimport {Link} from 'react-router-dom';\nimport {TruncatedDescription} from '@common/ui/truncated-description';\nimport {CommentBarContextProvider} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport {CommentBarNewCommentForm} from '@app/web-player/tracks/waveform/comment-bar-new-comment-form';\nimport {AdHost} from '@common/admin/ads/ad-host';\nimport {useCommentPermissions} from '@app/web-player/tracks/hooks/use-comment-permissions';\n\nexport function AlbumPage() {\n const {canView: showComments, canCreate: allowCommenting} =\n useCommentPermissions();\n const query = useAlbum({\n autoUpdate: true,\n defaultRelations: true,\n });\n const {canEdit} = useAlbumPermissions(query.data?.album);\n\n if (query.data) {\n return (\n <Fragment>\n <CommentBarContextProvider>\n <PageMetaTags query={query} />\n <AdHost slot=\"general_top\" className=\"mb-44\" />\n <AlbumPageHeader album={query.data.album} />\n {allowCommenting ? (\n <CommentBarNewCommentForm\n className=\"mb-16\"\n commentable={query.data.album}\n />\n ) : null}\n </CommentBarContextProvider>\n {query.data.album.tags?.length ? (\n <FocusScope>\n <ChipList className=\"mb-16\" selectable>\n {query.data.album.tags.map(tag => (\n <Chip elementType={Link} to={`/tag/${tag.name}`} key={tag.id}>\n #{tag.display_name || tag.name}\n </Chip>\n ))}\n </ChipList>\n </FocusScope>\n ) : null}\n <TruncatedDescription\n description={query.data.album.description}\n className=\"text-sm mt-24\"\n />\n <AdHost slot=\"album_above\" className=\"mt-34\" />\n <AlbumTrackTable album={query.data.album} />\n {showComments && (\n <CommentList\n className=\"mt-34\"\n commentable={query.data.album}\n canDeleteAllComments={canEdit}\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-44\" />\n </Fragment>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\ninterface AlbumTrackTableProps {\n album: Album;\n}\nfunction AlbumTrackTable({album}: AlbumTrackTableProps) {\n const {data, sortDescriptor, onSortChange} = useSortableTableData(\n album.tracks\n );\n return (\n <div className=\"mt-44\">\n <TrackTable\n queueGroupId={queueGroupId(album)}\n tracks={data}\n sortDescriptor={sortDescriptor}\n onSortChange={onSortChange}\n hideTrackImage\n hideArtist\n hideAlbum\n hidePopularity={false}\n />\n {!album.tracks?.length ? (\n <IllustratedMessage\n className=\"mt-34\"\n title={<Trans message=\"Nothing to display\" />}\n description={\n <Trans message=\"This album does not have any tracks yet\" />\n }\n />\n ) : null}\n </div>\n );\n}\n\ninterface PlaylistPageHeaderProps {\n album: Album;\n}\nfunction AlbumPageHeader({album}: PlaylistPageHeaderProps) {\n const totalDuration = album.tracks?.reduce(\n (t, track) => t + (track.duration || 0),\n 0\n );\n\n return (\n <Fragment>\n <MediaPageHeaderLayout\n className=\"mb-28\"\n image={<AlbumImage album={album} className=\"rounded\" />}\n title={album.name}\n subtitle={\n <AvatarGroup>\n {album.artists?.map(artist => (\n <Avatar\n key={artist.id}\n circle\n src={getSmallArtistImage(artist)}\n label={artist.name}\n link={getArtistLink(artist)}\n />\n ))}\n </AvatarGroup>\n }\n description={\n <BulletSeparatedItems className=\"text-sm text-muted\">\n {album.tracks?.length ? (\n <Trans\n message=\"[one 1 track|other :count tracks]\"\n values={{count: album.tracks.length}}\n />\n ) : null}\n {album.tracks?.length ? (\n <FormattedDuration ms={totalDuration} verbose />\n ) : null}\n <FormattedDate date={album.release_date} />\n </BulletSeparatedItems>\n }\n actionButtons={\n <TrackActionsBar\n item={album}\n managesItem={false}\n buttonGap={undefined}\n buttonSize=\"sm\"\n buttonRadius=\"rounded-full\"\n buttonClassName={actionButtonClassName()}\n >\n <PlaybackToggleButton\n disabled={!album.tracks?.length}\n buttonType=\"text\"\n queueId={queueGroupId(album)}\n className={actionButtonClassName({isFirst: true})}\n />\n </TrackActionsBar>\n }\n />\n </Fragment>\n );\n}\n","import {\n useInfiniteData,\n UseInfiniteDataProps,\n} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Track} from '@app/web-player/tracks/track';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\n\nexport const libraryTracksQueryKey = (userId: number | 'me') => {\n const user = getBootstrapData().user;\n // make sure we are using \"me\" as ID for current user\n // everywhere, so it's easier to invalidate queries\n if (userId === user?.id) {\n userId = 'me';\n }\n return ['tracks', 'library', userId];\n};\n\nexport function useUserLikedTracks(\n userId: number | 'me',\n options?: Partial<UseInfiniteDataProps<Track>>\n) {\n return useInfiniteData<Track>({\n queryKey: libraryTracksQueryKey(userId),\n endpoint: `users/${userId}/liked-tracks`,\n defaultOrderBy: 'likes.created_at',\n defaultOrderDir: 'desc',\n ...options,\n });\n}\n","import {StaticPageTitle} from '@common/seo/static-page-title';\nimport {Trans} from '@common/i18n/trans';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport React from 'react';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {VirtualTableBody} from '@app/web-player/playlists/virtual-table-body';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {useAuth} from '@common/auth/use-auth';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {PageErrorMessage} from '@common/errors/page-error-message';\nimport {TableDataItem} from '@common/ui/tables/types/table-data-item';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {useUserLikedTracks} from '@app/web-player/library/requests/use-user-liked-tracks';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nexport function LibraryTracksPage() {\n const trackCount = useLibraryStore(s => Object.keys(s.track).length);\n\n const query = useUserLikedTracks('me', {willSortOrFilter: true});\n const {\n isInitialLoading,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n items,\n isError,\n } = query;\n\n const {user} = useAuth();\n const {trans} = useTrans();\n const queueId = queueGroupId(user!, 'libraryTracks', sortDescriptor);\n\n if (isError) {\n return <PageErrorMessage />;\n }\n\n return (\n <div>\n <StaticPageTitle>\n <Trans message=\"Your tracks\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <div className=\"flex flex-wrap items-center gap-24 justify-between mb-34\">\n <h1 className=\"text-2xl font-semibold w-max md:w-full whitespace-nowrap\">\n {trackCount ? (\n <Trans\n message=\"[one 1 liked song|other :count liked songs]\"\n values={{count: trackCount}}\n />\n ) : (\n <Trans message=\"My songs\" />\n )}\n </h1>\n <PlaybackToggleButton\n queueId={queueId}\n buttonType=\"text\"\n className=\"min-w-128 flex-shrink-0\"\n />\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 flex-auto\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within tracks'))}\n />\n </div>\n <TrackTable\n queueGroupId={queueId}\n tracks={isInitialLoading ? getPlaceholderItems(trackCount) : items}\n sortDescriptor={sortDescriptor}\n onSortChange={setSortDescriptor}\n hideAddedAtColumn={false}\n tableBody={<VirtualTableBody query={query} totalItems={trackCount} />}\n />\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={\n <Trans message=\"You have not added any songs to your library yet.\" />\n }\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n );\n}\n\nfunction getPlaceholderItems(totalTracks: number): TableDataItem[] {\n // 30 tracks per page by default\n return [...new Array(Math.min(totalTracks, 30)).keys()].map((key, index) => {\n return {\n isPlaceholder: true,\n id: `placeholder-${key}`,\n };\n });\n}\n","import {SortDescriptor} from '@common/ui/tables/types/sort-descriptor';\nimport {Menu, MenuTrigger} from '@common/ui/navigation/menu/menu-trigger';\nimport {Button} from '@common/ui/buttons/button';\nimport {ArrowDropDownIcon} from '@common/icons/material/ArrowDropDown';\nimport {Trans} from '@common/i18n/trans';\nimport {Item} from '@common/ui/forms/listbox/item';\nimport React from 'react';\nimport {MessageDescriptor} from '@common/i18n/message-descriptor';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {SortIcon} from '@common/icons/material/Sort';\n\ninterface Props {\n items: Record<string, MessageDescriptor>;\n sortDescriptor: SortDescriptor;\n setSortDescriptor: (sort: SortDescriptor) => void;\n}\nexport function LibraryPageSortDropdown({\n items,\n sortDescriptor,\n setSortDescriptor,\n}: Props) {\n const isMobile = useIsMobileMediaQuery();\n const selectedValue = `${sortDescriptor.orderBy}:${sortDescriptor.orderDir}`;\n return (\n <MenuTrigger\n selectionMode=\"single\"\n selectedValue={selectedValue}\n onSelectionChange={newValue => {\n const [orderBy, orderDir] = (newValue as string).split(':');\n setSortDescriptor({\n orderBy,\n orderDir: orderDir as SortDescriptor['orderDir'],\n });\n }}\n >\n {isMobile ? (\n <IconButton>\n <SortIcon />\n </IconButton>\n ) : (\n <Button\n variant=\"outline\"\n className=\"flex-shrink-0\"\n endIcon={<ArrowDropDownIcon />}\n >\n <Trans {...items[selectedValue]} />\n </Button>\n )}\n <Menu>\n {Object.entries(items).map(([value, label]) => (\n <Item key={value} value={value}>\n <Trans {...label} />\n </Item>\n ))}\n </Menu>\n </MenuTrigger>\n );\n}\n","import {\n useInfiniteData,\n UseInfiniteDataProps,\n} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Album} from '@app/web-player/albums/album';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\n\nexport const libraryAlbumsQueryKey = (\n userId: number | 'me',\n queryParams?: Record<string, string | number>\n) => {\n const user = getBootstrapData().user;\n // make sure we are using \"me\" as ID for current user\n // everywhere, so it's easier to invalidate queries\n if (userId === user?.id) {\n userId = 'me';\n }\n const key: any[] = ['albums', 'library', userId];\n if (queryParams) {\n key.push(queryParams);\n }\n return key;\n};\n\nexport function useUserLikedAlbums(\n userId: number | 'me',\n options?: Partial<UseInfiniteDataProps<Album>>\n) {\n return useInfiniteData<Album>({\n queryKey: libraryAlbumsQueryKey(userId),\n endpoint: `users/${userId}/liked-albums`,\n defaultOrderBy: 'likes.created_at',\n defaultOrderDir: 'desc',\n ...options,\n });\n}\n","import {StaticPageTitle} from '@common/seo/static-page-title';\nimport {Trans} from '@common/i18n/trans';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport React from 'react';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {PageErrorMessage} from '@common/errors/page-error-message';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {PlayableMediaGridSkeleton} from '@app/web-player/playable-item/player-media-grid-skeleton';\nimport {LibraryPageSortDropdown} from '@app/web-player/library/library-page-sort-dropdown';\nimport {useUserLikedAlbums} from '@app/web-player/library/requests/use-user-liked-albums';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nconst sortItems = {\n 'likes.created_at:desc': message('Recently added'),\n 'name:asc': message('A-Z'),\n 'release_date:desc': message('Release date'),\n};\n\nexport function LibraryAlbumsPage() {\n const {trans} = useTrans();\n const totalItems = useLibraryStore(s => Object.keys(s.album).length);\n const query = useUserLikedAlbums('me', {willSortOrFilter: true});\n const {\n isInitialLoading,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n items,\n isError,\n } = query;\n\n if (isError) {\n return <PageErrorMessage />;\n }\n\n return (\n <div>\n <StaticPageTitle>\n <Trans message=\"Your albums\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <h1 className=\"text-2xl font-semibold mb-20\">\n {totalItems ? (\n <Trans\n message=\"[one 1 liked album|other :count liked albums]\"\n values={{count: totalItems}}\n />\n ) : (\n <Trans message=\"My albums\" />\n )}\n </h1>\n <div className=\"flex items-center gap-24 justify-between\">\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 flex-auto\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within albums'))}\n />\n <LibraryPageSortDropdown\n items={sortItems}\n sortDescriptor={sortDescriptor}\n setSortDescriptor={setSortDescriptor}\n />\n </div>\n <div className=\"mt-34\">\n <AnimatePresence initial={false} mode=\"wait\">\n {isInitialLoading ? (\n <PlayableMediaGridSkeleton itemCount={totalItems} />\n ) : (\n <m.div key=\"media-grid\" {...opacityAnimation}>\n <ContentGrid>\n {items.map(album => (\n <AlbumGridItem key={album.id} album={album} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </ContentGrid>\n </m.div>\n )}\n </AnimatePresence>\n </div>\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={\n <Trans message=\"You have not added any albums to your library yet.\" />\n }\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n );\n}\n","import {\n useInfiniteData,\n UseInfiniteDataProps,\n} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {Artist} from '@app/web-player/artists/artist';\n\nexport const libraryArtistsQueryKey = (userId: number | 'me') => {\n const user = getBootstrapData().user;\n // make sure we are using \"me\" as ID for current user\n // everywhere, so it's easier to invalidate queries\n if (userId === user?.id) {\n userId = 'me';\n }\n return ['artists', 'library', userId];\n};\n\nexport function useUserLikedArtists(\n userId: number | 'me',\n options?: Partial<UseInfiniteDataProps<Artist>>\n) {\n return useInfiniteData<Artist>({\n queryKey: libraryArtistsQueryKey(userId),\n endpoint: `users/${userId}/liked-artists`,\n defaultOrderBy: 'likes.created_at',\n defaultOrderDir: 'desc',\n ...options,\n });\n}\n","import {StaticPageTitle} from '@common/seo/static-page-title';\nimport {Trans} from '@common/i18n/trans';\nimport {useLibraryStore} from '@app/web-player/library/state/likes-store';\nimport React from 'react';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {PageErrorMessage} from '@common/errors/page-error-message';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {ArtistGridItem} from '@app/web-player/artists/artist-grid-item';\nimport {PlayableMediaGridSkeleton} from '@app/web-player/playable-item/player-media-grid-skeleton';\nimport {LibraryPageSortDropdown} from '@app/web-player/library/library-page-sort-dropdown';\nimport {useUserLikedArtists} from '@app/web-player/library/requests/use-user-liked-artists';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nconst sortItems = {\n 'likes.created_at:desc': message('Recently added'),\n 'name:asc': message('A-Z'),\n};\n\nexport function LibraryArtistsPage() {\n const {trans} = useTrans();\n const totalItems = useLibraryStore(s => Object.keys(s.artist).length);\n const query = useUserLikedArtists('me', {willSortOrFilter: true});\n const {\n isInitialLoading,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n items,\n isError,\n } = query;\n\n if (isError) {\n return <PageErrorMessage />;\n }\n\n return (\n <div>\n <StaticPageTitle>\n <Trans message=\"Your artists\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <h1 className=\"text-2xl font-semibold mb-20\">\n {totalItems ? (\n <Trans\n message=\"[one 1 liked artist|other :count liked artists]\"\n values={{count: totalItems}}\n />\n ) : (\n <Trans message=\"My artists\" />\n )}\n </h1>\n <div className=\"flex items-center gap-24 justify-between\">\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 flex-auto\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within artists'))}\n />\n <LibraryPageSortDropdown\n items={sortItems}\n sortDescriptor={sortDescriptor}\n setSortDescriptor={setSortDescriptor}\n />\n </div>\n <div className=\"mt-34\">\n <AnimatePresence initial={false} mode=\"wait\">\n {isInitialLoading ? (\n <PlayableMediaGridSkeleton\n itemCount={totalItems}\n itemRadius=\"rounded-full\"\n showDescription={false}\n />\n ) : (\n <m.div key=\"media-grid\" {...opacityAnimation}>\n <ContentGrid>\n {items.map(artist => (\n <ArtistGridItem key={artist.id} artist={artist} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </ContentGrid>\n </m.div>\n )}\n </AnimatePresence>\n </div>\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={\n <Trans message=\"You have not added any artists to your library yet.\" />\n }\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n );\n}\n","import {StaticPageTitle} from '@common/seo/static-page-title';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {VirtualTableBody} from '@app/web-player/playlists/virtual-table-body';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {useAuth} from '@common/auth/use-auth';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {PageErrorMessage} from '@common/errors/page-error-message';\nimport {TableDataItem} from '@common/ui/tables/types/table-data-item';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {Track} from '@app/web-player/tracks/track';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nexport const libraryHistoryQueryKey = ['tracks', 'history', 'me'];\n\nexport function LibraryHistoryPage() {\n const {user} = useAuth();\n\n const query = useInfiniteData<Track>({\n queryKey: libraryHistoryQueryKey,\n endpoint: `tracks/plays/${user!.id}`,\n defaultOrderBy: 'track_plays.created_at',\n defaultOrderDir: 'desc',\n paginate: 'simple',\n willSortOrFilter: false,\n });\n const {isInitialLoading, searchQuery, setSearchQuery, items, isError} = query;\n\n const {trans} = useTrans();\n const queueId = queueGroupId(user!, 'playHistory');\n\n if (isError) {\n return <PageErrorMessage />;\n }\n\n return (\n <div>\n <StaticPageTitle>\n <Trans message=\"Listening history\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <div className=\"flex flex-wrap items-center gap-24 justify-between mb-34\">\n <h1 className=\"text-2xl font-semibold w-max md:w-full whitespace-nowrap\">\n <Trans message=\"Listening history\" />\n </h1>\n <PlaybackToggleButton\n queueId={queueId}\n buttonType=\"text\"\n className=\"min-w-128 flex-shrink-0\"\n />\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 flex-auto\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within history'))}\n />\n </div>\n <TrackTable\n enableSorting={false}\n queueGroupId={queueId}\n tracks={isInitialLoading ? getPlaceholderItems() : items}\n hideAddedAtColumn={false}\n tableBody={<VirtualTableBody query={query} />}\n />\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={<Trans message=\"You have not played any songs yet.\" />}\n />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-34\" />\n </div>\n );\n}\n\nfunction getPlaceholderItems(): TableDataItem[] {\n // 30 tracks per page by default\n return [...new Array(10).keys()].map(key => {\n return {\n isPlaceholder: true,\n id: `placeholder-${key}`,\n };\n });\n}\n","import {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport React, {Fragment} from 'react';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {AvatarGroup} from '@common/ui/images/avatar-group';\nimport {Avatar} from '@common/ui/images/avatar';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {Album} from '@app/web-player/albums/album';\nimport {getSmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {getArtistLink} from '@app/web-player/artists/artist-link';\nimport {FormattedDate} from '@common/i18n/formatted-date';\nimport {useSortableTableData} from '@common/ui/tables/use-sortable-table-data';\nimport {BulletSeparatedItems} from '@app/web-player/layout/bullet-separated-items';\nimport {CommentList} from '@common/comments/comment-list/comment-list';\nimport {useTrack} from '@app/web-player/tracks/requests/use-track';\nimport {useTrackPermissions} from '@app/web-player/tracks/hooks/use-track-permissions';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {AlbumImage} from '@app/web-player/albums/album-image/album-image';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {FormattedNumber} from '@common/i18n/formatted-number';\nimport {TruncatedDescription} from '@common/ui/truncated-description';\nimport {Waveform} from '@app/web-player/tracks/waveform/waveform';\nimport {CommentBarContextProvider} from '@app/web-player/tracks/waveform/comment-bar-context';\nimport {CommentBarNewCommentForm} from '@app/web-player/tracks/waveform/comment-bar-new-comment-form';\nimport {GenreLink} from '@app/web-player/genres/genre-link';\nimport {PageMetaTags} from '@common/http/page-meta-tags';\nimport {PageStatus} from '@common/http/page-status';\nimport {TrackActionsBar} from '@app/web-player/tracks/track-actions-bar';\nimport {Chip} from '@common/ui/forms/input-field/chip-field/chip';\nimport {ChipList} from '@common/ui/forms/input-field/chip-field/chip-list';\nimport {Link} from 'react-router-dom';\nimport {FocusScope} from '@react-aria/focus';\nimport {trackIsLocallyUploaded} from '@app/web-player/tracks/utils/track-is-locally-uploaded';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {AdHost} from '@common/admin/ads/ad-host';\nimport {useCommentPermissions} from '@app/web-player/tracks/hooks/use-comment-permissions';\n\nexport function TrackPage() {\n const {canView: showComments, canCreate: allowCommenting} =\n useCommentPermissions();\n const query = useTrack({autoUpdate: true});\n const {canEdit} = useTrackPermissions([query.data?.track]);\n\n if (query.data) {\n return (\n <Fragment>\n <CommentBarContextProvider>\n <PageMetaTags query={query} />\n <AdHost slot=\"general_top\" className=\"mb-44\" />\n <TrackPageHeader track={query.data.track} />\n {allowCommenting ? (\n <CommentBarNewCommentForm\n className=\"mb-16\"\n commentable={query.data.track}\n />\n ) : null}\n </CommentBarContextProvider>\n {query.data.track.tags.length ? (\n <FocusScope>\n <ChipList className=\"mb-16\" selectable>\n {query.data.track.tags.map(tag => (\n <Chip elementType={Link} to={`/tag/${tag.name}`} key={tag.id}>\n #{tag.display_name || tag.name}\n </Chip>\n ))}\n </ChipList>\n </FocusScope>\n ) : null}\n <TruncatedDescription\n description={query.data.track.description}\n className=\"text-sm mt-24\"\n />\n {showComments ? (\n <CommentList\n className=\"mt-34\"\n commentable={query.data.track}\n canDeleteAllComments={canEdit}\n />\n ) : null}\n {query.data.track.album && (\n <AlbumTrackTable album={query.data.track.album} />\n )}\n <AdHost slot=\"general_bottom\" className=\"mt-44\" />\n </Fragment>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\ninterface AlbumTrackTableProps {\n album: Album;\n}\nfunction AlbumTrackTable({album}: AlbumTrackTableProps) {\n const {data, sortDescriptor, onSortChange} = useSortableTableData(\n album.tracks\n );\n return (\n <div className=\"mt-44\">\n <div className=\"flex items-center gap-16 bg-hover rounded overflow-hidden mb-14\">\n <AlbumImage\n album={album}\n className=\"flex-shrink-0 rounded\"\n size=\"w-70 h-70\"\n />\n <div className=\"flex-auto\">\n <div className=\"text-sm\">\n <Trans message=\"From the album\" />\n </div>\n <div className=\"font-semibold text-sm\">{album.name}</div>\n </div>\n </div>\n <TrackTable\n queueGroupId={queueGroupId(album)}\n tracks={data}\n sortDescriptor={sortDescriptor}\n onSortChange={onSortChange}\n hideTrackImage\n hideArtist\n hideAlbum\n hidePopularity={false}\n />\n {!album.tracks?.length ? (\n <IllustratedMessage\n className=\"mt-34\"\n title={<Trans message=\"Nothing to display\" />}\n description={\n <Trans message=\"This album does not have any tracks yet\" />\n }\n />\n ) : null}\n </div>\n );\n}\n\ninterface TrackPageHeaderProps {\n track: Track;\n}\nfunction TrackPageHeader({track}: TrackPageHeaderProps) {\n const isMobile = useIsMobileMediaQuery();\n const {player} = useSettings();\n const releaseDate = track.album?.release_date || track.created_at;\n const genre = track.genres?.[0];\n\n const showWave =\n !isMobile &&\n player?.seekbar_type === 'waveform' &&\n trackIsLocallyUploaded(track);\n\n return (\n <Fragment>\n <MediaPageHeaderLayout\n className=\"mb-28\"\n image={<TrackImage track={track} />}\n title={track.name}\n subtitle={\n <AvatarGroup>\n {track.artists?.map(artist => (\n <Avatar\n key={artist.id}\n circle\n src={getSmallArtistImage(artist)}\n label={artist.name}\n link={getArtistLink(artist)}\n />\n ))}\n </AvatarGroup>\n }\n description={\n <BulletSeparatedItems className=\"text-sm text-muted\">\n {track.duration ? (\n <FormattedDuration ms={track.duration} verbose />\n ) : null}\n {releaseDate && <FormattedDate date={releaseDate} />}\n {genre && <GenreLink genre={genre} />}\n {track.plays && !player?.enable_repost ? (\n <Trans\n message=\":count plays\"\n values={{count: <FormattedNumber value={track.plays} />}}\n />\n ) : null}\n </BulletSeparatedItems>\n }\n actionButtons={\n <TrackActionsBar\n item={track}\n managesItem={false}\n buttonGap={undefined}\n buttonSize=\"sm\"\n buttonRadius=\"rounded-full\"\n buttonClassName={actionButtonClassName()}\n >\n <PlaybackToggleButton\n buttonType=\"text\"\n track={track}\n tracks={\n track.album?.tracks?.length ? track.album.tracks : undefined\n }\n className={actionButtonClassName({isFirst: true})}\n queueId={queueGroupId(track.album || track)}\n />\n </TrackActionsBar>\n }\n footer={showWave ? <Waveform track={track} /> : undefined}\n />\n </Fragment>\n );\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useParams} from 'react-router-dom';\nimport {User} from '@common/auth/user';\n\ninterface getTrackResponse extends BackendResponse {\n user: User;\n}\n\nexport function useUserProfile() {\n const {userId} = useParams();\n return useQuery(userProfileQueryKey(userId!), () => fetchUser(userId!));\n}\n\nfunction fetchUser(userId: number | string) {\n return apiClient\n .get<getTrackResponse>(`users/${userId}`)\n .then(response => response.data);\n}\n\nexport function userProfileQueryKey(userId: number | string) {\n return ['users', +userId, 'profile'];\n}\n","import {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Repost} from '@app/web-player/reposts/repost';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {AudiotrackIcon} from '@common/icons/material/Audiotrack';\nimport {Trans} from '@common/i18n/trans';\nimport {TrackListItem} from '@app/web-player/tracks/track-list/track-list-item';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport React from 'react';\nimport {ProfileContentProps} from '@app/web-player/user-profile/user-profile-page';\nimport {AlbumListItem} from '@app/web-player/albums/album-list/album-list-item';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {TrackGridItem} from '@app/web-player/tracks/track-grid-item';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\n\nexport function ProfileRepostsPanel({user}: ProfileContentProps) {\n const isMobile = useIsMobileMediaQuery();\n const query = useInfiniteData<Repost>({\n queryKey: ['reposts', user.id],\n endpoint: `users/${user.id}/reposts`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AudiotrackIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No reposts yet\" />}\n description={\n <Trans\n message=\"Follow :user for updates on tracks and albums they repost in the future.\"\n values={{user: user.display_name}}\n />\n }\n />\n );\n }\n\n if (isMobile) {\n return (\n <div>\n <ContentGrid>\n {query.items.map(repost => {\n if (repost.repostable?.model_type === 'track') {\n return (\n <TrackGridItem track={repost.repostable} key={repost.id} />\n );\n } else if (repost.repostable?.model_type === 'album') {\n return (\n <AlbumGridItem album={repost.repostable} key={repost.id} />\n );\n }\n return null;\n })}\n </ContentGrid>\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n }\n\n return (\n <div>\n {query.items.map(repost => {\n if (repost.repostable?.model_type === 'track') {\n return (\n <TrackListItem\n className=\"mb-40\"\n key={repost.id}\n track={repost.repostable}\n reposter={user}\n />\n );\n } else if (repost.repostable?.model_type === 'album') {\n return (\n <AlbumListItem\n key={repost.id}\n album={repost.repostable}\n className=\"mb-40\"\n />\n );\n }\n return null;\n })}\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {useUserLikedTracks} from '@app/web-player/library/requests/use-user-liked-tracks';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {AudiotrackIcon} from '@common/icons/material/Audiotrack';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {ProfileContentProps} from '@app/web-player/user-profile/user-profile-page';\nimport {TrackList} from '@app/web-player/tracks/track-list/track-list';\n\nexport function ProfileTracksPanel({user}: ProfileContentProps) {\n const query = useUserLikedTracks(user.id);\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AudiotrackIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No tracks yet\" />}\n description={\n <Trans\n message=\"Follow :user for updates on tracks they like in the future.\"\n values={{user: user.display_name}}\n />\n }\n />\n );\n }\n\n return <TrackList query={query} />;\n}\n","import {\n useInfiniteData,\n UseInfiniteDataProps,\n} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\nimport {Playlist} from '@app/web-player/playlists/playlist';\n\nexport const libraryPlaylistsQueryKey = (\n userId: number | 'me',\n queryParams?: Record<string, string | number>\n) => {\n const user = getBootstrapData().user;\n // make sure we are using \"me\" as ID for current user\n // everywhere, so it's easier to invalidate queries\n if (userId === user?.id) {\n userId = 'me';\n }\n const key: any[] = ['playlists', 'library', userId];\n if (queryParams) {\n key.push(queryParams);\n }\n return key;\n};\n\nexport function useUserPlaylists(\n userId: number | 'me',\n options?: Partial<UseInfiniteDataProps<Playlist>>\n) {\n return useInfiniteData<Playlist>({\n queryKey: libraryPlaylistsQueryKey(userId),\n endpoint: `users/${userId}/playlists`,\n defaultOrderBy: 'updated_at',\n defaultOrderDir: 'desc',\n ...options,\n });\n}\n","import {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport React from 'react';\nimport {ProfileContentProps} from '@app/web-player/user-profile/user-profile-page';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {PlaylistGridItem} from '@app/web-player/playlists/playlist-grid-item';\nimport {QueueMusicIcon} from '@common/icons/material/QueueMusic';\nimport {useUserPlaylists} from '@app/web-player/library/requests/use-user-playlists';\n\nexport function ProfilePlaylistsPanel({user}: ProfileContentProps) {\n const query = useUserPlaylists(user.id);\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<QueueMusicIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No playlists yet\" />}\n description={\n <Trans\n message=\"Follow :user for updates on playlists they create in the future.\"\n values={{user: user.display_name}}\n />\n }\n />\n );\n }\n\n return (\n <div>\n <ContentGrid>\n {query.items.map(playlist => (\n <PlaylistGridItem key={playlist.id} playlist={playlist} />\n ))}\n </ContentGrid>\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {ProfileContentProps} from '@app/web-player/user-profile/user-profile-page';\nimport {useUserLikedAlbums} from '@app/web-player/library/requests/use-user-liked-albums';\nimport {AlbumIcon} from '@common/icons/material/Album';\nimport {AlbumList} from '@app/web-player/albums/album-list/album-list';\n\nexport function ProfileAlbumsPanel({user}: ProfileContentProps) {\n const query = useUserLikedAlbums(user.id, {\n queryParams: {\n with: 'tracks',\n },\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AlbumIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No albums yet\" />}\n description={\n <Trans\n message=\"Follow :user for updates on albums they like in the future.\"\n values={{user: user.display_name}}\n />\n }\n />\n );\n }\n\n return <AlbumList query={query} />;\n}\n","import {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {Trans} from '@common/i18n/trans';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport React from 'react';\nimport {ProfileContentProps} from '@app/web-player/user-profile/user-profile-page';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {useUserLikedArtists} from '@app/web-player/library/requests/use-user-liked-artists';\nimport {MicIcon} from '@common/icons/material/Mic';\nimport {ArtistGridItem} from '@app/web-player/artists/artist-grid-item';\n\nexport function ProfileArtistsPanel({user}: ProfileContentProps) {\n const query = useUserLikedArtists(user.id);\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<MicIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No artists yet\" />}\n description={\n <Trans\n message=\"Follow :user for updates on artists they like in the future.\"\n values={{user: user.display_name}}\n />\n }\n />\n );\n }\n\n return (\n <div>\n <ContentGrid>\n {query.items.map(artist => (\n <ArtistGridItem key={artist.id} artist={artist} />\n ))}\n </ContentGrid>\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {Trans} from '@common/i18n/trans';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {User} from '@common/auth/user';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport React from 'react';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {BookmarkBorderIcon} from '@common/icons/material/BookmarkBorder';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {FollowerListItem} from '@app/web-player/artists/artist-page/followers-panel/follower-list-item';\n\ninterface Props {\n user: User;\n}\nexport function ProfileFollowersPanel({user}: Props) {\n const query = useInfiniteData<User>({\n queryKey: ['users', user.id, 'followers'],\n endpoint: `users/${user.id}/followers`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<BookmarkBorderIcon size=\"lg\" className=\"text-muted\" />}\n description={\n <Trans\n message=\"Seems like no one is following :name yet.\"\n values={{name: user.display_name}}\n />\n }\n />\n );\n }\n\n return (\n <div>\n {query.items.map(follower => (\n <FollowerListItem key={follower.id} follower={follower} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {Trans} from '@common/i18n/trans';\nimport {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {User} from '@common/auth/user';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport React from 'react';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {BookmarkBorderIcon} from '@common/icons/material/BookmarkBorder';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {FollowerListItem} from '@app/web-player/artists/artist-page/followers-panel/follower-list-item';\n\ninterface Props {\n user: User;\n}\nexport function ProfileFollowedUsersPanel({user}: Props) {\n const query = useInfiniteData<User>({\n queryKey: ['users', user.id, 'followed-users'],\n endpoint: `users/${user.id}/followed-users`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<BookmarkBorderIcon size=\"lg\" className=\"text-muted\" />}\n description={\n <Trans\n message=\"Seems like :name is not following anyone yet.\"\n values={{name: user.display_name}}\n />\n }\n />\n );\n }\n\n return (\n <div>\n {query.items.map(follower => (\n <FollowerListItem key={follower.id} follower={follower} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </div>\n );\n}\n","import {useMutation} from '@tanstack/react-query';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {toast} from '@common/ui/toast/toast';\nimport {message} from '@common/i18n/message';\nimport {apiClient, queryClient} from '@common/http/query-client';\nimport {onFormQueryError} from '@common/errors/on-form-query-error';\nimport {UseFormReturn} from 'react-hook-form';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {Album} from '@app/web-player/albums/album';\nimport {useAuth} from '@common/auth/use-auth';\nimport {UserLink} from '@app/web-player/user-profile/user-link';\nimport {userProfileQueryKey} from '@app/web-player/user-profile/requests/use-user-profile';\n\ninterface Response extends BackendResponse {\n album: Album;\n}\n\nexport interface UpdateProfilePayload {\n user: {\n avatar?: string;\n first_name?: string;\n last_name?: string;\n username?: string;\n };\n profile: {\n city?: string;\n country?: string;\n description?: string;\n };\n links: UserLink[];\n}\n\nexport function useUpdateUserProfile(\n form: UseFormReturn<UpdateProfilePayload>\n) {\n const {user} = useAuth();\n const {trans} = useTrans();\n return useMutation(\n (payload: UpdateProfilePayload) => updateProfile(payload),\n {\n onSuccess: () => {\n toast(trans(message('Profile updated')));\n if (user) {\n queryClient.invalidateQueries(userProfileQueryKey(user.id));\n }\n },\n onError: err => onFormQueryError(err, form),\n }\n );\n}\n\nfunction updateProfile(payload: UpdateProfilePayload): Promise<Response> {\n return apiClient.put('users/profile/update', payload).then(r => r.data);\n}\n","import {useController} from 'react-hook-form';\nimport {mergeProps} from '@react-aria/utils';\nimport React from 'react';\nimport {ComboBox, ComboboxProps} from './combobox';\n\ntype Props<T extends object> = ComboboxProps<T> & {\n name: string;\n selectionMode?: 'single';\n};\nexport function FormComboBox<T extends object>({children, ...props}: Props<T>) {\n const {\n field: {onChange, onBlur, value = '', ref},\n fieldState: {invalid, error},\n } = useController({\n name: props.name,\n });\n\n const formProps: Partial<ComboboxProps<T>> = {\n onSelectionChange: onChange,\n onBlur,\n selectedValue: value,\n defaultInputValue: value,\n invalid,\n errorMessage: error?.message,\n };\n\n return (\n <ComboBox ref={ref} {...mergeProps(formProps, props)}>\n {children}\n </ComboBox>\n );\n}\n","import {Dialog} from '@common/ui/overlays/dialog/dialog';\nimport {DialogHeader} from '@common/ui/overlays/dialog/dialog-header';\nimport {Trans} from '@common/i18n/trans';\nimport {DialogBody} from '@common/ui/overlays/dialog/dialog-body';\nimport {DialogFooter} from '@common/ui/overlays/dialog/dialog-footer';\nimport {Button} from '@common/ui/buttons/button';\nimport {useDialogContext} from '@common/ui/overlays/dialog/dialog-context';\nimport {\n UpdateProfilePayload,\n useUpdateUserProfile,\n} from '@app/web-player/user-profile/requests/use-update-user-profile';\nimport {useForm} from 'react-hook-form';\nimport {User} from '@common/auth/user';\nimport {Form} from '@common/ui/forms/form';\nimport {FormTextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {FormImageSelector} from '@common/ui/images/image-selector';\nimport {FileUploadProvider} from '@common/uploads/uploader/file-upload-provider';\nimport {ProfileLinksForm} from '@app/admin/artist-datatable-page/artist-form/profile-links-form';\nimport {Option} from '@common/ui/forms/combobox/combobox';\nimport {FormComboBox} from '@common/ui/forms/combobox/form-combobox';\nimport {useValueLists} from '@common/http/value-lists';\n\ninterface Props {\n user: User;\n}\nexport function EditProfileDialog({user}: Props) {\n const {close, formId} = useDialogContext();\n const {data} = useValueLists(['countries']);\n const form = useForm<UpdateProfilePayload>({\n defaultValues: {\n user: {\n username: user.username,\n avatar: user.avatar,\n first_name: user.first_name,\n last_name: user.last_name,\n },\n profile: {\n city: user.profile?.city,\n country: user.profile?.country,\n description: user.profile?.description,\n },\n links: user.links,\n },\n });\n const updateProfile = useUpdateUserProfile(form);\n return (\n <Dialog size=\"xl\">\n <DialogHeader>\n <Trans message=\"Edit your profile\" />\n </DialogHeader>\n <DialogBody>\n <Form\n id={formId}\n form={form}\n onSubmit={values =>\n updateProfile.mutate(values, {onSuccess: () => close()})\n }\n >\n <FileUploadProvider>\n <div className=\"md:flex items-start gap-30\">\n <FormImageSelector\n label={<Trans message=\"Avatar\" />}\n name=\"user.avatar\"\n diskPrefix=\"avatars\"\n variant=\"square\"\n previewSize=\"w-200 h-200\"\n className=\"max-md:mb-20\"\n />\n <div className=\"flex-auto\">\n <FormTextField\n name=\"user.username\"\n label={<Trans message=\"Username\" />}\n className=\"mb-24\"\n />\n <div className=\"flex items-center gap-24\">\n <FormTextField\n name=\"user.first_name\"\n label={<Trans message=\"First name\" />}\n className=\"flex-1 mb-24\"\n />\n <FormTextField\n name=\"user.last_name\"\n label={<Trans message=\"Last name\" />}\n className=\"flex-1 mb-24\"\n />\n </div>\n <div className=\"flex items-center gap-24\">\n <FormTextField\n name=\"profile.city\"\n label={<Trans message=\"City\" />}\n className=\"flex-1 mb-24\"\n />\n <FormComboBox\n className=\"flex-1 mb-24\"\n selectionMode=\"single\"\n name=\"profile.country\"\n label={<Trans message=\"Country\" />}\n >\n {data?.countries?.map(country => (\n <Option key={country.code} value={country.name}>\n {country.name}\n </Option>\n ))}\n </FormComboBox>\n </div>\n <FormTextField\n name=\"profile.description\"\n label={<Trans message=\"Description\" />}\n inputElementType=\"textarea\"\n rows={4}\n />\n </div>\n </div>\n <div className=\"mt-24\">\n <div className=\"mb-16 pb-16 border-b\">\n <Trans message=\"Your links\" />\n </div>\n <ProfileLinksForm />\n </div>\n </FileUploadProvider>\n </Form>\n </DialogBody>\n <DialogFooter>\n <Button\n type=\"button\"\n onClick={() => {\n close();\n }}\n >\n <Trans message=\"Cancel\" />\n </Button>\n <Button\n form={formId}\n type=\"submit\"\n variant=\"flat\"\n color=\"primary\"\n disabled={updateProfile.isLoading}\n >\n <Trans message=\"Save\" />\n </Button>\n </DialogFooter>\n </Dialog>\n );\n}\n","import {useAuth} from '@common/auth/use-auth';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {UserImage} from '@app/web-player/users/user-image';\nimport {BulletSeparatedItems} from '@app/web-player/layout/bullet-separated-items';\nimport {Link} from 'react-router-dom';\nimport {Trans} from '@common/i18n/trans';\nimport {ProfileDescription} from '@app/web-player/user-profile/profile-description';\nimport React from 'react';\nimport {User} from '@common/auth/user';\nimport {userFollowsStore} from '@app/web-player/users/user-follows-store';\nimport {useFollowUser} from '@app/web-player/users/use-follow-user';\nimport {useUnfollowUser} from '@app/web-player/users/use-unfollow-user';\nimport {Button} from '@common/ui/buttons/button';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {EditIcon} from '@common/icons/material/Edit';\nimport {EditProfileDialog} from '@app/web-player/user-profile/edit-profile-dialog';\n\ninterface ProfileHeaderProps {\n user: User;\n tabLink: (tabName: string) => string;\n}\n\nexport function ProfileHeader({user, tabLink}: ProfileHeaderProps) {\n const {user: currentUser} = useAuth();\n\n return (\n <MediaPageHeaderLayout\n image={\n <UserImage\n user={user}\n size=\"w-240 h-240\"\n className=\"rounded\"\n showProBadge\n />\n }\n title={user.display_name}\n subtitle={\n <BulletSeparatedItems className=\"text-sm text-muted z-20 w-max mx-auto\">\n {user.followers_count && user.followers_count > 0 ? (\n <Link to={tabLink('followers')} className=\"hover:underline\">\n <Trans\n message=\":count followers\"\n values={{count: user.followers_count}}\n />\n </Link>\n ) : null}\n {user.followed_users_count && user.followed_users_count > 0 ? (\n <Link to={tabLink('following')} className=\"hover:underline\">\n <Trans\n message=\"Following :count\"\n values={{count: user.followed_users_count}}\n />\n </Link>\n ) : null}\n </BulletSeparatedItems>\n }\n actionButtons={\n <div className=\"flex items-center justify-center md:justify-start\">\n <FollowButton user={user} />\n {currentUser?.id === user.id && <EditButton user={user} />}\n </div>\n }\n footer={<ProfileDescription profile={user.profile} links={user.links} />}\n />\n );\n}\n\ninterface EditButtonProps {\n user: User;\n}\n\nfunction EditButton({user}: EditButtonProps) {\n return (\n <DialogTrigger type=\"modal\">\n <Button\n variant=\"outline\"\n radius=\"rounded-full\"\n startIcon={<EditIcon />}\n className={actionButtonClassName()}\n >\n <Trans message=\"Edit\" />\n </Button>\n <EditProfileDialog user={user} />\n </DialogTrigger>\n );\n}\n\nfunction FollowButton({user}: EditButtonProps) {\n const {user: currentUser} = useAuth();\n const isFollowing = userFollowsStore(s => s.isFollowing(user.id));\n const followUser = useFollowUser();\n const unfollowUser = useUnfollowUser();\n\n if (isFollowing) {\n return (\n <Button\n variant=\"flat\"\n color=\"primary\"\n className={actionButtonClassName({isFirst: true})}\n radius=\"rounded-full\"\n onClick={() => unfollowUser.mutate({user})}\n disabled={currentUser?.id === user.id || unfollowUser.isLoading}\n >\n <Trans message=\"Unfollow\" />\n </Button>\n );\n }\n\n return (\n <Button\n variant=\"flat\"\n color=\"primary\"\n className={actionButtonClassName({isFirst: true})}\n radius=\"rounded-full\"\n onClick={() => followUser.mutate({user})}\n disabled={currentUser?.id === user.id || followUser.isLoading}\n >\n <Trans message=\"Follow\" />\n </Button>\n );\n}\n","import {useUserProfile} from '@app/web-player/user-profile/requests/use-user-profile';\nimport {User} from '@common/auth/user';\nimport {PageStatus} from '@common/http/page-status';\nimport React, {Fragment, useCallback} from 'react';\nimport {Tabs} from '@common/ui/tabs/tabs';\nimport {TabList} from '@common/ui/tabs/tab-list';\nimport {Tab} from '@common/ui/tabs/tab';\nimport {Trans} from '@common/i18n/trans';\nimport {TabPanel, TabPanels} from '@common/ui/tabs/tab-panels';\nimport {Link, useParams} from 'react-router-dom';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {ProfileRepostsPanel} from '@app/web-player/user-profile/panels/profile-reposts-panel';\nimport {ProfileTracksPanel} from '@app/web-player/user-profile/panels/profile-tracks-panel';\nimport {ProfilePlaylistsPanel} from '@app/web-player/user-profile/panels/profile-playlists-panel';\nimport {ProfileAlbumsPanel} from '@app/web-player/user-profile/panels/profile-albums-panel';\nimport {ProfileArtistsPanel} from '@app/web-player/user-profile/panels/profile-artists-panel';\nimport {ProfileFollowersPanel} from '@app/web-player/user-profile/panels/profile-followers-panel';\nimport {ProfileFollowedUsersPanel} from '@app/web-player/user-profile/panels/profile-followed-users-panel';\nimport {ProfileHeader} from '@app/web-player/user-profile/header/profile-header';\nimport {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';\n\nconst profileTabs = [\n 'tracks',\n 'playlists',\n 'reposts',\n 'albums',\n 'artists',\n 'followers',\n 'following',\n];\n\nif (!getBootstrapData().settings.player?.enable_repost) {\n profileTabs.splice(2, 1);\n}\n\nexport function UserProfilePage() {\n const query = useUserProfile();\n\n if (query.data) {\n return <PageContent user={query.data.user} />;\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\nexport interface ProfileContentProps {\n user: User;\n}\nfunction PageContent({user}: ProfileContentProps) {\n const {player} = useSettings();\n const {tabName = 'tracks'} = useParams();\n\n const selectedTab = profileTabs.indexOf(tabName) || 0;\n\n const tabLink = useCallback(\n (tabName: string) => {\n return `/user/${user.id}/${user.display_name}/${tabName}`;\n },\n [user]\n );\n\n return (\n <Fragment>\n <ProfileHeader user={user} tabLink={tabLink} />\n <Tabs className=\"mt-48\" isLazy selectedTab={selectedTab}>\n <TabList>\n <Tab elementType={Link} to={tabLink('tracks')}>\n <Trans message=\"Liked tracks\" />\n </Tab>\n <Tab elementType={Link} to={tabLink('playlists')}>\n <Trans message=\"Public playlists\" />\n </Tab>\n {player?.enable_repost && (\n <Tab elementType={Link} to={tabLink('reposts')}>\n <Trans message=\"Reposts\" />\n </Tab>\n )}\n <Tab elementType={Link} to={tabLink('albums')}>\n <Trans message=\"Liked albums\" />\n </Tab>\n <Tab elementType={Link} to={tabLink('artists')}>\n <Trans message=\"Liked artists\" />\n </Tab>\n <Tab elementType={Link} to={tabLink('followers')}>\n <Trans message=\"Followers\" />\n </Tab>\n <Tab elementType={Link} to={tabLink('following')}>\n <Trans message=\"Following\" />\n </Tab>\n </TabList>\n <TabPanels className=\"mt-24\">\n <TabPanel>\n <ProfileTracksPanel user={user} />\n </TabPanel>\n <TabPanel>\n <ProfilePlaylistsPanel user={user} />\n </TabPanel>\n {player?.enable_repost && (\n <TabPanel>\n <ProfileRepostsPanel user={user} />\n </TabPanel>\n )}\n <TabPanel>\n <ProfileAlbumsPanel user={user} />\n </TabPanel>\n <TabPanel>\n <ProfileArtistsPanel user={user} />\n </TabPanel>\n <TabPanel>\n <ProfileFollowersPanel user={user} />\n </TabPanel>\n <TabPanel>\n <ProfileFollowedUsersPanel user={user} />\n </TabPanel>\n </TabPanels>\n </Tabs>\n </Fragment>\n );\n}\n","import {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';\nimport {Track} from '@app/web-player/tracks/track';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {AudiotrackIcon} from '@common/icons/material/Audiotrack';\nimport {Trans} from '@common/i18n/trans';\nimport React, {Fragment, useState} from 'react';\nimport {Link, useParams} from 'react-router-dom';\nimport {Album} from '@app/web-player/albums/album';\nimport {AlbumIcon} from '@common/icons/material/Album';\nimport {Tabs} from '@common/ui/tabs/tabs';\nimport {TabList} from '@common/ui/tabs/tab-list';\nimport {Tab} from '@common/ui/tabs/tab';\nimport {TabPanel, TabPanels} from '@common/ui/tabs/tab-panels';\nimport {TrackList} from '@app/web-player/tracks/track-list/track-list';\nimport {AlbumList} from '@app/web-player/albums/album-list/album-list';\n\nconst tagTabNames = {\n tracks: 0,\n albums: 1,\n};\n\nexport function TagMediaPage() {\n const params = useParams();\n const tagName = params.tagName!;\n const tabName = params['*']?.split('/').pop() || tagTabNames.tracks;\n const [selectedTab, setSelectedTab] = useState(\n tagTabNames[tabName as keyof typeof tagTabNames] || 0\n );\n return (\n <Fragment>\n <h1 className=\"text-3xl mb-40\">\n {tabName === 'albums' ? (\n <Trans\n message=\"Most popular albums for #:tag\"\n values={{tag: tagName}}\n />\n ) : (\n <Trans\n message=\"Most popular tracks for #:tag\"\n values={{tag: tagName}}\n />\n )}\n </h1>\n <Tabs selectedTab={selectedTab} onTabChange={setSelectedTab}>\n <TabList>\n <Tab elementType={Link} to={`/tag/${tagName}`}>\n <Trans message=\"Tracks\" />\n </Tab>\n <Tab elementType={Link} to={`/tag/${tagName}/albums`}>\n <Trans message=\"Albums\" />\n </Tab>\n </TabList>\n <TabPanels className=\"pt-24\">\n <TabPanel>\n <TracksPanel tagName={tagName!} />\n </TabPanel>\n <TabPanel>\n <AlbumsPanel tagName={tagName!} />\n </TabPanel>\n </TabPanels>\n </Tabs>\n </Fragment>\n );\n}\n\ninterface TracksPanelProps {\n tagName: string;\n}\nfunction AlbumsPanel({tagName}: TracksPanelProps) {\n const query = useInfiniteData<Album>({\n queryKey: ['albums', 'tags', tagName],\n endpoint: `tags/${tagName}/albums`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AlbumIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No albums yet\" />}\n description={\n <Trans message=\"This tag is not attached to any albums yet, check back later.\" />\n }\n />\n );\n }\n\n return <AlbumList query={query} />;\n}\n\nfunction TracksPanel({tagName}: TracksPanelProps) {\n const query = useInfiniteData<Track>({\n queryKey: ['tracks', 'tags', tagName],\n endpoint: `tags/${tagName}/tracks`,\n });\n\n if (query.isInitialLoading) {\n return <FullPageLoader className=\"min-h-100\" />;\n }\n\n if (!query.items.length) {\n return (\n <IllustratedMessage\n imageHeight=\"h-auto\"\n imageMargin=\"mb-14\"\n image={<AudiotrackIcon size=\"lg\" className=\"text-muted\" />}\n title={<Trans message=\"No tracks yet\" />}\n description={\n <Trans message=\"This tag is not attached to any tracks yet, check back later.\" />\n }\n />\n );\n }\n\n return <TrackList query={query} />;\n}\n","import {useQuery} from '@tanstack/react-query';\nimport {apiClient} from '@common/http/query-client';\nimport {BackendResponse} from '@common/http/backend-response/backend-response';\nimport {useParams} from 'react-router-dom';\nimport {Track} from '@app/web-player/tracks/track';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {Genre} from '@app/web-player/genres/genre';\n\nexport type RadioSeed = Artist | Track | Genre;\n\ninterface Response extends BackendResponse {\n type: 'artist' | 'genre' | 'track';\n seed: RadioSeed;\n recommendations: Track[];\n}\n\nexport function useRadioRecommendations() {\n const {seedType, seedId} = useParams();\n return useQuery(\n ['radio', seedType, +seedId!],\n () => fetchRecommendations(seedType!, seedId!),\n // different suggestions are returned every time, don't reload in background\n {staleTime: Infinity}\n );\n}\n\nfunction fetchRecommendations(seedType: string, seedId: string | number) {\n return apiClient\n .get<Response>(`radio/${seedType}/${seedId}`)\n .then(response => response.data);\n}\n","import React, {Fragment, useMemo} from 'react';\nimport {PageMetaTags} from '@common/http/page-meta-tags';\nimport {PageStatus} from '@common/http/page-status';\nimport {\n RadioSeed,\n useRadioRecommendations,\n} from '@app/web-player/radio/requests/use-radio-recommendations';\nimport {useSortableTableData} from '@common/ui/tables/use-sortable-table-data';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {\n actionButtonClassName,\n MediaPageHeaderLayout,\n} from '@app/web-player/layout/media-page-header-layout';\nimport {TrackImage} from '@app/web-player/tracks/track-image/track-image';\nimport {Trans} from '@common/i18n/trans';\nimport {BulletSeparatedItems} from '@app/web-player/layout/bullet-separated-items';\nimport {FormattedDuration} from '@common/i18n/formatted-duration';\nimport {PlaybackToggleButton} from '@app/web-player/playable-item/playback-toggle-button';\nimport {queueGroupId} from '@app/web-player/queue-group-id';\nimport {SmallArtistImage} from '@app/web-player/artists/artist-image/small-artist-image';\nimport {GenreImage} from '@app/web-player/genres/genre-image';\nimport {useParams} from 'react-router-dom';\nimport {NotFoundPage} from '@common/ui/not-found-page/not-found-page';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nconst validSeeds: RadioSeed['model_type'][] = ['artist', 'track', 'genre'];\n\nexport function RadioPage() {\n const {seedType} = useParams();\n const query = useRadioRecommendations();\n const {data, onSortChange, sortDescriptor} = useSortableTableData(\n query.data?.recommendations\n );\n\n const totalDuration = useMemo(() => {\n return data.reduce((total, track) => {\n return total + (track.duration || 0);\n }, 0);\n }, [data]);\n\n if (!validSeeds.includes(seedType as any)) {\n return <NotFoundPage />;\n }\n\n if (query.data) {\n const seed = query.data.seed;\n const queueId = queueGroupId(seed, 'radio');\n return (\n <Fragment>\n <PageMetaTags query={query} />\n <AdHost slot=\"general_top\" className=\"mb-44\" />\n <MediaPageHeaderLayout\n image={<Image seed={seed} />}\n title={\n <Trans\n message=\":name radio\"\n values={{\n name:\n 'display_name' in seed && seed.display_name\n ? seed.display_name\n : seed.name,\n }}\n />\n }\n subtitle={\n <BulletSeparatedItems className=\"text-sm text-muted justify-center md:justify-start\">\n <RadioType seed={seed} />\n <Trans\n message=\"[one 1 song|other :count songs]\"\n values={{count: data.length}}\n />\n <FormattedDuration ms={totalDuration} verbose />\n </BulletSeparatedItems>\n }\n actionButtons={\n <div className=\"text-center md:text-start\">\n <PlaybackToggleButton\n tracks={data}\n disabled={!data.length}\n buttonType=\"text\"\n queueId={queueId}\n className={actionButtonClassName({isFirst: true})}\n />\n </div>\n }\n />\n <TrackTable\n className=\"mt-34\"\n tracks={data}\n queueGroupId={queueId}\n onSortChange={onSortChange}\n sortDescriptor={sortDescriptor}\n />\n <AdHost slot=\"general_bottom\" className=\"mt-44\" />\n </Fragment>\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\ninterface SeedImageProps {\n seed: RadioSeed;\n}\nfunction Image({seed}: SeedImageProps) {\n switch (seed.model_type) {\n case 'artist':\n return (\n <SmallArtistImage\n artist={seed}\n size=\"w-240 h-240\"\n wrapperClassName=\"mx-auto\"\n className=\"rounded\"\n />\n );\n case 'genre':\n return (\n <GenreImage\n genre={seed}\n size=\"w-240 h-240\"\n className=\"rounded mx-auto\"\n />\n );\n default:\n return (\n <TrackImage\n track={seed}\n size=\"w-240 h-240\"\n className=\"rounded mx-auto\"\n />\n );\n }\n}\n\nfunction RadioType({seed}: SeedImageProps) {\n switch (seed.model_type) {\n case 'artist':\n return <Trans message=\"Artist radio\" />;\n case 'genre':\n return <Trans message=\"Genre radio\" />;\n default:\n return <Trans message=\"Track radio\" />;\n }\n}\n","import {\n SearchResponse,\n useSearchResults,\n} from '@app/web-player/search/requests/use-search-results';\nimport {mainSearchModels} from '@app/web-player/search/search-autocomplete';\nimport {Link, useParams} from 'react-router-dom';\nimport {PageStatus} from '@common/http/page-status';\nimport React, {Fragment, ReactNode, useEffect, useMemo, useState} from 'react';\nimport {Tabs} from '@common/ui/tabs/tabs';\nimport {TabList} from '@common/ui/tabs/tab-list';\nimport {Tab} from '@common/ui/tabs/tab';\nimport {Trans} from '@common/i18n/trans';\nimport {TabPanel, TabPanels} from '@common/ui/tabs/tab-panels';\nimport {Track} from '@app/web-player/tracks/track';\nimport {TrackTable} from '@app/web-player/tracks/track-table/track-table';\nimport {KeyboardArrowRightIcon} from '@common/icons/material/KeyboardArrowRight';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {ArtistGridItem} from '@app/web-player/artists/artist-grid-item';\nimport {AlbumGridItem} from '@app/web-player/albums/album-grid-item';\nimport {PlaylistGridItem} from '@app/web-player/playlists/playlist-grid-item';\nimport {UserGridItem} from '@app/web-player/users/user-grid-item';\nimport {Artist} from '@app/web-player/artists/artist';\nimport {Album} from '@app/web-player/albums/album';\nimport {Playlist} from '@app/web-player/playlists/playlist';\nimport {User} from '@common/auth/user';\nimport {IllustratedMessage} from '@common/ui/images/illustrated-message';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {useSettings} from '@common/core/settings/use-settings';\nimport {UseQueryResult} from '@tanstack/react-query';\nimport {useIsMobileMediaQuery} from '@common/utils/hooks/is-mobile-media-query';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {message} from '@common/i18n/message';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\n\nexport function SearchResultsPage() {\n const {searchQuery} = useParams();\n const query = useSearchResults({\n query: searchQuery,\n types: mainSearchModels,\n limit: 20,\n });\n\n return (\n <Fragment>\n <MobileSearchBar />\n <PageContent query={query} />\n </Fragment>\n );\n}\n\nfunction MobileSearchBar() {\n const isMobile = useIsMobileMediaQuery();\n const {searchQuery = ''} = useParams();\n const navigate = useNavigate();\n const {trans} = useTrans();\n if (!isMobile) {\n return null;\n }\n\n return (\n <TextField\n defaultValue={searchQuery}\n onChange={e => {\n navigate(`/search/${e.target.value}`, {replace: true});\n }}\n autoFocus\n className=\"w-full\"\n size=\"lg\"\n placeholder={trans(message('Search...'))}\n />\n );\n}\n\ninterface PageContentProps {\n query: UseQueryResult<SearchResponse>;\n}\nfunction PageContent({query}: PageContentProps) {\n const {branding} = useSettings();\n\n if (query.data) {\n return <SearchResults results={query.data?.results} />;\n }\n\n if (query.fetchStatus === 'idle') {\n return (\n <IllustratedMessage\n className=\"mt-40\"\n image={<SearchIcon size=\"xl\" />}\n imageHeight=\"h-auto\"\n imageMargin=\"mb-12\"\n title={\n <Trans\n message=\"Search :siteName\"\n values={{siteName: branding.site_name}}\n />\n }\n description={\n <Trans message=\"Find songs, artists, albums, playlists and more.\" />\n }\n />\n );\n }\n\n return <PageStatus query={query} loaderClassName=\"absolute inset-0 m-auto\" />;\n}\n\ninterface SearchResultsProps {\n results: SearchResponse['results'];\n}\nfunction SearchResults({results}: SearchResultsProps) {\n const {tabName = 'all', searchQuery} = useParams();\n const tabNames = useMemo(() => {\n const names = ['tracks', 'artists', 'albums', 'playlists', 'users'].filter(\n tabName => results[tabName as keyof SearchResponse['results']]?.length\n );\n return ['all', ...names];\n }, [results]);\n\n const tabIndex = tabNames.indexOf(tabName as any);\n\n const [selectedTab, setSelectedTab] = useState(tabIndex > -1 ? tabIndex : 0);\n\n // change tab when url changes\n useEffect(() => {\n if (tabIndex !== selectedTab) {\n setSelectedTab(tabIndex);\n }\n }, [tabIndex, selectedTab]);\n\n const tabLink = (tabName?: string) => {\n let base = `/search/${searchQuery}`;\n if (tabName) {\n base += `/${tabName}`;\n }\n return base;\n };\n\n const haveResults = Object.entries(results).some(\n ([, items]) => items?.length\n );\n\n if (!haveResults) {\n return (\n <IllustratedMessage\n className=\"mt-40\"\n image={<SearchIcon size=\"xl\" />}\n imageHeight=\"h-auto\"\n title={\n <Trans\n message=\"Not results for “:query“\"\n values={{query: searchQuery}}\n />\n }\n description={<Trans message=\"Please try a different search query\" />}\n />\n );\n }\n\n return (\n <Tabs selectedTab={selectedTab} onTabChange={setSelectedTab}>\n <TabList>\n <Tab elementType={Link} to={tabLink()}>\n <Trans message=\"Top results\" />\n </Tab>\n {results.tracks?.length ? (\n <Tab elementType={Link} to={tabLink('tracks')}>\n <Trans message=\"Tracks\" />\n </Tab>\n ) : null}\n {results.artists?.length ? (\n <Tab elementType={Link} to={tabLink('artists')}>\n <Trans message=\"Artists\" />\n </Tab>\n ) : null}\n {results.albums?.length ? (\n <Tab elementType={Link} to={tabLink('albums')}>\n <Trans message=\"Albums\" />\n </Tab>\n ) : null}\n {results.playlists?.length ? (\n <Tab elementType={Link} to={tabLink('playlists')}>\n <Trans message=\"Playlists\" />\n </Tab>\n ) : null}\n {results.users?.length ? (\n <Tab elementType={Link} to={tabLink('users')}>\n <Trans message=\"Profiles\" />\n </Tab>\n ) : null}\n </TabList>\n <TabPanels className=\"pt-8\">\n <TabPanel>\n <TopResultsPanel results={results} />\n </TabPanel>\n {results.tracks?.length ? (\n <TabPanel>\n <TrackResults tracks={results.tracks} />\n </TabPanel>\n ) : null}\n {results.artists?.length ? (\n <TabPanel>\n <ArtistResults artists={results.artists} />\n </TabPanel>\n ) : null}\n {results.albums?.length ? (\n <TabPanel>\n <AlbumResults albums={results.albums} />\n </TabPanel>\n ) : null}\n {results.playlists?.length ? (\n <TabPanel>\n <PlaylistResults playlists={results.playlists} />\n </TabPanel>\n ) : null}\n {results.users?.length ? (\n <TabPanel>\n <ProfileResults users={results.users} />\n </TabPanel>\n ) : null}\n </TabPanels>\n </Tabs>\n );\n}\n\nfunction TopResultsPanel({\n results: {artists, albums, tracks, playlists, users},\n}: SearchResultsProps) {\n return (\n <Fragment>\n {tracks?.length ? (\n <TrackResults tracks={tracks.slice(0, 5)} showMore />\n ) : null}\n {artists?.length ? (\n <ArtistResults artists={artists.slice(0, 5)} showMore />\n ) : null}\n {albums?.length ? (\n <AlbumResults albums={albums.slice(0, 5)} showMore />\n ) : null}\n {playlists?.length ? (\n <PlaylistResults playlists={playlists.slice(0, 5)} showMore />\n ) : null}\n {users?.length ? (\n <ProfileResults users={users.slice(0, 5)} showMore />\n ) : null}\n </Fragment>\n );\n}\n\ninterface TracksPanelProps {\n tracks: Track[];\n showMore?: boolean;\n}\nfunction TrackResults({tracks, showMore}: TracksPanelProps) {\n return (\n <div className=\"py-24\">\n <PanelTitle to={showMore ? 'tracks' : undefined}>\n <Trans message=\"Tracks\" />\n </PanelTitle>\n <TrackTable tracks={tracks} />\n </div>\n );\n}\n\ninterface ArtistResultsProps {\n artists: Artist[];\n showMore?: boolean;\n}\nfunction ArtistResults({artists, showMore}: ArtistResultsProps) {\n return (\n <div className=\"py-24\">\n <PanelTitle to={showMore ? 'artists' : undefined}>\n <Trans message=\"Artists\" />\n </PanelTitle>\n <ContentGrid>\n {artists.map(artist => (\n <ArtistGridItem key={artist.id} artist={artist} />\n ))}\n </ContentGrid>\n </div>\n );\n}\n\ninterface AlbumResultsProps {\n albums: Album[];\n showMore?: boolean;\n}\nfunction AlbumResults({albums, showMore}: AlbumResultsProps) {\n return (\n <div className=\"py-24\">\n <PanelTitle to={showMore ? 'albums' : undefined}>\n <Trans message=\"Albums\" />\n </PanelTitle>\n <ContentGrid>\n {albums.map(album => (\n <AlbumGridItem key={album.id} album={album} />\n ))}\n </ContentGrid>\n </div>\n );\n}\n\ninterface PlaylistResultsProps {\n playlists: Playlist[];\n showMore?: boolean;\n}\nfunction PlaylistResults({playlists, showMore}: PlaylistResultsProps) {\n return (\n <div className=\"py-24\">\n <PanelTitle to={showMore ? 'playlists' : undefined}>\n <Trans message=\"Playlists\" />\n </PanelTitle>\n <ContentGrid>\n {playlists.map(album => (\n <PlaylistGridItem key={album.id} playlist={album} />\n ))}\n </ContentGrid>\n </div>\n );\n}\n\ninterface ProfileResultsProps {\n users: User[];\n showMore?: boolean;\n}\nfunction ProfileResults({users, showMore}: ProfileResultsProps) {\n return (\n <div className=\"py-24\">\n <PanelTitle to={showMore ? 'users' : undefined}>\n <Trans message=\"Profiles\" />\n </PanelTitle>\n <ContentGrid>\n {users.map(user => (\n <UserGridItem key={user.id} user={user} />\n ))}\n </ContentGrid>\n </div>\n );\n}\n\ninterface PanelTitleProps {\n children: ReactNode;\n to?: string;\n}\nfunction PanelTitle({children, to}: PanelTitleProps) {\n return (\n <h2 className=\"text-2xl font-medium mb-24 w-max\">\n {to ? (\n <Link to={to} className=\"hover:text-primary flex items-center gap-2\">\n {children}\n <KeyboardArrowRightIcon className=\"mt-4\" />\n </Link>\n ) : (\n children\n )}\n </h2>\n );\n}\n","import {Trans} from '@common/i18n/trans';\nimport {AudiotrackIcon} from '@common/icons/material/Audiotrack';\nimport {StaticPageTitle} from '@common/seo/static-page-title';\nimport React, {Fragment, ReactElement, ReactNode} from 'react';\nimport {Link, Navigate} from 'react-router-dom';\nimport {AlbumIcon} from '@common/icons/material/Album';\nimport {MicIcon} from '@common/icons/material/Mic';\nimport {PlaylistPlayIcon} from '@common/icons/material/PlaylistPlay';\nimport {HistoryIcon} from '@common/icons/material/History';\nimport {SvgIconProps} from '@common/icons/svg-icon';\nimport {getPlaylistLink} from '@app/web-player/playlists/playlist-link';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {PlaylistAddIcon} from '@common/icons/material/PlaylistAdd';\nimport {CreatePlaylistDialog} from '@app/web-player/playlists/crupdate-dialog/create-playlist-dialog';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\nimport {useUserPlaylists} from '@app/web-player/library/requests/use-user-playlists';\nimport {PlaylistImage} from '@app/web-player/playlists/playlist-image';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {AdHost} from '@common/admin/ads/ad-host';\nimport {useIsTabletMediaQuery} from '@common/utils/hooks/is-tablet-media-query';\n\nexport function LibraryPage() {\n const navigate = useNavigate();\n const authHandler = useAuthClickCapture();\n const query = useUserPlaylists('me');\n const isSmallScreen = useIsTabletMediaQuery();\n\n if (!isSmallScreen) {\n return <Navigate to=\"/library/songs\" replace />;\n }\n\n return (\n <Fragment>\n <StaticPageTitle>\n <Trans message=\"Your tracks\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <div className=\"flex items-center justify-between gap-24 mb-20\">\n <h1 className=\"text-2xl font-semibold whitespace-nowrap\">\n <Trans message=\"Your library\" />\n </h1>\n <DialogTrigger\n type=\"modal\"\n onClose={newPlaylist => {\n if (newPlaylist) {\n navigate(getPlaylistLink(newPlaylist));\n }\n }}\n >\n <IconButton className=\"flex-shrink-0\" onClickCapture={authHandler}>\n <PlaylistAddIcon />\n </IconButton>\n <CreatePlaylistDialog />\n </DialogTrigger>\n </div>\n <div>\n <MenuItem\n icon={<AudiotrackIcon className=\"text-main\" />}\n to=\"/library/songs\"\n >\n <Trans message=\"Songs\" />\n </MenuItem>\n <MenuItem icon={<PlaylistPlayIcon />} to=\"/library/playlists\">\n <Trans message=\"Playlists\" />\n </MenuItem>\n <MenuItem icon={<AlbumIcon />} to=\"/library/albums\">\n <Trans message=\"Albums\" />\n </MenuItem>\n <MenuItem icon={<MicIcon />} to=\"/library/artists\">\n <Trans message=\"Artists\" />\n </MenuItem>\n <MenuItem icon={<HistoryIcon />} to=\"/library/history\">\n <Trans message=\"Play history\" />\n </MenuItem>\n {query.items.map(playlist => (\n <MenuItem\n key={playlist.id}\n wrapIcon={false}\n icon={\n <PlaylistImage\n size=\"w-42 h-42\"\n className=\"rounded\"\n playlist={playlist}\n />\n }\n to={getPlaylistLink(playlist)}\n >\n {playlist.name}\n </MenuItem>\n ))}\n <InfiniteScrollSentinel query={query} />\n </div>\n </Fragment>\n );\n}\n\ninterface MenuItemProps {\n icon: ReactElement<SvgIconProps>;\n children: ReactNode;\n to: string;\n wrapIcon?: boolean;\n}\nfunction MenuItem({icon, children, to, wrapIcon = true}: MenuItemProps) {\n return (\n <Link className=\"flex items-center gap-14 mb-18 text-sm\" to={to}>\n {wrapIcon ? (\n <div className=\"rounded bg-chip p-8 w-42 h-42\">{icon}</div>\n ) : (\n icon\n )}\n {children}\n </Link>\n );\n}\n","import {StaticPageTitle} from '@common/seo/static-page-title';\nimport {Trans} from '@common/i18n/trans';\nimport React from 'react';\nimport {TextField} from '@common/ui/forms/input-field/text-field/text-field';\nimport {SearchIcon} from '@common/icons/material/Search';\nimport {message} from '@common/i18n/message';\nimport {useTrans} from '@common/i18n/use-trans';\nimport {PageErrorMessage} from '@common/errors/page-error-message';\nimport {ContentGrid} from '@app/web-player/playable-item/content-grid';\nimport {InfiniteScrollSentinel} from '@common/ui/infinite-scroll/infinite-scroll-sentinel';\nimport {AnimatePresence, m} from 'framer-motion';\nimport {opacityAnimation} from '@common/ui/animation/opacity-animation';\nimport {MediaPageNoResultsMessage} from '@app/web-player/layout/media-page-no-results-message';\nimport {PlayableMediaGridSkeleton} from '@app/web-player/playable-item/player-media-grid-skeleton';\nimport {LibraryPageSortDropdown} from '@app/web-player/library/library-page-sort-dropdown';\nimport {useUserPlaylists} from '@app/web-player/library/requests/use-user-playlists';\nimport {PlaylistGridItem} from '@app/web-player/playlists/playlist-grid-item';\nimport {useAuthUserPlaylists} from '@app/web-player/playlists/requests/use-auth-user-playlists';\nimport {getPlaylistLink} from '@app/web-player/playlists/playlist-link';\nimport {IconButton} from '@common/ui/buttons/icon-button';\nimport {PlaylistAddIcon} from '@common/icons/material/PlaylistAdd';\nimport {CreatePlaylistDialog} from '@app/web-player/playlists/crupdate-dialog/create-playlist-dialog';\nimport {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger';\nimport {useNavigate} from '@common/utils/hooks/use-navigate';\nimport {useAuthClickCapture} from '@app/web-player/use-auth-click-capture';\nimport {AdHost} from '@common/admin/ads/ad-host';\n\nconst sortItems = {\n 'updated_at:desc': message('Recently updated'),\n 'name:asc': message('A-Z'),\n 'views:desc': message('Most viewed'),\n 'plays:desc': message('Most played'),\n};\n\nexport function LibraryPlaylistsPage() {\n const navigate = useNavigate();\n const authHandler = useAuthClickCapture();\n const {trans} = useTrans();\n const {data} = useAuthUserPlaylists();\n const totalItems = data.playlists.length;\n const query = useUserPlaylists('me', {willSortOrFilter: true});\n const {\n isInitialLoading,\n sortDescriptor,\n setSortDescriptor,\n searchQuery,\n setSearchQuery,\n items,\n isError,\n } = query;\n\n if (isError) {\n return <PageErrorMessage />;\n }\n\n return (\n <div>\n <StaticPageTitle>\n <Trans message=\"Your playlists\" />\n </StaticPageTitle>\n <AdHost slot=\"general_top\" className=\"mb-34\" />\n <div className=\"flex items-center justify-between gap-24 mb-20\">\n <h1 className=\"text-2xl font-semibold whitespace-nowrap\">\n {totalItems ? (\n <Trans\n message=\"[one 1 playlist|other :count playlists]\"\n values={{count: totalItems}}\n />\n ) : (\n <Trans message=\"My playlists\" />\n )}\n </h1>\n <DialogTrigger\n type=\"modal\"\n onClose={newPlaylist => {\n if (newPlaylist) {\n navigate(getPlaylistLink(newPlaylist));\n }\n }}\n >\n <IconButton className=\"flex-shrink-0\" onClickCapture={authHandler}>\n <PlaylistAddIcon />\n </IconButton>\n <CreatePlaylistDialog />\n </DialogTrigger>\n </div>\n\n <div className=\"flex items-center gap-24 justify-between\">\n <TextField\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n className=\"max-w-512 flex-auto\"\n size=\"sm\"\n startAdornment={<SearchIcon />}\n placeholder={trans(message('Search within playlists'))}\n />\n <LibraryPageSortDropdown\n items={sortItems}\n sortDescriptor={sortDescriptor}\n setSortDescriptor={setSortDescriptor}\n />\n </div>\n <div className=\"mt-34\">\n <AnimatePresence initial={false} mode=\"wait\">\n {isInitialLoading ? (\n <PlayableMediaGridSkeleton itemCount={totalItems} />\n ) : (\n <m.div key=\"media-grid\" {...opacityAnimation}>\n <ContentGrid>\n {items.map(playlist => (\n <PlaylistGridItem key={playlist.id} playlist={playlist} />\n ))}\n <InfiniteScrollSentinel query={query} />\n </ContentGrid>\n </m.div>\n )}\n </AnimatePresence>\n </div>\n {!items.length && !isInitialLoading && (\n <MediaPageNoResultsMessage\n className=\"mt-34\"\n searchQuery={searchQuery}\n description={\n <Trans message=\"You have not added any playlists to your library yet.\" />\n }\n />\n )}\n </div>\n );\n}\n","import React, {useMemo} from 'react';\nimport {playerStoreOptions} from '@app/web-player/state/player-store-options';\nimport {PlayerContext} from '@common/player/player-context';\nimport {TrackListItem} from '@app/web-player/tracks/track-list/track-list-item';\nimport {useTrack} from '@app/web-player/tracks/requests/use-track';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {Track} from '@app/web-player/tracks/track';\nimport {trackToMediaItem} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport {PlayerOutlet} from '@common/player/ui/player-outlet';\nimport {PlayerPoster} from '@common/player/ui/controls/player-poster';\n\nexport function TrackEmbed() {\n const {data} = useTrack({\n autoUpdate: false,\n });\n return (\n <div className=\"rounded border bg-alt p-14 h-[174px]\">\n {!data?.track ? <FullPageLoader /> : <EmbedContent track={data.track} />}\n </div>\n );\n}\n\ninterface EmbedContentProps {\n track: Track;\n}\nfunction EmbedContent({track}: EmbedContentProps) {\n const options: PlayerStoreOptions = useMemo(() => {\n const mediaItem = trackToMediaItem(track);\n return {\n ...playerStoreOptions,\n initialData: {\n queue: [mediaItem],\n cuedMediaId: mediaItem.id,\n state: {\n repeat: false,\n },\n },\n };\n }, [track]);\n return (\n <PlayerContext id=\"web-player\" options={options}>\n <div className=\"flex gap-24\">\n <div className=\"relative flex-shrink-0 rounded bg-black overflow-hidden\">\n <PlayerPoster className=\"absolute inset-0\" />\n <PlayerOutlet className=\"w-144 h-144\" />\n </div>\n <TrackListItem\n track={track}\n hideArtwork\n hideActions\n linksInNewTab\n className=\"flex-auto\"\n />\n </div>\n </PlayerContext>\n );\n}\n","import React, {useMemo} from 'react';\nimport {playerStoreOptions} from '@app/web-player/state/player-store-options';\nimport {PlayerContext} from '@common/player/player-context';\nimport {FullPageLoader} from '@common/ui/progress/full-page-loader';\nimport {\n tracksToMediaItems,\n trackToMediaItem,\n} from '@app/web-player/tracks/utils/track-to-media-item';\nimport {useAlbum} from '@app/web-player/albums/requests/use-album';\nimport {Album} from '@app/web-player/albums/album';\nimport {AlbumListItem} from '@app/web-player/albums/album-list/album-list-item';\nimport {PlayerStoreOptions} from '@common/player/state/player-store-options';\nimport {PlayerOutlet} from '@common/player/ui/player-outlet';\n\nexport function AlbumEmbed() {\n const {data} = useAlbum({\n autoUpdate: false,\n with: 'tracks',\n });\n return (\n <div className=\"rounded border bg-alt p-14 h-384\">\n {!data?.album ? <FullPageLoader /> : <EmbedContent album={data.album} />}\n </div>\n );\n}\n\ninterface EmbedContentProps {\n album: Album;\n}\nfunction EmbedContent({album}: EmbedContentProps) {\n const options: PlayerStoreOptions = useMemo(() => {\n return {\n ...playerStoreOptions,\n initialData: {\n queue: album.tracks?.length ? tracksToMediaItems(album.tracks) : [],\n cuedMediaId: album.tracks?.length\n ? trackToMediaItem(album.tracks[0]).id\n : undefined,\n state: {\n repeat: false,\n },\n },\n };\n }, [album]);\n return (\n <PlayerContext id=\"web-player\" options={options}>\n <div className=\"flex gap-24 items-start h-full\">\n <div className=\"flex-shrink-0 rounded bg-black overflow-hidden\">\n <PlayerOutlet className=\"w-144 h-144\" />\n </div>\n <AlbumListItem\n album={album}\n maxHeight=\"h-full\"\n className=\"flex-auto\"\n hideArtwork\n hideActions\n linksInNewTab\n />\n </div>\n </PlayerContext>\n );\n}\n","import {useSettings} from '@common/core/settings/use-settings';\nimport {ChannelPage} from '@app/web-player/channels/channel-page';\nimport React from 'react';\n\nexport function HomepageChannelPage() {\n const {homepage} = useSettings();\n let slugOrId = 'discover';\n if (homepage.type.startsWith('channel') && homepage.value) {\n slugOrId = homepage.value;\n }\n return <ChannelPage slugOrId={slugOrId} />;\n}\n","import {RouteObject, useRoutes} from 'react-router-dom';\nimport {ChannelPage} from '@app/web-player/channels/channel-page';\nimport React from 'react';\nimport {WebPlayerLayout} from '@app/web-player/layout/web-player-layout';\nimport {ArtistPage} from '@app/web-player/artists/artist-page/artist-page';\nimport {PlaylistPage} from '@app/web-player/playlists/playlist-page/playlist-page';\nimport {AlbumPage} from '@app/web-player/albums/album-page';\nimport {LibraryTracksPage} from '@app/web-player/library/library-tracks-page';\nimport {AuthRoute} from '@common/auth/guards/auth-route';\nimport {LibraryAlbumsPage} from '@app/web-player/library/library-albums-page';\nimport {LibraryArtistsPage} from '@app/web-player/library/library-artists-page';\nimport {LibraryHistoryPage} from '@app/web-player/library/library-history-page';\nimport {TrackPage} from '@app/web-player/tracks/track-page';\nimport {UserProfilePage} from '@app/web-player/user-profile/user-profile-page';\nimport {TagMediaPage} from '@app/web-player/genres/tag-media-page';\nimport {RadioPage} from '@app/web-player/radio/radio-page';\nimport {SearchResultsPage} from '@app/web-player/search/search-results-page';\nimport {LibraryPage} from '@app/web-player/library/library-page';\nimport {LibraryPlaylistsPage} from '@app/web-player/library/library-playlists-page';\nimport {TrackEmbed} from '@app/web-player/tracks/track-embed';\nimport {AlbumEmbed} from '@app/web-player/albums/album-embed';\nimport {HomepageChannelPage} from '@app/web-player/channels/homepage-channel-page';\n\nconst RouteConfig: RouteObject[] = [\n {\n path: 'track/:trackId/:trackName/embed',\n element: <TrackEmbed />,\n },\n {\n path: 'album/:albumId/:artistName/:albumName/embed',\n element: <AlbumEmbed />,\n },\n {\n path: '/',\n element: <WebPlayerLayout />,\n children: [\n {\n index: true,\n element: <HomepageChannelPage />,\n },\n {\n path: ':slugOrId',\n element: <ChannelPage />,\n },\n {\n path: 'channel/:slugOrId',\n element: <ChannelPage />,\n },\n {\n path: 'channel/:slugOrId/:filter',\n element: <ChannelPage />,\n },\n // artists\n {\n path: 'artist/:artistId/:artistName',\n element: <ArtistPage />,\n },\n {\n path: 'artist/:artistId',\n element: <ArtistPage />,\n },\n // playlists\n {\n path: 'playlist/:playlistId/:playlistName',\n element: <PlaylistPage />,\n },\n // albums\n {\n path: 'album/:albumId/:artistName/:albumName',\n element: <AlbumPage />,\n },\n // tracks\n {\n path: 'track/:trackId/:trackName',\n element: <TrackPage />,\n },\n // tags\n {\n path: 'tag/:tagName',\n element: <TagMediaPage />,\n },\n {\n path: 'tag/:tagName/tracks',\n element: <TagMediaPage />,\n },\n {\n path: 'tag/:tagName/albums',\n element: <TagMediaPage />,\n },\n // user profile\n {\n path: 'user/:userId/:userName',\n element: <UserProfilePage />,\n },\n {\n path: 'user/:userId/:userName/:tabName',\n element: <UserProfilePage />,\n },\n // radio\n {\n path: 'radio/:seedType/:seedId/:seeName',\n element: <RadioPage />,\n },\n // search\n {\n path: 'search',\n element: <SearchResultsPage />,\n },\n {\n path: 'search/:searchQuery',\n element: <SearchResultsPage />,\n },\n {\n path: 'search/:searchQuery/:tabName',\n element: <SearchResultsPage />,\n },\n // library\n {\n path: 'library',\n element: (\n <AuthRoute>\n <LibraryPage />\n </AuthRoute>\n ),\n },\n {\n path: 'library/songs',\n element: (\n <AuthRoute>\n <LibraryTracksPage />\n </AuthRoute>\n ),\n },\n {\n path: 'library/playlists',\n element: (\n <AuthRoute>\n <LibraryPlaylistsPage />\n </AuthRoute>\n ),\n },\n {\n path: 'library/albums',\n element: (\n <AuthRoute>\n <LibraryAlbumsPage />\n </AuthRoute>\n ),\n },\n {\n path: 'library/artists',\n element: (\n <AuthRoute>\n <LibraryArtistsPage />\n </AuthRoute>\n ),\n },\n {\n path: 'library/history',\n element: (\n <AuthRoute>\n <LibraryHistoryPage />\n </AuthRoute>\n ),\n },\n ],\n },\n];\n\nexport default function WebPlayerRoutes() {\n return useRoutes(RouteConfig);\n}\n"],"names":["client","options","notifyOptions","pageParam","query","_state$fetchMeta","_state$fetchMeta$fetc","_state$fetchMeta2","_state$fetchMeta2$fet","_state$data","_state$data2","state","result","isFetching","isRefetching","isFetchingNextPage","isFetchingPreviousPage","arg1","arg2","arg3","queryKey","defaultOrderDir","defaultOrderBy","queryParams","sortDescriptor","searchQuery","props","initialPage","endpoint","paginate","transformResponse","willSortOrFilter","setSearchQuery","useState","setSortDescriptor","initialQueryKey","useRef","params","lastResponse","hasNextPage","items","useMemo","_a","p","firstPage","_b","totalItems","_d","_c","r","channel","filter","isInitialLoading","fetchNextPage","children","loaderMarginTop","style","className","_variant","loadMoreExtraContent","size","sentinelRef","isLoading","loadMoreClickCount","setLoadMoreClickCount","innerVariant","useEffect","sentinelEl","observer","entry","content","jsxs","jsx","keepFirst","first","currentIndex","temporaryValue","randomIndex","id","defaultVolume","array","toAdd","index","copyOfArray","tail","action","getPointer","item","actionHandlers","details","key","cuedMedia","a","b","__publicField","lockType","document","element","type","handler","val","host","onChange","fscreen","set","get","subscription","orientation","adapter","onFullscreenChange","isFullscreen","isSupported","el","canFullscreen","video","adapters","onPipChange","factory","canPip","initialData","deepMerge","setInLocalStorage","value","_setInLocalStorage","store","listeners","internalListeners","s","payload","rates","qualities","quality","tracks","trackId","isVisible","isBuffering","media","queue","url","provider","keybindsHandler","e","initialQueue","isSeeking","isMuted","speed","newRepeat","currentRepeat","_e","newQueue","time","timeStr","resolve","reject","previousProvider","timeoutId","unsubscribe","mediaItems","queuePointer","afterCuedMedia","shuffledNewItems","m","mediaId","mediaToCue","newListeners","event","l","createContext","selector","equalityFn","useContext","overrideQueueAndPlay","queueId","lastTrack","response","src","track","queueGroupId","album","color","isDarkMode","radius","variant","disabled","buttonType","equalizerColor","isHover","setIsHover","modelIsQueued","modelIsPlaying","player","statusIcon","sharedProps","newIndex","t","model","kind","base","image","title","subtitle","link","likeButton","contextDialog","navigate","cloneElement","isLoggedIn","user","backendPayload","dialogContext","useCallback","data","closeMenu","loadTracks","setPlaylistPanelIsActive","addToPlaylist","playlists","playlist","authHandler","playlistPanelIsActive","description","close","contextValue","pathname","previousPathname","header","forwardRef","endIcon","startIcon","to","buttonProps","ref","Element","addToLibrary","getMessage","likeables","likeable","removeFromLibrary","copyLink","artistId","getRedirectUri","seed","absolute","artist_provider","trans","firstTrackImage","isMobile","height","code","inputRef","copied","artist","showRadioButton","canEdit","DeleteButton","deleteArtist","canDelete","isLiked","repostable","toggleRepost","isReposted","deleteAlbum","genre","defaultImage","trackIds","showAddToQueueButton","firstTrack","shouldShowRadio","headerProps","Fragment","deleteTracks","isCreator","playlistId","copyAlbumLink","isFollowing","followPlaylist","unFollowPlaylist","updatePlaylist","togglePublic","toggleCollaborative","deletePlaylist","follow","unfollow","owner","showProBadge","showBadge","isNested","margin","genreName","meta","groupId","isCued","isPlaying","rowIndex","isHovered","trackIndex","setHover","d","hideTrackImage","selectedRows","row","hideArtist","hideAlbum","hideHeaderRow","hidePopularity","hideAddedAtColumn","renderRowAs","tableProps","filteredColumns","col","domProps","placeholderRowCount","bodyRef","scrollableRef","scrollOffset","getScrollParent","virtualizer","instance","cb","offset","virtualRows","virtualHeight","virtualItem","dataCount","enabled","err","waveData","canvas","context","lineData","playerDuration","duration","currentTime","setCurrentTime","flushSync","pointer","disableCommenting","markerIsVisible","setMarkerIsVisible","newCommentInputRef","newCommentPositionRef","comments","hasPermission","commentBarContext","trackRef","getThumbPercent","useInteractOutside","comment","canvasRef","progressCanvasRef","isInView","setIsInView","setIsVisible","themeSelector","entries","onChangeEnd","sliderProps","thumbIds","newValue","commentable","inReplyTo","other","onSuccess","autoFocus","createComment","useObjectRef","inputIsExpanded","setInputIsExpanded","inputValue","setInputValue","clearInput","labels","showPlays","count","managesItem","buttonClassName","buttonGap","buttonSize","buttonRadius","memo","reposter","hideArtwork","hideActions","linksInNewTab","managesTrack","showWave","fn","wait","callFirst","timeout","debouncedFn","clear","flush","call","debounceWrapper","args","callNow","itemWidth","enablePrev","setEnablePrev","enableNext","setEnableNext","updateNavStatus","handleScroll","debounce","useLayoutEffect","firstGridItem","scrollAmount","contentModel","layout","nestedChannel","slot","settings","isSubscribed","adCode","dot","useId","parentEl","promises","pattern","match","slugOrId","artistName","cancelToken","YoutubeCommand","YouTubePlayerState","results","site_name","pause","sourceEvent","providerApi","providerName","emit","guest_role","permissions","isActive","branding","logoUrl","newPlaylist","mediaIsCued","isAudioProvider","queueItems","miniPlayerIsHidden","button","subscribe","getCurrentTime","providerKey","iconSize","stopPropagation","playerReady","label","animationActive","setAnimationActive","QueuedTrack","PlaybackButtons","menu","hasUnreadNotif","registration","primaryArtist","menuItems","MenuItem","trackColor","fillColor","seek","setIsSeeking","play","getState","pauseWhileSeeking","wasPlayingBeforeDragging","activeColor","isShuffling","repeating","base_url","buttonColor","volume","rightSidenavStatus","setRightSidenavStatus","isNumber","minWidth","videoId","posterURL","img","poster","internalStateRef","iframeRef","info","internalState","buffered","onCued","loadVideoById","origin","initialVideoId","setInitialVideoId","updateVideoIds","prevId","addGlobalListener","removeAllGlobalListeners","useGlobalListeners","youtubeApi","command","arg","initialVideoUrl","registerApi","internalProviderApi","muted","callback","start","loop","stop","updateCurrentTime","updateBuffered","timeRange","seconds","newTime","toggleTextTrackModes","newTrackId","textTracks","oldTrack","nextTrack","timeRafLoop","onTextTracksChange","autoPlay","events","caption","Suspense","hideDuringPlayback","posterUrl","shouldHidePoster","clickRef","togglePlay","isMaximized","isQueueOpen","overlayRef","playerClickHandler","haveVideo","handleKeyDown","setQuery","isOpen","setIsOpen","ComboBox","groupName","collection","activeIndex","ActionButtons","billing","showUploadButton","showTryProButton","isMobileMode","isOverlay","hideQueue","actionButtons","footer","centerItems","isFirst","alt","links","profile","shortDescription","artistPage","genres","initialTracks","showingAll","setShowingAll","topTracks","viewMode","initialAlbums","AlbumTrackTable","onSortChange","setViewMode","similarArtists","similar","text","href","attributes","attr","_ref","tagName","str","opts","tokens","token","images","maxHeight","managesAlbum","activeTrack","isLast","playerActions","albums","searchParams","haveSimilar","haveBio","activeTabs","tab","selectedTabId","i","u","draft","follower","followUser","currentUser","unfollowUser","selectedIndex","isListView","tabIds","load","Children","firstLink","avatar","child","totalDuration","editor","hasTracks","indexOrIndexes","indexes","insertBefore","itemsToBeMoved","moved","insertionIndex","oldIndexes","ids","removeTracks","canRemove","isTouchDevice","selectRow","domRef","previewRef","reorderTracks","sortableProps","oldIndex","mergeProps","PageContent","showUpvotesOnly","changeVote","upvotes","setUpvotes","downvotes","setDownvotes","currentVote","setCurrentVote","syncLocalState","replyFormVisible","setReplyFormVisible","showReplyButton","position","deleteComments","reportComment","isDeleteDialogOpen","setIsDeleteDialogOpen","showDeleteButton","handleReport","handleDelete","isConfirmed","auth","message","parts","canDeleteAllComments","linkifiedDescription","wrapperRef","contentRef","isOverflowing","setIsOverflowing","isShowingAll","setIsShowingAll","wrapperHeight","canView","showComments","allowCommenting","FocusScope","tag","userId","trackCount","isError","getPlaceholderItems","totalTracks","selectedValue","orderBy","orderDir","sortItems","releaseDate","repost","form","onBlur","invalid","error","formProps","formId","updateProfile","values","country","Option","tabLink","tabName","selectedTab","setSelectedTab","seedType","seedId","total","Image","tabIndex","_f","_g","_h","_i","_j","artists","users","showMore","icon","wrapIcon","EmbedContent","mediaItem","homepage"],"mappings":"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","x_google_ignoreList":[0,1,15,112,188]}
Save
Cancel