small refactoring webplayer api

This commit is contained in:
euzu
2025-04-18 19:07:47 +02:00
parent 93cfb17ecb
commit f6cdce3cf5
7 changed files with 53 additions and 13 deletions
+5 -3
View File
@@ -6,13 +6,14 @@ import {PlaylistCategories, PlaylistItem} from "../model/playlist";
const PLAYLIST_API_PATH = 'playlist';
const TARGET_UPDATE_API_PATH = 'playlist/update';
const REVERSE_URL_API_PATH = 'playlist/reverse';
const WEBPLAYER_URL_API_PATH = 'playlist/webplayer';
export default interface PlaylistApiService extends ApiService {
getPlaylist(req: PlaylistRequest): Observable<PlaylistCategories>;
updateTargets(targets: string[]): Observable<any>;
getReverseUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string>;
getWebPlayerUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string>;
}
export class DefaultPlaylistApiService extends DefaultApiService implements PlaylistApiService {
@@ -28,7 +29,8 @@ export class DefaultPlaylistApiService extends DefaultApiService implements Play
return this.post(TARGET_UPDATE_API_PATH, targets);
}
getReverseUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string> {
return this.post(REVERSE_URL_API_PATH + '/' + req.sourceId, item);
getWebPlayerUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string> {
return this.post(WEBPLAYER_URL_API_PATH + '/' + req.sourceId, item);
}
}
@@ -122,7 +122,9 @@ export default function PlaylistBrowser(props: PlaylistBrowserProps) {
<SourceSelector onDownload={handleSourceDownload} serverConfig={config}/>
</div>
<LoadingIndicator loading={progress}/>
<PlaylistViewer playlist={playlist} searchChannel={searchChannel}
<PlaylistViewer playlist={playlist}
playlistRequest={playlistRequest}
searchChannel={searchChannel}
onProgress={handleProgress} onCopy={handleOnCopy} onPlay={handleOnPlay}
onDownload={handleOnDownload}
onWebSearch={handleOnWebSearch}
@@ -1,18 +1,21 @@
import React, {useCallback, useState, useRef, useEffect} from 'react';
import './playlist-tree.scss';
import {PlaylistCategories, PlaylistGroup, PlaylistItem} from "../../model/playlist";
import {PlaylistCategories, PlaylistGroup, PlaylistItem, PlaylistItemType} from "../../model/playlist";
import copyToClipboard from "../../utils/clipboard";
import {first} from "rxjs/operators";
import {noop} from "rxjs";
import {useSnackbar} from "notistack";
import {getIconByName} from "../../icons/icons";
import ServerConfig from "../../model/server-config";
import {PlaylistRequest, PlaylistRequestType} from "../../model/playlist-request";
import {useServices} from "../../provider/service-provider";
export type PlaylistTreeState = { [key: number]: boolean };
interface PlaylistTreeProps {
serverConfig: ServerConfig;
data: PlaylistCategories;
playlistRequest: PlaylistRequest;
state: PlaylistTreeState;
onCopy: (playlistItem: PlaylistItem) => void;
onPlay?: (playlistItem: PlaylistItem) => void;
@@ -21,8 +24,9 @@ interface PlaylistTreeProps {
}
export default function PlaylistTree(props: PlaylistTreeProps) {
const {serverConfig, data, onCopy, onPlay, onDownload, onWebSearch} = props;
const {serverConfig, data, playlistRequest, onCopy, onPlay, onDownload, onWebSearch} = props;
const services = useServices();
const [, setForceUpdate] = useState(undefined);
const expanded = useRef<PlaylistTreeState>({});
const {enqueueSnackbar/*, closeSnackbar*/} = useSnackbar();
@@ -59,9 +63,35 @@ export default function PlaylistTree(props: PlaylistTreeProps) {
setForceUpdate({});
}, []);
const handleClipboardRealUrl = useCallback((e: any) => {
const item = getPlaylistItemById(e.target.dataset.item);
if (item) {
let virtual_id = undefined;
switch (playlistRequest.rtype) {
case PlaylistRequestType.TARGET:
virtual_id = item.virtual_id;
break;
case PlaylistRequestType.INPUT:
case PlaylistRequestType.XTREAM:
case PlaylistRequestType.M3U:
break;
}
if (virtual_id) {
onCopy(item);
copyToClipboard(''+virtual_id).pipe(first()).subscribe({
next: value => enqueueSnackbar(value ? "URL copied to clipboard" : "Copy to clipboard failed!", {variant: value ? 'success' : 'error'}),
error: _ => enqueueSnackbar("Copy to clipboard failed!", {variant: 'error'}),
complete: noop,
});
}
}
}, [enqueueSnackbar, getPlaylistItemById, onCopy, playlistRequest, services]);
const handleClipboardUrl = useCallback((e: any) => {
const item = getPlaylistItemById(e.target.dataset.item);
if (item) {
onCopy(item);
copyToClipboard(item.url).pipe(first()).subscribe({
next: value => enqueueSnackbar(value ? "URL copied to clipboard" : "Copy to clipboard failed!", {variant: value ? 'success' : 'error'}),
@@ -119,6 +149,9 @@ export default function PlaylistTree(props: PlaylistTreeProps) {
<div className={'tool-button'} data-item={entry.id} onClick={handleClipboardUrl}>
{getIconByName('LinkRounded')}
</div>
<div className={'tool-button'} data-item={entry.id} onClick={handleClipboardRealUrl}>
{getIconByName('LinkRounded')}
</div>
{onPlay && <div className={'tool-button'} data-item={entry.id} onClick={handlePlayUrl}>
{getIconByName('PlayArrow')}
</div>}
@@ -100,6 +100,7 @@ interface PlaylistViewerProps {
playlist: PlaylistCategories;
searchChannel: Observable<SearchRequest>;
videoChannel: Observable<[PlaylistItem, PlaylistRequest]>;
playlistRequest: PlaylistRequest;
onProgress: (value: boolean) => void;
onCopy: (playlistItem: PlaylistItem) => void;
onPlay?: (playlistItem: PlaylistItem) => void;
@@ -108,7 +109,7 @@ interface PlaylistViewerProps {
}
export default function PlaylistViewer(props: PlaylistViewerProps) {
const {serverConfig, playlist, searchChannel, videoChannel,
const {serverConfig, playlist, playlistRequest, searchChannel, videoChannel,
onProgress, onCopy, onPlay, onDownload, onWebSearch} = props;
const {enqueueSnackbar/*, closeSnackbar*/} = useSnackbar();
const [data, setData] = useState<PlaylistCategories>(EmptyPlaylistCategories);
@@ -161,7 +162,9 @@ export default function PlaylistViewer(props: PlaylistViewerProps) {
case 'player' :
return <PlaylistVideo data={data} channel={videoChannel} onPlay={onPlay}/>
default:
return <PlaylistTree data={data} state={checked}
return <PlaylistTree data={data}
playlistRequest={playlistRequest}
state={checked}
onCopy={onCopy} onPlay={undefined}
onDownload={onDownload}
onWebSearch={onWebSearch}
@@ -116,7 +116,7 @@ export const VideoPlayer = ({channel, onReady}: VideoPlayerProps) => {
if (playlistItem.item_type === PlaylistItemType.LiveHls) {
playVideo(playlistItem, playlistItem.url);
} else {
services.playlist().getReverseUrl(playlistItem, playlistRequest).pipe(first()).subscribe({
services.playlist().getWebPlayerUrl(playlistItem, playlistRequest).pipe(first()).subscribe({
next: (url: string) => {
playVideo(playlistItem, url);
},
+2 -2
View File
@@ -55,8 +55,8 @@ export default class PlaylistService {
return this.playlistApiService.updateTargets(targets);
}
getReverseUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string> {
return this.playlistApiService.getReverseUrl(item, req);
getWebPlayerUrl(item: PlaylistItem, req: PlaylistRequest): Observable<string> {
return this.playlistApiService.getWebPlayerUrl(item, req);
}
}
+2 -2
View File
@@ -216,7 +216,7 @@ async fn playlist_content(
}
}
async fn playlist_reverse(
async fn playlist_webplayer(
axum::extract::Path(target_id): axum::extract::Path<u32>,
axum::extract::State(app_state): axum::extract::State<Arc<AppState>>,
axum::extract::Json(playlist_item): axum::extract::Json<XtreamPlaylistItem>,
@@ -302,7 +302,7 @@ pub fn v1_api_register(web_auth_enabled: bool, app_state: Arc<AppState>, web_ui_
.route("/config/main", axum::routing::post(save_config_main))
.route("/config/user", axum::routing::post(save_config_api_proxy_user))
.route("/config/apiproxy", axum::routing::post(save_config_api_proxy_config))
.route("/playlist/reverse/{target_id}", axum::routing::post(playlist_reverse))
.route("/playlist/webplayer/{target_id}", axum::routing::post(playlist_webplayer))
.route("/playlist/update", axum::routing::post(playlist_update))
.route("/playlist", axum::routing::post(playlist_content))
.route("/file/download", axum::routing::post(download_api::queue_download_file))