feat: add playlist name

This commit is contained in:
Ante Brähler
2025-01-06 17:45:10 +01:00
parent 953f54657c
commit 500455c093
8 changed files with 43 additions and 20 deletions

View File

@@ -1,6 +1,6 @@
class Channel {
static nextId = 0;
constructor(name, url, avatar, mode, headers = [], group = null, playlist = null) {
constructor(name, url, avatar, mode, headers = [], group = null, playlist = null, playlistName = null) {
this.id = Channel.nextId++;
this.name = name;
this.url = url;
@@ -10,6 +10,7 @@ class Channel {
this.headers = headers;
this.group = group;
this.playlist = playlist;
this.playlistName = playlistName;
}
restream() {

View File

@@ -34,10 +34,10 @@ class ChannelService {
return this.channels;
}
getFilteredChannels({ playlist, group }) {
getFilteredChannels({ playlistName, group }) {
let filtered = this.channels;
if (playlist) {
filtered = filtered.filter(ch => ch.playlist && ch.playlist == playlist);
if (playlistName) {
filtered = filtered.filter(ch => ch.playlistName && ch.playlistName.toLowerCase() == playlistName.toLowerCase());
}
if (group) {
filtered = filtered.filter(ch => ch.group && ch.group.toLowerCase() === group.toLowerCase());
@@ -45,7 +45,7 @@ class ChannelService {
return filtered;
}
addChannel({ name, url, avatar, mode, headersJson, group = false, playlist = false }) {
addChannel({ name, url, avatar, mode, headersJson, group = null, playlist = null, playlistName = null }) {
const existing = this.channels.find(channel => channel.url === url);
if (existing) {
@@ -53,7 +53,7 @@ class ChannelService {
}
const headers = JSON.parse(headersJson);
const newChannel = new Channel(name, url, avatar, mode, headers, group, playlist);
const newChannel = new Channel(name, url, avatar, mode, headers, group, playlist, playlistName);
this.channels.push(newChannel);
return newChannel;

View File

@@ -3,7 +3,7 @@ const ChannelService = require('./ChannelService');
class PlaylistService {
async addPlaylist(playlistUrl, mode, headersJson) {
async addPlaylist(playlistUrl, playlistName, mode, headersJson) {
const response = await fetch(playlistUrl);
const content = await response.text();
@@ -21,7 +21,8 @@ class PlaylistService {
mode: mode,
headersJson: headersJson,
group: channel.group.title,
playlist: playlistUrl
playlist: playlistUrl,
playlistName: playlistName
});
} catch (error) {
console.error(error);
@@ -42,7 +43,7 @@ class PlaylistService {
for(let channel of channels) {
channel = await ChannelService.updateChannel(channel.id, updatedAttributes);
}
return channels;
}

View File

@@ -4,9 +4,10 @@ const Channel = require('../models/Channel');
module.exports = (io, socket) => {
socket.on('add-playlist', async ({ playlist, mode, headersJson }) => {
socket.on('add-playlist', async ({ playlist, playlistName, mode, headersJson }) => {
try {
const channels = await PlaylistService.addPlaylist(playlist, mode, headersJson);
const channels = await PlaylistService.addPlaylist(playlist, playlistName, mode, headersJson);
if (channels) {
channels.forEach(channel => {
io.emit('channel-added', channel);
@@ -21,7 +22,8 @@ module.exports = (io, socket) => {
socket.on('update-playlist', async ({ playlist, updatedAttributes }) => {
try {
const channels = PlaylistService.updatePlaylist(playlist, updatedAttributes);
const channels = await PlaylistService.updatePlaylist(playlist, updatedAttributes);
channels.forEach(channel => {
io.emit('channel-updated', channel.toFrontendJson());
});
@@ -34,7 +36,7 @@ module.exports = (io, socket) => {
socket.on('delete-playlist', async (playlist) => {
try {
const channels = PlaylistService.deletePlaylist(playlist);
const channels = await PlaylistService.deletePlaylist(playlist);
channels.forEach(channel => {
io.emit('channel-deleted', channel.id);
});

View File

@@ -34,14 +34,14 @@ function App() {
// Get unique playlists from channels
const playlists = useMemo(() => {
const uniquePlaylists = new Set(channels.map(channel => channel.playlist).filter(playlist => playlist !== null));
const uniquePlaylists = new Set(channels.map(channel => channel.playlistName).filter(playlistName => playlistName !== null));
return ['All Channels', ...Array.from(uniquePlaylists)];
}, [channels]);
const filteredChannels = useMemo(() => {
//Filter by playlist
const filteredByPlaylist = selectedPlaylist === 'All Channels' ? channels : channels.filter(channel =>
channel.playlist === selectedPlaylist
channel.playlistName === selectedPlaylist
);
//Filter by group

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext } from 'react';
import { Info, Plus, Trash2, X } from 'lucide-react';
import { Plus, Trash2, X } from 'lucide-react';
import socketService from '../../services/SocketService';
import { CustomHeader, Channel, ChannelMode } from '../../types';
import CustomHeaderInput from './CustomHeaderInput';
@@ -22,6 +22,7 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
const [mode, setMode] = useState<ChannelMode>('proxy');
const [headers, setHeaders] = useState<CustomHeader[]>([]);
const [playlistName, setPlaylistName] = useState('');
const [playlistUrl, setPlaylistUrl] = useState('');
const { addToast } = useContext(ToastContext);
@@ -33,6 +34,7 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
setAvatar(channel.avatar);
setMode(channel.mode);
setHeaders(channel.headers);
setPlaylistName(channel.playlistName);
setPlaylistUrl(channel.playlist);
setIsEditMode(true);
setType('channel'); // Default to "channel" if a channel object exists
@@ -42,6 +44,7 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
setAvatar('');
setMode('proxy');
setHeaders([]);
setPlaylistName('');
setPlaylistUrl('');
setIsEditMode(false);
setType('channel'); // Default to "channel" if a channel object exists
@@ -81,7 +84,7 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
);
} else if (type === 'playlist') {
if (!playlistUrl.trim()) return;
socketService.addPlaylist(playlistUrl.trim(), mode, JSON.stringify(headers));
socketService.addPlaylist(playlistUrl.trim(), playlistName.trim(), mode, JSON.stringify(headers));
}
addToast({
@@ -107,10 +110,11 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
if(channel!.playlist !== playlistUrl.trim()) {
// If the playlist URL has changed, we need to reload the playlist (delete old channels and fetch again)
socketService.deletePlaylist(channel!.playlist);
socketService.addPlaylist(playlistUrl.trim(), mode, JSON.stringify(headers));
socketService.addPlaylist(playlistUrl.trim(), playlistName.trim(), mode, JSON.stringify(headers));
} else {
socketService.updatePlaylist(playlistUrl.trim(), {
playlist: playlistUrl.trim(),
playlistName: playlistName.trim(),
mode: mode,
headers: headers,
});
@@ -277,6 +281,20 @@ function ChannelModal({ isOpen, onClose, channel }: ChannelModalProps) {
{type === 'playlist' && (
<>
{/* Playlist fields */}
<div>
<label htmlFor="name" className="block text-sm font-medium mb-1">
Playlist Name
</label>
<input
type="text"
id="playlistName"
value={playlistName}
onChange={(e) => setPlaylistName(e.target.value)}
className="w-full bg-gray-700 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Enter playlist name"
required
/>
</div>
<div>
<label htmlFor="playlistUrl" className="block text-sm font-medium mb-1">
M3U Playlist URL

View File

@@ -98,10 +98,10 @@ class SocketService {
}
// Add playlist
addPlaylist(playlist: string, mode: ChannelMode, headersJson: string) {
addPlaylist(playlist: string, playlistName: string, mode: ChannelMode, headersJson: string) {
if (!this.socket) throw new Error('Socket is not connected.');
this.socket.emit('add-playlist', { playlist, mode, headersJson });
this.socket.emit('add-playlist', { playlist, playlistName, mode, headersJson });
}
// Update playlist

View File

@@ -29,6 +29,7 @@ export interface Channel {
headers: CustomHeader[];
group: string;
playlist: string;
playlistName: string;
}
export interface ChatMessage {