mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-27 13:34:28 +00:00
Add !funkwhaleplaylist command
This commit is contained in:
parent
7db084c724
commit
36b06c574a
12 changed files with 99 additions and 65 deletions
45
poetry.lock
generated
45
poetry.lock
generated
|
@ -86,7 +86,7 @@ description = "Composable command line interface toolkit"
|
|||
name = "click"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "7.1"
|
||||
version = "7.1.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
|
@ -186,7 +186,7 @@ description = "Python audio data toolkit (ID3 and MP3)"
|
|||
name = "eyed3"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
|
||||
[package.dependencies]
|
||||
deprecation = "*"
|
||||
|
@ -217,7 +217,7 @@ description = "Infer file type and MIME type of any file/buffer. No external dep
|
|||
name = "filetype"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
|
@ -486,7 +486,7 @@ description = "Persistent/Functional/Immutable data structures"
|
|||
name = "pyrsistent"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.15.7"
|
||||
version = "0.16.0"
|
||||
|
||||
[package.dependencies]
|
||||
six = "*"
|
||||
|
@ -586,7 +586,7 @@ description = "A multipurpose bot and web framework"
|
|||
name = "royalnet"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<4.0"
|
||||
version = "5.6.2"
|
||||
version = "5.6.5"
|
||||
|
||||
[package.dependencies]
|
||||
dateparser = ">=0.7.2,<0.8.0"
|
||||
|
@ -716,7 +716,7 @@ description = "Database Abstraction Library"
|
|||
name = "sqlalchemy"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.3.13"
|
||||
version = "1.3.15"
|
||||
|
||||
[package.extras]
|
||||
mssql = ["pyodbc"]
|
||||
|
@ -864,10 +864,10 @@ description = "YouTube video downloader"
|
|||
name = "youtube-dl"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.3.8"
|
||||
version = "2020.3.24"
|
||||
|
||||
[metadata]
|
||||
content-hash = "8d7780d1bc898479dda8255988247547650f4034a3ef6e37db47f7ccda1a9d5f"
|
||||
content-hash = "f0931c9aade41f1ac239401a324cb550f0961b83c1759b5a84effb10e1bba7f2"
|
||||
python-versions = "^3.8"
|
||||
|
||||
[metadata.files]
|
||||
|
@ -952,8 +952,8 @@ chardet = [
|
|||
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-7.1-py2.py3-none-any.whl", hash = "sha256:91eb2c43db0254aaf3b14a3c4e0db914a900aa09bbc33c6e87ede4a8f7c969dc"},
|
||||
{file = "click-7.1.tar.gz", hash = "sha256:482f552f2d5452b9eeffc44165e8b790dd53f75bcce099a812b65e0357e860e2"},
|
||||
{file = "click-7.1.1-py2.py3-none-any.whl", hash = "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"},
|
||||
{file = "click-7.1.1.tar.gz", hash = "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
||||
|
@ -1002,17 +1002,17 @@ deprecation = [
|
|||
{file = "discord.py-1.3.2-py3-none-any.whl", hash = "sha256:7424be26b07b37ecad4404d9383d685995a0e0b3df3f9c645bdd3a4d977b83b4"},
|
||||
]
|
||||
eyed3 = [
|
||||
{file = "eyeD3-0.9.3-py2.py3-none-any.whl", hash = "sha256:82e838a45db298bedf5bfa284e936f9c2216550106d47673bafa1ae262292a36"},
|
||||
{file = "eyeD3-0.9.3-py3.8.egg", hash = "sha256:cb750a56163a55181a840bd5f6a78299de247c19c97160055c65e39066a3e422"},
|
||||
{file = "eyeD3-0.9.3.tar.gz", hash = "sha256:33020d86aa1ffb4a130e10c27d0c3f9fa05989b862d454e95195ff08eeb67375"},
|
||||
{file = "eyeD3-0.9.4-py2.py3-none-any.whl", hash = "sha256:4cba88297ded486ac5b127b4dd5944c453be52c015ed82400fde30907e2972f8"},
|
||||
{file = "eyeD3-0.9.4-py3.8.egg", hash = "sha256:b7ac8695d7acdbd67d5e6edc48e9e082faae40ed852cf3e0fcd6d878624ee8d4"},
|
||||
{file = "eyeD3-0.9.4.tar.gz", hash = "sha256:11099464e438c11a1d701e723a5065c1556fb59878ad9dce29f924dac3a07a96"},
|
||||
]
|
||||
ffmpeg-python = [
|
||||
{file = "ffmpeg-python-0.2.0.tar.gz", hash = "sha256:65225db34627c578ef0e11c8b1eb528bb35e024752f6f10b78c011f6f64c4127"},
|
||||
{file = "ffmpeg_python-0.2.0-py3-none-any.whl", hash = "sha256:ac441a0404e053f8b6a1113a77c0f452f1cfc62f6344a769475ffdc0f56c23c5"},
|
||||
]
|
||||
filetype = [
|
||||
{file = "filetype-1.0.5-py2.py3-none-any.whl", hash = "sha256:4967124d982a71700d94a08c49c4926423500e79382a92070f5ab248d44fe461"},
|
||||
{file = "filetype-1.0.5.tar.gz", hash = "sha256:17a3b885f19034da29640b083d767e0f13c2dcb5dcc267945c8b6e5a5a9013c7"},
|
||||
{file = "filetype-1.0.6-py2.py3-none-any.whl", hash = "sha256:fd6d0ec56820acccf8c9fb6c3ba7e04a302f6ff6c70bcc09daf4842ae9e2ac30"},
|
||||
{file = "filetype-1.0.6.tar.gz", hash = "sha256:99d2b923921cadbe6e451249091ca7156b4beaee6e741bd711a582d4dd2f2881"},
|
||||
]
|
||||
future = [
|
||||
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
|
||||
|
@ -1065,6 +1065,9 @@ greenlet = [
|
|||
{file = "greenlet-0.4.15-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214"},
|
||||
{file = "greenlet-0.4.15-cp37-cp37m-win32.whl", hash = "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043"},
|
||||
{file = "greenlet-0.4.15-cp37-cp37m-win_amd64.whl", hash = "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304"},
|
||||
{file = "greenlet-0.4.15-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e538b8dae561080b542b0f5af64d47ef859f22517f7eca617bb314e0e03fd7ef"},
|
||||
{file = "greenlet-0.4.15-cp38-cp38-win32.whl", hash = "sha256:51155342eb4d6058a0ffcd98a798fe6ba21195517da97e15fca3db12ab201e6e"},
|
||||
{file = "greenlet-0.4.15-cp38-cp38-win_amd64.whl", hash = "sha256:7457d685158522df483196b16ec648b28f8e847861adb01a55d41134e7734122"},
|
||||
{file = "greenlet-0.4.15.tar.gz", hash = "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc"},
|
||||
]
|
||||
h11 = [
|
||||
|
@ -1259,7 +1262,7 @@ pyreadline = [
|
|||
{file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},
|
||||
]
|
||||
pyrsistent = [
|
||||
{file = "pyrsistent-0.15.7.tar.gz", hash = "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280"},
|
||||
{file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
|
||||
|
@ -1308,8 +1311,8 @@ riotwatcher = [
|
|||
{file = "riotwatcher-2.7.1.tar.gz", hash = "sha256:5349271c7e00637b7619491a6070e66603705db60558ea2a690e7016f6e6d9a4"},
|
||||
]
|
||||
royalnet = [
|
||||
{file = "royalnet-5.6.2-py3-none-any.whl", hash = "sha256:57c9c5de1bbc0a258af489c46eaca326a3b408fe7988fdf6e050f34d5feeaed3"},
|
||||
{file = "royalnet-5.6.2.tar.gz", hash = "sha256:b421b84d2cad1ea27016e300f7b005836dd6f5f14975e5b372a91f1f4d52dfd7"},
|
||||
{file = "royalnet-5.6.5-py3-none-any.whl", hash = "sha256:ee5d1774fc507cc1be291fefe5716ee7e6bec80ccf1ffd5a6d2278721c7a477b"},
|
||||
{file = "royalnet-5.6.5.tar.gz", hash = "sha256:4555bbdf2bc4c75e90f2b465a022178ad6cd6302906c0c5adfe7a7d6e1dbcb06"},
|
||||
]
|
||||
royalspells = [
|
||||
{file = "royalspells-3.2.tar.gz", hash = "sha256:2bd4a9a66514532e35c02c3907425af48c7cb292364c4843c795719a82b25dfe"},
|
||||
|
@ -1323,7 +1326,7 @@ six = [
|
|||
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
|
||||
]
|
||||
sqlalchemy = [
|
||||
{file = "SQLAlchemy-1.3.13.tar.gz", hash = "sha256:64a7b71846db6423807e96820993fa12a03b89127d278290ca25c0b11ed7b4fb"},
|
||||
{file = "SQLAlchemy-1.3.15.tar.gz", hash = "sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445"},
|
||||
]
|
||||
starlette = [
|
||||
{file = "starlette-0.12.13.tar.gz", hash = "sha256:9597bc28e3c4659107c1c4a45ec32dc45e947d78fe56230222be673b2c36454a"},
|
||||
|
@ -1422,6 +1425,6 @@ yarl = [
|
|||
{file = "yarl-1.4.2.tar.gz", hash = "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b"},
|
||||
]
|
||||
youtube-dl = [
|
||||
{file = "youtube_dl-2020.3.8-py2.py3-none-any.whl", hash = "sha256:f9d33129ea4941bea234cdba811c0f97e61c2235a877cf395a869aeea065e009"},
|
||||
{file = "youtube_dl-2020.3.8.tar.gz", hash = "sha256:1b098b7ae41551f46dbae70e56dbabdf39c8faf50e072d0c0b42c44d64afebf8"},
|
||||
{file = "youtube_dl-2020.3.24-py2.py3-none-any.whl", hash = "sha256:c0be39ea9bca72fa02a0d2d043c5e9bd8ea8e0fe79705e891161d6fcd29da59e"},
|
||||
{file = "youtube_dl-2020.3.24.tar.gz", hash = "sha256:4b03efe439f7cae26eba909821d1df00a9a4eb82741cb2e8b78fe29702bd4633"},
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[tool.poetry]
|
||||
name = "royalpack"
|
||||
version = "5.6.2"
|
||||
version = "5.7"
|
||||
description = "A Royalnet command pack for the Royal Games community"
|
||||
authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"]
|
||||
license = "AGPL-3.0+"
|
||||
|
@ -25,7 +25,7 @@
|
|||
steam = "^0.9.1"
|
||||
|
||||
[tool.poetry.dependencies.royalnet]
|
||||
version = "^5.6"
|
||||
version = "~5.6.5"
|
||||
# Maybe... there is a way to make these selectable?
|
||||
extras = [
|
||||
"telegram",
|
||||
|
|
|
@ -37,6 +37,7 @@ from .dota import DotaCommand
|
|||
from .magickfiorygi import MagickfiorygiCommand
|
||||
from .brawlhalla import BrawlhallaCommand
|
||||
from .diarioshuffle import DiarioshuffleCommand
|
||||
from .funkwhaleplaylist import FunkwhaleplaylistCommand
|
||||
|
||||
# Enter the commands of your Pack here!
|
||||
available_commands = [
|
||||
|
@ -78,6 +79,7 @@ available_commands = [
|
|||
MagickfiorygiCommand,
|
||||
BrawlhallaCommand,
|
||||
DiarioshuffleCommand,
|
||||
FunkwhaleplaylistCommand,
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
|
|
|
@ -16,7 +16,7 @@ class FunkwhaleCommand(PlayCommand):
|
|||
def get_embed_color(self):
|
||||
return 0x009FE3
|
||||
|
||||
async def get_url(self, args):
|
||||
async def get_urls(self, args):
|
||||
search = urllib.parse.quote(args.joined(require_at_least=1))
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(self.config["Funkwhale"]["instance_url"] +
|
||||
|
@ -24,4 +24,4 @@ class FunkwhaleCommand(PlayCommand):
|
|||
j = await response.json()
|
||||
if len(j["tracks"]) < 1:
|
||||
raise UserError("Nessun file audio trovato con il nome richiesto.")
|
||||
return f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}'
|
||||
return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}']
|
||||
|
|
32
royalpack/commands/funkwhaleplaylist.py
Normal file
32
royalpack/commands/funkwhaleplaylist.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from .play import PlayCommand
|
||||
from royalnet.commands import *
|
||||
import aiohttp
|
||||
import urllib.parse
|
||||
|
||||
|
||||
class FunkwhaleplaylistCommand(PlayCommand):
|
||||
name: str = "funkwhaleplaylist"
|
||||
|
||||
aliases = ["fwp", "fwplaylist", "funkwhalep"]
|
||||
|
||||
description: str = "Cerca una playlist su RoyalWhale e aggiungila alla coda della chat vocale."
|
||||
|
||||
syntax = "{ricerca}"
|
||||
|
||||
def get_embed_color(self):
|
||||
return 0x009FE3
|
||||
|
||||
async def get_urls(self, args):
|
||||
search = urllib.parse.quote(args.joined(require_at_least=1))
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(self.config["Funkwhale"]["instance_url"] +
|
||||
f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response:
|
||||
j = await response.json()
|
||||
if len(j["results"]) < 1:
|
||||
raise UserError("Nessuna playlist trovata con il nome richiesto.")
|
||||
playlist = j["results"][0]
|
||||
playlist_id = playlist["id"]
|
||||
async with session.get(self.config["Funkwhale"]["instance_url"] +
|
||||
f"/api/v1/playlists/{playlist_id}/tracks") as response:
|
||||
j = await response.json()
|
||||
return list(map(lambda t: f'{self.config["Funkwhale"]["instance_url"]}{t["track"]["listen_url"]}', j["results"]))
|
|
@ -10,7 +10,7 @@ class GooglevideoCommand(PlayCommand):
|
|||
|
||||
syntax = "{ricerca}"
|
||||
|
||||
async def get_url(self, args):
|
||||
return f"gvsearch:{args.joined()}"
|
||||
async def get_urls(self, args):
|
||||
return [f"gvsearch:{args.joined()}"]
|
||||
|
||||
# Too bad gvsearch: always finds nothing.
|
||||
|
|
|
@ -14,12 +14,12 @@ class PlayCommand(Command):
|
|||
|
||||
syntax = "{url}"
|
||||
|
||||
async def get_url(self, args: CommandArgs):
|
||||
async def get_urls(self, args: CommandArgs):
|
||||
url = args.joined(require_at_least=1)
|
||||
if not (url.startswith("http://") or url.startswith("https://")):
|
||||
raise InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato"
|
||||
f" ([c]http://[/c] o [c]https://[/c]).")
|
||||
return url
|
||||
return [url]
|
||||
|
||||
def get_embed_color(self) -> Optional[int]:
|
||||
return None
|
||||
|
@ -46,14 +46,19 @@ class PlayCommand(Command):
|
|||
else:
|
||||
user_str = str(f"<@{user_discord.discord_id}>")
|
||||
|
||||
urls = await self.get_urls(args)
|
||||
|
||||
play_task: aio.Task = self.loop.create_task(
|
||||
self.interface.call_herald_event("discord", "discord_play",
|
||||
url=await self.get_url(args),
|
||||
urls=urls,
|
||||
guild_id=guild_id,
|
||||
user=user_str,
|
||||
force_color=self.get_embed_color())
|
||||
)
|
||||
|
||||
await data.reply("⌛ Attendi un attimo...")
|
||||
if len(urls) > 1:
|
||||
await data.reply("⌛ Attendi qualche minuto...")
|
||||
else:
|
||||
await data.reply("⌛ Attendi un attimo...")
|
||||
|
||||
await play_task
|
||||
|
|
|
@ -10,5 +10,5 @@ class SoundcloudCommand(PlayCommand):
|
|||
|
||||
syntax = "{ricerca}"
|
||||
|
||||
async def get_url(self, args):
|
||||
return f"scsearch:{args.joined()}"
|
||||
async def get_urls(self, args):
|
||||
return [f"scsearch:{args.joined()}"]
|
||||
|
|
|
@ -10,7 +10,7 @@ class YahoovideoCommand(PlayCommand):
|
|||
|
||||
syntax = "{ricerca}"
|
||||
|
||||
async def get_url(self, args):
|
||||
return f"yvsearch:{args.joined()}"
|
||||
async def get_urls(self, args):
|
||||
return [f"yvsearch:{args.joined()}"]
|
||||
|
||||
# Too bad yvsearch: always finds nothing.
|
||||
|
|
|
@ -10,5 +10,5 @@ class YoutubeCommand(PlayCommand):
|
|||
|
||||
syntax = "{ricerca}"
|
||||
|
||||
async def get_url(self, args):
|
||||
return f"ytsearch:{args.joined()}"
|
||||
async def get_urls(self, args):
|
||||
return [f"ytsearch:{args.joined()}"]
|
||||
|
|
|
@ -13,7 +13,7 @@ class DiscordPlayEvent(rc.Event):
|
|||
name = "discord_play"
|
||||
|
||||
async def run(self,
|
||||
url: str,
|
||||
urls: List[str],
|
||||
guild_id: Optional[int] = None,
|
||||
user: Optional[str] = None,
|
||||
force_color: Optional[int] = None,
|
||||
|
@ -23,18 +23,8 @@ class DiscordPlayEvent(rc.Event):
|
|||
|
||||
serf: rsd.DiscordSerf = self.serf
|
||||
client: discord.Client = self.serf.client
|
||||
|
||||
# TODO: fix this in Royalnet sometime
|
||||
candidate_players: List[rsd.VoicePlayer] = []
|
||||
for player in serf.voice_players:
|
||||
player: rsd.VoicePlayer
|
||||
if not player.voice_client.is_connected():
|
||||
continue
|
||||
if guild_id is not None:
|
||||
guild = client.get_guild(guild_id)
|
||||
if guild != player.voice_client.guild:
|
||||
continue
|
||||
candidate_players.append(player)
|
||||
guild: discord.Guild = client.get_guild(guild_id) if guild_id is not None else None
|
||||
candidate_players: List[rsd.VoicePlayer] = serf.find_voice_players(guild)
|
||||
|
||||
if len(candidate_players) == 0:
|
||||
raise rc.UserError("Il bot non è in nessun canale vocale.\n"
|
||||
|
@ -45,21 +35,23 @@ class DiscordPlayEvent(rc.Event):
|
|||
raise rc.CommandError("Non so in che Server riprodurre questo file...\n"
|
||||
"Invia il comando su Discord, per favore!")
|
||||
|
||||
ytds = await rbd.YtdlDiscord.from_url(url)
|
||||
added: List[rbd.YtdlDiscord] = []
|
||||
too_long: List[rbd.YtdlDiscord] = []
|
||||
if isinstance(voice_player.playing, RoyalQueue):
|
||||
for index, ytd in enumerate(ytds):
|
||||
if ytd.info.duration >= datetime.timedelta(seconds=self.config["Play"]["max_song_duration"]):
|
||||
too_long.append(ytd)
|
||||
continue
|
||||
await ytd.convert_to_pcm()
|
||||
added.append(ytd)
|
||||
voice_player.playing.contents.append(ytd)
|
||||
if not voice_player.voice_client.is_playing():
|
||||
await voice_player.start()
|
||||
else:
|
||||
raise rc.CommandError(f"Non so come aggiungere musica a [c]{voice_player.playing.__class__.__qualname__}[/c]!")
|
||||
|
||||
for url in urls:
|
||||
ytds = await rbd.YtdlDiscord.from_url(url)
|
||||
if isinstance(voice_player.playing, RoyalQueue):
|
||||
for index, ytd in enumerate(ytds):
|
||||
if ytd.info.duration >= datetime.timedelta(seconds=self.config["Play"]["max_song_duration"]):
|
||||
too_long.append(ytd)
|
||||
continue
|
||||
await ytd.convert_to_pcm()
|
||||
added.append(ytd)
|
||||
voice_player.playing.contents.append(ytd)
|
||||
if not voice_player.voice_client.is_playing():
|
||||
await voice_player.start()
|
||||
else:
|
||||
raise rc.CommandError(f"Non so come aggiungere musica a [c]{voice_player.playing.__class__.__qualname__}[/c]!")
|
||||
|
||||
main_channel: discord.TextChannel = client.get_channel(self.config["Discord"]["main_channel_id"])
|
||||
|
||||
|
@ -85,7 +77,7 @@ class DiscordPlayEvent(rc.Event):
|
|||
))
|
||||
|
||||
if len(added) + len(too_long) == 0:
|
||||
raise
|
||||
raise rc.InvalidInputError("Non è stato aggiunto nessun file alla coda.")
|
||||
|
||||
return {
|
||||
"added": [{
|
||||
|
|
|
@ -1 +1 @@
|
|||
semantic = "5.6.2"
|
||||
semantic = "5.7"
|
||||
|
|
Loading…
Reference in a new issue