Added start and end position for each track
This commit is contained in:
@@ -30,7 +30,6 @@ from function import (
|
||||
settings,
|
||||
send,
|
||||
time as ctime,
|
||||
formatTime,
|
||||
format_time,
|
||||
get_source,
|
||||
get_user,
|
||||
@@ -122,10 +121,14 @@ class Basic(commands.Cog):
|
||||
await send(ctx, 'connect', player.channel)
|
||||
|
||||
@commands.hybrid_command(name="play", aliases=get_aliases("play"))
|
||||
@app_commands.describe(query="Input a query or a searchable link.")
|
||||
@app_commands.describe(
|
||||
query="Input a query or a searchable link.",
|
||||
start="Specify a time you would like to start, e.g. 1:00",
|
||||
end="Specify a time you would like to end, e.g. 4:00"
|
||||
)
|
||||
@app_commands.autocomplete(query=play_autocomplete)
|
||||
@commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild)
|
||||
async def play(self, ctx: commands.Context, *, query: str) -> None:
|
||||
async def play(self, ctx: commands.Context, *, query: str, start: str = "0", end: str = "0") -> None:
|
||||
"Loads your input and added it to the queue."
|
||||
player: voicelink.Player = ctx.guild.voice_client
|
||||
if not player:
|
||||
@@ -140,10 +143,10 @@ class Basic(commands.Cog):
|
||||
|
||||
try:
|
||||
if isinstance(tracks, voicelink.Playlist):
|
||||
index = await player.add_track(tracks.tracks)
|
||||
index = await player.add_track(tracks.tracks, start_time=format_time(start), end_time=format_time(end))
|
||||
await send(ctx, "playlistLoad", tracks.name, index)
|
||||
else:
|
||||
position = await player.add_track(tracks[0])
|
||||
position = await player.add_track(tracks[0], start_time=format_time(start), end_time=format_time(end))
|
||||
texts = await get_lang(ctx.guild.id, "live", "trackLoad_pos", "trackLoad")
|
||||
await ctx.send((f"`{texts[0]}`" if tracks[0].is_stream else "") + (texts[1].format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length, position) if position >= 1 and player.is_playing else texts[2].format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length)), allowed_mentions=False)
|
||||
except voicelink.QueueFull as e:
|
||||
@@ -250,10 +253,14 @@ class Basic(commands.Cog):
|
||||
await player.do_next()
|
||||
|
||||
@commands.hybrid_command(name="playtop", aliases=get_aliases("playtop"))
|
||||
@app_commands.describe(query="Input a query or a searchable link.")
|
||||
@app_commands.describe(
|
||||
query="Input a query or a searchable link.",
|
||||
start="Specify a time you would like to start, e.g. 1:00",
|
||||
end="Specify a time you would like to end, e.g. 4:00"
|
||||
)
|
||||
@app_commands.autocomplete(query=play_autocomplete)
|
||||
@commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild)
|
||||
async def playtop(self, ctx: commands.Context, *, query: str):
|
||||
async def playtop(self, ctx: commands.Context, *, query: str, start: str = "0", end: str = "0"):
|
||||
"Adds a song with the given url or query on the top of the queue."
|
||||
player: voicelink.Player = ctx.guild.voice_client
|
||||
if not player:
|
||||
@@ -268,10 +275,10 @@ class Basic(commands.Cog):
|
||||
|
||||
try:
|
||||
if isinstance(tracks, voicelink.Playlist):
|
||||
index = await player.add_track(tracks.tracks, at_font=True)
|
||||
index = await player.add_track(tracks.tracks, start_time=format_time(start), end_time=format_time(end), at_font=True)
|
||||
await send(ctx, "playlistLoad", tracks.name, index)
|
||||
else:
|
||||
position = await player.add_track(tracks[0], at_font=True)
|
||||
position = await player.add_track(tracks[0], start_time=format_time(start), end_time=format_time(end), at_font=True)
|
||||
texts = await get_lang(ctx.guild.id, "live", "trackLoad_pos", "trackLoad")
|
||||
await ctx.send((f"`{texts[0]}`" if tracks[0].is_stream else "") + (texts[1].format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length, position) if position >= 1 and player.is_playing else texts[2].format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length)), allowed_mentions=False)
|
||||
|
||||
@@ -283,9 +290,13 @@ class Basic(commands.Cog):
|
||||
await player.do_next()
|
||||
|
||||
@commands.hybrid_command(name="forceplay", aliases=get_aliases("forceplay"))
|
||||
@app_commands.describe(query="Input a query or a searchable link.")
|
||||
@app_commands.describe(
|
||||
query="Input a query or a searchable link.",
|
||||
start="Specify a time you would like to start, e.g. 1:00",
|
||||
end="Specify a time you would like to end, e.g. 4:00"
|
||||
)
|
||||
@commands.dynamic_cooldown(cooldown_check, commands.BucketType.guild)
|
||||
async def forceplay(self, ctx: commands.Context, query: str):
|
||||
async def forceplay(self, ctx: commands.Context, *, query: str, start: str = "0", end: str = "0"):
|
||||
"Enforce playback using the given URL or query."
|
||||
player: voicelink.Player = ctx.guild.voice_client
|
||||
if not player:
|
||||
@@ -300,11 +311,11 @@ class Basic(commands.Cog):
|
||||
|
||||
try:
|
||||
if isinstance(tracks, voicelink.Playlist):
|
||||
index = await player.add_track(tracks.tracks, at_font=True)
|
||||
index = await player.add_track(tracks.tracks, start_time=format_time(start), end_time=format_time(end), at_font=True)
|
||||
await send(ctx, "playlistLoad", tracks.name, index)
|
||||
else:
|
||||
texts = await get_lang(ctx.guild.id, "live", "trackLoad")
|
||||
await player.add_track(tracks[0], at_font=True)
|
||||
await player.add_track(tracks[0], start_time=format_time(start), end_time=format_time(end), at_font=True)
|
||||
await ctx.send((f"`{texts[0]}`" if tracks[0].is_stream else "") + texts[1].format(tracks[0].title, tracks[0].uri, tracks[0].author, tracks[0].formatted_length), allowed_mentions=False)
|
||||
|
||||
except voicelink.QueueFull as e:
|
||||
@@ -404,7 +415,7 @@ class Basic(commands.Cog):
|
||||
return await send(ctx, "noPlayer", ephemeral=True)
|
||||
|
||||
if not player.node._available:
|
||||
return await send(ctx, "nnodeReconnectode")
|
||||
return await send(ctx, "nodeReconnectode")
|
||||
|
||||
if not player.is_privileged(ctx.author):
|
||||
if ctx.author in player.previous_votes:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import time
|
||||
import time, re
|
||||
import function as func
|
||||
|
||||
from datetime import timezone
|
||||
@@ -8,6 +9,7 @@ from typing import List, Dict, Union, Optional
|
||||
from discord import User, Member, VoiceChannel
|
||||
from discord.ext import commands
|
||||
from voicelink import Player, Track, Playlist, NodePool, decode, LoopType
|
||||
from addons import lyricsPlatform
|
||||
|
||||
RATELIMIT_COUNTER: Dict[int, Dict[str, float]] = {}
|
||||
SCOPES = {
|
||||
@@ -560,6 +562,21 @@ async def getSettings(bot: commands.Bot, data: Dict) -> Dict:
|
||||
"user_id": str(user_id)
|
||||
}
|
||||
|
||||
async def getLyrics(bot: commands.Bot, data: Dict) -> Dict:
|
||||
title, artist, platform = data.get("title", ""), data.get("artist", ""), data.get("platform", "")
|
||||
if not platform or platform not in lyricsPlatform:
|
||||
platform = func.settings.lyrics_platform
|
||||
|
||||
song: dict[str, str] = await lyricsPlatform.get(platform)().get_lyrics(title, artist)
|
||||
payload = {
|
||||
"op": "getLyrics",
|
||||
"user_id": data.get("user_id"),
|
||||
"lyrics": {_: re.findall(r'.*\n(?:.*\n){,22}', v) for _, v in song.items()} if song else {},
|
||||
"callback": data.get("callback")
|
||||
}
|
||||
|
||||
return payload
|
||||
|
||||
async def updateSettings(bot: commands.Bot, data: Dict) -> None:
|
||||
user_id = int(data.get("user_id"))
|
||||
guild_id = int(data.get("guild_id"))
|
||||
@@ -588,22 +605,23 @@ async def updateSettings(bot: commands.Bot, data: Dict) -> None:
|
||||
|
||||
await func.update_settings(guild.id, {"$set": data})
|
||||
|
||||
methods: Dict[str, Union[SystemMethod, PlayerMethod]] = {
|
||||
METHODS: Dict[str, Union[SystemMethod, PlayerMethod]] = {
|
||||
"initBot": SystemMethod(initBot, credit=0),
|
||||
"initUser": SystemMethod(initUser, credit=0),
|
||||
"getPlaylist": SystemMethod(getPlaylist),
|
||||
"updatePlaylist": SystemMethod(updatePlaylist),
|
||||
"getMutualGuilds": SystemMethod(getMutualGuilds),
|
||||
"getSettings": SystemMethod(getSettings),
|
||||
"getLyrics": SystemMethod(getLyrics),
|
||||
"updateSettings": SystemMethod(updateSettings),
|
||||
"getRecommendation": SystemMethod(getRecommendation, credit=5),
|
||||
"closeConnection": SystemMethod(closeConnection, credit=0),
|
||||
"getTracks": SystemMethod(getTracks, credit=5),
|
||||
"initPlayer": PlayerMethod(initPlayer),
|
||||
"skipTo": PlayerMethod(skipTo),
|
||||
"backTo": PlayerMethod(backTo),
|
||||
"moveTrack": PlayerMethod(moveTrack),
|
||||
"addTracks": PlayerMethod(addTracks, auto_connect=True),
|
||||
"getTracks": PlayerMethod(getTracks, auto_connect=True),
|
||||
"shuffleTrack": PlayerMethod(shuffleTrack, credit=3),
|
||||
"repeatTrack": PlayerMethod(repeatTrack),
|
||||
"removeTrack": PlayerMethod(removeTrack),
|
||||
@@ -615,7 +633,7 @@ methods: Dict[str, Union[SystemMethod, PlayerMethod]] = {
|
||||
|
||||
async def process_methods(ipc_client, bot: commands.Bot, data: Dict) -> None:
|
||||
op: str = data.get("op", "")
|
||||
method = methods.get(op)
|
||||
method = METHODS.get(op)
|
||||
if not method or not (user_id := data.get("user_id")):
|
||||
return
|
||||
|
||||
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "請提供有效的歌曲索引!",
|
||||
"voicelinkDuplicateTrack": "抱歉,此歌曲已在隊列中。",
|
||||
|
||||
"deocdeError": "解碼文件時出現問題!"
|
||||
"deocdeError": "解碼文件時出現問題!",
|
||||
"invalidStartTime": "無效的開始時間! 時間必須在 `00:00` 和 `{0}` 之間。",
|
||||
"invalidEndTime": "無效的結束時間! 時間必須在 `00:00` 和 `{0}` 之間。",
|
||||
"invalidTimeOrder": "結束時間不能小於或等於開始時間。"
|
||||
}
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "Bitte gib einen gültigen Track-Index an!",
|
||||
"voicelinkDuplicateTrack": "Entschuldigung, dieser Track ist bereits in der Warteschlange.",
|
||||
|
||||
"deocdeError": "Beim Dekodieren der Datei ist etwas schief gelaufen!"
|
||||
"deocdeError": "Beim Dekodieren der Datei ist etwas schief gelaufen!",
|
||||
"invalidStartTime": "Ungültiger Startzeit! Die Zeit muss innerhalb von `00:00` und `{0}` liegen.",
|
||||
"invalidEndTime": "Ungültiger Endzeit! Die Zeit muss innerhalb von `00:00` und `{0}` liegen.",
|
||||
"invalidTimeOrder": "Der Endzeit darf nicht kleiner oder gleich dem Startzeit sein."
|
||||
}
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "Please provide a valid track index!",
|
||||
"voicelinkDuplicateTrack": "Sorry, this track is already in the queue.",
|
||||
|
||||
"deocdeError": "Something went wrong while decoding the file!"
|
||||
"deocdeError": "Something went wrong while decoding the file!",
|
||||
"invalidStartTime": "Invalid start time, it must be between `00:00` and `{0}`",
|
||||
"invalidEndTime": "Invalid end time, it must be between `00:00` and `{0}`",
|
||||
"invalidTimeOrder": "End time cannot be less than or equal to start time"
|
||||
}
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "¡Proporcione un índice de pista válido!",
|
||||
"voicelinkDuplicateTrack": "Lo siento, esta canción ya está en la cola.",
|
||||
|
||||
"deocdeError": "¡Algo salió mal al decodificar el archivo!"
|
||||
"deocdeError": "¡Algo salió mal al decodificar el archivo!",
|
||||
"invalidStartTime": "Tiempo de inicio inválido! El tiempo debe estar entre `00:00` y `{0}`.",
|
||||
"invalidEndTime": "Tiempo de finalización inválido! El tiempo debe estar entre `00:00` y `{0}`.",
|
||||
"invalidTimeOrder": "El tiempo final no puede ser menor o igual que el tiempo de inicio."
|
||||
}
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "有効なトラックインデックスを指定してください!",
|
||||
"voicelinkDuplicateTrack": "申し訳ありませんが、このトラックは既にキューに存在します。",
|
||||
|
||||
"deocdeError": "ファイルのデコード中に問題が発生しました!"
|
||||
"deocdeError": "ファイルのデコード中に問題が発生しました!",
|
||||
"invalidStartTime": "無効な開始時間!時間は `00:00` と `{0}` の間に設定する必要があります。",
|
||||
"invalidEndTime": "無効な終了時間!時間は `00:00` と `{0}` の間に設定する必要があります。",
|
||||
"invalidTimeOrder": "終了時間は開始時間より大きくない必要があります。"
|
||||
}
|
||||
@@ -187,5 +187,8 @@
|
||||
"voicelinkOutofList": "유효한 트랙 인덱스를 제공해주세요!",
|
||||
"voicelinkDuplicateTrack": "죄송합니다. 이 트랙은 이미 큐에 있습니다.",
|
||||
|
||||
"deocdeError": "파일 디코딩 중 문제가 발생했습니다!"
|
||||
"deocdeError": "파일 디코딩 중 문제가 발생했습니다!",
|
||||
"invalidStartTime": "효력 없는 시작 시간! 시간은 `00:00` 과 `{0}` 사이에 설정해야 합니다.",
|
||||
"invalidEndTime": "효력 없는 종료 시간! 시간은 `00:00` 과 `{0}` 사이에 설정해야 합니다.",
|
||||
"invalidTimeOrder": "종료 시간은 시작 시간보다 클수 있어야 합니다."
|
||||
}
|
||||
@@ -186,5 +186,8 @@
|
||||
"voicelinkOutofList": "Пожалуйста, предоставьте действительный индекс трека!",
|
||||
"voicelinkDuplicateTrack": "Извините, этот трек уже есть в очереди.",
|
||||
|
||||
"deocdeError": "Что-то пошло не так при декодировании файла!"
|
||||
"deocdeError": "Что-то пошло не так при декодировании файла!",
|
||||
"invalidStartTime": "Hевозможное время начала! Вход времени должен быть внутри `00:00` и `{0}`.",
|
||||
"invalidEndTime": "Невозможное время конца! Вход времени должен быть внутри `00:00` и `{0}`.",
|
||||
"invalidTimeOrder": "Время конца не может быть меньше или равно времени начала."
|
||||
}
|
||||
|
||||
@@ -186,5 +186,8 @@
|
||||
"voicelinkOutofList": "Будь ласка, надайте дійсний індекс треку!",
|
||||
"voicelinkDuplicateTrack": "Вибачте, цей трек уже є в черзі.",
|
||||
|
||||
"deocdeError": "Щось пішло не так під час декодування файлу!"
|
||||
"deocdeError": "Щось пішло не так під час декодування файлу!",
|
||||
"invalidStartTime": "Недійснений час початку! Час має бути в межах `00:00` та `{0}`.",
|
||||
"invalidEndTime": "Недійснений час закінчення! Час має бути в межах `00:00` та `{0}`.",
|
||||
"invalidTimeOrder": "Час закінчення не може бути меншим або рівним часу початку."
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import requests, zipfile, os, shutil, argparse
|
||||
from io import BytesIO
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
__version__ = "v2.6.9b3"
|
||||
__version__ = "v2.6.9b4"
|
||||
|
||||
GITHUB_API_URL = "https://api.github.com/repos/ChocoMeow/Vocard/releases/latest"
|
||||
VOCARD_URL = "https://github.com/ChocoMeow/Vocard/archive/"
|
||||
|
||||
@@ -62,7 +62,8 @@ class Track:
|
||||
"requester",
|
||||
"is_stream",
|
||||
"is_seekable",
|
||||
"position"
|
||||
"position",
|
||||
"end_time"
|
||||
)
|
||||
|
||||
def __init__(
|
||||
@@ -102,6 +103,8 @@ class Track:
|
||||
self.is_seekable: bool = info.get("isSeekable", True)
|
||||
self.position: int = info.get("position", 0)
|
||||
|
||||
self.end_time: Optional[int] = None
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, Track):
|
||||
return False
|
||||
|
||||
@@ -496,7 +496,7 @@ class Player(VoiceProtocol):
|
||||
|
||||
self._node._players.pop(self.guild.id)
|
||||
await self.send(method=RequestMethod.delete)
|
||||
|
||||
|
||||
async def play(
|
||||
self,
|
||||
track: Track,
|
||||
@@ -511,41 +511,58 @@ class Player(VoiceProtocol):
|
||||
|
||||
if track.spotify:
|
||||
if not track.original:
|
||||
search: Track = (await self._node.get_tracks(
|
||||
f"ytsearch:{track.author} - {track.title}",
|
||||
requester=track.requester
|
||||
))
|
||||
|
||||
if not search:
|
||||
raise TrackLoadError("Can't not found a playable source!")
|
||||
search_results = await self._node.get_tracks(f"ytmsearch:{track.author} - {track.title}", requester=track.requester)
|
||||
if not search_results:
|
||||
raise TrackLoadError("Can't find a playable source!")
|
||||
track.original = search_results[0]
|
||||
|
||||
track.original = search[0]
|
||||
|
||||
data = {
|
||||
"encodedTrack": track.original.track_id if track.original else track.track_id,
|
||||
"position": str(start if start else track.position),
|
||||
"endTime": str(end if end else track.original.length)
|
||||
"position": str(start if start else track.position)
|
||||
}
|
||||
|
||||
if end or track.end_time:
|
||||
data["endTime"] = str(end if end else track.end_time)
|
||||
|
||||
await self.send(method=RequestMethod.patch, query=f"noReplace={ignore_if_playing}", data=data)
|
||||
|
||||
self._current = track
|
||||
|
||||
if self.volume != 100:
|
||||
await self.set_volume(self.volume)
|
||||
|
||||
|
||||
self._logger.debug(f"Player in {self.guild.name}({self.guild.id}) playing {track.title} from uri {track.uri} with a length of {track.length}")
|
||||
return self._current
|
||||
|
||||
async def add_track(self, raw_tracks: Union[Track, List[Track]], *, at_font: bool = False, duplicate: bool = True) -> int:
|
||||
def _validate_time(self, track: Track, start_time: int, end_time: int) -> None:
|
||||
if start_time or end_time:
|
||||
if not end_time:
|
||||
end_time = track.length
|
||||
|
||||
if start_time >= end_time:
|
||||
raise VoicelinkException(self.get_msg("invalidStartTime"))
|
||||
|
||||
track_length = track.length
|
||||
if not 0 <= start_time <= track_length:
|
||||
raise VoicelinkException(self.get_msg("invalidStartTime", func.time(track_length)))
|
||||
if not 0 <= end_time <= track_length:
|
||||
raise VoicelinkException(self.get_msg("invalidEndTime", func.time(track_length)))
|
||||
|
||||
track.position = start_time
|
||||
track.end_time = end_time
|
||||
|
||||
async def add_track(self, raw_tracks: Union[Track, List[Track]], *, start_time: int = 0, end_time: int = 0, at_front: bool = False, duplicate: bool = True) -> int:
|
||||
tracks: List[Track] = []
|
||||
_duplicate_tracks = [] if self.queue._allow_duplicate and duplicate else [track.uri for track in self.queue._queue]
|
||||
raw_tracks = raw_tracks[0] if isinstance(raw_tracks, List) and len(raw_tracks) == 1 else raw_tracks
|
||||
|
||||
|
||||
try:
|
||||
if (is_list := isinstance(raw_tracks, List)):
|
||||
for track in raw_tracks:
|
||||
if track.uri in _duplicate_tracks:
|
||||
continue
|
||||
|
||||
self._validate_time(track, start_time, end_time)
|
||||
self.queue.put_at_front(track) if at_front else self.queue.put(track)
|
||||
tracks.append(track)
|
||||
_duplicate_tracks.append(track.uri)
|
||||
@@ -553,7 +570,8 @@ class Player(VoiceProtocol):
|
||||
if raw_tracks.uri in _duplicate_tracks:
|
||||
raise DuplicateTrack(self.get_msg("voicelinkDuplicateTrack"))
|
||||
|
||||
position = self.queue.put_at_front(raw_tracks) if at_font else self.queue.put(raw_tracks)
|
||||
self._validate_time(raw_tracks, start_time, end_time)
|
||||
position = self.queue.put_at_front(raw_tracks) if at_front else self.queue.put(raw_tracks)
|
||||
tracks.append(raw_tracks)
|
||||
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user