mirror of
https://github.com/chrisb09/MusicBot.git
synced 2026-11-05 17:02:35 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c3ec7960 | ||
|
|
6752695b43 | ||
|
|
bb17c984a2 | ||
|
|
a7807b96e2 | ||
|
|
2e9dd5df49 | ||
|
|
1ad16181d0 | ||
|
|
bb53bad1ff | ||
|
|
8a1066cc87 | ||
|
|
23c2dfa78e | ||
|
|
18bf6ac0f6 | ||
|
|
fd6de60fc7 | ||
|
|
4c8ff655d8 | ||
|
|
ac8661c904 | ||
|
|
4f926baf76 | ||
|
|
c5ecf89852 | ||
|
|
a52103620a | ||
|
|
fa5e33e2a5 | ||
|
|
781a94ea91 | ||
|
|
ff1ede9d12 | ||
|
|
90d9a1631a | ||
|
|
c4502bbe16 | ||
|
|
2d4f2671c9 | ||
|
|
e595de2033 | ||
|
|
53875f2791 | ||
|
|
cd7e643228 | ||
|
|
0e1f0d3bfa | ||
|
|
2c76164f6d | ||
|
|
788cd40f2c | ||
|
|
1e12e4e01d | ||
|
|
c4cbfe2a11 | ||
|
|
bbed9e8990 | ||
|
|
354a0b3def | ||
|
|
2faef67b30 | ||
|
|
aee076c854 | ||
|
|
b76f6fa07c | ||
|
|
ec4e9e624c | ||
|
|
a7be2c4602 | ||
|
|
6007d3e99b | ||
|
|
a17b2f20ee | ||
|
|
4375d4caa8 | ||
|
|
c22807bcbb | ||
|
|
baf629a910 | ||
|
|
c4e11d682e | ||
|
|
041ab27b94 | ||
|
|
85aebe8a89 | ||
|
|
3c306a8d7a | ||
|
|
cadaf94cf7 | ||
|
|
15a47a7b4d | ||
|
|
92fca22059 | ||
|
|
0cdc0d2d34 | ||
|
|
1d1dfe103e | ||
|
|
ab39d2cd48 | ||
|
|
32d165d1b3 | ||
|
|
8457f944cd | ||
|
|
c404e92932 | ||
|
|
6af86cae5d | ||
|
|
9421730229 | ||
|
|
b76e31c7e2 | ||
|
|
6056ff2c13 | ||
|
|
8c92a7a75a | ||
|
|
e942f3ef21 | ||
|
|
157da6c0da | ||
|
|
03b909a3f5 | ||
|
|
e08c1491c2 | ||
|
|
95de05ff2d | ||
|
|
e242fa9557 | ||
|
|
b83028fb97 | ||
|
|
7273b5bf42 | ||
|
|
6f6064521b | ||
|
|
48263ec60a | ||
|
|
c6e5b8cbda | ||
|
|
3b8892d2c0 | ||
|
|
54cb757dc5 | ||
|
|
c4de816c7c | ||
|
|
ccb421e110 | ||
|
|
23334e4253 | ||
|
|
826aec2492 | ||
|
|
c397afcf8d | ||
|
|
95c07eab8e | ||
|
|
58e0e5737d | ||
|
|
84bc57e3cf | ||
|
|
67f6169e61 | ||
|
|
6f7c47757b | ||
|
|
0a353e0fa3 | ||
|
|
ddf95da19f | ||
|
|
d5bb16d143 | ||
|
|
d47cfee8bf | ||
|
|
1ee089e7ad | ||
|
|
7255e4b6db | ||
|
|
4e314da86d | ||
|
|
ec06cf10e9 | ||
|
|
ad972185d4 | ||
|
|
bc64b45d5c | ||
|
|
699c2a0e6e | ||
|
|
ebf6e43084 | ||
|
|
6527afb88c | ||
|
|
18e142ed88 | ||
|
|
797d306a4e | ||
|
|
267bf71d47 | ||
|
|
88a89f2178 | ||
|
|
8d2f60eba5 | ||
|
|
b4c9a125e5 | ||
|
|
36c53cfd41 | ||
|
|
d1223e9795 | ||
|
|
cebdbc3aa5 | ||
|
|
be4f235071 | ||
|
|
e8df9e9523 | ||
|
|
9a79308065 | ||
|
|
7a55e76a35 | ||
|
|
c92c55ca52 | ||
|
|
2bb43b57ba | ||
|
|
403a43530f | ||
|
|
51f9024498 | ||
|
|
9f7ad33707 | ||
|
|
fa5241490f | ||
|
|
27fd75aa67 | ||
|
|
c5a583b96f | ||
|
|
f1e301b48e | ||
|
|
61d4c51276 | ||
|
|
cbdbe7bf4b | ||
|
|
baa3a60b05 | ||
|
|
338dafca0c | ||
|
|
b1dddb649b | ||
|
|
3eb284da55 | ||
|
|
5fb969283d | ||
|
|
ae8b5cfe90 | ||
|
|
b6fa7de7e2 | ||
|
|
a4f13ca2de | ||
|
|
5172deb12d | ||
|
|
179f447a70 | ||
|
|
f4a937cc6b | ||
|
|
0b4c6c9af1 | ||
|
|
f17058a344 | ||
|
|
4fcf86a5d6 | ||
|
|
94362d640b | ||
|
|
7192d55732 | ||
|
|
11c9b00510 | ||
|
|
4579d6ca09 | ||
|
|
c3a9937c90 | ||
|
|
8650f82210 | ||
|
|
3ba13d2daa | ||
|
|
dace101c30 | ||
|
|
05e8ec6814 | ||
|
|
646ed6e9b1 | ||
|
|
a501b00ab7 | ||
|
|
6ae683b749 | ||
|
|
235af8c8c6 | ||
|
|
33e4e8e5ce | ||
|
|
20b23a3b0d | ||
|
|
d616c1e386 | ||
|
|
e6f2b23ca9 | ||
|
|
fbfea7ab1f | ||
|
|
bc85fb9597 | ||
|
|
a34f06669d | ||
|
|
6508c2b62c | ||
|
|
fb53b9e8ea | ||
|
|
75abab2832 | ||
|
|
13d9fa87d8 | ||
|
|
c0d40b2594 | ||
|
|
327cfe7d21 | ||
|
|
b4e83fd3f0 | ||
|
|
c902c1eace | ||
|
|
39a787c3c9 | ||
|
|
cdc20ce500 | ||
|
|
7dcd7badb3 | ||
|
|
1a0a73ac7c | ||
|
|
eb1fb776a5 | ||
|
|
82349d380b | ||
|
|
3c5deca55e | ||
|
|
e1b9e0165a | ||
|
|
2e701d0d23 | ||
|
|
259e3d716b | ||
|
|
43398449c7 | ||
|
|
e7f00fe088 | ||
|
|
1a9364acae | ||
|
|
19234998f1 | ||
|
|
31037775d1 | ||
|
|
e0b1bb0d06 | ||
|
|
1f810aa36f | ||
|
|
e7a8cec0b4 | ||
|
|
ae07ac2598 | ||
|
|
d75098fdd9 | ||
|
|
ac87cc13d7 | ||
|
|
34bffe0148 | ||
|
|
15f3cf07a8 | ||
|
|
c0f0d45138 | ||
|
|
2eddaccb86 | ||
|
|
87b2f4f93a | ||
|
|
88970314ad | ||
|
|
0de4e2afcc | ||
|
|
2671ac18c8 | ||
|
|
68a992c79e | ||
|
|
9bf233ec79 | ||
|
|
b41dcded98 | ||
|
|
b6239ed608 | ||
|
|
9dfe613921 | ||
|
|
865119e2ae | ||
|
|
c616f9c92a | ||
|
|
2737a85a61 |
No files matched your search
@@ -0,0 +1,52 @@
|
||||
# Java Maven CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-java/ for more details
|
||||
#
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
# specify the version you desire here
|
||||
- image: cimg/openjdk:11.0
|
||||
|
||||
# Specify service dependencies here if necessary
|
||||
# CircleCI maintains a library of pre-built images
|
||||
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||
# - image: circleci/postgres:9.4
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
environment:
|
||||
# Customize the JVM maximum heap limit
|
||||
MAVEN_OPTS: -Xmx3200m
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "pom.xml" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v1-dependencies-
|
||||
|
||||
- run: mvn dependency:go-offline
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
key: v1-dependencies-{{ checksum "pom.xml" }}
|
||||
|
||||
# run tests!
|
||||
- run: mvn integration-test
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- build:
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
- gh-pages-generated
|
||||
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at j@gro.sh. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: jagrosh
|
||||
patreon: jagrosh
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -1,24 +0,0 @@
|
||||
[download]: https://github.com/jagrosh/MusicBot/releases/latest
|
||||
[release]: https://img.shields.io/github/release/jagrosh/MusicBot.svg
|
||||
[setup]: https://github.com/jagrosh/MusicBot/wiki/Setup
|
||||
[rpi]: https://github.com/jagrosh/MusicBot/wiki/JMusicBot-on-Raspberry-Pi
|
||||
[features]: https://github.com/jagrosh/MusicBot/projects/1
|
||||
|
||||
## General Troubleshooting
|
||||
|
||||
Please check off these steps before suggesting a feature or reporting a bug:
|
||||
|
||||
- [ ] I am running the [latest version][download]: [![Release][release]][download]
|
||||
- [ ] I have followed all instructions on the [setup page][setup] (and if applicable, [Raspberry Pi][rpi])
|
||||
- [ ] I have read through the [planned and suggested features][features]
|
||||
|
||||
## Issue
|
||||
|
||||
### Issue Type
|
||||
|
||||
- [ ] Bug Report
|
||||
- [ ] Feature Request
|
||||
|
||||
### Description
|
||||
|
||||
Replace this with a description of your bug or feature request. Please provide screenshots and logs as applicable.
|
||||
@@ -0,0 +1,57 @@
|
||||
name: Bug Report
|
||||
description: Report a bug or unexpected behavior
|
||||
title: "[Bug Report] Title Here "
|
||||
labels: []
|
||||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: Please provide a clear and concise description of what the bug is.
|
||||
placeholder: The bug is...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Provide steps you can take to reliably reproduce this bug
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Result
|
||||
description: What did you expect to happen when this bug occurred?
|
||||
placeholder: I expected...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: debug
|
||||
attributes:
|
||||
label: Debug Output
|
||||
description: Please run the `debug` command and paste it here or upload it as an attachment. If you cannot run the command, please provide information about your system such as operating system version, JMusicBot version, etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-info
|
||||
attributes:
|
||||
label: Additional Info
|
||||
description: Any additional info that you think might be useful or relevant to this bug
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Before submitting your issue, please affirm the following
|
||||
options:
|
||||
- label: I have looked for information about this [within the documentation](https://jmusicbot.com/)
|
||||
required: true
|
||||
- label: I have searched for similar issues [on the issues page](https://github.com/jagrosh/MusicBot/issues?q=is%3Aissue)
|
||||
required: true
|
||||
- label: "I am running the latest version of the bot: "
|
||||
required: true
|
||||
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question
|
||||
url: https://github.com/jagrosh/MusicBot/discussions/categories/questions
|
||||
about: For general questions, please check the Discussions
|
||||
- name: Troubleshooting
|
||||
url: https://github.com/jagrosh/MusicBot/discussions/categories/troubleshooting
|
||||
about: For troubleshooting help, please check the Discussions
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
title: "[Feature Request] Title Here"
|
||||
labels: []
|
||||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: Please provide a clear and concise description of what the problem is.
|
||||
placeholder: A common problem users face is...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: What is your ideal solution to the problem?
|
||||
description: Describe a clear and concise description of what you want to happen.
|
||||
placeholder: My solution to the above problem is...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: procedure
|
||||
attributes:
|
||||
label: How would this feature be used?
|
||||
description: Describe the basic flow/steps of using this feature.
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-info
|
||||
attributes:
|
||||
label: Additional Info
|
||||
description: Any additional info that you think might be useful or relevant to this feature request
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Before submitting your issue, please affirm the following
|
||||
options:
|
||||
- label: I have checked [the documentation](https://jmusicbot.com/) to make sure this feature doesn't already exist
|
||||
required: true
|
||||
- label: I have searched for [similar feature requests](https://github.com/jagrosh/MusicBot/labels/enhancement)
|
||||
required: true
|
||||
- label: I have confirmed that my requests is **not** on the [list of things that will not be added](https://jmusicbot.com/things-that-wont-be-added)
|
||||
required: true
|
||||
- label: "I am running the latest version of the bot: "
|
||||
required: true
|
||||
@@ -0,0 +1,14 @@
|
||||
### This pull request...
|
||||
- [ ] Fixes a bug
|
||||
- [ ] Introduces a new feature
|
||||
- [ ] Improves an existing feature
|
||||
- [ ] Boosts code quality or performance
|
||||
|
||||
### Description
|
||||
Replace this with a description of the pull request
|
||||
|
||||
### Purpose
|
||||
Replace this with a description of the problem or use-case
|
||||
|
||||
### Relevant Issue(s)
|
||||
This PR closes issue #...
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Build and Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: maven
|
||||
- name: Build and Test with Maven
|
||||
run: mvn --batch-mode --update-snapshots verify
|
||||
@@ -0,0 +1,70 @@
|
||||
name: Make Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_number:
|
||||
description: 'Version Number'
|
||||
required: true
|
||||
type: string
|
||||
info:
|
||||
description: 'Description of this Release'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build_jar:
|
||||
name: Build Jar
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: maven
|
||||
- name: Set Version
|
||||
uses: datamonsters/replace-action@v2
|
||||
with:
|
||||
files: 'pom.xml'
|
||||
replacements: 'Snapshot=${{ github.event.inputs.version_number }}'
|
||||
- name: Build with Maven
|
||||
run: mvn --batch-mode --update-snapshots verify
|
||||
- name: Rename jar
|
||||
run: mv target/*-All.jar JMusicBot-${{ github.event.inputs.version_number }}.jar
|
||||
- name: Upload jar
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: jar
|
||||
path: JMusicBot-${{ github.event.inputs.version_number }}.jar
|
||||
if-no-files-found: error
|
||||
create_release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: build_jar
|
||||
steps:
|
||||
- name: Download a Build Artifact
|
||||
uses: actions/download-artifact@v3.0.0
|
||||
with:
|
||||
name: jar
|
||||
path: .
|
||||
- name: Show Artifacts
|
||||
run: ls -R
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.event.inputs.version_number }}
|
||||
name: Version ${{ github.event.inputs.version_number }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
artifacts: "*.jar"
|
||||
body: |
|
||||
${{ github.event.inputs.info }}
|
||||
|
||||
---
|
||||
### Setup
|
||||
https://jmusicbot.com/setup
|
||||
https://jmusicbot.com/config
|
||||
# Download: [JMusicBot-${{ github.event.inputs.version_number }}.jar](https://github.com/jagrosh/MusicBot/releases/download/${{ github.event.inputs.version_number }}/JMusicBot-${{ github.event.inputs.version_number }}.jar)
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
/nbproject/
|
||||
/target/
|
||||
/Playlists/
|
||||
/test/
|
||||
*.json
|
||||
*.txt
|
||||
/nbproject/
|
||||
nb*.xml
|
||||
@@ -1,36 +1,60 @@
|
||||
<img align="right" src="https://i.imgur.com/zrE80HY.png" height="200" width="200">
|
||||
|
||||
# JMusicBot
|
||||
|
||||
[](https://github.com/jagrosh/MusicBot/releases/latest)
|
||||
[](https://github.com/jagrosh/MusicBot/stargazers)
|
||||
[](https://github.com/jagrosh/MusicBot/releases/latest)
|
||||
[](https://github.com/jagrosh/MusicBot/blob/master/LICENSE)
|
||||
[](https://discord.gg/0p9LSGoRLu6Pet0k)
|
||||
[](https://discord.gg/0p9LSGoRLu6Pet0k)<br>
|
||||
[](https://dl.circleci.com/status-badge/redirect/gh/jagrosh/MusicBot/tree/master)
|
||||
[](https://github.com/jagrosh/MusicBot/actions/workflows/build-and-test.yml)
|
||||
[](https://www.codefactor.io/repository/github/jagrosh/musicbot)
|
||||
|
||||
# JMusicBot
|
||||
A Discord music bot with a clean interface, and that is easy to set up and run yourself
|
||||
A cross-platform Discord music bot with a clean interface, and that is easy to set up and run yourself!
|
||||
|
||||
[](https://github.com/jagrosh/MusicBot/wiki/Setup)
|
||||
[](https://jmusicbot.com/setup)
|
||||
|
||||
# Features
|
||||
* Easy to run (just make sure Java is installed, and run!)
|
||||
* Fast loading of songs
|
||||
* No external keys needed (besides a Discord Bot token)
|
||||
* Smooth playback
|
||||
* Server-specific setup for the "DJ" role that can moderate the music
|
||||
* Clean and beautiful menus
|
||||
* Channel-topic playback bar
|
||||
* Supports many sites, including Youtube, Soundcloud, and more
|
||||
* Supports many online radio/streams
|
||||
* Supports local files
|
||||
* Playlist support (both web/youtube, and local)
|
||||
## Features
|
||||
* Easy to run (just make sure Java is installed, and run!)
|
||||
* Fast loading of songs
|
||||
* No external keys needed (besides a Discord Bot token)
|
||||
* Smooth playback
|
||||
* Server-specific setup for the "DJ" role that can moderate the music
|
||||
* Clean and beautiful menus
|
||||
* Supports many sites, including Youtube, Soundcloud, and more
|
||||
* Supports many online radio/streams
|
||||
* Supports local files
|
||||
* Playlist support (both web/youtube, and local)
|
||||
|
||||
# Setup
|
||||
Please see the [Setup Page](https://github.com/jagrosh/MusicBot/wiki/Setup) in the wiki to run this bot yourself!
|
||||
## Supported sources and formats
|
||||
JMusicBot supports all sources and formats supported by [lavaplayer](https://github.com/sedmelluq/lavaplayer#supported-formats):
|
||||
### Sources
|
||||
* YouTube
|
||||
* SoundCloud
|
||||
* Bandcamp
|
||||
* Vimeo
|
||||
* Twitch streams
|
||||
* Local files
|
||||
* HTTP URLs
|
||||
### Formats
|
||||
* MP3
|
||||
* FLAC
|
||||
* WAV
|
||||
* Matroska/WebM (AAC, Opus or Vorbis codecs)
|
||||
* MP4/M4A (AAC codec)
|
||||
* OGG streams (Opus, Vorbis and FLAC codecs)
|
||||
* AAC streams
|
||||
* Stream playlists (M3U and PLS)
|
||||
|
||||
# Questions/Suggestions/Bug Reports
|
||||
**Please read the [Suggested/Planned Features List](https://github.com/jagrosh/MusicBot/projects/1) before suggesting a feature**. If you'd like to suggest changes to how the bot functions, recommend more customization options, or report bugs, feel free to either open an [Issue](https://github.com/jagrosh/MusicBot/issues) on this repository, or join [my Discord server](https://discord.gg/0p9LSGoRLu6Pet0k). (Note: I will not accept any feature requests that will require additional API keys, nor any non-music features). If you like this bot, be sure to add a star to the libraries that make this possible: [**JDA**](https://github.com/DV8FromTheWorld/JDA) and [**lavaplayer**](https://github.com/sedmelluq/lavaplayer)
|
||||
## Example
|
||||

|
||||
|
||||
# Example
|
||||

|
||||
## Setup
|
||||
Please see the [Setup Page](https://jmusicbot.com/setup) to run this bot yourself!
|
||||
|
||||
# Editing
|
||||
This bot (and the source code here) is not meant to be edited. The main purpose of having the source public is to show the capabilities of the libraries, and to allow others to understand how the bot works. There are many requirements and dependencies required to edit and compile it, and there will not be support provided for people looking to make changes on their own. Instead, consider making a feature request (see the above section). If you still choose to make edits, please do so in accordance with the Apache 2.0 License.
|
||||
## Questions/Suggestions/Bug Reports
|
||||
**Please read the [Issues List](https://github.com/jagrosh/MusicBot/issues) before suggesting a feature**. If you have a question, need troubleshooting help, or want to brainstorm a new feature, please start a [Discussion](https://github.com/jagrosh/MusicBot/discussions). If you'd like to suggest a feature or report a reproducible bug, please open an [Issue](https://github.com/jagrosh/MusicBot/issues) on this repository. If you like this bot, be sure to add a star to the libraries that make this possible: [**JDA**](https://github.com/DV8FromTheWorld/JDA) and [**lavaplayer**](https://github.com/sedmelluq/lavaplayer)!
|
||||
|
||||
## Editing
|
||||
This bot (and the source code here) might not be easy to edit for inexperienced programmers. The main purpose of having the source public is to show the capabilities of the libraries, to allow others to understand how the bot works, and to allow those knowledgeable about java, JDA, and Discord bot development to contribute. There are many requirements and dependencies required to edit and compile it, and there will not be support provided for people looking to make changes on their own. Instead, consider making a feature request (see the above section). If you choose to make edits, please do so in accordance with the Apache 2.0 License.
|
||||
@@ -3,48 +3,93 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.jagrosh</groupId>
|
||||
<artifactId>JMusicBot</artifactId>
|
||||
<version>0.2.1</version>
|
||||
<version>Snapshot</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dv8tion</id>
|
||||
<name>m2-dv8tion</name>
|
||||
<url>https://m2.dv8tion.net/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>bintray</name>
|
||||
<url>http://jcenter.bintray.com</url>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>always</updatePolicy>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>m2.duncte123.dev</id>
|
||||
<name>m2-duncte123</name>
|
||||
<url>https://m2.duncte123.dev/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>arbjergDev-snapshots</id>
|
||||
<name>Lavalink Repository</name>
|
||||
<url>https://maven.lavalink.dev/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!-- Discord Dependencies -->
|
||||
<dependency>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>3.8.1_447</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sedmelluq</groupId>
|
||||
<artifactId>lavaplayer</artifactId>
|
||||
<version>1.3.10</version>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>4.4.1_353</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jagrosh</groupId>
|
||||
<artifactId>jda-utilities</artifactId>
|
||||
<version>2.1.4</version>
|
||||
<version>3.0.5</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<!-- Music Dependencies -->
|
||||
<dependency>
|
||||
<groupId>dev.arbjerg</groupId>
|
||||
<artifactId>lavaplayer</artifactId>
|
||||
<version>727959e9f621fc457b3a5adafcfffb55fdeaa538-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.jagrosh</groupId>
|
||||
<artifactId>JLyrics</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dunctebot</groupId>
|
||||
<artifactId>sourcemanagers</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Misc Internal Dependencies -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<version>1.2.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe</groupId>
|
||||
<artifactId>config</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.15.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing Dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -54,39 +99,52 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.jagrosh.jmusicbot.JMusicBot</mainClass>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>All</shadedClassifierName>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>*:*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>reference.conf</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Main-Class>com.jagrosh.jmusicbot.JMusicBot</Main-Class>
|
||||
<Specification-Title>${project.artifactId}</Specification-Title>
|
||||
<Specification-Version>${project.version}</Specification-Version>
|
||||
<Implementation-Title>${project.artifactId}</Implementation-Title>
|
||||
<Implementation-Version>${project.version}</Implementation-Version>
|
||||
<Implementation-Vendor-Id>${project.groupId}</Implementation-Vendor-Id>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This will have this script check for a new version of JMusicBot every
|
||||
# startup (and download it if the latest version isn't currently downloaded)
|
||||
DOWNLOAD=true
|
||||
|
||||
# This will cause the script to run in a loop so that the bot auto-restarts
|
||||
# when you use the shutdown command
|
||||
LOOP=true
|
||||
|
||||
download() {
|
||||
if [ $DOWNLOAD == true ]; then
|
||||
URL=$(curl -s https://api.github.com/repos/jagrosh/MusicBot/releases/latest \
|
||||
| grep -i "browser_download_url.*\.jar" \
|
||||
| sed 's/.*\(http.*\)"/\1/')
|
||||
FILENAME=$(echo $URL | sed 's/.*\/\([^\/]*\)/\1/')
|
||||
if [ -f $FILENAME ]; then
|
||||
echo "Latest version already downloaded (${FILENAME})"
|
||||
else
|
||||
curl -L $URL -o $FILENAME
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run() {
|
||||
java -Dnogui=true -jar $(ls -t JMusicBot* | head -1)
|
||||
}
|
||||
|
||||
while
|
||||
download
|
||||
run
|
||||
$LOOP
|
||||
do
|
||||
continue
|
||||
done
|
||||
@@ -18,6 +18,7 @@ package com.jagrosh.jmusicbot;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import com.jagrosh.jdautilities.commons.waiter.EventWaiter;
|
||||
import com.jagrosh.jmusicbot.audio.AloneInVoiceHandler;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.NowplayingHandler;
|
||||
import com.jagrosh.jmusicbot.audio.PlayerManager;
|
||||
@@ -25,9 +26,9 @@ import com.jagrosh.jmusicbot.gui.GUI;
|
||||
import com.jagrosh.jmusicbot.playlist.PlaylistLoader;
|
||||
import com.jagrosh.jmusicbot.settings.SettingsManager;
|
||||
import java.util.Objects;
|
||||
import net.dv8tion.jda.core.JDA;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -42,6 +43,7 @@ public class Bot
|
||||
private final PlayerManager players;
|
||||
private final PlaylistLoader playlists;
|
||||
private final NowplayingHandler nowplaying;
|
||||
private final AloneInVoiceHandler aloneInVoiceHandler;
|
||||
|
||||
private boolean shuttingDown = false;
|
||||
private JDA jda;
|
||||
@@ -58,6 +60,8 @@ public class Bot
|
||||
this.players.init();
|
||||
this.nowplaying = new NowplayingHandler(this);
|
||||
this.nowplaying.init();
|
||||
this.aloneInVoiceHandler = new AloneInVoiceHandler(this);
|
||||
this.aloneInVoiceHandler.init();
|
||||
}
|
||||
|
||||
public BotConfig getConfig()
|
||||
@@ -94,6 +98,11 @@ public class Bot
|
||||
{
|
||||
return nowplaying;
|
||||
}
|
||||
|
||||
public AloneInVoiceHandler getAloneInVoiceHandler()
|
||||
{
|
||||
return aloneInVoiceHandler;
|
||||
}
|
||||
|
||||
public JDA getJDA()
|
||||
{
|
||||
@@ -109,9 +118,9 @@ public class Bot
|
||||
|
||||
public void resetGame()
|
||||
{
|
||||
Game game = config.getGame()==null || config.getGame().getName().equalsIgnoreCase("none") ? null : config.getGame();
|
||||
if(!Objects.equals(jda.getPresence().getGame(), game))
|
||||
jda.getPresence().setGame(game);
|
||||
Activity game = config.getGame()==null || config.getGame().getName().equalsIgnoreCase("none") ? null : config.getGame();
|
||||
if(!Objects.equals(jda.getPresence().getActivity(), game))
|
||||
jda.getPresence().setActivity(game);
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
@@ -130,7 +139,6 @@ public class Bot
|
||||
{
|
||||
ah.stopAndClear();
|
||||
ah.getPlayer().destroy();
|
||||
nowplaying.updateTopic(g.getIdLong(), ah, true);
|
||||
}
|
||||
});
|
||||
jda.shutdown();
|
||||
|
||||
@@ -23,16 +23,10 @@ import com.typesafe.config.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import net.dv8tion.jda.core.OnlineStatus;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
|
||||
/**
|
||||
* @author Your Name
|
||||
* Changes from original source:
|
||||
* - Changed "searching" to "finding"
|
||||
*
|
||||
*
|
||||
* @author John Grosh (jagrosh)
|
||||
@@ -41,15 +35,19 @@ public class BotConfig
|
||||
{
|
||||
private final Prompt prompt;
|
||||
private final static String CONTEXT = "Config";
|
||||
private final static String START_TOKEN = "/// START OF JMUSICBOT CONFIG ///";
|
||||
private final static String END_TOKEN = "/// END OF JMUSICBOT CONFIG ///";
|
||||
|
||||
private Path path = null;
|
||||
private String token, prefix, altprefix, helpWord, playlistsFolder,
|
||||
successEmoji, warningEmoji, errorEmoji, loadingEmoji, searchingEmoji;
|
||||
private boolean stayInChannel, songInGame, npImages, updatealerts, useEval, dbots;
|
||||
private long owner, maxSeconds;
|
||||
private long owner, maxSeconds, aloneTimeUntilStop;
|
||||
private double skipratio;
|
||||
private OnlineStatus status;
|
||||
private Game game;
|
||||
|
||||
private Activity game;
|
||||
private Config aliases, transforms;
|
||||
|
||||
private boolean valid = false;
|
||||
|
||||
public BotConfig(Prompt prompt)
|
||||
@@ -65,21 +63,12 @@ public class BotConfig
|
||||
try
|
||||
{
|
||||
// get the path to the config, default config.txt
|
||||
path = Paths.get(System.getProperty("config.file", System.getProperty("config", "config.txt")));
|
||||
if(path.toFile().exists())
|
||||
{
|
||||
if(System.getProperty("config.file") == null)
|
||||
System.setProperty("config.file", System.getProperty("config", "config.txt"));
|
||||
ConfigFactory.invalidateCaches();
|
||||
}
|
||||
path = getConfigPath();
|
||||
|
||||
// load in the config file, plus the default values
|
||||
//Config config = ConfigFactory.parseFile(path.toFile()).withFallback(ConfigFactory.load());
|
||||
Config config = ConfigFactory.load();
|
||||
|
||||
// info on where the config is being loaded from
|
||||
prompt.alert(Prompt.Level.INFO, CONTEXT, "Loading config from "+path.toAbsolutePath().toString());
|
||||
|
||||
// set values
|
||||
token = config.getString("token");
|
||||
prefix = config.getString("prefix");
|
||||
@@ -99,11 +88,15 @@ public class BotConfig
|
||||
updatealerts = config.getBoolean("updatealerts");
|
||||
useEval = config.getBoolean("eval");
|
||||
maxSeconds = config.getLong("maxtime");
|
||||
aloneTimeUntilStop = config.getLong("alonetimeuntilstop");
|
||||
playlistsFolder = config.getString("playlistsfolder");
|
||||
aliases = config.getConfig("aliases");
|
||||
transforms = config.getConfig("transforms");
|
||||
skipratio = config.getDouble("skipratio");
|
||||
dbots = owner == 113156185389092864L;
|
||||
|
||||
// we may need to get some additional data and write a new config file
|
||||
List<String> lines = new LinkedList<>();
|
||||
// we may need to write a new config file
|
||||
boolean write = false;
|
||||
|
||||
// validate bot token
|
||||
if(token==null || token.isEmpty() || token.equalsIgnoreCase("BOT_TOKEN_HERE"))
|
||||
@@ -114,12 +107,12 @@ public class BotConfig
|
||||
+ "\nBot Token: ");
|
||||
if(token==null)
|
||||
{
|
||||
prompt.alert(Prompt.Level.WARNING, CONTEXT, "No token provided! Exiting.");
|
||||
prompt.alert(Prompt.Level.WARNING, CONTEXT, "No token provided! Exiting.\n\nConfig Location: " + path.toAbsolutePath().toString());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.add("token="+token);
|
||||
write = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,36 +133,78 @@ public class BotConfig
|
||||
}
|
||||
if(owner<=0)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, CONTEXT, "Invalid User ID! Exiting.");
|
||||
System.exit(0);
|
||||
prompt.alert(Prompt.Level.ERROR, CONTEXT, "Invalid User ID! Exiting.\n\nConfig Location: " + path.toAbsolutePath().toString());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.add("owner="+owner);
|
||||
write = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!lines.isEmpty())
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
lines.stream().forEach(s -> builder.append(s).append("\r\n"));
|
||||
try
|
||||
{
|
||||
Files.write(path, builder.toString().trim().getBytes());
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.WARNING, CONTEXT, "Failed to write new config options to config.txt: "+ex
|
||||
+ "\nPlease make sure that the files are not on your desktop or some other restricted area.");
|
||||
}
|
||||
}
|
||||
if(write)
|
||||
writeToFile();
|
||||
|
||||
// if we get through the whole config, it's good to go
|
||||
valid = true;
|
||||
}
|
||||
catch (ConfigException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, CONTEXT, ex + ": " + ex.getMessage());
|
||||
prompt.alert(Prompt.Level.ERROR, CONTEXT, ex + ": " + ex.getMessage() + "\n\nConfig Location: " + path.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToFile()
|
||||
{
|
||||
byte[] bytes = loadDefaultConfig().replace("BOT_TOKEN_HERE", token)
|
||||
.replace("0 // OWNER ID", Long.toString(owner))
|
||||
.trim().getBytes();
|
||||
try
|
||||
{
|
||||
Files.write(path, bytes);
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.WARNING, CONTEXT, "Failed to write new config options to config.txt: "+ex
|
||||
+ "\nPlease make sure that the files are not on your desktop or some other restricted area.\n\nConfig Location: "
|
||||
+ path.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static String loadDefaultConfig()
|
||||
{
|
||||
String original = OtherUtil.loadResource(new JMusicBot(), "/reference.conf");
|
||||
return original==null
|
||||
? "token = BOT_TOKEN_HERE\r\nowner = 0 // OWNER ID"
|
||||
: original.substring(original.indexOf(START_TOKEN)+START_TOKEN.length(), original.indexOf(END_TOKEN)).trim();
|
||||
}
|
||||
|
||||
private static Path getConfigPath()
|
||||
{
|
||||
Path path = OtherUtil.getPath(System.getProperty("config.file", System.getProperty("config", "config.txt")));
|
||||
if(path.toFile().exists())
|
||||
{
|
||||
if(System.getProperty("config.file") == null)
|
||||
System.setProperty("config.file", System.getProperty("config", path.toAbsolutePath().toString()));
|
||||
ConfigFactory.invalidateCaches();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static void writeDefaultConfig()
|
||||
{
|
||||
Prompt prompt = new Prompt(null, null, true, true);
|
||||
prompt.alert(Prompt.Level.INFO, "JMusicBot Config", "Generating default config file");
|
||||
Path path = BotConfig.getConfigPath();
|
||||
byte[] bytes = BotConfig.loadDefaultConfig().getBytes();
|
||||
try
|
||||
{
|
||||
prompt.alert(Prompt.Level.INFO, "JMusicBot Config", "Writing default config file to " + path.toAbsolutePath().toString());
|
||||
Files.write(path, bytes);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot Config", "An error occurred writing the default config file: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +233,11 @@ public class BotConfig
|
||||
return token;
|
||||
}
|
||||
|
||||
public double getSkipRatio()
|
||||
{
|
||||
return skipratio;
|
||||
}
|
||||
|
||||
public long getOwnerId()
|
||||
{
|
||||
return owner;
|
||||
@@ -228,11 +268,16 @@ public class BotConfig
|
||||
return searchingEmoji;
|
||||
}
|
||||
|
||||
public Game getGame()
|
||||
public Activity getGame()
|
||||
{
|
||||
return game;
|
||||
}
|
||||
|
||||
public boolean isGameNone()
|
||||
{
|
||||
return game != null && game.getName().equalsIgnoreCase("none");
|
||||
}
|
||||
|
||||
public OnlineStatus getStatus()
|
||||
{
|
||||
return status;
|
||||
@@ -287,6 +332,11 @@ public class BotConfig
|
||||
{
|
||||
return FormatUtil.formatTime(maxSeconds * 1000);
|
||||
}
|
||||
|
||||
public long getAloneTimeUntilStop()
|
||||
{
|
||||
return aloneTimeUntilStop;
|
||||
}
|
||||
|
||||
public boolean isTooLong(AudioTrack track)
|
||||
{
|
||||
@@ -294,4 +344,21 @@ public class BotConfig
|
||||
return false;
|
||||
return Math.round(track.getDuration()/1000.0) > maxSeconds;
|
||||
}
|
||||
|
||||
public String[] getAliases(String command)
|
||||
{
|
||||
try
|
||||
{
|
||||
return aliases.getStringList(command).toArray(new String[0]);
|
||||
}
|
||||
catch(NullPointerException | ConfigException.Missing e)
|
||||
{
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Config getTransforms()
|
||||
{
|
||||
return transforms;
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,13 @@ import com.jagrosh.jmusicbot.gui.GUI;
|
||||
import com.jagrosh.jmusicbot.settings.SettingsManager;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import java.awt.Color;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import net.dv8tion.jda.core.*;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import net.dv8tion.jda.api.*;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import net.dv8tion.jda.api.utils.cache.CacheFlag;
|
||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -41,53 +45,133 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class JMusicBot
|
||||
{
|
||||
public final static String PLAY_EMOJI = "\u25B6";
|
||||
public final static String PAUSE_EMOJI = "\u23F8";
|
||||
public final static String STOP_EMOJI = "\u23F9";
|
||||
public final static Permission[] RECOMMENDED_PERMS = new Permission[]{Permission.MESSAGE_READ, Permission.MESSAGE_WRITE, Permission.MESSAGE_HISTORY, Permission.MESSAGE_ADD_REACTION,
|
||||
public final static Logger LOG = LoggerFactory.getLogger(JMusicBot.class);
|
||||
public final static Permission[] RECOMMENDED_PERMS = {Permission.MESSAGE_READ, Permission.MESSAGE_WRITE, Permission.MESSAGE_HISTORY, Permission.MESSAGE_ADD_REACTION,
|
||||
Permission.MESSAGE_EMBED_LINKS, Permission.MESSAGE_ATTACH_FILES, Permission.MESSAGE_MANAGE, Permission.MESSAGE_EXT_EMOJI,
|
||||
Permission.MANAGE_CHANNEL, Permission.VOICE_CONNECT, Permission.VOICE_SPEAK, Permission.NICKNAME_CHANGE};
|
||||
Permission.VOICE_CONNECT, Permission.VOICE_SPEAK, Permission.NICKNAME_CHANGE};
|
||||
public final static GatewayIntent[] INTENTS = {GatewayIntent.DIRECT_MESSAGES, GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES};
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// startup log
|
||||
Logger log = LoggerFactory.getLogger("Startup");
|
||||
|
||||
// create prompt to handle startup
|
||||
Prompt prompt = new Prompt("JMusicBot", "Switching to nogui mode. You can manually start in nogui mode by including the -Dnogui=true flag.",
|
||||
"true".equalsIgnoreCase(System.getProperty("nogui", "false")));
|
||||
|
||||
// check deprecated nogui mode (new way of setting it is -Dnogui=true)
|
||||
for(String arg: args)
|
||||
if("-nogui".equalsIgnoreCase(arg))
|
||||
if(args.length > 0)
|
||||
switch(args[0].toLowerCase())
|
||||
{
|
||||
prompt.alert(Prompt.Level.WARNING, "GUI", "The -nogui flag has been deprecated. "
|
||||
+ "Please use the -Dnogui=true flag before the name of the jar. Example: java -jar -Dnogui=true JMusicBot.jar");
|
||||
break;
|
||||
case "generate-config":
|
||||
BotConfig.writeDefaultConfig();
|
||||
return;
|
||||
default:
|
||||
}
|
||||
startBot();
|
||||
}
|
||||
|
||||
private static void startBot()
|
||||
{
|
||||
// create prompt to handle startup
|
||||
Prompt prompt = new Prompt("JMusicBot");
|
||||
|
||||
// get and check latest version
|
||||
String version = OtherUtil.checkVersion(prompt);
|
||||
// startup checks
|
||||
OtherUtil.checkVersion(prompt);
|
||||
OtherUtil.checkJavaVersion(prompt);
|
||||
|
||||
// load config
|
||||
BotConfig config = new BotConfig(prompt);
|
||||
config.load();
|
||||
if(!config.isValid())
|
||||
return;
|
||||
LOG.info("Loaded config from " + config.getConfigLocation());
|
||||
|
||||
// set up the listener
|
||||
EventWaiter waiter = new EventWaiter();
|
||||
SettingsManager settings = new SettingsManager();
|
||||
Bot bot = new Bot(waiter, config, settings);
|
||||
CommandClient client = createCommandClient(config, settings, bot);
|
||||
|
||||
|
||||
if(!prompt.isNoGUI())
|
||||
{
|
||||
try
|
||||
{
|
||||
GUI gui = new GUI(bot);
|
||||
bot.setGUI(gui);
|
||||
gui.init();
|
||||
|
||||
LOG.info("Loaded config from " + config.getConfigLocation());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.error("Could not start GUI. If you are "
|
||||
+ "running on a server or in a location where you cannot display a "
|
||||
+ "window, please run in nogui mode using the -Dnogui=true flag.");
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to log in and start
|
||||
try
|
||||
{
|
||||
JDA jda = JDABuilder.create(config.getToken(), Arrays.asList(INTENTS))
|
||||
.enableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE)
|
||||
.disableCache(CacheFlag.ACTIVITY, CacheFlag.CLIENT_STATUS, CacheFlag.EMOTE, CacheFlag.ONLINE_STATUS)
|
||||
.setActivity(config.isGameNone() ? null : Activity.playing("loading..."))
|
||||
.setStatus(config.getStatus()==OnlineStatus.INVISIBLE || config.getStatus()==OnlineStatus.OFFLINE
|
||||
? OnlineStatus.INVISIBLE : OnlineStatus.DO_NOT_DISTURB)
|
||||
.addEventListeners(client, waiter, new Listener(bot))
|
||||
.setBulkDeleteSplittingEnabled(true)
|
||||
.build();
|
||||
bot.setJDA(jda);
|
||||
|
||||
// check if something about the current startup is not supported
|
||||
String unsupportedReason = OtherUtil.getUnsupportedBotReason(jda);
|
||||
if (unsupportedReason != null)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", "JMusicBot cannot be run on this Discord bot: " + unsupportedReason);
|
||||
try{ Thread.sleep(5000);}catch(InterruptedException ignored){} // this is awful but until we have a better way...
|
||||
jda.shutdown();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// other check that will just be a warning now but may be required in the future
|
||||
// check if the user has changed the prefix and provide info about the
|
||||
// message content intent
|
||||
if(!"@mention".equals(config.getPrefix()))
|
||||
{
|
||||
prompt.alert(Prompt.Level.INFO, "JMusicBot", "You currently have a custom prefix set. "
|
||||
+ "If your prefix is not working, make sure that the 'MESSAGE CONTENT INTENT' is Enabled "
|
||||
+ "on https://discord.com/developers/applications/" + jda.getSelfUser().getId() + "/bot");
|
||||
}
|
||||
}
|
||||
catch (LoginException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", ex + "\nPlease make sure you are "
|
||||
+ "editing the correct config.txt file, and that you have used the "
|
||||
+ "correct token (not the 'secret'!)\nConfig Location: " + config.getConfigLocation());
|
||||
System.exit(1);
|
||||
}
|
||||
catch(IllegalArgumentException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", "Some aspect of the configuration is "
|
||||
+ "invalid: " + ex + "\nConfig Location: " + config.getConfigLocation());
|
||||
System.exit(1);
|
||||
}
|
||||
catch(ErrorResponseException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", ex + "\nInvalid reponse returned when "
|
||||
+ "attempting to connect, please make sure you're connected to the internet");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static CommandClient createCommandClient(BotConfig config, SettingsManager settings, Bot bot)
|
||||
{
|
||||
// instantiate about command
|
||||
AboutCommand aboutCommand = new AboutCommand(Color.BLUE.brighter(),
|
||||
"a music bot that is [easy to host yourself!](https://github.com/jagrosh/MusicBot) (v"+version+")",
|
||||
"a music bot that is [easy to host yourself!](https://github.com/jagrosh/MusicBot) (v" + OtherUtil.getCurrentVersion() + ")",
|
||||
new String[]{"High-quality music playback", "FairQueue™ Technology", "Easy to host yourself"},
|
||||
RECOMMENDED_PERMS);
|
||||
aboutCommand.setIsAuthor(false);
|
||||
aboutCommand.setReplacementCharacter("\uD83C\uDFB6");
|
||||
aboutCommand.setReplacementCharacter("\uD83C\uDFB6"); // 🎶
|
||||
|
||||
// set up the command client
|
||||
CommandClientBuilder cb = new CommandClientBuilder()
|
||||
@@ -100,96 +184,62 @@ public class JMusicBot
|
||||
.setGuildSettingsManager(settings)
|
||||
.addCommands(aboutCommand,
|
||||
new PingCommand(),
|
||||
new SettingsCmd(),
|
||||
new SettingsCmd(bot),
|
||||
|
||||
new LyricsCmd(bot),
|
||||
new NowplayingCmd(bot),
|
||||
new PlayCmd(bot, config.getLoading()),
|
||||
new PlayCmd(bot),
|
||||
new PlaylistsCmd(bot),
|
||||
new QueueCmd(bot),
|
||||
new RemoveCmd(bot),
|
||||
new SearchCmd(bot, config.getSearching()),
|
||||
new SCSearchCmd(bot, config.getSearching()),
|
||||
new SearchCmd(bot),
|
||||
new SCSearchCmd(bot),
|
||||
new ShuffleCmd(bot),
|
||||
new SkipCmd(bot),
|
||||
|
||||
|
||||
new ForceRemoveCmd(bot),
|
||||
new ForceskipCmd(bot),
|
||||
new MoveTrackCmd(bot),
|
||||
new PauseCmd(bot),
|
||||
new PlaynextCmd(bot, config.getLoading()),
|
||||
new PlaynextCmd(bot),
|
||||
new RepeatCmd(bot),
|
||||
new SkiptoCmd(bot),
|
||||
new StopCmd(bot),
|
||||
new VolumeCmd(bot),
|
||||
|
||||
new SetdjCmd(),
|
||||
new SettcCmd(),
|
||||
new SetvcCmd(),
|
||||
|
||||
new PrefixCmd(bot),
|
||||
new QueueTypeCmd(bot),
|
||||
new SetdjCmd(bot),
|
||||
new SkipratioCmd(bot),
|
||||
new SettcCmd(bot),
|
||||
new SetvcCmd(bot),
|
||||
|
||||
new AutoplaylistCmd(bot),
|
||||
new DebugCmd(bot),
|
||||
new PlaylistCmd(bot),
|
||||
new SetavatarCmd(),
|
||||
new SetgameCmd(),
|
||||
new SetavatarCmd(bot),
|
||||
new SetgameCmd(bot),
|
||||
new SetnameCmd(bot),
|
||||
new SetstatusCmd(),
|
||||
new SetstatusCmd(bot),
|
||||
new ShutdownCmd(bot)
|
||||
);
|
||||
|
||||
// enable eval if applicable
|
||||
if(config.useEval())
|
||||
cb.addCommand(new EvalCmd(bot));
|
||||
boolean nogame = false;
|
||||
if(config.getStatus()!=OnlineStatus.UNKNOWN)
|
||||
|
||||
// set status if set in config
|
||||
if(config.getStatus() != OnlineStatus.UNKNOWN)
|
||||
cb.setStatus(config.getStatus());
|
||||
if(config.getGame()==null)
|
||||
|
||||
// set game
|
||||
if(config.getGame() == null)
|
||||
cb.useDefaultGame();
|
||||
else if(config.getGame().getName().equalsIgnoreCase("none"))
|
||||
{
|
||||
cb.setGame(null);
|
||||
nogame = true;
|
||||
}
|
||||
else if(config.isGameNone())
|
||||
cb.setActivity(null);
|
||||
else
|
||||
cb.setGame(config.getGame());
|
||||
CommandClient client = cb.build();
|
||||
cb.setActivity(config.getGame());
|
||||
|
||||
if(!prompt.isNoGUI())
|
||||
{
|
||||
try
|
||||
{
|
||||
GUI gui = new GUI(bot);
|
||||
bot.setGUI(gui);
|
||||
gui.init();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.error("Could not start GUI. If you are "
|
||||
+ "running on a server or in a location where you cannot display a "
|
||||
+ "window, please run in nogui mode using the -Dnogui=true flag.");
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Loaded config from "+config.getConfigLocation());
|
||||
|
||||
// attempt to log in and start
|
||||
try
|
||||
{
|
||||
JDA jda = new JDABuilder(AccountType.BOT)
|
||||
.setToken(config.getToken())
|
||||
.setAudioEnabled(true)
|
||||
.setGame(nogame ? null : Game.playing("loading..."))
|
||||
.setStatus(config.getStatus()==OnlineStatus.INVISIBLE||config.getStatus()==OnlineStatus.OFFLINE ? OnlineStatus.INVISIBLE : OnlineStatus.DO_NOT_DISTURB)
|
||||
.addEventListener(client, waiter, new Listener(bot))
|
||||
.setBulkDeleteSplittingEnabled(true)
|
||||
.build();
|
||||
bot.setJDA(jda);
|
||||
}
|
||||
catch (LoginException ex)
|
||||
{
|
||||
log.error(ex+"\nPlease make sure you are "
|
||||
+ "editing the correct config.txt file, and that you have used the "
|
||||
+ "correct token (not the 'secret'!)");
|
||||
System.exit(1);
|
||||
}
|
||||
catch(IllegalArgumentException ex)
|
||||
{
|
||||
log.error("Some aspect of the configuration is invalid: "+ex);
|
||||
System.exit(1);
|
||||
}
|
||||
return cb.build();
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,17 @@ package com.jagrosh.jmusicbot;
|
||||
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.dv8tion.jda.core.JDA;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.core.events.ReadyEvent;
|
||||
import net.dv8tion.jda.core.events.ShutdownEvent;
|
||||
import net.dv8tion.jda.core.events.guild.GuildJoinEvent;
|
||||
import net.dv8tion.jda.core.events.message.guild.GuildMessageDeleteEvent;
|
||||
import net.dv8tion.jda.core.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.events.ReadyEvent;
|
||||
import net.dv8tion.jda.api.events.ShutdownEvent;
|
||||
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -45,11 +47,11 @@ public class Listener extends ListenerAdapter
|
||||
@Override
|
||||
public void onReady(ReadyEvent event)
|
||||
{
|
||||
if(event.getJDA().getGuilds().isEmpty())
|
||||
if(event.getJDA().getGuildCache().isEmpty())
|
||||
{
|
||||
Logger log = LoggerFactory.getLogger("MusicBot");
|
||||
log.warn("This bot is not on any guilds! Use the following link to add the bot to your guilds!");
|
||||
log.warn(event.getJDA().asBot().getInviteUrl(JMusicBot.RECOMMENDED_PERMS));
|
||||
log.warn(event.getJDA().getInviteUrl(JMusicBot.RECOMMENDED_PERMS));
|
||||
}
|
||||
credit(event.getJDA());
|
||||
event.getJDA().getGuilds().forEach((guild) ->
|
||||
@@ -58,21 +60,20 @@ public class Listener extends ListenerAdapter
|
||||
{
|
||||
String defpl = bot.getSettingsManager().getSettings(guild).getDefaultPlaylist();
|
||||
VoiceChannel vc = bot.getSettingsManager().getSettings(guild).getVoiceChannel(guild);
|
||||
if(defpl!=null && vc!=null)
|
||||
if(defpl!=null && vc!=null && bot.getPlayerManager().setUpHandler(guild).playFromDefault())
|
||||
{
|
||||
if(bot.getPlayerManager().setUpHandler(guild).playFromDefault())
|
||||
guild.getAudioManager().openAudioConnection(vc);
|
||||
guild.getAudioManager().openAudioConnection(vc);
|
||||
}
|
||||
}
|
||||
catch(Exception ex) {}
|
||||
catch(Exception ignore) {}
|
||||
});
|
||||
if(bot.getConfig().useUpdateAlerts())
|
||||
{
|
||||
bot.getThreadpool().scheduleWithFixedDelay(() ->
|
||||
{
|
||||
User owner = bot.getJDA().getUserById(bot.getConfig().getOwnerId());
|
||||
if(owner!=null)
|
||||
try
|
||||
{
|
||||
User owner = bot.getJDA().retrieveUserById(bot.getConfig().getOwnerId()).complete();
|
||||
String currentVersion = OtherUtil.getCurrentVersion();
|
||||
String latestVersion = OtherUtil.getLatestVersion();
|
||||
if(latestVersion!=null && !currentVersion.equalsIgnoreCase(latestVersion))
|
||||
@@ -81,6 +82,7 @@ public class Listener extends ListenerAdapter
|
||||
owner.openPrivateChannel().queue(pc -> pc.sendMessage(msg).queue());
|
||||
}
|
||||
}
|
||||
catch(Exception ignored) {} // ignored
|
||||
}, 0, 24, TimeUnit.HOURS);
|
||||
}
|
||||
}
|
||||
@@ -90,7 +92,13 @@ public class Listener extends ListenerAdapter
|
||||
{
|
||||
bot.getNowplayingHandler().onMessageDelete(event.getGuild(), event.getMessageIdLong());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event)
|
||||
{
|
||||
bot.getAloneInVoiceHandler().onVoiceUpdate(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShutdown(ShutdownEvent event)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2021 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Michaili K (mysteriouscursor+git@protonmail.com)
|
||||
*/
|
||||
public class AloneInVoiceHandler
|
||||
{
|
||||
private final Bot bot;
|
||||
private final HashMap<Long, Instant> aloneSince = new HashMap<>();
|
||||
private long aloneTimeUntilStop = 0;
|
||||
|
||||
public AloneInVoiceHandler(Bot bot)
|
||||
{
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
aloneTimeUntilStop = bot.getConfig().getAloneTimeUntilStop();
|
||||
if(aloneTimeUntilStop > 0)
|
||||
bot.getThreadpool().scheduleWithFixedDelay(() -> check(), 0, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void check()
|
||||
{
|
||||
Set<Long> toRemove = new HashSet<>();
|
||||
for(Map.Entry<Long, Instant> entrySet: aloneSince.entrySet())
|
||||
{
|
||||
if(entrySet.getValue().getEpochSecond() > Instant.now().getEpochSecond() - aloneTimeUntilStop) continue;
|
||||
|
||||
Guild guild = bot.getJDA().getGuildById(entrySet.getKey());
|
||||
|
||||
if(guild == null)
|
||||
{
|
||||
toRemove.add(entrySet.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
((AudioHandler) guild.getAudioManager().getSendingHandler()).stopAndClear();
|
||||
guild.getAudioManager().closeAudioConnection();
|
||||
|
||||
toRemove.add(entrySet.getKey());
|
||||
}
|
||||
toRemove.forEach(id -> aloneSince.remove(id));
|
||||
}
|
||||
|
||||
public void onVoiceUpdate(GuildVoiceUpdateEvent event)
|
||||
{
|
||||
if(aloneTimeUntilStop <= 0) return;
|
||||
|
||||
Guild guild = event.getEntity().getGuild();
|
||||
if(!bot.getPlayerManager().hasHandler(guild)) return;
|
||||
|
||||
boolean alone = isAlone(guild);
|
||||
boolean inList = aloneSince.containsKey(guild.getIdLong());
|
||||
|
||||
if(!alone && inList)
|
||||
aloneSince.remove(guild.getIdLong());
|
||||
else if(alone && !inList)
|
||||
aloneSince.put(guild.getIdLong(), Instant.now());
|
||||
}
|
||||
|
||||
private boolean isAlone(Guild guild)
|
||||
{
|
||||
if(guild.getAudioManager().getConnectedChannel() == null) return false;
|
||||
return guild.getAudioManager().getConnectedChannel().getMembers().stream()
|
||||
.noneMatch(x ->
|
||||
!x.getVoiceState().isDeafened()
|
||||
&& !x.getUser().isBot());
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.jagrosh.jmusicbot.JMusicBot;
|
||||
import com.jagrosh.jmusicbot.playlist.PlaylistLoader.Playlist;
|
||||
import com.jagrosh.jmusicbot.queue.AbstractQueue;
|
||||
import com.jagrosh.jmusicbot.settings.QueueType;
|
||||
import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
@@ -26,19 +28,17 @@ import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import com.jagrosh.jmusicbot.queue.FairQueue;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import static com.jagrosh.jmusicbot.utils.FormatUtil.formatTime;
|
||||
import static com.jagrosh.jmusicbot.utils.FormatUtil.volumeIcon;
|
||||
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioTrack;
|
||||
import net.dv8tion.jda.core.EmbedBuilder;
|
||||
import net.dv8tion.jda.core.JDA;
|
||||
import net.dv8tion.jda.core.MessageBuilder;
|
||||
import net.dv8tion.jda.core.audio.AudioSendHandler;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import java.nio.ByteBuffer;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,7 +46,10 @@ import net.dv8tion.jda.core.entities.User;
|
||||
*/
|
||||
public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
{
|
||||
private final FairQueue<QueuedTrack> queue = new FairQueue<>();
|
||||
public final static String PLAY_EMOJI = "\u25B6"; // ▶
|
||||
public final static String PAUSE_EMOJI = "\u23F8"; // ⏸
|
||||
public final static String STOP_EMOJI = "\u23F9"; // ⏹
|
||||
|
||||
private final List<AudioTrack> defaultQueue = new LinkedList<>();
|
||||
private final Set<String> votes = new HashSet<>();
|
||||
|
||||
@@ -55,12 +58,20 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
private final long guildId;
|
||||
|
||||
private AudioFrame lastFrame;
|
||||
private AbstractQueue<QueuedTrack> queue;
|
||||
|
||||
protected AudioHandler(PlayerManager manager, Guild guild, AudioPlayer player)
|
||||
{
|
||||
this.manager = manager;
|
||||
this.audioPlayer = player;
|
||||
this.guildId = guild.getIdLong();
|
||||
|
||||
this.setQueueType(manager.getBot().getSettingsManager().getSettings(guildId).getQueueType());
|
||||
}
|
||||
|
||||
public void setQueueType(QueueType type)
|
||||
{
|
||||
queue = type.createInstance(queue);
|
||||
}
|
||||
|
||||
public int addTrackToFront(QueuedTrack qtrack)
|
||||
@@ -88,7 +99,7 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
return queue.add(qtrack);
|
||||
}
|
||||
|
||||
public FairQueue<QueuedTrack> getQueue()
|
||||
public AbstractQueue<QueuedTrack> getQueue()
|
||||
{
|
||||
return queue;
|
||||
}
|
||||
@@ -116,11 +127,12 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
return audioPlayer;
|
||||
}
|
||||
|
||||
public long getRequester()
|
||||
public RequestMetadata getRequestMetadata()
|
||||
{
|
||||
if(audioPlayer.getPlayingTrack()==null || audioPlayer.getPlayingTrack().getUserData(Long.class)==null)
|
||||
return 0;
|
||||
return audioPlayer.getPlayingTrack().getUserData(Long.class);
|
||||
if(audioPlayer.getPlayingTrack() == null)
|
||||
return RequestMetadata.EMPTY;
|
||||
RequestMetadata rm = audioPlayer.getPlayingTrack().getUserData(RequestMetadata.class);
|
||||
return rm == null ? RequestMetadata.EMPTY : rm;
|
||||
}
|
||||
|
||||
public boolean playFromDefault()
|
||||
@@ -155,19 +167,27 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
@Override
|
||||
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason)
|
||||
{
|
||||
RepeatMode repeatMode = manager.getBot().getSettingsManager().getSettings(guildId).getRepeatMode();
|
||||
// if the track ended normally, and we're in repeat mode, re-add it to the queue
|
||||
if(endReason==AudioTrackEndReason.FINISHED && manager.getBot().getSettingsManager().getSettings(guildId).getRepeatMode())
|
||||
if(endReason==AudioTrackEndReason.FINISHED && repeatMode != RepeatMode.OFF)
|
||||
{
|
||||
queue.add(new QueuedTrack(track.makeClone(), track.getUserData(Long.class)==null ? 0L : track.getUserData(Long.class)));
|
||||
QueuedTrack clone = new QueuedTrack(track.makeClone(), track.getUserData(RequestMetadata.class));
|
||||
if(repeatMode == RepeatMode.ALL)
|
||||
queue.add(clone);
|
||||
else
|
||||
queue.addAt(0, clone);
|
||||
}
|
||||
|
||||
if(queue.isEmpty())
|
||||
{
|
||||
if(!playFromDefault())
|
||||
{
|
||||
manager.getBot().getNowplayingHandler().onTrackUpdate(guildId, null, this);
|
||||
manager.getBot().getNowplayingHandler().onTrackUpdate(null);
|
||||
if(!manager.getBot().getConfig().getStay())
|
||||
manager.getBot().closeAudioConnection(guildId);
|
||||
// unpause, in the case when the player was paused and the track has been skipped.
|
||||
// this is to prevent the player being paused next time it's being used.
|
||||
player.setPaused(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -181,7 +201,7 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
public void onTrackStart(AudioPlayer player, AudioTrack track)
|
||||
{
|
||||
votes.clear();
|
||||
manager.getBot().getNowplayingHandler().onTrackUpdate(guildId, track, this);
|
||||
manager.getBot().getNowplayingHandler().onTrackUpdate(track);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,16 +213,17 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
Guild guild = guild(jda);
|
||||
AudioTrack track = audioPlayer.getPlayingTrack();
|
||||
MessageBuilder mb = new MessageBuilder();
|
||||
mb.append(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing in "+guild.getSelfMember().getVoiceState().getChannel().getName()+"...**"));
|
||||
mb.append(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing in "+guild.getSelfMember().getVoiceState().getChannel().getAsMention()+"...**"));
|
||||
EmbedBuilder eb = new EmbedBuilder();
|
||||
eb.setColor(guild.getSelfMember().getColor());
|
||||
if(getRequester() != 0)
|
||||
RequestMetadata rm = getRequestMetadata();
|
||||
if(rm.getOwner() != 0L)
|
||||
{
|
||||
User u = guild.getJDA().getUserById(getRequester());
|
||||
User u = guild.getJDA().getUserById(rm.user.id);
|
||||
if(u==null)
|
||||
eb.setAuthor("Unknown (ID:"+getRequester()+")", null, null);
|
||||
eb.setAuthor(FormatUtil.formatUsername(rm.user), null, rm.user.avatar);
|
||||
else
|
||||
eb.setAuthor(u.getName()+"#"+u.getDiscriminator(), null, u.getEffectiveAvatarUrl());
|
||||
eb.setAuthor(FormatUtil.formatUsername(u), null, u.getEffectiveAvatarUrl());
|
||||
}
|
||||
|
||||
try
|
||||
@@ -223,12 +244,12 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
eb.setFooter("Source: " + track.getInfo().author, null);
|
||||
|
||||
double progress = (double)audioPlayer.getPlayingTrack().getPosition()/track.getDuration();
|
||||
eb.setDescription((audioPlayer.isPaused() ? JMusicBot.PAUSE_EMOJI : JMusicBot.PLAY_EMOJI)
|
||||
eb.setDescription(getStatusEmoji()
|
||||
+ " "+FormatUtil.progressBar(progress)
|
||||
+ " `[" + FormatUtil.formatTime(track.getPosition()) + "/" + FormatUtil.formatTime(track.getDuration()) + "]` "
|
||||
+ FormatUtil.volumeIcon(audioPlayer.getVolume()));
|
||||
|
||||
return mb.setEmbed(eb.build()).build();
|
||||
return mb.setEmbeds(eb.build()).build();
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
@@ -238,32 +259,20 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
Guild guild = guild(jda);
|
||||
return new MessageBuilder()
|
||||
.setContent(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing...**"))
|
||||
.setEmbed(new EmbedBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setTitle("No music playing")
|
||||
.setDescription(JMusicBot.STOP_EMOJI+" "+FormatUtil.progressBar(-1)+" "+FormatUtil.volumeIcon(audioPlayer.getVolume()))
|
||||
.setDescription(STOP_EMOJI+" "+FormatUtil.progressBar(-1)+" "+FormatUtil.volumeIcon(audioPlayer.getVolume()))
|
||||
.setColor(guild.getSelfMember().getColor())
|
||||
.build()).build();
|
||||
}
|
||||
|
||||
public String getTopicFormat(JDA jda)
|
||||
|
||||
public String getStatusEmoji()
|
||||
{
|
||||
if(isMusicPlaying(jda))
|
||||
{
|
||||
long userid = getRequester();
|
||||
AudioTrack track = audioPlayer.getPlayingTrack();
|
||||
String title = track.getInfo().title;
|
||||
if(title==null || title.equals("Unknown Title"))
|
||||
title = track.getInfo().uri;
|
||||
return "**"+title+"** ["+(userid==0 ? "autoplay" : "<@"+userid+">")+"]"
|
||||
+ "\n"+(audioPlayer.isPaused()?"\u23F8":"\u25B6")+" "
|
||||
+"["+formatTime(track.getDuration())+"] "
|
||||
+volumeIcon(audioPlayer.getVolume());
|
||||
}
|
||||
else return "No music playing \u23F9 " + volumeIcon(audioPlayer.getVolume());
|
||||
return audioPlayer.isPaused() ? PAUSE_EMOJI : PLAY_EMOJI;
|
||||
}
|
||||
|
||||
// Audio Send Handler methods
|
||||
@Override
|
||||
/*@Override
|
||||
public boolean canProvide()
|
||||
{
|
||||
if (lastFrame == null)
|
||||
@@ -282,6 +291,19 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
lastFrame = null;
|
||||
|
||||
return data;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public boolean canProvide()
|
||||
{
|
||||
lastFrame = audioPlayer.provide();
|
||||
return lastFrame != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer provide20MsAudio()
|
||||
{
|
||||
return ByteBuffer.wrap(lastFrame.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,19 +18,18 @@ package com.jagrosh.jmusicbot.audio;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.entities.Pair;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.dv8tion.jda.core.MessageBuilder;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.exceptions.RateLimitedException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -49,7 +48,8 @@ public class NowplayingHandler
|
||||
|
||||
public void init()
|
||||
{
|
||||
bot.getThreadpool().scheduleWithFixedDelay(() -> updateAll(), 0, 5, TimeUnit.SECONDS);
|
||||
if(!bot.getConfig().useNPImages())
|
||||
bot.getThreadpool().scheduleWithFixedDelay(() -> updateAll(), 0, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void setLastNPMessage(Message m)
|
||||
@@ -98,52 +98,18 @@ public class NowplayingHandler
|
||||
}
|
||||
toRemove.forEach(id -> lastNP.remove(id));
|
||||
}
|
||||
|
||||
public void updateTopic(long guildId, AudioHandler handler, boolean wait)
|
||||
{
|
||||
Guild guild = bot.getJDA().getGuildById(guildId);
|
||||
if(guild==null)
|
||||
return;
|
||||
Settings settings = bot.getSettingsManager().getSettings(guildId);
|
||||
TextChannel tchan = settings.getTextChannel(guild);
|
||||
if(tchan!=null && guild.getSelfMember().hasPermission(tchan, Permission.MANAGE_CHANNEL))
|
||||
{
|
||||
String otherText;
|
||||
if(tchan.getTopic()==null || tchan.getTopic().isEmpty())
|
||||
otherText = "\u200B";
|
||||
else if(tchan.getTopic().contains("\u200B"))
|
||||
otherText = tchan.getTopic().substring(tchan.getTopic().lastIndexOf("\u200B"));
|
||||
else
|
||||
otherText = "\u200B\n "+tchan.getTopic();
|
||||
String text = handler.getTopicFormat(bot.getJDA()) + otherText;
|
||||
if(!text.equals(tchan.getTopic()))
|
||||
{
|
||||
try
|
||||
{
|
||||
if(wait)
|
||||
tchan.getManager().setTopic(text).complete();
|
||||
else
|
||||
tchan.getManager().setTopic(text).queue();
|
||||
}
|
||||
catch(PermissionException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "event"-based methods
|
||||
public void onTrackUpdate(long guildId, AudioTrack track, AudioHandler handler)
|
||||
public void onTrackUpdate(AudioTrack track)
|
||||
{
|
||||
// update bot status if applicable
|
||||
if(bot.getConfig().getSongInStatus())
|
||||
{
|
||||
if(track!=null && bot.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inVoiceChannel()).count()<=1)
|
||||
bot.getJDA().getPresence().setGame(Game.listening(track.getInfo().title));
|
||||
bot.getJDA().getPresence().setActivity(Activity.listening(track.getInfo().title));
|
||||
else
|
||||
bot.resetGame();
|
||||
}
|
||||
|
||||
// update channel topic if applicable
|
||||
updateTopic(guildId, handler, false);
|
||||
}
|
||||
|
||||
public void onMessageDelete(Guild guild, long messageId)
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.dunctebot.sourcemanagers.DuncteBotSources;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
|
||||
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -37,8 +38,10 @@ public class PlayerManager extends DefaultAudioPlayerManager
|
||||
|
||||
public void init()
|
||||
{
|
||||
TransformativeAudioSourceManager.createTransforms(bot.getConfig().getTransforms()).forEach(t -> registerSourceManager(t));
|
||||
AudioSourceManagers.registerRemoteSources(this);
|
||||
AudioSourceManagers.registerLocalSource(this);
|
||||
DuncteBotSources.registerAll(this, "en-US");
|
||||
source(YoutubeAudioSourceManager.class).setPlaylistPageCount(10);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 John Grosh <john.a.grosh@gmail.com>.
|
||||
* Copyright 2021 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,10 @@
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
|
||||
import com.jagrosh.jmusicbot.queue.Queueable;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -30,19 +31,19 @@ public class QueuedTrack implements Queueable
|
||||
|
||||
public QueuedTrack(AudioTrack track, User owner)
|
||||
{
|
||||
this(track, owner.getIdLong());
|
||||
this(track, new RequestMetadata(owner));
|
||||
}
|
||||
|
||||
public QueuedTrack(AudioTrack track, long owner)
|
||||
public QueuedTrack(AudioTrack track, RequestMetadata rm)
|
||||
{
|
||||
this.track = track;
|
||||
this.track.setUserData(owner);
|
||||
this.track.setUserData(rm == null ? RequestMetadata.EMPTY : rm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdentifier()
|
||||
{
|
||||
return track.getUserData(Long.class);
|
||||
return track.getUserData() == null ? 0L : track.getUserData(RequestMetadata.class).getOwner();
|
||||
}
|
||||
|
||||
public AudioTrack getTrack()
|
||||
@@ -53,6 +54,9 @@ public class QueuedTrack implements Queueable
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "`[" + FormatUtil.formatTime(track.getDuration()) + "]` **" + track.getInfo().title + "** - <@" + track.getUserData(Long.class) + ">";
|
||||
String entry = "`[" + FormatUtil.formatTime(track.getDuration()) + "]` ";
|
||||
AudioTrackInfo trackInfo = track.getInfo();
|
||||
entry = entry + (trackInfo.uri.startsWith("http") ? "[**" + trackInfo.title + "**]("+trackInfo.uri+")" : "**" + trackInfo.title + "**");
|
||||
return entry + " - <@" + track.getUserData(RequestMetadata.class).getOwner() + ">";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2021 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class RequestMetadata
|
||||
{
|
||||
public static final RequestMetadata EMPTY = new RequestMetadata(null);
|
||||
|
||||
public final UserInfo user;
|
||||
|
||||
public RequestMetadata(User user)
|
||||
{
|
||||
this.user = user == null ? null : new UserInfo(user.getIdLong(), user.getName(), user.getDiscriminator(), user.getEffectiveAvatarUrl());
|
||||
}
|
||||
|
||||
public long getOwner()
|
||||
{
|
||||
return user == null ? 0L : user.id;
|
||||
}
|
||||
|
||||
public class RequestInfo
|
||||
{
|
||||
public final String query, url;
|
||||
|
||||
private RequestInfo(String query, String url)
|
||||
{
|
||||
this.query = query;
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
|
||||
public class UserInfo
|
||||
{
|
||||
public final long id;
|
||||
public final String username, discrim, avatar;
|
||||
|
||||
private UserInfo(long id, String username, String discrim, String avatar)
|
||||
{
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.discrim = discrim;
|
||||
this.avatar = avatar;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2021 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioItem;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioReference;
|
||||
import com.typesafe.config.Config;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class TransformativeAudioSourceManager extends YoutubeAudioSourceManager
|
||||
{
|
||||
private final static Logger log = LoggerFactory.getLogger(TransformativeAudioSourceManager.class);
|
||||
private final String name, regex, replacement, selector, format;
|
||||
|
||||
public TransformativeAudioSourceManager(String name, Config object)
|
||||
{
|
||||
this(name, object.getString("regex"), object.getString("replacement"), object.getString("selector"), object.getString("format"));
|
||||
}
|
||||
|
||||
public TransformativeAudioSourceManager(String name, String regex, String replacement, String selector, String format)
|
||||
{
|
||||
this.name = name;
|
||||
this.regex = regex;
|
||||
this.replacement = replacement;
|
||||
this.selector = selector;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioItem loadItem(AudioPlayerManager apm, AudioReference ar)
|
||||
{
|
||||
if(ar.identifier == null || !ar.identifier.matches(regex))
|
||||
return null;
|
||||
try
|
||||
{
|
||||
String url = ar.identifier.replaceAll(regex, replacement);
|
||||
Document doc = Jsoup.connect(url).get();
|
||||
String value = doc.selectFirst(selector).ownText();
|
||||
String formattedValue = String.format(format, value);
|
||||
return super.loadItem(apm, new AudioReference(formattedValue, null));
|
||||
}
|
||||
catch (PatternSyntaxException ex)
|
||||
{
|
||||
log.info(String.format("Invalid pattern syntax '%s' in source '%s'", regex, name));
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn(String.format("Failed to resolve URL in source '%s': ", name), ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn(String.format("Exception in source '%s'", name), ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransformativeAudioSourceManager> createTransforms(Config transforms)
|
||||
{
|
||||
try
|
||||
{
|
||||
return transforms.root().entrySet().stream()
|
||||
.map(e -> new TransformativeAudioSourceManager(e.getKey(), transforms.getConfig(e.getKey())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn("Invalid transform ", ex);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.jagrosh.jmusicbot.commands;
|
||||
|
||||
import com.jagrosh.jdautilities.command.Command;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -29,17 +30,19 @@ public abstract class DJCommand extends MusicCommand
|
||||
public DJCommand(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.category = new Category("DJ", event ->
|
||||
{
|
||||
if(event.getAuthor().getId().equals(event.getClient().getOwnerId()))
|
||||
return true;
|
||||
if(event.getGuild()==null)
|
||||
return true;
|
||||
if(event.getMember().hasPermission(Permission.MANAGE_SERVER))
|
||||
return true;
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
Role dj = settings.getRole(event.getGuild());
|
||||
return dj!=null && (event.getMember().getRoles().contains(dj) || dj.getIdLong()==event.getGuild().getIdLong());
|
||||
});
|
||||
this.category = new Category("DJ", event -> checkDJPermission(event));
|
||||
}
|
||||
|
||||
public static boolean checkDJPermission(CommandEvent event)
|
||||
{
|
||||
if(event.getAuthor().getId().equals(event.getClient().getOwnerId()))
|
||||
return true;
|
||||
if(event.getGuild()==null)
|
||||
return true;
|
||||
if(event.getMember().hasPermission(Permission.MANAGE_SERVER))
|
||||
return true;
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
Role dj = settings.getRole(event.getGuild());
|
||||
return dj!=null && (event.getMember().getRoles().contains(dj) || dj.getIdLong()==event.getGuild().getIdLong());
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,10 @@ import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import net.dv8tion.jda.core.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -52,7 +52,7 @@ public abstract class MusicCommand extends Command
|
||||
try
|
||||
{
|
||||
event.getMessage().delete().queue();
|
||||
} catch(PermissionException e){}
|
||||
} catch(PermissionException ignore){}
|
||||
event.replyInDm(event.getClient().getError()+" You can only use that command in "+tchannel.getAsMention()+"!");
|
||||
return;
|
||||
}
|
||||
@@ -70,18 +70,27 @@ public abstract class MusicCommand extends Command
|
||||
GuildVoiceState userState = event.getMember().getVoiceState();
|
||||
if(!userState.inVoiceChannel() || userState.isDeafened() || (current!=null && !userState.getChannel().equals(current)))
|
||||
{
|
||||
event.replyError("You must be listening in "+(current==null ? "a voice channel" : "**"+current.getName()+"**")+" to use that!");
|
||||
event.replyError("You must be listening in "+(current==null ? "a voice channel" : current.getAsMention())+" to use that!");
|
||||
return;
|
||||
}
|
||||
|
||||
VoiceChannel afkChannel = userState.getGuild().getAfkChannel();
|
||||
if(afkChannel != null && afkChannel.equals(userState.getChannel()))
|
||||
{
|
||||
event.replyError("You cannot use that command in an AFK channel!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!event.getGuild().getSelfMember().getVoiceState().inVoiceChannel())
|
||||
{
|
||||
try
|
||||
{
|
||||
event.getGuild().getAudioManager().openAudioConnection(userState.getChannel());
|
||||
event.getGuild().getAudioManager().setSelfDeafened(true);
|
||||
}
|
||||
catch(PermissionException ex)
|
||||
{
|
||||
event.reply(event.getClient().getError()+" I am unable to connect to **"+userState.getChannel().getName()+"**!");
|
||||
event.reply(event.getClient().getError()+" I am unable to connect to "+userState.getChannel().getAsMention()+"!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2018 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.admin;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class PrefixCmd extends AdminCommand
|
||||
{
|
||||
public PrefixCmd(Bot bot)
|
||||
{
|
||||
this.name = "prefix";
|
||||
this.help = "sets a server-specific prefix";
|
||||
this.arguments = "<prefix|NONE>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
if(event.getArgs().isEmpty())
|
||||
{
|
||||
event.replyError("Please include a prefix or NONE");
|
||||
return;
|
||||
}
|
||||
|
||||
Settings s = event.getClient().getSettingsFor(event.getGuild());
|
||||
if(event.getArgs().equalsIgnoreCase("none"))
|
||||
{
|
||||
s.setPrefix(null);
|
||||
event.replySuccess("Prefix cleared.");
|
||||
}
|
||||
else
|
||||
{
|
||||
s.setPrefix(event.getArgs());
|
||||
event.replySuccess("Custom prefix set to `" + event.getArgs() + "` on *" + event.getGuild().getName() + "*");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2022 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.admin;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.QueueType;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wolfgang Schwendtbauer
|
||||
*/
|
||||
public class QueueTypeCmd extends AdminCommand
|
||||
{
|
||||
public QueueTypeCmd(Bot bot)
|
||||
{
|
||||
super();
|
||||
this.name = "queuetype";
|
||||
this.help = "changes the queue type";
|
||||
this.arguments = "[" + String.join("|", QueueType.getNames()) + "]";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
String args = event.getArgs();
|
||||
QueueType value;
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
|
||||
if (args.isEmpty())
|
||||
{
|
||||
QueueType currentType = settings.getQueueType();
|
||||
event.reply(currentType.getEmoji() + " Current queue type is: `" + currentType.getUserFriendlyName() + "`.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
value = QueueType.valueOf(args.toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
event.replyError("Invalid queue type. Valid types are: [" + String.join("|", QueueType.getNames()) + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.getQueueType() != value)
|
||||
{
|
||||
settings.setQueueType(value);
|
||||
|
||||
AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler();
|
||||
if (handler != null)
|
||||
handler.setQueueType(value);
|
||||
}
|
||||
|
||||
event.reply(value.getEmoji() + " Queue type was set to `" + value.getUserFriendlyName() + "`.");
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,11 @@ package com.jagrosh.jmusicbot.commands.admin;
|
||||
import java.util.List;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.commons.utils.FinderUtil;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -29,11 +30,12 @@ import net.dv8tion.jda.core.entities.Role;
|
||||
*/
|
||||
public class SetdjCmd extends AdminCommand
|
||||
{
|
||||
public SetdjCmd()
|
||||
public SetdjCmd(Bot bot)
|
||||
{
|
||||
this.name = "setdj";
|
||||
this.help = "sets the DJ role for certain music commands";
|
||||
this.arguments = "<rolename|NONE>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,10 +18,11 @@ package com.jagrosh.jmusicbot.commands.admin;
|
||||
import java.util.List;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.commons.utils.FinderUtil;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -29,11 +30,12 @@ import net.dv8tion.jda.core.entities.TextChannel;
|
||||
*/
|
||||
public class SettcCmd extends AdminCommand
|
||||
{
|
||||
public SettcCmd()
|
||||
public SettcCmd(Bot bot)
|
||||
{
|
||||
this.name = "settc";
|
||||
this.help = "sets the text channel for music commands";
|
||||
this.arguments = "<channel|NONE>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,10 +18,11 @@ package com.jagrosh.jmusicbot.commands.admin;
|
||||
import java.util.List;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.commons.utils.FinderUtil;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -29,11 +30,12 @@ import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
*/
|
||||
public class SetvcCmd extends AdminCommand
|
||||
{
|
||||
public SetvcCmd()
|
||||
public SetvcCmd(Bot bot)
|
||||
{
|
||||
this.name = "setvc";
|
||||
this.help = "sets the voice channel for playing music";
|
||||
this.arguments = "<channel|NONE>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,7 +62,7 @@ public class SetvcCmd extends AdminCommand
|
||||
else
|
||||
{
|
||||
s.setVoiceChannel(list.get(0));
|
||||
event.reply(event.getClient().getSuccess()+" Music can now only be played in **"+list.get(0).getName()+"**");
|
||||
event.reply(event.getClient().getSuccess()+" Music can now only be played in "+list.get(0).getAsMention());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2018 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.admin;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class SkipratioCmd extends AdminCommand
|
||||
{
|
||||
public SkipratioCmd(Bot bot)
|
||||
{
|
||||
this.name = "setskip";
|
||||
this.help = "sets a server-specific skip percentage";
|
||||
this.arguments = "<0 - 100>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
int val = Integer.parseInt(event.getArgs().endsWith("%") ? event.getArgs().substring(0,event.getArgs().length()-1) : event.getArgs());
|
||||
if( val < 0 || val > 100)
|
||||
{
|
||||
event.replyError("The provided value must be between 0 and 100!");
|
||||
return;
|
||||
}
|
||||
Settings s = event.getClient().getSettingsFor(event.getGuild());
|
||||
s.setSkipRatio(val / 100.0);
|
||||
event.replySuccess("Skip percentage has been set to `" + val + "%` of listeners on *" + event.getGuild().getName() + "*");
|
||||
}
|
||||
catch(NumberFormatException ex)
|
||||
{
|
||||
event.replyError("Please include an integer between 0 and 100 (default is 55). This number is the percentage of listening users that must vote to skip a song.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2019 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.dj;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.commons.utils.FinderUtil;
|
||||
import com.jagrosh.jdautilities.menu.OrderedMenu;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Michaili K.
|
||||
*/
|
||||
public class ForceRemoveCmd extends DJCommand
|
||||
{
|
||||
public ForceRemoveCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.name = "forceremove";
|
||||
this.help = "removes all entries by a user from the queue";
|
||||
this.arguments = "<user>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = false;
|
||||
this.bePlaying = true;
|
||||
this.botPermissions = new Permission[]{Permission.MESSAGE_EMBED_LINKS};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
if (event.getArgs().isEmpty())
|
||||
{
|
||||
event.replyError("You need to mention a user!");
|
||||
return;
|
||||
}
|
||||
|
||||
AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler();
|
||||
if (handler.getQueue().isEmpty())
|
||||
{
|
||||
event.replyError("There is nothing in the queue!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
User target;
|
||||
List<Member> found = FinderUtil.findMembers(event.getArgs(), event.getGuild());
|
||||
|
||||
if(found.isEmpty())
|
||||
{
|
||||
event.replyError("Unable to find the user!");
|
||||
return;
|
||||
}
|
||||
else if(found.size()>1)
|
||||
{
|
||||
OrderedMenu.Builder builder = new OrderedMenu.Builder();
|
||||
for(int i=0; i<found.size() && i<4; i++)
|
||||
{
|
||||
Member member = found.get(i);
|
||||
builder.addChoice("**"+member.getUser().getName()+"**#"+member.getUser().getDiscriminator());
|
||||
}
|
||||
|
||||
builder
|
||||
.setSelection((msg, i) -> removeAllEntries(found.get(i-1).getUser(), event))
|
||||
.setText("Found multiple users:")
|
||||
.setColor(event.getSelfMember().getColor())
|
||||
.useNumbers()
|
||||
.setUsers(event.getAuthor())
|
||||
.useCancelButton(true)
|
||||
.setCancel((msg) -> {})
|
||||
.setEventWaiter(bot.getWaiter())
|
||||
.setTimeout(1, TimeUnit.MINUTES)
|
||||
|
||||
.build().display(event.getChannel());
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
target = found.get(0).getUser();
|
||||
}
|
||||
|
||||
removeAllEntries(target, event);
|
||||
|
||||
}
|
||||
|
||||
private void removeAllEntries(User target, CommandEvent event)
|
||||
{
|
||||
int count = ((AudioHandler) event.getGuild().getAudioManager().getSendingHandler()).getQueue().removeAll(target.getIdLong());
|
||||
if (count == 0)
|
||||
{
|
||||
event.replyWarning("**"+target.getName()+"** doesn't have any songs in the queue!");
|
||||
}
|
||||
else
|
||||
{
|
||||
event.replySuccess("Successfully removed `"+count+"` entries from "+FormatUtil.formatUsername(target)+".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,9 @@ package com.jagrosh.jmusicbot.commands.dj;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.RequestMetadata;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,7 +33,7 @@ public class ForceskipCmd extends DJCommand
|
||||
super(bot);
|
||||
this.name = "forceskip";
|
||||
this.help = "skips the current song";
|
||||
this.aliases = new String[]{"modskip"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
@@ -40,9 +41,9 @@ public class ForceskipCmd extends DJCommand
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
AudioHandler handler = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
User u = event.getJDA().getUserById(handler.getRequester());
|
||||
RequestMetadata rm = handler.getRequestMetadata();
|
||||
event.reply(event.getClient().getSuccess()+" Skipped **"+handler.getPlayer().getPlayingTrack().getInfo().title
|
||||
+"** (requested by "+(u==null ? "someone" : "**"+u.getName()+"**")+")");
|
||||
+"** "+(rm.getOwner() == 0L ? "(autoplay)" : "(requested by **" + FormatUtil.formatUsername(rm.user) + "**)"));
|
||||
handler.getPlayer().stopTrack();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.jagrosh.jmusicbot.commands.dj;
|
||||
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.queue.AbstractQueue;
|
||||
|
||||
/**
|
||||
* Command that provides users the ability to move a track in the playlist.
|
||||
*/
|
||||
public class MoveTrackCmd extends DJCommand
|
||||
{
|
||||
|
||||
public MoveTrackCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.name = "movetrack";
|
||||
this.help = "move a track in the current queue to a different position";
|
||||
this.arguments = "<from> <to>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
int from;
|
||||
int to;
|
||||
|
||||
String[] parts = event.getArgs().split("\\s+", 2);
|
||||
if(parts.length < 2)
|
||||
{
|
||||
event.replyError("Please include two valid indexes.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Validate the args
|
||||
from = Integer.parseInt(parts[0]);
|
||||
to = Integer.parseInt(parts[1]);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
event.replyError("Please provide two valid indexes.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == to)
|
||||
{
|
||||
event.replyError("Can't move a track to the same position.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that from and to are available
|
||||
AudioHandler handler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler();
|
||||
AbstractQueue<QueuedTrack> queue = handler.getQueue();
|
||||
if (isUnavailablePosition(queue, from))
|
||||
{
|
||||
String reply = String.format("`%d` is not a valid position in the queue!", from);
|
||||
event.replyError(reply);
|
||||
return;
|
||||
}
|
||||
if (isUnavailablePosition(queue, to))
|
||||
{
|
||||
String reply = String.format("`%d` is not a valid position in the queue!", to);
|
||||
event.replyError(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the track
|
||||
QueuedTrack track = queue.moveItem(from - 1, to - 1);
|
||||
String trackTitle = track.getTrack().getInfo().title;
|
||||
String reply = String.format("Moved **%s** from position `%d` to `%d`.", trackTitle, from, to);
|
||||
event.replySuccess(reply);
|
||||
}
|
||||
|
||||
private static boolean isUnavailablePosition(AbstractQueue<QueuedTrack> queue, int position)
|
||||
{
|
||||
return (position < 1 || position > queue.size());
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class PauseCmd extends DJCommand
|
||||
super(bot);
|
||||
this.name = "pause";
|
||||
this.help = "pauses the current song";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,23 +16,16 @@
|
||||
package com.jagrosh.jmusicbot.commands.dj;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.menu.ButtonMenu;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.commands.music.PlayCmd;
|
||||
import static com.jagrosh.jmusicbot.commands.music.PlayCmd.CANCEL;
|
||||
import static com.jagrosh.jmusicbot.commands.music.PlayCmd.LOAD;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -42,13 +35,14 @@ public class PlaynextCmd extends DJCommand
|
||||
{
|
||||
private final String loadingEmoji;
|
||||
|
||||
public PlaynextCmd(Bot bot, String loadingEmoji)
|
||||
public PlaynextCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.loadingEmoji = loadingEmoji;
|
||||
this.loadingEmoji = bot.getConfig().getLoading();
|
||||
this.name = "playnext";
|
||||
this.arguments = "<title|URL>";
|
||||
this.help = "plays a single song next";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = true;
|
||||
this.bePlaying = false;
|
||||
}
|
||||
@@ -69,9 +63,9 @@ public class PlaynextCmd extends DJCommand
|
||||
|
||||
private class ResultHandler implements AudioLoadResultHandler
|
||||
{
|
||||
final Message m;
|
||||
final CommandEvent event;
|
||||
final boolean ytsearch;
|
||||
private final Message m;
|
||||
private final CommandEvent event;
|
||||
private final boolean ytsearch;
|
||||
|
||||
private ResultHandler(Message m, CommandEvent event, boolean ytsearch)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jagrosh.jmusicbot.commands.dj;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
|
||||
/**
|
||||
@@ -31,7 +32,8 @@ public class RepeatCmd extends DJCommand
|
||||
super(bot);
|
||||
this.name = "repeat";
|
||||
this.help = "re-adds music to the queue when finished";
|
||||
this.arguments = "[on|off]";
|
||||
this.arguments = "[off|all|single]";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = true;
|
||||
}
|
||||
|
||||
@@ -39,29 +41,37 @@ public class RepeatCmd extends DJCommand
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
boolean value;
|
||||
String args = event.getArgs();
|
||||
RepeatMode value;
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
if(event.getArgs().isEmpty())
|
||||
if(args.isEmpty())
|
||||
{
|
||||
value = !settings.getRepeatMode();
|
||||
if(settings.getRepeatMode() == RepeatMode.OFF)
|
||||
value = RepeatMode.ALL;
|
||||
else
|
||||
value = RepeatMode.OFF;
|
||||
}
|
||||
else if(event.getArgs().equalsIgnoreCase("true") || event.getArgs().equalsIgnoreCase("on"))
|
||||
else if(args.equalsIgnoreCase("false") || args.equalsIgnoreCase("off"))
|
||||
{
|
||||
value = true;
|
||||
value = RepeatMode.OFF;
|
||||
}
|
||||
else if(event.getArgs().equalsIgnoreCase("false") || event.getArgs().equalsIgnoreCase("off"))
|
||||
else if(args.equalsIgnoreCase("true") || args.equalsIgnoreCase("on") || args.equalsIgnoreCase("all"))
|
||||
{
|
||||
value = false;
|
||||
value = RepeatMode.ALL;
|
||||
}
|
||||
else if(args.equalsIgnoreCase("one") || args.equalsIgnoreCase("single"))
|
||||
{
|
||||
value = RepeatMode.SINGLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
event.replyError("Valid options are `on` or `off` (or leave empty to toggle)");
|
||||
event.replyError("Valid options are `off`, `all` or `single` (or leave empty to toggle between `off` and `all`)");
|
||||
return;
|
||||
}
|
||||
settings.setRepeatMode(value);
|
||||
event.replySuccess("Repeat mode is now `"+(value ? "ON" : "OFF")+"`");
|
||||
event.replySuccess("Repeat mode is now `"+value.getUserFriendlyName()+"`");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(CommandEvent event) {}
|
||||
public void doCommand(CommandEvent event) { /* Intentionally Empty */ }
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class SkiptoCmd extends DJCommand
|
||||
this.name = "skipto";
|
||||
this.help = "skips to the specified song";
|
||||
this.arguments = "<position>";
|
||||
this.aliases = new String[]{"jumpto"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ public class StopCmd extends DJCommand
|
||||
super(bot);
|
||||
this.name = "stop";
|
||||
this.help = "stops the current song and clears the queue";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class VolumeCmd extends DJCommand
|
||||
{
|
||||
super(bot);
|
||||
this.name = "volume";
|
||||
this.aliases = new String[]{"vol"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.help = "sets or shows volume";
|
||||
this.arguments = "[0-150]";
|
||||
}
|
||||
|
||||
@@ -18,12 +18,15 @@ package com.jagrosh.jmusicbot.commands.general;
|
||||
import com.jagrosh.jdautilities.command.Command;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.settings.QueueType;
|
||||
import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import net.dv8tion.jda.core.EmbedBuilder;
|
||||
import net.dv8tion.jda.core.MessageBuilder;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -31,11 +34,13 @@ import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
*/
|
||||
public class SettingsCmd extends Command
|
||||
{
|
||||
public SettingsCmd()
|
||||
private final static String EMOJI = "\uD83C\uDFA7"; // 🎧
|
||||
|
||||
public SettingsCmd(Bot bot)
|
||||
{
|
||||
this.name = "settings";
|
||||
this.help = "shows the bots settings";
|
||||
this.aliases = new String[]{"status"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = true;
|
||||
}
|
||||
|
||||
@@ -44,24 +49,30 @@ public class SettingsCmd extends Command
|
||||
{
|
||||
Settings s = event.getClient().getSettingsFor(event.getGuild());
|
||||
MessageBuilder builder = new MessageBuilder()
|
||||
.append("\uD83C\uDFA7 **")
|
||||
.append(event.getSelfUser().getName())
|
||||
.append(EMOJI + " **")
|
||||
.append(FormatUtil.filter(event.getSelfUser().getName()))
|
||||
.append("** settings:");
|
||||
TextChannel tchan = s.getTextChannel(event.getGuild());
|
||||
VoiceChannel vchan = s.getVoiceChannel(event.getGuild());
|
||||
Role role = s.getRole(event.getGuild());
|
||||
EmbedBuilder ebuilder = new EmbedBuilder()
|
||||
.setColor(event.getSelfMember().getColor())
|
||||
.setDescription("Text Channel: "+(tchan==null ? "Any" : "**#"+tchan.getName()+"**")
|
||||
+ "\nVoice Channel: "+(vchan==null ? "Any" : "**"+vchan.getName()+"**")
|
||||
+ "\nDJ Role: "+(role==null ? "None" : "**"+role.getName()+"**")
|
||||
+ "\nRepeat Mode: **"+(s.getRepeatMode() ? "On" : "Off")+"**"
|
||||
+ "\nDefault Playlist: "+(s.getDefaultPlaylist()==null ? "None" : "**"+s.getDefaultPlaylist()+"**")
|
||||
.setDescription("Text Channel: " + (tchan == null ? "Any" : "**#" + tchan.getName() + "**")
|
||||
+ "\nVoice Channel: " + (vchan == null ? "Any" : vchan.getAsMention())
|
||||
+ "\nDJ Role: " + (role == null ? "None" : "**" + role.getName() + "**")
|
||||
+ "\nCustom Prefix: " + (s.getPrefix() == null ? "None" : "`" + s.getPrefix() + "`")
|
||||
+ "\nRepeat Mode: " + (s.getRepeatMode() == RepeatMode.OFF
|
||||
? s.getRepeatMode().getUserFriendlyName()
|
||||
: "**"+s.getRepeatMode().getUserFriendlyName()+"**")
|
||||
+ "\nQueue Type: " + (s.getQueueType() == QueueType.FAIR
|
||||
? s.getQueueType().getUserFriendlyName()
|
||||
: "**"+s.getQueueType().getUserFriendlyName()+"**")
|
||||
+ "\nDefault Playlist: " + (s.getDefaultPlaylist() == null ? "None" : "**" + s.getDefaultPlaylist() + "**")
|
||||
)
|
||||
.setFooter(event.getJDA().getGuilds().size()+" servers | "
|
||||
+event.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inVoiceChannel()).count()
|
||||
+" audio connections", null);
|
||||
event.getChannel().sendMessage(builder.setEmbed(ebuilder.build()).build()).queue();
|
||||
.setFooter(event.getJDA().getGuilds().size() + " servers | "
|
||||
+ event.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inVoiceChannel()).count()
|
||||
+ " audio connections", null);
|
||||
event.getChannel().sendMessage(builder.setEmbeds(ebuilder.build()).build()).queue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2018 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.music;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jlyrics.LyricsClient;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class LyricsCmd extends MusicCommand
|
||||
{
|
||||
private final LyricsClient client = new LyricsClient();
|
||||
|
||||
public LyricsCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.name = "lyrics";
|
||||
this.arguments = "[song name]";
|
||||
this.help = "shows the lyrics of a song";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.botPermissions = new Permission[]{Permission.MESSAGE_EMBED_LINKS};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
String title;
|
||||
if(event.getArgs().isEmpty())
|
||||
{
|
||||
AudioHandler sendingHandler = (AudioHandler) event.getGuild().getAudioManager().getSendingHandler();
|
||||
if (sendingHandler.isMusicPlaying(event.getJDA()))
|
||||
title = sendingHandler.getPlayer().getPlayingTrack().getInfo().title;
|
||||
else
|
||||
{
|
||||
event.replyError("There must be music playing to use that!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
title = event.getArgs();
|
||||
event.getChannel().sendTyping().queue();
|
||||
client.getLyrics(title).thenAccept(lyrics ->
|
||||
{
|
||||
if(lyrics == null)
|
||||
{
|
||||
event.replyError("Lyrics for `" + title + "` could not be found!" + (event.getArgs().isEmpty() ? " Try entering the song name manually (`lyrics [song name]`)" : ""));
|
||||
return;
|
||||
}
|
||||
|
||||
EmbedBuilder eb = new EmbedBuilder()
|
||||
.setAuthor(lyrics.getAuthor())
|
||||
.setColor(event.getSelfMember().getColor())
|
||||
.setTitle(lyrics.getTitle(), lyrics.getURL());
|
||||
if(lyrics.getContent().length()>15000)
|
||||
{
|
||||
event.replyWarning("Lyrics for `" + title + "` found but likely not correct: " + lyrics.getURL());
|
||||
}
|
||||
else if(lyrics.getContent().length()>2000)
|
||||
{
|
||||
String content = lyrics.getContent().trim();
|
||||
while(content.length() > 2000)
|
||||
{
|
||||
int index = content.lastIndexOf("\n\n", 2000);
|
||||
if(index == -1)
|
||||
index = content.lastIndexOf("\n", 2000);
|
||||
if(index == -1)
|
||||
index = content.lastIndexOf(" ", 2000);
|
||||
if(index == -1)
|
||||
index = 2000;
|
||||
event.reply(eb.setDescription(content.substring(0, index).trim()).build());
|
||||
content = content.substring(index).trim();
|
||||
eb.setAuthor(null).setTitle(null, null);
|
||||
}
|
||||
event.reply(eb.setDescription(content).build());
|
||||
}
|
||||
else
|
||||
event.reply(eb.setDescription(lyrics.getContent()).build());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,7 +33,7 @@ public class NowplayingCmd extends MusicCommand
|
||||
super(bot);
|
||||
this.name = "nowplaying";
|
||||
this.help = "shows the song that is currently playing";
|
||||
this.aliases = new String[]{"np","current"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.botPermissions = new Permission[]{Permission.MESSAGE_EMBED_LINKS};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,15 +26,14 @@ import com.jagrosh.jdautilities.menu.ButtonMenu;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import com.jagrosh.jmusicbot.playlist.PlaylistLoader.Playlist;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -42,18 +41,19 @@ import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
*/
|
||||
public class PlayCmd extends MusicCommand
|
||||
{
|
||||
public final static String LOAD = "\uD83D\uDCE5";
|
||||
public final static String CANCEL = "\uD83D\uDEAB";
|
||||
private final static String LOAD = "\uD83D\uDCE5"; // 📥
|
||||
private final static String CANCEL = "\uD83D\uDEAB"; // 🚫
|
||||
|
||||
private final String loadingEmoji;
|
||||
|
||||
public PlayCmd(Bot bot, String loadingEmoji)
|
||||
public PlayCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.loadingEmoji = loadingEmoji;
|
||||
this.loadingEmoji = bot.getConfig().getLoading();
|
||||
this.name = "play";
|
||||
this.arguments = "<title|URL|subcommand>";
|
||||
this.help = "plays the provided song";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = true;
|
||||
this.bePlaying = false;
|
||||
this.children = new Command[]{new PlaylistCmd(bot)};
|
||||
@@ -67,20 +67,13 @@ public class PlayCmd extends MusicCommand
|
||||
AudioHandler handler = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
if(handler.getPlayer().getPlayingTrack()!=null && handler.getPlayer().isPaused())
|
||||
{
|
||||
boolean isDJ = event.getMember().hasPermission(Permission.MANAGE_SERVER);
|
||||
if(!isDJ)
|
||||
isDJ = event.isOwner();
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
Role dj = settings.getRole(event.getGuild());
|
||||
if(!isDJ && dj!=null)
|
||||
isDJ = event.getMember().getRoles().contains(dj);
|
||||
if(!isDJ)
|
||||
event.replyError("Only DJs can unpause the player!");
|
||||
else
|
||||
if(DJCommand.checkDJPermission(event))
|
||||
{
|
||||
handler.getPlayer().setPaused(false);
|
||||
event.replySuccess("Resumed **"+handler.getPlayer().getPlayingTrack().getInfo().title+"**.");
|
||||
}
|
||||
else
|
||||
event.replyError("Only DJs can unpause the player!");
|
||||
return;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(event.getClient().getWarning()+" Play Commands:\n");
|
||||
@@ -99,9 +92,9 @@ public class PlayCmd extends MusicCommand
|
||||
|
||||
private class ResultHandler implements AudioLoadResultHandler
|
||||
{
|
||||
final Message m;
|
||||
final CommandEvent event;
|
||||
final boolean ytsearch;
|
||||
private final Message m;
|
||||
private final CommandEvent event;
|
||||
private final boolean ytsearch;
|
||||
|
||||
private ResultHandler(Message m, CommandEvent event, boolean ytsearch)
|
||||
{
|
||||
@@ -139,7 +132,7 @@ public class PlayCmd extends MusicCommand
|
||||
m.editMessage(addMsg).queue();
|
||||
}).setFinalAction(m ->
|
||||
{
|
||||
try{m.clearReactions().queue();}catch(PermissionException ex){}
|
||||
try{ m.clearReactions().queue(); }catch(PermissionException ignore) {}
|
||||
}).build().display(m);
|
||||
}
|
||||
}
|
||||
@@ -180,7 +173,12 @@ public class PlayCmd extends MusicCommand
|
||||
else
|
||||
{
|
||||
int count = loadPlaylist(playlist, null);
|
||||
if(count==0)
|
||||
if(playlist.getTracks().size() == 0)
|
||||
{
|
||||
m.editMessage(FormatUtil.filter(event.getClient().getWarning()+" The playlist "+(playlist.getName()==null ? "" : "(**"+playlist.getName()
|
||||
+"**) ")+" could not be loaded or contained 0 entries")).queue();
|
||||
}
|
||||
else if(count==0)
|
||||
{
|
||||
m.editMessage(FormatUtil.filter(event.getClient().getWarning()+" All entries in this playlist "+(playlist.getName()==null ? "" : "(**"+playlist.getName()
|
||||
+"**) ")+"were longer than the allowed maximum (`"+bot.getConfig().getMaxTime()+"`)")).queue();
|
||||
|
||||
@@ -31,7 +31,7 @@ public class PlaylistsCmd extends MusicCommand
|
||||
super(bot);
|
||||
this.name = "playlists";
|
||||
this.help = "shows the available playlists";
|
||||
this.aliases = new String[]{"pls"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = true;
|
||||
this.beListening = false;
|
||||
this.beListening = false;
|
||||
|
||||
@@ -20,16 +20,17 @@ import java.util.concurrent.TimeUnit;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.menu.Paginator;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.JMusicBot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import com.jagrosh.jmusicbot.settings.QueueType;
|
||||
import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.MessageBuilder;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -38,22 +39,24 @@ import net.dv8tion.jda.core.exceptions.PermissionException;
|
||||
public class QueueCmd extends MusicCommand
|
||||
{
|
||||
private final Paginator.Builder builder;
|
||||
|
||||
public QueueCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.name = "queue";
|
||||
this.help = "shows the current queue";
|
||||
this.arguments = "[pagenum]";
|
||||
this.aliases = new String[]{"list"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.bePlaying = true;
|
||||
this.botPermissions = new Permission[]{Permission.MESSAGE_ADD_REACTION,Permission.MESSAGE_EMBED_LINKS};
|
||||
builder = new Paginator.Builder()
|
||||
.setColumns(1)
|
||||
.setFinalAction(m -> {try{m.clearReactions().queue();}catch(PermissionException e){}})
|
||||
.setFinalAction(m -> {try{m.clearReactions().queue();}catch(PermissionException ignore){}})
|
||||
.setItemsPerPage(10)
|
||||
.waitOnSinglePage(false)
|
||||
.useNumberedItems(true)
|
||||
.showPageNumbers(true)
|
||||
.wrapPageEnds(true)
|
||||
.setEventWaiter(bot.getWaiter())
|
||||
.setTimeout(1, TimeUnit.MINUTES);
|
||||
}
|
||||
@@ -66,7 +69,7 @@ public class QueueCmd extends MusicCommand
|
||||
{
|
||||
pagenum = Integer.parseInt(event.getArgs());
|
||||
}
|
||||
catch(NumberFormatException e){}
|
||||
catch(NumberFormatException ignore){}
|
||||
AudioHandler ah = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
List<QueuedTrack> list = ah.getQueue().getList();
|
||||
if(list.isEmpty())
|
||||
@@ -75,7 +78,7 @@ public class QueueCmd extends MusicCommand
|
||||
Message nonowp = ah.getNoMusicPlaying(event.getJDA());
|
||||
Message built = new MessageBuilder()
|
||||
.setContent(event.getClient().getWarning() + " There is no music in the queue!")
|
||||
.setEmbed((nowp==null ? nonowp : nowp).getEmbeds().get(0)).build();
|
||||
.setEmbeds((nowp==null ? nonowp : nowp).getEmbeds().get(0)).build();
|
||||
event.reply(built, m ->
|
||||
{
|
||||
if(nowp!=null)
|
||||
@@ -92,7 +95,7 @@ public class QueueCmd extends MusicCommand
|
||||
}
|
||||
Settings settings = event.getClient().getSettingsFor(event.getGuild());
|
||||
long fintotal = total;
|
||||
builder.setText((i1,i2) -> getQueueTitle(ah, event.getClient().getSuccess(), songs.length, fintotal, settings.getRepeatMode()))
|
||||
builder.setText((i1,i2) -> getQueueTitle(ah, event.getClient().getSuccess(), songs.length, fintotal, settings.getRepeatMode(), settings.getQueueType()))
|
||||
.setItems(songs)
|
||||
.setUsers(event.getAuthor())
|
||||
.setColor(event.getSelfMember().getColor())
|
||||
@@ -100,16 +103,17 @@ public class QueueCmd extends MusicCommand
|
||||
builder.build().paginate(event.getChannel(), pagenum);
|
||||
}
|
||||
|
||||
private String getQueueTitle(AudioHandler ah, String success, int songslength, long total, boolean repeatmode)
|
||||
private String getQueueTitle(AudioHandler ah, String success, int songslength, long total, RepeatMode repeatmode, QueueType queueType)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(ah.getPlayer().getPlayingTrack()!=null)
|
||||
{
|
||||
sb.append(ah.getPlayer().isPaused() ? JMusicBot.PAUSE_EMOJI : JMusicBot.PLAY_EMOJI).append(" **")
|
||||
sb.append(ah.getStatusEmoji()).append(" **")
|
||||
.append(ah.getPlayer().getPlayingTrack().getInfo().title).append("**\n");
|
||||
}
|
||||
return FormatUtil.filter(sb.append(success).append(" Current Queue | ").append(songslength)
|
||||
.append(" entries | `").append(FormatUtil.formatTime(total)).append("` ")
|
||||
.append(repeatmode ? "| \uD83D\uDD01" : "").toString());
|
||||
.append("| ").append(queueType.getEmoji()).append(" `").append(queueType.getUserFriendlyName()).append('`')
|
||||
.append(repeatmode.getEmoji() != null ? " | "+repeatmode.getEmoji() : "").toString());
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -36,7 +36,7 @@ public class RemoveCmd extends MusicCommand
|
||||
this.name = "remove";
|
||||
this.help = "removes a song from the queue";
|
||||
this.arguments = "<position|ALL>";
|
||||
this.aliases = new String[]{"delete"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = true;
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ import com.jagrosh.jmusicbot.Bot;
|
||||
*/
|
||||
public class SCSearchCmd extends SearchCmd
|
||||
{
|
||||
public SCSearchCmd(Bot bot, String searchingEmoji)
|
||||
public SCSearchCmd(Bot bot)
|
||||
{
|
||||
super(bot, searchingEmoji);
|
||||
super(bot);
|
||||
this.searchPrefix = "scsearch:";
|
||||
this.name = "scsearch";
|
||||
this.help = "searches Soundcloud for a provided query";
|
||||
this.aliases = new String[]{};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@ import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.QueuedTrack;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.Permission;
|
||||
import net.dv8tion.jda.core.entities.Message;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -41,12 +41,12 @@ public class SearchCmd extends MusicCommand
|
||||
private final OrderedMenu.Builder builder;
|
||||
private final String searchingEmoji;
|
||||
|
||||
public SearchCmd(Bot bot, String searchingEmoji)
|
||||
public SearchCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
this.searchingEmoji = searchingEmoji;
|
||||
this.searchingEmoji = bot.getConfig().getSearching();
|
||||
this.name = "search";
|
||||
this.aliases = new String[]{"ytsearch"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.arguments = "<query>";
|
||||
this.help = "searches Youtube for a provided query";
|
||||
this.beListening = true;
|
||||
@@ -73,8 +73,9 @@ public class SearchCmd extends MusicCommand
|
||||
|
||||
private class ResultHandler implements AudioLoadResultHandler
|
||||
{
|
||||
final Message m;
|
||||
final CommandEvent event;
|
||||
private final Message m;
|
||||
private final CommandEvent event;
|
||||
|
||||
private ResultHandler(Message m, CommandEvent event)
|
||||
{
|
||||
this.m = m;
|
||||
@@ -114,8 +115,8 @@ public class SearchCmd extends MusicCommand
|
||||
}
|
||||
AudioHandler handler = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
int pos = handler.addTrack(new QueuedTrack(track, event.getAuthor()))+1;
|
||||
event.replySuccess("Added **"+track.getInfo().title
|
||||
+"** (`"+FormatUtil.formatTime(track.getDuration())+"`) "+(pos==0 ? "to begin playing"
|
||||
event.replySuccess("Added **" + FormatUtil.filter(track.getInfo().title)
|
||||
+ "** (`" + FormatUtil.formatTime(track.getDuration()) + "`) " + (pos==0 ? "to begin playing"
|
||||
: " to the queue at position "+pos));
|
||||
})
|
||||
.setCancel((msg) -> {})
|
||||
|
||||
@@ -31,6 +31,7 @@ public class ShuffleCmd extends MusicCommand
|
||||
super(bot);
|
||||
this.name = "shuffle";
|
||||
this.help = "shuffles songs you have added";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = true;
|
||||
this.bePlaying = true;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@ package com.jagrosh.jmusicbot.commands.music;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.RequestMetadata;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import net.dv8tion.jda.core.entities.User;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,7 +33,7 @@ public class SkipCmd extends MusicCommand
|
||||
super(bot);
|
||||
this.name = "skip";
|
||||
this.help = "votes to skip the current song";
|
||||
this.aliases = new String[]{"voteskip"};
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.beListening = true;
|
||||
this.bePlaying = true;
|
||||
}
|
||||
@@ -41,7 +42,12 @@ public class SkipCmd extends MusicCommand
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
AudioHandler handler = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
if(event.getAuthor().getIdLong()==handler.getRequester())
|
||||
RequestMetadata rm = handler.getRequestMetadata();
|
||||
double skipRatio = bot.getSettingsManager().getSettings(event.getGuild()).getSkipRatio();
|
||||
if(skipRatio == -1) {
|
||||
skipRatio = bot.getConfig().getSkipRatio();
|
||||
}
|
||||
if(event.getAuthor().getIdLong() == rm.getOwner() || skipRatio == 0)
|
||||
{
|
||||
event.reply(event.getClient().getSuccess()+" Skipped **"+handler.getPlayer().getPlayingTrack().getInfo().title+"**");
|
||||
handler.getPlayer().stopTrack();
|
||||
@@ -60,13 +66,12 @@ public class SkipCmd extends MusicCommand
|
||||
}
|
||||
int skippers = (int)event.getSelfMember().getVoiceState().getChannel().getMembers().stream()
|
||||
.filter(m -> handler.getVotes().contains(m.getUser().getId())).count();
|
||||
int required = (int)Math.ceil(listeners * .55);
|
||||
msg+= skippers+" votes, "+required+"/"+listeners+" needed]`";
|
||||
int required = (int)Math.ceil(listeners * skipRatio);
|
||||
msg += skippers + " votes, " + required + "/" + listeners + " needed]`";
|
||||
if(skippers>=required)
|
||||
{
|
||||
User u = event.getJDA().getUserById(handler.getRequester());
|
||||
msg+="\n"+event.getClient().getSuccess()+" Skipped **"+handler.getPlayer().getPlayingTrack().getInfo().title
|
||||
+"**"+(handler.getRequester()==0 ? "" : " (requested by "+(u==null ? "someone" : "**"+u.getName()+"**")+")");
|
||||
msg += "\n" + event.getClient().getSuccess() + " Skipped **" + handler.getPlayer().getPlayingTrack().getInfo().title
|
||||
+ "** " + (rm.getOwner() == 0L ? "(autoplay)" : "(requested by **" + FormatUtil.formatUsername(rm.user) + "**)");
|
||||
handler.getPlayer().stopTrack();
|
||||
}
|
||||
event.reply(msg);
|
||||
|
||||
@@ -35,6 +35,7 @@ public class AutoplaylistCmd extends OwnerCommand
|
||||
this.name = "autoplaylist";
|
||||
this.arguments = "<name|NONE>";
|
||||
this.help = "sets the default playlist for the server";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2017 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.commands.owner;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jdautilities.commons.JDAUtilitiesInfo;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.PlayerLibrary;
|
||||
import net.dv8tion.jda.api.JDAInfo;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class DebugCmd extends OwnerCommand
|
||||
{
|
||||
private final static String[] PROPERTIES = {"java.version", "java.vm.name", "java.vm.specification.version",
|
||||
"java.runtime.name", "java.runtime.version", "java.specification.version", "os.arch", "os.name"};
|
||||
|
||||
private final Bot bot;
|
||||
|
||||
public DebugCmd(Bot bot)
|
||||
{
|
||||
this.bot = bot;
|
||||
this.name = "debug";
|
||||
this.help = "shows debug info";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("```\nSystem Properties:");
|
||||
for(String key: PROPERTIES)
|
||||
sb.append("\n ").append(key).append(" = ").append(System.getProperty(key));
|
||||
sb.append("\n\nJMusicBot Information:")
|
||||
.append("\n Version = ").append(OtherUtil.getCurrentVersion())
|
||||
.append("\n Owner = ").append(bot.getConfig().getOwnerId())
|
||||
.append("\n Prefix = ").append(bot.getConfig().getPrefix())
|
||||
.append("\n AltPrefix = ").append(bot.getConfig().getAltPrefix())
|
||||
.append("\n MaxSeconds = ").append(bot.getConfig().getMaxSeconds())
|
||||
.append("\n NPImages = ").append(bot.getConfig().useNPImages())
|
||||
.append("\n SongInStatus = ").append(bot.getConfig().getSongInStatus())
|
||||
.append("\n StayInChannel = ").append(bot.getConfig().getStay())
|
||||
.append("\n UseEval = ").append(bot.getConfig().useEval())
|
||||
.append("\n UpdateAlerts = ").append(bot.getConfig().useUpdateAlerts());
|
||||
sb.append("\n\nDependency Information:")
|
||||
.append("\n JDA Version = ").append(JDAInfo.VERSION)
|
||||
.append("\n JDA-Utilities Version = ").append(JDAUtilitiesInfo.VERSION)
|
||||
.append("\n Lavaplayer Version = ").append(PlayerLibrary.VERSION);
|
||||
long total = Runtime.getRuntime().totalMemory() / 1024 / 1024;
|
||||
long used = total - (Runtime.getRuntime().freeMemory() / 1024 / 1024);
|
||||
sb.append("\n\nRuntime Information:")
|
||||
.append("\n Total Memory = ").append(total)
|
||||
.append("\n Used Memory = ").append(used);
|
||||
sb.append("\n\nDiscord Information:")
|
||||
.append("\n ID = ").append(event.getJDA().getSelfUser().getId())
|
||||
.append("\n Guilds = ").append(event.getJDA().getGuildCache().size())
|
||||
.append("\n Users = ").append(event.getJDA().getUserCache().size());
|
||||
sb.append("\n```");
|
||||
|
||||
if(event.isFromType(ChannelType.PRIVATE)
|
||||
|| event.getSelfMember().hasPermission(event.getTextChannel(), Permission.MESSAGE_ATTACH_FILES))
|
||||
event.getChannel().sendFile(sb.toString().getBytes(), "debug_information.txt").queue();
|
||||
else
|
||||
event.reply("Debug Information: " + sb.toString());
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import javax.script.ScriptEngineManager;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -27,10 +28,14 @@ import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
*/
|
||||
public class EvalCmd extends OwnerCommand
|
||||
{
|
||||
private final Bot bot;
|
||||
|
||||
public EvalCmd(Bot bot)
|
||||
{
|
||||
this.bot = bot;
|
||||
this.name = "eval";
|
||||
this.help = "evaluates nashorn code";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
@@ -38,10 +43,13 @@ public class EvalCmd extends OwnerCommand
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
ScriptEngine se = new ScriptEngineManager().getEngineByName("Nashorn");
|
||||
se.put("bot", bot);
|
||||
se.put("event", event);
|
||||
se.put("jda", event.getJDA());
|
||||
se.put("guild", event.getGuild());
|
||||
se.put("channel", event.getChannel());
|
||||
if (event.getChannelType() != ChannelType.PRIVATE) {
|
||||
se.put("guild", event.getGuild());
|
||||
se.put("channel", event.getChannel());
|
||||
}
|
||||
try
|
||||
{
|
||||
event.reply(event.getClient().getSuccess()+" Evaluated Successfully:\n```\n"+se.eval(event.getArgs())+" ```");
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.jagrosh.jdautilities.command.Command;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import com.jagrosh.jmusicbot.commands.owner.AutoplaylistCmd;
|
||||
import com.jagrosh.jmusicbot.playlist.PlaylistLoader.Playlist;
|
||||
|
||||
/**
|
||||
@@ -38,6 +37,7 @@ public class PlaylistCmd extends OwnerCommand
|
||||
this.name = "playlist";
|
||||
this.arguments = "<append|delete|make|setdefault>";
|
||||
this.help = "playlist management";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.children = new OwnerCommand[]{
|
||||
new ListCmd(),
|
||||
new AppendlistCmd(),
|
||||
@@ -72,7 +72,12 @@ public class PlaylistCmd extends OwnerCommand
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
String pname = event.getArgs().replaceAll("\\s+", "_");
|
||||
if(bot.getPlaylistLoader().getPlaylist(pname)==null)
|
||||
pname = pname.replaceAll("[*?|\\/\":<>]", "");
|
||||
if(pname == null || pname.isEmpty())
|
||||
{
|
||||
event.replyError("Please provide a name for the playlist!");
|
||||
}
|
||||
else if(bot.getPlaylistLoader().getPlaylist(pname) == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -18,9 +18,10 @@ package com.jagrosh.jmusicbot.commands.owner;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import net.dv8tion.jda.core.entities.Icon;
|
||||
import net.dv8tion.jda.api.entities.Icon;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -28,11 +29,12 @@ import net.dv8tion.jda.core.entities.Icon;
|
||||
*/
|
||||
public class SetavatarCmd extends OwnerCommand
|
||||
{
|
||||
public SetavatarCmd()
|
||||
public SetavatarCmd(Bot bot)
|
||||
{
|
||||
this.name = "setavatar";
|
||||
this.help = "sets the avatar of the bot";
|
||||
this.arguments = "<url>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
package com.jagrosh.jmusicbot.commands.owner;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -25,11 +26,12 @@ import net.dv8tion.jda.core.entities.Game;
|
||||
*/
|
||||
public class SetgameCmd extends OwnerCommand
|
||||
{
|
||||
public SetgameCmd()
|
||||
public SetgameCmd(Bot bot)
|
||||
{
|
||||
this.name = "setgame";
|
||||
this.help = "sets the game the bot is playing";
|
||||
this.arguments = "[action] [game]";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
this.children = new OwnerCommand[]{
|
||||
new SetlistenCmd(),
|
||||
@@ -44,7 +46,7 @@ public class SetgameCmd extends OwnerCommand
|
||||
String title = event.getArgs().toLowerCase().startsWith("playing") ? event.getArgs().substring(7).trim() : event.getArgs();
|
||||
try
|
||||
{
|
||||
event.getJDA().getPresence().setGame(title.isEmpty() ? null : Game.playing(title));
|
||||
event.getJDA().getPresence().setActivity(title.isEmpty() ? null : Activity.playing(title));
|
||||
event.reply(event.getClient().getSuccess()+" **"+event.getSelfUser().getName()
|
||||
+"** is "+(title.isEmpty() ? "no longer playing anything." : "now playing `"+title+"`"));
|
||||
}
|
||||
@@ -76,7 +78,7 @@ public class SetgameCmd extends OwnerCommand
|
||||
}
|
||||
try
|
||||
{
|
||||
event.getJDA().getPresence().setGame(Game.streaming(parts[1], "https://twitch.tv/"+parts[0]));
|
||||
event.getJDA().getPresence().setActivity(Activity.streaming(parts[1], "https://twitch.tv/"+parts[0]));
|
||||
event.replySuccess("**"+event.getSelfUser().getName()
|
||||
+"** is now streaming `"+parts[1]+"`");
|
||||
}
|
||||
@@ -109,7 +111,7 @@ public class SetgameCmd extends OwnerCommand
|
||||
String title = event.getArgs().toLowerCase().startsWith("to") ? event.getArgs().substring(2).trim() : event.getArgs();
|
||||
try
|
||||
{
|
||||
event.getJDA().getPresence().setGame(Game.listening(title));
|
||||
event.getJDA().getPresence().setActivity(Activity.listening(title));
|
||||
event.replySuccess("**"+event.getSelfUser().getName()+"** is now listening to `"+title+"`");
|
||||
} catch(Exception e) {
|
||||
event.reply(event.getClient().getError()+" The game could not be set!");
|
||||
@@ -139,7 +141,7 @@ public class SetgameCmd extends OwnerCommand
|
||||
String title = event.getArgs();
|
||||
try
|
||||
{
|
||||
event.getJDA().getPresence().setGame(Game.watching(title));
|
||||
event.getJDA().getPresence().setActivity(Activity.watching(title));
|
||||
event.replySuccess("**"+event.getSelfUser().getName()+"** is now watching `"+title+"`");
|
||||
} catch(Exception e) {
|
||||
event.reply(event.getClient().getError()+" The game could not be set!");
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.jagrosh.jmusicbot.commands.owner;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import net.dv8tion.jda.core.exceptions.RateLimitedException;
|
||||
import net.dv8tion.jda.api.exceptions.RateLimitedException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -31,19 +31,25 @@ public class SetnameCmd extends OwnerCommand
|
||||
this.name = "setname";
|
||||
this.help = "sets the name of the bot";
|
||||
this.arguments = "<name>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
String oldname = event.getSelfUser().getName();
|
||||
event.getSelfUser().getManager().setName(event.getArgs()).complete(false);
|
||||
event.reply(event.getClient().getSuccess()+" Name changed from `"+oldname+"` to `"+event.getArgs()+"`");
|
||||
} catch(RateLimitedException e) {
|
||||
}
|
||||
catch(RateLimitedException e)
|
||||
{
|
||||
event.reply(event.getClient().getError()+" Name can only be changed twice per hour!");
|
||||
} catch(Exception e) {
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
event.reply(event.getClient().getError()+" That name is not valid!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
package com.jagrosh.jmusicbot.commands.owner;
|
||||
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import net.dv8tion.jda.core.OnlineStatus;
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -25,11 +26,12 @@ import net.dv8tion.jda.core.OnlineStatus;
|
||||
*/
|
||||
public class SetstatusCmd extends OwnerCommand
|
||||
{
|
||||
public SetstatusCmd()
|
||||
public SetstatusCmd(Bot bot)
|
||||
{
|
||||
this.name = "setstatus";
|
||||
this.help = "sets the status the bot displays";
|
||||
this.arguments = "<status>";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public class ShutdownCmd extends OwnerCommand
|
||||
this.bot = bot;
|
||||
this.name = "shutdown";
|
||||
this.help = "safely shuts down";
|
||||
this.aliases = bot.getConfig().getAliases(this.name);
|
||||
this.guildOnly = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ public class Prompt
|
||||
private final String noguiMessage;
|
||||
|
||||
private boolean nogui;
|
||||
private boolean noprompt;
|
||||
private Scanner scanner;
|
||||
|
||||
public Prompt(String title)
|
||||
@@ -39,14 +40,15 @@ public class Prompt
|
||||
|
||||
public Prompt(String title, String noguiMessage)
|
||||
{
|
||||
this(title, noguiMessage, "true".equalsIgnoreCase(System.getProperty("nogui")));
|
||||
this(title, noguiMessage, "true".equalsIgnoreCase(System.getProperty("nogui")), "true".equalsIgnoreCase(System.getProperty("noprompt")));
|
||||
}
|
||||
|
||||
public Prompt(String title, String noguiMessage, boolean nogui)
|
||||
public Prompt(String title, String noguiMessage, boolean nogui, boolean noprompt)
|
||||
{
|
||||
this.title = title;
|
||||
this.noguiMessage = noguiMessage == null ? "Switching to nogui mode. You can manually start in nogui mode by including the -Dnogui=true flag." : noguiMessage;
|
||||
this.nogui = nogui;
|
||||
this.noprompt = noprompt;
|
||||
}
|
||||
|
||||
public boolean isNoGUI()
|
||||
@@ -61,9 +63,18 @@ public class Prompt
|
||||
Logger log = LoggerFactory.getLogger(context);
|
||||
switch(level)
|
||||
{
|
||||
case INFO: log.info(message); break;
|
||||
case WARNING: log.warn(message); break;
|
||||
case ERROR: log.error(message); break;
|
||||
case INFO:
|
||||
log.info(message);
|
||||
break;
|
||||
case WARNING:
|
||||
log.warn(message);
|
||||
break;
|
||||
case ERROR:
|
||||
log.error(message);
|
||||
break;
|
||||
default:
|
||||
log.info(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -73,9 +84,18 @@ public class Prompt
|
||||
int option = 0;
|
||||
switch(level)
|
||||
{
|
||||
case INFO: option = JOptionPane.INFORMATION_MESSAGE; break;
|
||||
case WARNING: option = JOptionPane.WARNING_MESSAGE; break;
|
||||
case ERROR: option = JOptionPane.ERROR_MESSAGE; break;
|
||||
case INFO:
|
||||
option = JOptionPane.INFORMATION_MESSAGE;
|
||||
break;
|
||||
case WARNING:
|
||||
option = JOptionPane.WARNING_MESSAGE;
|
||||
break;
|
||||
case ERROR:
|
||||
option = JOptionPane.ERROR_MESSAGE;
|
||||
break;
|
||||
default:
|
||||
option = JOptionPane.PLAIN_MESSAGE;
|
||||
break;
|
||||
}
|
||||
JOptionPane.showMessageDialog(null, "<html><body><p style='width: 400px;'>"+message, title, option);
|
||||
}
|
||||
@@ -90,6 +110,8 @@ public class Prompt
|
||||
|
||||
public String prompt(String content)
|
||||
{
|
||||
if(noprompt)
|
||||
return null;
|
||||
if(nogui)
|
||||
{
|
||||
if(scanner==null)
|
||||
|
||||
@@ -51,7 +51,7 @@ public class GUI extends JFrame
|
||||
setVisible(true);
|
||||
addWindowListener(new WindowListener()
|
||||
{
|
||||
@Override public void windowOpened(WindowEvent e) {}
|
||||
@Override public void windowOpened(WindowEvent e) { /* unused */ }
|
||||
@Override public void windowClosing(WindowEvent e)
|
||||
{
|
||||
try
|
||||
@@ -63,11 +63,11 @@ public class GUI extends JFrame
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@Override public void windowClosed(WindowEvent e) {}
|
||||
@Override public void windowIconified(WindowEvent e) {}
|
||||
@Override public void windowDeiconified(WindowEvent e) {}
|
||||
@Override public void windowActivated(WindowEvent e) {}
|
||||
@Override public void windowDeactivated(WindowEvent e) {}
|
||||
@Override public void windowClosed(WindowEvent e) { /* unused */ }
|
||||
@Override public void windowIconified(WindowEvent e) { /* unused */ }
|
||||
@Override public void windowDeiconified(WindowEvent e) { /* unused */ }
|
||||
@Override public void windowActivated(WindowEvent e) { /* unused */ }
|
||||
@Override public void windowDeactivated(WindowEvent e) { /* unused */ }
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.List;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh <john.a.grosh@gmail.com>
|
||||
*/
|
||||
public class GuildsPanel extends JPanel
|
||||
{
|
||||
private final Bot bot;
|
||||
private final JList guildList;
|
||||
private final JTextArea guildQueue;
|
||||
private int index = -1;
|
||||
|
||||
public GuildsPanel(Bot bot)
|
||||
{
|
||||
super();
|
||||
super.setLayout(new GridBagLayout());
|
||||
this.bot = bot;
|
||||
|
||||
guildList = new JList();
|
||||
guildQueue = new JTextArea();
|
||||
guildList.setModel(new DefaultListModel());
|
||||
guildList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
guildList.setFixedCellHeight(20);
|
||||
guildList.setPreferredSize(new Dimension(100,300));
|
||||
guildQueue.setPreferredSize(new Dimension(300,300));
|
||||
guildQueue.setEditable(false);
|
||||
JScrollPane pane = new JScrollPane();
|
||||
JScrollPane pane2 = new JScrollPane();
|
||||
pane.setViewportView(guildList);
|
||||
pane2.setViewportView(guildQueue);
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.fill = GridBagConstraints.BOTH;
|
||||
c.anchor = GridBagConstraints.LINE_START;
|
||||
c.gridx = 0;
|
||||
c.gridwidth = 1;
|
||||
super.add(pane, c);
|
||||
c.gridx = 1;
|
||||
c.gridwidth = 3;
|
||||
super.add(pane2, c);
|
||||
//bot.registerPanel(this);
|
||||
guildList.addListSelectionListener((ListSelectionEvent e) -> {
|
||||
index = guildList.getSelectedIndex();
|
||||
//bot.updatePanel();
|
||||
});
|
||||
}
|
||||
|
||||
public void updateList(List<Guild> guilds)
|
||||
{
|
||||
String[] strs = new String[guilds.size()];
|
||||
for(int i=0; i<guilds.size(); i++)
|
||||
strs[i] = guilds.get(i).getName();
|
||||
guildList.setListData(strs);
|
||||
}
|
||||
|
||||
public int getIndex()
|
||||
{
|
||||
return guildList.getSelectedIndex();
|
||||
}
|
||||
|
||||
/*public void updatePanel(AudioHandler handler) {
|
||||
StringBuilder builder = new StringBuilder("Now Playing: ");
|
||||
if(handler==null || handler.getCurrentTrack()==null)
|
||||
{
|
||||
builder.append("nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(handler.getCurrentTrack().getTrack().getInfo().title)
|
||||
.append(" [")
|
||||
.append(FormatUtil.formatTime(handler.getCurrentTrack().getTrack().getDuration()))
|
||||
.append("]\n");
|
||||
for(int i=0; i<handler.getQueue().size(); i++)
|
||||
builder.append("\n").append(i+1).append(". ").append(handler.getQueue().get(i).getTrack().getInfo().title);
|
||||
}
|
||||
guildQueue.setText(builder.toString());
|
||||
guildQueue.updateUI();
|
||||
}*/
|
||||
|
||||
}
|
||||
@@ -1,147 +1,157 @@
|
||||
/*
|
||||
* Copyright 2017 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.gui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import javax.swing.*;
|
||||
/**
|
||||
*
|
||||
* @author Lawrence Dol
|
||||
*/
|
||||
public class TextAreaOutputStream extends OutputStream {
|
||||
|
||||
// *************************************************************************************************
|
||||
// INSTANCE MEMBERS
|
||||
// *************************************************************************************************
|
||||
|
||||
private byte[] oneByte; // array for write(int val);
|
||||
private Appender appender; // most recent action
|
||||
|
||||
public TextAreaOutputStream(JTextArea txtara) {
|
||||
this(txtara,1000);
|
||||
}
|
||||
|
||||
public TextAreaOutputStream(JTextArea txtara, int maxlin) {
|
||||
if(maxlin<1) { throw new IllegalArgumentException("TextAreaOutputStream maximum lines must be positive (value="+maxlin+")"); }
|
||||
oneByte=new byte[1];
|
||||
appender=new Appender(txtara,maxlin);
|
||||
}
|
||||
|
||||
/** Clear the current console text area. */
|
||||
public synchronized void clear() {
|
||||
if(appender!=null) { appender.clear(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
appender=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int val) {
|
||||
oneByte[0]=(byte)val;
|
||||
write(oneByte,0,1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] ba) {
|
||||
write(ba,0,ba.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] ba,int str,int len) {
|
||||
if(appender!=null) { appender.append(bytesToString(ba,str,len)); }
|
||||
}
|
||||
|
||||
//@edu.umd.cs.findbugs.annotations.SuppressWarnings("DM_DEFAULT_ENCODING")
|
||||
static private String bytesToString(byte[] ba, int str, int len) {
|
||||
try { return new String(ba,str,len,"UTF-8"); } catch(UnsupportedEncodingException thr) { return new String(ba,str,len); } // all JVMs are required to support UTF-8
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
// STATIC MEMBERS
|
||||
// *************************************************************************************************
|
||||
|
||||
static class Appender
|
||||
implements Runnable
|
||||
{
|
||||
private final JTextArea textArea;
|
||||
private final int maxLines; // maximum lines allowed in text area
|
||||
private final LinkedList<Integer> lengths; // length of lines within text area
|
||||
private final List<String> values; // values waiting to be appended
|
||||
|
||||
private int curLength; // length of current line
|
||||
private boolean clear;
|
||||
private boolean queue;
|
||||
|
||||
Appender(JTextArea txtara, int maxlin) {
|
||||
textArea =txtara;
|
||||
maxLines =maxlin;
|
||||
lengths =new LinkedList<>();
|
||||
values =new ArrayList<>();
|
||||
|
||||
curLength=0;
|
||||
clear =false;
|
||||
queue =true;
|
||||
}
|
||||
|
||||
synchronized void append(String val) {
|
||||
values.add(val);
|
||||
if(queue) { queue=false; EventQueue.invokeLater(this); }
|
||||
}
|
||||
|
||||
synchronized void clear() {
|
||||
clear=true;
|
||||
curLength=0;
|
||||
lengths.clear();
|
||||
values.clear();
|
||||
if(queue) { queue=false; EventQueue.invokeLater(this); }
|
||||
}
|
||||
|
||||
// MUST BE THE ONLY METHOD THAT TOUCHES textArea!
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
if(clear) { textArea.setText(""); }
|
||||
values.stream().map((val) -> {
|
||||
curLength+=val.length();
|
||||
return val;
|
||||
}).map((val) -> {
|
||||
if(val.endsWith(EOL1) || val.endsWith(EOL2)) {
|
||||
if(lengths.size()>=maxLines) { textArea.replaceRange("",0,lengths.removeFirst()); }
|
||||
lengths.addLast(curLength);
|
||||
curLength=0;
|
||||
}
|
||||
return val;
|
||||
}).forEach((val) -> {
|
||||
textArea.append(val);
|
||||
});
|
||||
values.clear();
|
||||
clear =false;
|
||||
queue =true;
|
||||
}
|
||||
|
||||
static private final String EOL1="\n";
|
||||
static private final String EOL2=System.getProperty("line.separator",EOL1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2017 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.gui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import javax.swing.*;
|
||||
/**
|
||||
*
|
||||
* @author Lawrence Dol
|
||||
*/
|
||||
public class TextAreaOutputStream extends OutputStream {
|
||||
|
||||
// *************************************************************************************************
|
||||
// INSTANCE MEMBERS
|
||||
// *************************************************************************************************
|
||||
|
||||
private byte[] oneByte; // array for write(int val);
|
||||
private Appender appender; // most recent action
|
||||
|
||||
public TextAreaOutputStream(JTextArea txtara) {
|
||||
this(txtara,1000);
|
||||
}
|
||||
|
||||
public TextAreaOutputStream(JTextArea txtara, int maxlin) {
|
||||
if(maxlin<1) { throw new IllegalArgumentException("TextAreaOutputStream maximum lines must be positive (value="+maxlin+")"); }
|
||||
oneByte=new byte[1];
|
||||
appender=new Appender(txtara,maxlin);
|
||||
}
|
||||
|
||||
/** Clear the current console text area. */
|
||||
public synchronized void clear() {
|
||||
if(appender!=null) { appender.clear(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
appender=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int val) {
|
||||
oneByte[0]=(byte)val;
|
||||
write(oneByte,0,1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] ba) {
|
||||
write(ba,0,ba.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] ba,int str,int len) {
|
||||
if(appender!=null) { appender.append(bytesToString(ba,str,len)); }
|
||||
}
|
||||
|
||||
//@edu.umd.cs.findbugs.annotations.SuppressWarnings("DM_DEFAULT_ENCODING")
|
||||
static private String bytesToString(byte[] ba, int str, int len) {
|
||||
try {
|
||||
return new String(ba,str,len,"UTF-8");
|
||||
} catch(UnsupportedEncodingException thr) {
|
||||
return new String(ba,str,len);
|
||||
} // all JVMs are required to support UTF-8
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
// STATIC MEMBERS
|
||||
// *************************************************************************************************
|
||||
|
||||
static class Appender
|
||||
implements Runnable
|
||||
{
|
||||
static private final String EOL1="\n";
|
||||
static private final String EOL2=System.getProperty("line.separator",EOL1);
|
||||
|
||||
private final JTextArea textArea;
|
||||
private final int maxLines; // maximum lines allowed in text area
|
||||
private final LinkedList<Integer> lengths; // length of lines within text area
|
||||
private final List<String> values; // values waiting to be appended
|
||||
|
||||
private int curLength; // length of current line
|
||||
private boolean clear;
|
||||
private boolean queue;
|
||||
|
||||
Appender(JTextArea txtara, int maxlin) {
|
||||
textArea =txtara;
|
||||
maxLines =maxlin;
|
||||
lengths =new LinkedList<>();
|
||||
values =new ArrayList<>();
|
||||
|
||||
curLength=0;
|
||||
clear =false;
|
||||
queue =true;
|
||||
}
|
||||
|
||||
private synchronized void append(String val) {
|
||||
values.add(val);
|
||||
if(queue) {
|
||||
queue=false;
|
||||
EventQueue.invokeLater(this);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void clear() {
|
||||
clear=true;
|
||||
curLength=0;
|
||||
lengths.clear();
|
||||
values.clear();
|
||||
if(queue) {
|
||||
queue=false;
|
||||
EventQueue.invokeLater(this);
|
||||
}
|
||||
}
|
||||
|
||||
// MUST BE THE ONLY METHOD THAT TOUCHES textArea!
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
if(clear) { textArea.setText(""); }
|
||||
values.stream().map((val) -> {
|
||||
curLength+=val.length();
|
||||
return val;
|
||||
}).map((val) -> {
|
||||
if(val.endsWith(EOL1) || val.endsWith(EOL2)) {
|
||||
if(lengths.size()>=maxLines) { textArea.replaceRange("",0,lengths.removeFirst()); }
|
||||
lengths.addLast(curLength);
|
||||
curLength=0;
|
||||
}
|
||||
return val;
|
||||
}).forEach((val) -> {
|
||||
textArea.append(val);
|
||||
});
|
||||
values.clear();
|
||||
clear =false;
|
||||
queue =true;
|
||||
}
|
||||
}
|
||||
} /* END PUBLIC CLASS */
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.jagrosh.jmusicbot.playlist;
|
||||
|
||||
import com.jagrosh.jmusicbot.BotConfig;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||
@@ -24,7 +25,6 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -46,14 +46,14 @@ public class PlaylistLoader
|
||||
{
|
||||
if(folderExists())
|
||||
{
|
||||
File folder = new File(config.getPlaylistsFolder());
|
||||
File folder = new File(OtherUtil.getPath(config.getPlaylistsFolder()).toString());
|
||||
return Arrays.asList(folder.listFiles((pathname) -> pathname.getName().endsWith(".txt")))
|
||||
.stream().map(f -> f.getName().substring(0,f.getName().length()-4)).collect(Collectors.toList());
|
||||
}
|
||||
else
|
||||
{
|
||||
createFolder();
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,29 +61,29 @@ public class PlaylistLoader
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.createDirectory(Paths.get(config.getPlaylistsFolder()));
|
||||
Files.createDirectory(OtherUtil.getPath(config.getPlaylistsFolder()));
|
||||
}
|
||||
catch (IOException ex) {}
|
||||
catch (IOException ignore) {}
|
||||
}
|
||||
|
||||
public boolean folderExists()
|
||||
{
|
||||
return Files.exists(Paths.get(config.getPlaylistsFolder()));
|
||||
return Files.exists(OtherUtil.getPath(config.getPlaylistsFolder()));
|
||||
}
|
||||
|
||||
public void createPlaylist(String name) throws IOException
|
||||
{
|
||||
Files.createFile(Paths.get(config.getPlaylistsFolder()+File.separator+name+".txt"));
|
||||
Files.createFile(OtherUtil.getPath(config.getPlaylistsFolder()+File.separator+name+".txt"));
|
||||
}
|
||||
|
||||
public void deletePlaylist(String name) throws IOException
|
||||
{
|
||||
Files.delete(Paths.get(config.getPlaylistsFolder()+File.separator+name+".txt"));
|
||||
Files.delete(OtherUtil.getPath(config.getPlaylistsFolder()+File.separator+name+".txt"));
|
||||
}
|
||||
|
||||
public void writePlaylist(String name, String text) throws IOException
|
||||
{
|
||||
Files.write(Paths.get(config.getPlaylistsFolder()+File.separator+name+".txt"), text.trim().getBytes());
|
||||
Files.write(OtherUtil.getPath(config.getPlaylistsFolder()+File.separator+name+".txt"), text.trim().getBytes());
|
||||
}
|
||||
|
||||
public Playlist getPlaylist(String name)
|
||||
@@ -96,7 +96,7 @@ public class PlaylistLoader
|
||||
{
|
||||
boolean[] shuffle = {false};
|
||||
List<String> list = new ArrayList<>();
|
||||
Files.readAllLines(Paths.get(config.getPlaylistsFolder()+File.separator+name+".txt")).forEach(str ->
|
||||
Files.readAllLines(OtherUtil.getPath(config.getPlaylistsFolder()+File.separator+name+".txt")).forEach(str ->
|
||||
{
|
||||
String s = str.trim();
|
||||
if(s.isEmpty())
|
||||
@@ -157,101 +157,90 @@ public class PlaylistLoader
|
||||
|
||||
public void loadTracks(AudioPlayerManager manager, Consumer<AudioTrack> consumer, Runnable callback)
|
||||
{
|
||||
if(!loaded)
|
||||
if(loaded)
|
||||
return;
|
||||
loaded = true;
|
||||
for(int i=0; i<items.size(); i++)
|
||||
{
|
||||
loaded = true;
|
||||
for(int i=0; i<items.size(); i++)
|
||||
boolean last = i+1 == items.size();
|
||||
int index = i;
|
||||
manager.loadItemOrdered(name, items.get(i), new AudioLoadResultHandler()
|
||||
{
|
||||
boolean last = i+1==items.size();
|
||||
int index = i;
|
||||
manager.loadItemOrdered(name, items.get(i), new AudioLoadResultHandler()
|
||||
private void done()
|
||||
{
|
||||
@Override
|
||||
public void trackLoaded(AudioTrack at)
|
||||
if(last)
|
||||
{
|
||||
if(config.isTooLong(at))
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "This track is longer than the allowed maximum"));
|
||||
else
|
||||
{
|
||||
at.setUserData(0L);
|
||||
tracks.add(at);
|
||||
consumer.accept(at);
|
||||
}
|
||||
if(last && callback!=null)
|
||||
callback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playlistLoaded(AudioPlaylist ap)
|
||||
{
|
||||
if(ap.isSearchResult())
|
||||
{
|
||||
if(config.isTooLong(ap.getTracks().get(0)))
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "This track is longer than the allowed maximum"));
|
||||
else
|
||||
{
|
||||
ap.getTracks().get(0).setUserData(0L);
|
||||
tracks.add(ap.getTracks().get(0));
|
||||
consumer.accept(ap.getTracks().get(0));
|
||||
}
|
||||
}
|
||||
else if(ap.getSelectedTrack()!=null)
|
||||
{
|
||||
if(config.isTooLong(ap.getSelectedTrack()))
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "This track is longer than the allowed maximum"));
|
||||
else
|
||||
{
|
||||
ap.getSelectedTrack().setUserData(0L);
|
||||
tracks.add(ap.getSelectedTrack());
|
||||
consumer.accept(ap.getSelectedTrack());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<AudioTrack> loaded = new ArrayList<>(ap.getTracks());
|
||||
if(shuffle)
|
||||
for(int first =0; first<loaded.size(); first++)
|
||||
{
|
||||
int second = (int)(Math.random()*loaded.size());
|
||||
AudioTrack tmp = loaded.get(first);
|
||||
loaded.set(first, loaded.get(second));
|
||||
loaded.set(second, tmp);
|
||||
}
|
||||
loaded.removeIf(track -> config.isTooLong(track));
|
||||
loaded.forEach(at -> at.setUserData(0L));
|
||||
tracks.addAll(loaded);
|
||||
loaded.forEach(at -> consumer.accept(at));
|
||||
}
|
||||
if(last && callback!=null)
|
||||
if(shuffle)
|
||||
shuffleTracks();
|
||||
if(callback != null)
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noMatches()
|
||||
@Override
|
||||
public void trackLoaded(AudioTrack at)
|
||||
{
|
||||
if(config.isTooLong(at))
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "This track is longer than the allowed maximum"));
|
||||
else
|
||||
{
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "No matches found."));
|
||||
if(last && callback!=null)
|
||||
callback.run();
|
||||
at.setUserData(0L);
|
||||
tracks.add(at);
|
||||
consumer.accept(at);
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFailed(FriendlyException fe)
|
||||
@Override
|
||||
public void playlistLoaded(AudioPlaylist ap)
|
||||
{
|
||||
if(ap.isSearchResult())
|
||||
{
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "Failed to load track: "+fe.getLocalizedMessage()));
|
||||
if(last && callback!=null)
|
||||
callback.run();
|
||||
trackLoaded(ap.getTracks().get(0));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(ap.getSelectedTrack()!=null)
|
||||
{
|
||||
trackLoaded(ap.getSelectedTrack());
|
||||
}
|
||||
else
|
||||
{
|
||||
List<AudioTrack> loaded = new ArrayList<>(ap.getTracks());
|
||||
if(shuffle)
|
||||
for(int first =0; first<loaded.size(); first++)
|
||||
{
|
||||
int second = (int)(Math.random()*loaded.size());
|
||||
AudioTrack tmp = loaded.get(first);
|
||||
loaded.set(first, loaded.get(second));
|
||||
loaded.set(second, tmp);
|
||||
}
|
||||
loaded.removeIf(track -> config.isTooLong(track));
|
||||
loaded.forEach(at -> at.setUserData(0L));
|
||||
tracks.addAll(loaded);
|
||||
loaded.forEach(at -> consumer.accept(at));
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noMatches()
|
||||
{
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "No matches found."));
|
||||
done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFailed(FriendlyException fe)
|
||||
{
|
||||
errors.add(new PlaylistLoadError(index, items.get(index), "Failed to load track: "+fe.getLocalizedMessage()));
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(shuffle)
|
||||
shuffleTracks();
|
||||
}
|
||||
|
||||
public void shuffleTracks()
|
||||
{
|
||||
if(tracks!=null)
|
||||
shuffle(tracks);
|
||||
shuffle(tracks);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2022 John Grosh (jagrosh).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.queue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wolfgang Schwendtbauer
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractQueue<T extends Queueable>
|
||||
{
|
||||
protected AbstractQueue(AbstractQueue<T> queue)
|
||||
{
|
||||
this.list = queue != null ? queue.getList() : new LinkedList<>();
|
||||
}
|
||||
|
||||
protected final List<T> list;
|
||||
|
||||
public abstract int add(T item);
|
||||
|
||||
public void addAt(int index, T item)
|
||||
{
|
||||
if(index >= list.size())
|
||||
list.add(item);
|
||||
else
|
||||
list.add(index, item);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public T pull() {
|
||||
return list.remove(0);
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public List<T> getList()
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
public T get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public T remove(int index)
|
||||
{
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
public int removeAll(long identifier)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i=list.size()-1; i>=0; i--)
|
||||
{
|
||||
if(list.get(i).getIdentifier()==identifier)
|
||||
{
|
||||
list.remove(i);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
list.clear();
|
||||
}
|
||||
|
||||
public int shuffle(long identifier)
|
||||
{
|
||||
List<Integer> iset = new ArrayList<>();
|
||||
for(int i=0; i<list.size(); i++)
|
||||
{
|
||||
if(list.get(i).getIdentifier()==identifier)
|
||||
iset.add(i);
|
||||
}
|
||||
for(int j=0; j<iset.size(); j++)
|
||||
{
|
||||
int first = iset.get(j);
|
||||
int second = iset.get((int)(Math.random()*iset.size()));
|
||||
T temp = list.get(first);
|
||||
list.set(first, list.get(second));
|
||||
list.set(second, temp);
|
||||
}
|
||||
return iset.size();
|
||||
}
|
||||
|
||||
public void skip(int number)
|
||||
{
|
||||
if (number > 0) {
|
||||
list.subList(0, number).clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an item to a different position in the list
|
||||
* @param from The position of the item
|
||||
* @param to The new position of the item
|
||||
* @return the moved item
|
||||
*/
|
||||
public T moveItem(int from, int to)
|
||||
{
|
||||
T item = list.remove(from);
|
||||
list.add(to, item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.queue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -25,15 +23,21 @@ import java.util.Set;
|
||||
* @author John Grosh (jagrosh)
|
||||
* @param <T>
|
||||
*/
|
||||
public class FairQueue<T extends Queueable> {
|
||||
private final List<T> list = new ArrayList<>();
|
||||
private final Set<Long> set = new HashSet<>();
|
||||
|
||||
public class FairQueue<T extends Queueable> extends AbstractQueue<T>
|
||||
{
|
||||
public FairQueue(AbstractQueue<T> queue)
|
||||
{
|
||||
super(queue);
|
||||
}
|
||||
|
||||
protected final Set<Long> set = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public int add(T item)
|
||||
{
|
||||
int lastIndex;
|
||||
for(lastIndex=list.size()-1; lastIndex>-1; lastIndex--)
|
||||
if(list.get(lastIndex).getIdentifier()==item.getIdentifier())
|
||||
if(list.get(lastIndex).getIdentifier() == item.getIdentifier())
|
||||
break;
|
||||
lastIndex++;
|
||||
set.clear();
|
||||
@@ -46,86 +50,5 @@ public class FairQueue<T extends Queueable> {
|
||||
list.add(lastIndex, item);
|
||||
return lastIndex;
|
||||
}
|
||||
|
||||
public void addAt(int index, T item)
|
||||
{
|
||||
if(index >= list.size())
|
||||
list.add(item);
|
||||
else
|
||||
list.add(index, item);
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public T pull()
|
||||
{
|
||||
return list.remove(0);
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public List<T> getList()
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
public T get(int index)
|
||||
{
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public T remove(int index)
|
||||
{
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
public int removeAll(long identifier)
|
||||
{
|
||||
int count = 0;
|
||||
for(int i=list.size()-1; i>=0; i--)
|
||||
{
|
||||
if(list.get(i).getIdentifier()==identifier)
|
||||
{
|
||||
list.remove(i);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
list.clear();
|
||||
}
|
||||
|
||||
public int shuffle(long identifier)
|
||||
{
|
||||
List<Integer> iset = new ArrayList<>();
|
||||
for(int i=0; i<list.size(); i++)
|
||||
{
|
||||
if(list.get(i).getIdentifier()==identifier)
|
||||
iset.add(i);
|
||||
}
|
||||
for(int j=0; j<iset.size(); j++)
|
||||
{
|
||||
int first = iset.get(j);
|
||||
int second = iset.get((int)(Math.random()*iset.size()));
|
||||
T temp = list.get(first);
|
||||
list.set(first, list.get(second));
|
||||
list.set(second, temp);
|
||||
}
|
||||
return iset.size();
|
||||
}
|
||||
|
||||
public void skip(int number)
|
||||
{
|
||||
for(int i=0; i<number; i++)
|
||||
list.remove(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2022 John Grosh (jagrosh).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.queue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wolfgang Schwendtbauer
|
||||
* @param <T>
|
||||
*/
|
||||
public class LinearQueue<T extends Queueable> extends AbstractQueue<T>
|
||||
{
|
||||
public LinearQueue(AbstractQueue<T> queue)
|
||||
{
|
||||
super(queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int add(T item)
|
||||
{
|
||||
list.add(item);
|
||||
return list.size() - 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2022 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.queue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wolfgang Schwendtbauer
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface QueueSupplier
|
||||
{
|
||||
<T extends Queueable> AbstractQueue<T> apply(AbstractQueue<T> queue);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2022 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.settings;
|
||||
|
||||
import com.jagrosh.jmusicbot.queue.AbstractQueue;
|
||||
import com.jagrosh.jmusicbot.queue.FairQueue;
|
||||
import com.jagrosh.jmusicbot.queue.LinearQueue;
|
||||
import com.jagrosh.jmusicbot.queue.Queueable;
|
||||
import com.jagrosh.jmusicbot.queue.QueueSupplier;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Wolfgang Schwendtbauer
|
||||
*/
|
||||
public enum QueueType
|
||||
{
|
||||
LINEAR("\u23E9", "Linear", LinearQueue::new), // ⏩
|
||||
FAIR("\uD83D\uDD22", "Fair", FairQueue::new); // 🔢
|
||||
|
||||
private final String userFriendlyName;
|
||||
private final String emoji;
|
||||
private final QueueSupplier supplier;
|
||||
|
||||
QueueType(final String emoji, final String userFriendlyName, QueueSupplier supplier)
|
||||
{
|
||||
this.userFriendlyName = userFriendlyName;
|
||||
this.emoji = emoji;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public static List<String> getNames()
|
||||
{
|
||||
return Arrays.stream(QueueType.values())
|
||||
.map(type -> type.name().toLowerCase())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public <T extends Queueable> AbstractQueue<T> createInstance(AbstractQueue<T> previous)
|
||||
{
|
||||
return supplier.apply(previous);
|
||||
}
|
||||
|
||||
public String getUserFriendlyName()
|
||||
{
|
||||
return userFriendlyName;
|
||||
}
|
||||
|
||||
public String getEmoji()
|
||||
{
|
||||
return emoji;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Michaili K
|
||||
*/
|
||||
public enum RepeatMode
|
||||
{
|
||||
OFF(null, "Off"),
|
||||
ALL("\uD83D\uDD01", "All"), // 🔁
|
||||
SINGLE("\uD83D\uDD02", "Single"); // 🔂
|
||||
|
||||
private final String emoji;
|
||||
private final String userFriendlyName;
|
||||
|
||||
private RepeatMode(String emoji, String userFriendlyName)
|
||||
{
|
||||
this.emoji = emoji;
|
||||
this.userFriendlyName = userFriendlyName;
|
||||
}
|
||||
|
||||
public String getEmoji()
|
||||
{
|
||||
return emoji;
|
||||
}
|
||||
|
||||
public String getUserFriendlyName()
|
||||
{
|
||||
return userFriendlyName;
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,12 @@
|
||||
package com.jagrosh.jmusicbot.settings;
|
||||
|
||||
import com.jagrosh.jdautilities.command.GuildSettingsProvider;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,9 +35,12 @@ public class Settings implements GuildSettingsProvider
|
||||
protected long roleId;
|
||||
private int volume;
|
||||
private String defaultPlaylist;
|
||||
private boolean repeatMode;
|
||||
|
||||
public Settings(SettingsManager manager, String textId, String voiceId, String roleId, int volume, String defaultPlaylist, boolean repeatMode)
|
||||
private RepeatMode repeatMode;
|
||||
private QueueType queueType;
|
||||
private String prefix;
|
||||
private double skipRatio;
|
||||
|
||||
public Settings(SettingsManager manager, String textId, String voiceId, String roleId, int volume, String defaultPlaylist, RepeatMode repeatMode, String prefix, double skipRatio, QueueType queueType)
|
||||
{
|
||||
this.manager = manager;
|
||||
try
|
||||
@@ -65,9 +70,12 @@ public class Settings implements GuildSettingsProvider
|
||||
this.volume = volume;
|
||||
this.defaultPlaylist = defaultPlaylist;
|
||||
this.repeatMode = repeatMode;
|
||||
this.prefix = prefix;
|
||||
this.skipRatio = skipRatio;
|
||||
this.queueType = queueType;
|
||||
}
|
||||
|
||||
public Settings(SettingsManager manager, long textId, long voiceId, long roleId, int volume, String defaultPlaylist, boolean repeatMode)
|
||||
public Settings(SettingsManager manager, long textId, long voiceId, long roleId, int volume, String defaultPlaylist, RepeatMode repeatMode, String prefix, double skipRatio, QueueType queueType)
|
||||
{
|
||||
this.manager = manager;
|
||||
this.textId = textId;
|
||||
@@ -76,6 +84,9 @@ public class Settings implements GuildSettingsProvider
|
||||
this.volume = volume;
|
||||
this.defaultPlaylist = defaultPlaylist;
|
||||
this.repeatMode = repeatMode;
|
||||
this.prefix = prefix;
|
||||
this.skipRatio = skipRatio;
|
||||
this.queueType = queueType;
|
||||
}
|
||||
|
||||
// Getters
|
||||
@@ -104,11 +115,32 @@ public class Settings implements GuildSettingsProvider
|
||||
return defaultPlaylist;
|
||||
}
|
||||
|
||||
public boolean getRepeatMode()
|
||||
public RepeatMode getRepeatMode()
|
||||
{
|
||||
return repeatMode;
|
||||
}
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public double getSkipRatio()
|
||||
{
|
||||
return skipRatio;
|
||||
}
|
||||
|
||||
public QueueType getQueueType()
|
||||
{
|
||||
return queueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPrefixes()
|
||||
{
|
||||
return prefix == null ? Collections.emptySet() : Collections.singleton(prefix);
|
||||
}
|
||||
|
||||
// Setters
|
||||
public void setTextChannel(TextChannel tc)
|
||||
{
|
||||
@@ -140,9 +172,27 @@ public class Settings implements GuildSettingsProvider
|
||||
this.manager.writeSettings();
|
||||
}
|
||||
|
||||
public void setRepeatMode(boolean mode)
|
||||
public void setRepeatMode(RepeatMode mode)
|
||||
{
|
||||
this.repeatMode = mode;
|
||||
this.manager.writeSettings();
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.manager.writeSettings();
|
||||
}
|
||||
|
||||
public void setSkipRatio(double skipRatio)
|
||||
{
|
||||
this.skipRatio = skipRatio;
|
||||
this.manager.writeSettings();
|
||||
}
|
||||
|
||||
public void setQueueType(QueueType queueType)
|
||||
{
|
||||
this.queueType = queueType;
|
||||
this.manager.writeSettings();
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,12 @@
|
||||
package com.jagrosh.jmusicbot.settings;
|
||||
|
||||
import com.jagrosh.jdautilities.command.GuildSettingsManager;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.util.HashMap;
|
||||
import net.dv8tion.jda.core.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,33 +30,55 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class SettingsManager implements GuildSettingsManager
|
||||
public class SettingsManager implements GuildSettingsManager<Settings>
|
||||
{
|
||||
private final static String SETTINGS_FILE = "serversettings.json";
|
||||
private final HashMap<Long,Settings> settings;
|
||||
|
||||
public SettingsManager()
|
||||
{
|
||||
this.settings = new HashMap<>();
|
||||
|
||||
try {
|
||||
JSONObject loadedSettings = new JSONObject(new String(Files.readAllBytes(Paths.get("serversettings.json"))));
|
||||
JSONObject loadedSettings = new JSONObject(new String(Files.readAllBytes(OtherUtil.getPath(SETTINGS_FILE))));
|
||||
loadedSettings.keySet().forEach((id) -> {
|
||||
JSONObject o = loadedSettings.getJSONObject(id);
|
||||
|
||||
// Legacy version support: On versions 0.3.3 and older, the repeat mode was represented as a boolean.
|
||||
if (!o.has("repeat_mode") && o.has("repeat") && o.getBoolean("repeat"))
|
||||
o.put("repeat_mode", RepeatMode.ALL);
|
||||
|
||||
|
||||
settings.put(Long.parseLong(id), new Settings(this,
|
||||
o.has("text_channel_id") ? o.getString("text_channel_id") : null,
|
||||
o.has("voice_channel_id")? o.getString("voice_channel_id"): null,
|
||||
o.has("dj_role_id") ? o.getString("dj_role_id") : null,
|
||||
o.has("volume") ? o.getInt("volume") : 100,
|
||||
o.has("default_playlist")? o.getString("default_playlist"): null,
|
||||
o.has("repeat") ? o.getBoolean("repeat") : false));
|
||||
o.has("text_channel_id") ? o.getString("text_channel_id") : null,
|
||||
o.has("voice_channel_id")? o.getString("voice_channel_id") : null,
|
||||
o.has("dj_role_id") ? o.getString("dj_role_id") : null,
|
||||
o.has("volume") ? o.getInt("volume") : 100,
|
||||
o.has("default_playlist")? o.getString("default_playlist") : null,
|
||||
o.has("repeat_mode") ? o.getEnum(RepeatMode.class, "repeat_mode"): RepeatMode.OFF,
|
||||
o.has("prefix") ? o.getString("prefix") : null,
|
||||
o.has("skip_ratio") ? o.getDouble("skip_ratio") : -1,
|
||||
o.has("queue_type") ? o.getEnum(QueueType.class, "queue_type") : QueueType.FAIR));
|
||||
});
|
||||
} catch (NoSuchFileException e) {
|
||||
// create an empty json file
|
||||
try {
|
||||
LoggerFactory.getLogger("Settings").info("serversettings.json will be created in " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
Files.write(OtherUtil.getPath("serversettings.json"), new JSONObject().toString(4).getBytes());
|
||||
} catch(IOException ex) {
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to create new settings file: "+ex);
|
||||
}
|
||||
return;
|
||||
} catch(IOException | JSONException e) {
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to load server settings (this is normal if no settings have been set yet): "+e);
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to load server settings: "+e);
|
||||
}
|
||||
|
||||
LoggerFactory.getLogger("Settings").info("serversettings.json loaded from " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets non-null settings for a Guild
|
||||
*
|
||||
*
|
||||
* @param guild the guild to get settings for
|
||||
* @return the existing settings, or new settings for that guild
|
||||
*/
|
||||
@@ -64,17 +87,17 @@ public class SettingsManager implements GuildSettingsManager
|
||||
{
|
||||
return getSettings(guild.getIdLong());
|
||||
}
|
||||
|
||||
|
||||
public Settings getSettings(long guildId)
|
||||
{
|
||||
return settings.computeIfAbsent(guildId, id -> createDefaultSettings());
|
||||
}
|
||||
|
||||
|
||||
private Settings createDefaultSettings()
|
||||
{
|
||||
return new Settings(this, 0, 0, 0, 100, null, false);
|
||||
return new Settings(this, 0, 0, 0, 100, null, RepeatMode.OFF, null, -1, QueueType.FAIR);
|
||||
}
|
||||
|
||||
|
||||
protected void writeSettings()
|
||||
{
|
||||
JSONObject obj = new JSONObject();
|
||||
@@ -89,14 +112,20 @@ public class SettingsManager implements GuildSettingsManager
|
||||
o.put("dj_role_id", Long.toString(s.roleId));
|
||||
if(s.getVolume()!=100)
|
||||
o.put("volume",s.getVolume());
|
||||
if(s.getDefaultPlaylist()!=null)
|
||||
if(s.getDefaultPlaylist() != null)
|
||||
o.put("default_playlist", s.getDefaultPlaylist());
|
||||
if(s.getRepeatMode())
|
||||
o.put("repeat", true);
|
||||
if(s.getRepeatMode()!=RepeatMode.OFF)
|
||||
o.put("repeat_mode", s.getRepeatMode());
|
||||
if(s.getPrefix() != null)
|
||||
o.put("prefix", s.getPrefix());
|
||||
if(s.getSkipRatio() != -1)
|
||||
o.put("skip_ratio", s.getSkipRatio());
|
||||
if(s.getQueueType() != QueueType.FAIR)
|
||||
o.put("queue_type", s.getQueueType().name());
|
||||
obj.put(Long.toString(key), o);
|
||||
});
|
||||
try {
|
||||
Files.write(Paths.get("serversettings.json"), obj.toString(4).getBytes());
|
||||
Files.write(OtherUtil.getPath(SETTINGS_FILE), obj.toString(4).getBytes());
|
||||
} catch(IOException ex){
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to write to file: "+ex);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.utils;
|
||||
|
||||
import com.jagrosh.jmusicbot.audio.RequestMetadata.UserInfo;
|
||||
import java.util.List;
|
||||
import net.dv8tion.jda.core.entities.Role;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -37,30 +39,35 @@ public class FormatUtil {
|
||||
seconds %= 60;
|
||||
return (hours>0 ? hours+":" : "") + (minutes<10 ? "0"+minutes : minutes) + ":" + (seconds<10 ? "0"+seconds : seconds);
|
||||
}
|
||||
|
||||
/*public static String embedFormat(AudioHandler handler)
|
||||
|
||||
public static String formatUsername(String username, String discrim)
|
||||
{
|
||||
if(handler==null)
|
||||
return "No music playing\n\u23F9 "+progressBar(-1)+" "+volumeIcon(100);
|
||||
else if (!handler.isMusicPlaying())
|
||||
return "No music playing\n\u23F9 "+progressBar(-1)+" "+volumeIcon(handler.getPlayer().getVolume());
|
||||
else
|
||||
if(discrim == null || discrim.equals("0000"))
|
||||
{
|
||||
AudioTrack track = handler.getPlayer().getPlayingTrack();
|
||||
double progress = (double)track.getPosition()/track.getDuration();
|
||||
return (handler.getPlayer().isPaused()?"\u23F8":"\u25B6")
|
||||
+" "+progressBar(progress)
|
||||
+" `["+formatTime(track.getPosition()) + "/" + formatTime(track.getDuration()) +"]` "
|
||||
+volumeIcon(handler.getPlayer().getVolume());
|
||||
return username;
|
||||
}
|
||||
}//*/
|
||||
else
|
||||
{
|
||||
return username + "#" + discrim;
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatUsername(UserInfo userinfo)
|
||||
{
|
||||
return formatUsername(userinfo.username, userinfo.discrim);
|
||||
}
|
||||
|
||||
public static String formatUsername(User user)
|
||||
{
|
||||
return formatUsername(user.getName(), user.getDiscriminator());
|
||||
}
|
||||
|
||||
public static String progressBar(double percent)
|
||||
{
|
||||
String str = "";
|
||||
for(int i=0; i<12; i++)
|
||||
if(i == (int)(percent*12))
|
||||
str+="\uD83D\uDD18";
|
||||
str+="\uD83D\uDD18"; // 🔘
|
||||
else
|
||||
str+="▬";
|
||||
return str;
|
||||
@@ -69,12 +76,12 @@ public class FormatUtil {
|
||||
public static String volumeIcon(int volume)
|
||||
{
|
||||
if(volume == 0)
|
||||
return "\uD83D\uDD07";
|
||||
return "\uD83D\uDD07"; // 🔇
|
||||
if(volume < 30)
|
||||
return "\uD83D\uDD08";
|
||||
return "\uD83D\uDD08"; // 🔈
|
||||
if(volume < 70)
|
||||
return "\uD83D\uDD09";
|
||||
return "\uD83D\uDD0A";
|
||||
return "\uD83D\uDD09"; // 🔉
|
||||
return "\uD83D\uDD0A"; // 🔊
|
||||
}
|
||||
|
||||
public static String listOfTChannels(List<TextChannel> list, String query)
|
||||
@@ -91,7 +98,7 @@ public class FormatUtil {
|
||||
{
|
||||
String out = " Multiple voice channels found matching \""+query+"\":";
|
||||
for(int i=0; i<6 && i<list.size(); i++)
|
||||
out+="\n - "+list.get(i).getName()+" (ID:"+list.get(i).getId()+")";
|
||||
out+="\n - "+list.get(i).getAsMention()+" (ID:"+list.get(i).getId()+")";
|
||||
if(list.size()>6)
|
||||
out+="\n**And "+(list.size()-6)+" more...**";
|
||||
return out;
|
||||
@@ -109,6 +116,9 @@ public class FormatUtil {
|
||||
|
||||
public static String filter(String input)
|
||||
{
|
||||
return input.replace("@everyone", "@\u0435veryone").replace("@here", "@h\u0435re").trim();
|
||||
return input.replace("\u202E","")
|
||||
.replace("@everyone", "@\u0435veryone") // cyrillic letter e
|
||||
.replace("@here", "@h\u0435re") // cyrillic letter e
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2024 John Grosh <john.a.grosh@gmail.com>.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jagrosh.jmusicbot.utils;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.turbo.TurboFilter;
|
||||
import ch.qos.logback.core.spi.FilterReply;
|
||||
import org.slf4j.Marker;
|
||||
|
||||
/**
|
||||
* A TurboFilter, currently only used to suppress specific log messages from libraries.
|
||||
*
|
||||
* @author Michaili K. <git@michaili.dev>
|
||||
*/
|
||||
public class LogBackTurboFilter extends TurboFilter
|
||||
{
|
||||
@Override
|
||||
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t)
|
||||
{
|
||||
// Suppresses the auth token warning from the YoutubeAudioSourceManager
|
||||
// https://github.com/jagrosh/MusicBot/pull/1490#issuecomment-1974070225
|
||||
if (logger.getName().equals("com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAccessTokenTracker")
|
||||
&& format.equals("YouTube auth tokens can't be retrieved because email and password is not set in YoutubeAudioSourceManager, age restricted videos will throw exceptions.")
|
||||
) {
|
||||
return FilterReply.DENY;
|
||||
}
|
||||
|
||||
return FilterReply.NEUTRAL;
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,18 @@ package com.jagrosh.jmusicbot.utils;
|
||||
|
||||
import com.jagrosh.jmusicbot.JMusicBot;
|
||||
import com.jagrosh.jmusicbot.entities.Prompt;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import net.dv8tion.jda.core.OnlineStatus;
|
||||
import net.dv8tion.jda.core.entities.Game;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.entities.ApplicationInfo;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -39,7 +44,58 @@ public class OtherUtil
|
||||
+ "Current version: %s\n"
|
||||
+ "New Version: %s\n\n"
|
||||
+ "Please visit https://github.com/jagrosh/MusicBot/releases/latest to get the latest release.";
|
||||
private final static String WINDOWS_INVALID_PATH = "c:\\windows\\system32\\";
|
||||
|
||||
/**
|
||||
* gets a Path from a String
|
||||
* also fixes the windows tendency to try to start in system32
|
||||
* any time the bot tries to access this path, it will instead start in the location of the jar file
|
||||
*
|
||||
* @param path the string path
|
||||
* @return the Path object
|
||||
*/
|
||||
public static Path getPath(String path)
|
||||
{
|
||||
Path result = Paths.get(path);
|
||||
// special logic to prevent trying to access system32
|
||||
if(result.toAbsolutePath().toString().toLowerCase().startsWith(WINDOWS_INVALID_PATH))
|
||||
{
|
||||
try
|
||||
{
|
||||
result = Paths.get(new File(JMusicBot.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile().getPath() + File.separator + path);
|
||||
}
|
||||
catch(URISyntaxException ignored) {}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a resource from the jar as a string
|
||||
*
|
||||
* @param clazz class base object
|
||||
* @param name name of resource
|
||||
* @return string containing the contents of the resource
|
||||
*/
|
||||
public static String loadResource(Object clazz, String name)
|
||||
{
|
||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(clazz.getClass().getResourceAsStream(name))))
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
reader.lines().forEach(line -> sb.append("\r\n").append(line));
|
||||
return sb.toString().trim();
|
||||
}
|
||||
catch(IOException ignored)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads image data from a URL
|
||||
*
|
||||
* @param url url of image
|
||||
* @return inputstream of url
|
||||
*/
|
||||
public static InputStream imageFromUrl(String url)
|
||||
{
|
||||
if(url==null)
|
||||
@@ -51,32 +107,43 @@ public class OtherUtil
|
||||
urlConnection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36");
|
||||
return urlConnection.getInputStream();
|
||||
}
|
||||
catch(IOException|IllegalArgumentException e) {}
|
||||
catch(IOException | IllegalArgumentException ignore) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Game parseGame(String game)
|
||||
/**
|
||||
* Parses an activity from a string
|
||||
*
|
||||
* @param game the game, including the action such as 'playing' or 'watching'
|
||||
* @return the parsed activity
|
||||
*/
|
||||
public static Activity parseGame(String game)
|
||||
{
|
||||
if(game==null || game.trim().isEmpty() || game.trim().equalsIgnoreCase("default"))
|
||||
return null;
|
||||
String lower = game.toLowerCase();
|
||||
if(lower.startsWith("playing"))
|
||||
return Game.playing(game.substring(7).trim());
|
||||
return Activity.playing(makeNonEmpty(game.substring(7).trim()));
|
||||
if(lower.startsWith("listening to"))
|
||||
return Game.listening(game.substring(12).trim());
|
||||
return Activity.listening(makeNonEmpty(game.substring(12).trim()));
|
||||
if(lower.startsWith("listening"))
|
||||
return Game.listening(game.substring(9).trim());
|
||||
return Activity.listening(makeNonEmpty(game.substring(9).trim()));
|
||||
if(lower.startsWith("watching"))
|
||||
return Game.watching(game.substring(8).trim());
|
||||
return Activity.watching(makeNonEmpty(game.substring(8).trim()));
|
||||
if(lower.startsWith("streaming"))
|
||||
{
|
||||
String[] parts = game.substring(9).trim().split("\\s+", 2);
|
||||
if(parts.length == 2)
|
||||
{
|
||||
return Game.streaming(parts[1], "https://twitch.tv/"+parts[0]);
|
||||
return Activity.streaming(makeNonEmpty(parts[1]), "https://twitch.tv/"+parts[0]);
|
||||
}
|
||||
}
|
||||
return Game.playing(game);
|
||||
return Activity.playing(game);
|
||||
}
|
||||
|
||||
public static String makeNonEmpty(String str)
|
||||
{
|
||||
return str == null || str.isEmpty() ? "\u200B" : str;
|
||||
}
|
||||
|
||||
public static OnlineStatus parseStatus(String status)
|
||||
@@ -87,7 +154,14 @@ public class OtherUtil
|
||||
return st == null ? OnlineStatus.ONLINE : st;
|
||||
}
|
||||
|
||||
public static String checkVersion(Prompt prompt)
|
||||
public static void checkJavaVersion(Prompt prompt)
|
||||
{
|
||||
if(!System.getProperty("java.vm.name").contains("64"))
|
||||
prompt.alert(Prompt.Level.WARNING, "Java Version",
|
||||
"It appears that you may not be using a supported Java version. Please use 64-bit java.");
|
||||
}
|
||||
|
||||
public static void checkVersion(Prompt prompt)
|
||||
{
|
||||
// Get current version number
|
||||
String version = getCurrentVersion();
|
||||
@@ -97,11 +171,8 @@ public class OtherUtil
|
||||
|
||||
if(latestVersion!=null && !latestVersion.equals(version))
|
||||
{
|
||||
prompt.alert(Prompt.Level.WARNING, "Version", String.format(NEW_VERSION_AVAILABLE, version, latestVersion));
|
||||
prompt.alert(Prompt.Level.WARNING, "JMusicBot Version", String.format(NEW_VERSION_AVAILABLE, version, latestVersion));
|
||||
}
|
||||
|
||||
// Return the current version
|
||||
return version;
|
||||
}
|
||||
|
||||
public static String getCurrentVersion()
|
||||
@@ -140,4 +211,20 @@ public class OtherUtil
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bot JMusicBot is being run on is supported & returns the reason if it is not.
|
||||
* @return A string with the reason, or null if it is supported.
|
||||
*/
|
||||
public static String getUnsupportedBotReason(JDA jda)
|
||||
{
|
||||
if (jda.getSelfUser().getFlags().contains(User.UserFlag.VERIFIED_BOT))
|
||||
return "The bot is verified. Using JMusicBot in a verified bot is not supported.";
|
||||
|
||||
ApplicationInfo info = jda.retrieveApplicationInfo().complete();
|
||||
if (info.isBotPublic())
|
||||
return "\"Public Bot\" is enabled. Using JMusicBot as a public bot is not supported. Please disable it in the Developer Dashboard.";
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -14,4 +14,6 @@
|
||||
<appender-ref ref="Simple"/>
|
||||
</root>
|
||||
|
||||
<turboFilter class="com.jagrosh.jmusicbot.utils.LogBackTurboFilter" />
|
||||
|
||||
</configuration>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,4 @@
|
||||
/// START OF JMUSICBOT CONFIG ///
|
||||
/////////////////////////////////////////////////////////
|
||||
// Config for the JMusicBot //
|
||||
/////////////////////////////////////////////////////////
|
||||
@@ -13,23 +14,22 @@
|
||||
// If you don't know how to get a bot token, please see the guide here:
|
||||
// https://github.com/jagrosh/MusicBot/wiki/Getting-a-Bot-Token
|
||||
|
||||
token=BOT_TOKEN_HERE
|
||||
token = BOT_TOKEN_HERE
|
||||
|
||||
|
||||
// This sets the owner of the bot
|
||||
// This needs to be the owner's ID (a 17-18 digit number)
|
||||
// https://github.com/jagrosh/MusicBot/wiki/Finding-Your-User-ID
|
||||
|
||||
owner=0
|
||||
owner = 0 // OWNER ID
|
||||
|
||||
|
||||
// This sets the prefix for the bot
|
||||
// The prefix is used to control the commands
|
||||
// If you use !!, the play command will be !!play
|
||||
// If you do not set this, the prefix will be a mention of the bot (@Botname play)
|
||||
// If you make this blank, the bot will not use a prefix
|
||||
|
||||
prefix="@mention"
|
||||
prefix = "@mention"
|
||||
|
||||
|
||||
// If you set this, it modifies the default game of the bot
|
||||
@@ -39,13 +39,13 @@ prefix="@mention"
|
||||
// where X is the title. If you don't include an action, it will use the
|
||||
// default of "Playing"
|
||||
|
||||
game="DEFAULT"
|
||||
game = "DEFAULT"
|
||||
|
||||
|
||||
// If you set this, it will modify the default status of bot
|
||||
// Valid values: ONLINE IDLE DND INVISIBLE
|
||||
|
||||
status=ONLINE
|
||||
status = ONLINE
|
||||
|
||||
|
||||
// If you set this to true, the bot will list the title of the song it is currently playing in its
|
||||
@@ -58,23 +58,23 @@ songinstatus=false
|
||||
// If you set this, the bot will also use this prefix in addition to
|
||||
// the one provided above
|
||||
|
||||
altprefix="NONE"
|
||||
altprefix = "NONE"
|
||||
|
||||
|
||||
// If you set these, it will change the various emojis
|
||||
|
||||
success="🎶"
|
||||
warning="💡"
|
||||
error="🚫"
|
||||
loading="⌚"
|
||||
searching="🔎"
|
||||
success = "🎶"
|
||||
warning = "💡"
|
||||
error = "🚫"
|
||||
loading = "⌚"
|
||||
searching = "🔎"
|
||||
|
||||
|
||||
// If you set this, you change the word used to view the help.
|
||||
// For example, if you set the prefix to !! and the help to cmds, you would type
|
||||
// !!cmds to see the help text
|
||||
|
||||
help=help
|
||||
help = help
|
||||
|
||||
|
||||
// If you set this, the "nowplaying" command will show youtube thumbnails
|
||||
@@ -82,27 +82,41 @@ help=help
|
||||
// This is because refreshing the boxes causes the image to be reloaded
|
||||
// every time it refreshes.
|
||||
|
||||
npimages=false
|
||||
npimages = false
|
||||
|
||||
|
||||
// If you set this, the bot will not leave a voice channel after it finishes a queue.
|
||||
// Keep in mind that being connected to a voice channel uses additional bandwith,
|
||||
// so this option is not recommended if bandwidth is a concern.
|
||||
|
||||
stayinchannel=false
|
||||
stayinchannel = false
|
||||
|
||||
|
||||
// This sets the maximum amount of seconds any track loaded can be. If not set or set
|
||||
// to any number less than or equal to zero, there is no maximum time length. This time
|
||||
// restriction applies to songs loaded from any source.
|
||||
|
||||
maxtime=0
|
||||
maxtime = 0
|
||||
|
||||
|
||||
// This sets the ratio of users that must vote to skip the currently playing song.
|
||||
// Guild owners can define their own skip ratios, but this will be used if a guild
|
||||
// has not defined their own skip ratio.
|
||||
|
||||
skipratio = 0.55
|
||||
|
||||
|
||||
// This sets the amount of seconds the bot will stay alone on a voice channel until it
|
||||
// automatically leaves the voice channel and clears the queue. If not set or set
|
||||
// to any number less than or equal to zero, the bot won't leave when alone.
|
||||
|
||||
alonetimeuntilstop = 0
|
||||
|
||||
|
||||
// This sets an alternative folder to be used as the Playlists folder
|
||||
// This can be a relative or absolute path
|
||||
|
||||
playlistsfolder=Playlists
|
||||
playlistsfolder = "Playlists"
|
||||
|
||||
|
||||
// By default, the bot will DM the owner if the bot is running and a new version of the bot
|
||||
@@ -111,6 +125,75 @@ playlistsfolder=Playlists
|
||||
updatealerts=true
|
||||
|
||||
|
||||
// Changing this changes the lyrics provider
|
||||
// Currently available providers: "A-Z Lyrics", "Genius", "MusicMatch", "LyricsFreak"
|
||||
// At the time of writing, I would recommend sticking with A-Z Lyrics or MusicMatch,
|
||||
// as Genius tends to have a lot of non-song results and you might get something
|
||||
// completely unrelated to what you want.
|
||||
// If you are interested in contributing a provider, please see
|
||||
// https://github.com/jagrosh/JLyrics
|
||||
|
||||
lyrics.default = "A-Z Lyrics"
|
||||
|
||||
|
||||
// These settings allow you to configure custom aliases for all commands.
|
||||
// Multiple aliases may be given, separated by commas.
|
||||
//
|
||||
// Example 1: Giving command "play" the alias "p":
|
||||
// play = [ p ]
|
||||
//
|
||||
// Example 2: Giving command "search" the aliases "yts" and "find":
|
||||
// search = [ yts, find ]
|
||||
|
||||
aliases {
|
||||
// General commands
|
||||
settings = [ status ]
|
||||
|
||||
// Music commands
|
||||
lyrics = []
|
||||
nowplaying = [ np, current ]
|
||||
play = []
|
||||
playlists = [ pls ]
|
||||
queue = [ list ]
|
||||
remove = [ delete ]
|
||||
scsearch = []
|
||||
search = [ ytsearch ]
|
||||
shuffle = []
|
||||
skip = [ voteskip ]
|
||||
|
||||
// Admin commands
|
||||
prefix = [ setprefix ]
|
||||
setdj = []
|
||||
setskip = [ setskippercent, skippercent, setskipratio ]
|
||||
settc = []
|
||||
setvc = []
|
||||
|
||||
// DJ Commands
|
||||
forceremove = [ forcedelete, modremove, moddelete, modelete ]
|
||||
forceskip = [ modskip ]
|
||||
movetrack = [ move ]
|
||||
pause = []
|
||||
playnext = []
|
||||
queuetype = []
|
||||
repeat = []
|
||||
skipto = [ jumpto ]
|
||||
stop = [ leave ]
|
||||
volume = [ vol ]
|
||||
}
|
||||
|
||||
|
||||
// Transforms are used to modify specific play inputs and convert them to different kinds of inputs
|
||||
// These are quite complicated to use, and have limited use-cases, but in theory allow for rough
|
||||
// whitelists or blacklists, roundabout loading from some sources, and customization of how things are
|
||||
// requested.
|
||||
//
|
||||
// These are NOT EASY to set up, so if you want to use these, you'll need to look through the code
|
||||
// for how they work and what fields are needed. Also, it's possible this feature might get entirely
|
||||
// removed in the future if I find a better way to do this.
|
||||
|
||||
transforms = {}
|
||||
|
||||
|
||||
// If you set this to true, it will enable the eval command for the bot owner. This command
|
||||
// allows the bot owner to run arbitrary code from the bot's account.
|
||||
//
|
||||
@@ -122,4 +205,7 @@ updatealerts=true
|
||||
// DO NOT ENABLE THIS IF YOU DON'T KNOW WHAT THIS DOES OR HOW TO USE IT
|
||||
// IF SOMEONE ASKS YOU TO ENABLE THIS, THERE IS AN 11/10 CHANCE THEY ARE TRYING TO SCAM YOU
|
||||
|
||||
eval=false
|
||||
eval=false
|
||||
|
||||
|
||||
/// END OF JMUSICBOT CONFIG ///
|
||||
+3
-3
@@ -24,12 +24,12 @@ import static org.junit.Assert.*;
|
||||
*
|
||||
* @author John Grosh (john.a.grosh@gmail.com)
|
||||
*/
|
||||
public class QueueTests
|
||||
public class FairQueueTest
|
||||
{
|
||||
@Test
|
||||
public void differentIdentifierSize()
|
||||
{
|
||||
FairQueue<Q> queue = new FairQueue<>();
|
||||
FairQueue<Q> queue = new FairQueue<>(null);
|
||||
int size = 100;
|
||||
for(int i=0; i<size; i++)
|
||||
queue.add(new Q(i));
|
||||
@@ -39,7 +39,7 @@ public class QueueTests
|
||||
@Test
|
||||
public void sameIdentifierSize()
|
||||
{
|
||||
FairQueue<Q> queue = new FairQueue<>();
|
||||
FairQueue<Q> queue = new FairQueue<>(null);
|
||||
int size = 100;
|
||||
for(int i=0; i<size; i++)
|
||||
queue.add(new Q(0));
|
||||
Reference in new issue
Block a user