Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add support for minecraft server status widget #1713

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
- [Mvg Connection](#mvg-connection)
- [Custom search](#custom-search)
- [Rescuetime overview](#rescuetime-overview)
- [Minecraft Server](#minecraft-server)
- **[Self-Hosted Services Widgets](#self-hosted-services-widgets)**
- [System Info](#system-info)
- [Cron Monitoring](#cron-monitoring-health-checks)
Expand Down Expand Up @@ -1378,6 +1379,45 @@ Show an overview of how you have spent your time for the current day.

---

### Minecraft Server

Show minecraft server status

<p align="center"><img width="380" src="https://i.ibb.co/hcmd4Wf/minecraft-widget.png" /></p>

#### Options

**Field** | **Type** | **Required** | **Description**
--- | --- | --- | ---
**`title`** | `string` | _Optional_ | Display title for server uses server address if not set.
**`server`** | `string` | Required | Server hostname or ip(:port) will use srv records.
**`bedrock`** | `boolean` | _Optional_ | If server is a bedrock edition server. (default false)
**`showMods`** | `boolean` | _Optional_ | Display mod list if available
**`showPlayers`** | `boolean` | _Optional_ | Display player list if available
**`showPlugins`** | `boolean` | _Optional_ | Display plugin list if available

#### Example

```yaml
- type: minecraft-status
options:
title: Venity Network
server: play.venitymc.com
bedrock: true
showMods: true
showPlayers: true
showPlugins: true
```
#### Info

- **CORS**: 🟢 Enabled
- **Auth**: 🟢 Not Required
- **Price**: 🟢 Free
- **Host**: [Minecraft Server Status](https://mcsrvstat.us/)
- **Privacy**: _See [Minecraft Server Status FAQ](https://mcsrvstat.us/faq)_

---



## Self-Hosted Services Widgets
Expand Down
258 changes: 258 additions & 0 deletions src/components/Widgets/MinecraftStatus.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
<template>
<div class="minecraft-wrapper">
<a class="minecraft-link" :href="serverLinkEndpoint">
<h3 class="minecraft-title">{{ title }}</h3>
</a>
<div class="minecraft-icon-wrapper">
<img :src="icon" alt="server-icon" class="minecraft-icon" />
</div>
<div class="minecraft-content-wrapper">
<StatusIndicator class="status-indicator" :statusSuccess="status ? online : undefined"
:statusText="status ? statusTooltip : undefined" />
<span v-if="title != server" class="minecraft-server">{{ server }}<br /></span>
<span v-if="!online" class="minecraft-status">Server Offline</span>
<span v-if="online" class="minecraft-version">
{{ software || (bedrock ? "Bedrock" : "Minecraft") }} {{ version }}
</span>
<ul v-if="online" class="minecraft-motd">
<li v-for="(line, idx) in motd" :key="idx">{{ line }}</li>
</ul>
<div v-if="showPlayers" class="player-list">
<span>{{ onlinePlayers }}/{{ maxPlayers }} Players</span>
<ul>
<li v-for="{ name, uuid } in players" :key="uuid">
<a :href="playerLinkEndpoint(uuid)">
<img :src="playerIconEndpoint(uuid)" :alt="`${name}'s Head'`"/>{{ name }}
</a>
</li>
</ul>
</div>
<div v-if="showMods" class="mod-list">
<span>{{ mods.length }} Mods</span>
<ul>
<li v-for="{ name, version } in mods" :key="name">
{{ name }}={{ version }}
</li>
</ul>
</div>
<div v-if="showPlugins" class="plugin-list">
<span>{{ plugins.length }} Plugins</span>
<ul>
<li v-for="{ name, version } in plugins" :key="name">
{{ name }}={{ version }}
</li>
</ul>
</div>
</div>
</div>
</template>

<script>
import WidgetMixin from '@/mixins/WidgetMixin';
import { widgetApiEndpoints } from '@/utils/defaults';
import StatusIndicator from '@/components/LinkItems/StatusIndicator.vue';

export default {
mixins: [WidgetMixin],
components: {
StatusIndicator,
},
data() {
return {
status: false,
online: false,
ip: '',
port: 0,
hostname: '',
iconData: null,
motd: null,
version: null,
software: null,
gamemode: null,
mods: [],
plugins: [],
players: [],
onlinePlayers: null,
maxPlayers: null,
};
},
computed: {
title() {
return this.options.title || this.options.server || this.error('options.server not set');
},
alt() {
return this.title;
},
icon() {
return `https://api.mcsrvstat.us/icon/${this.server}`;
},
server() {
return this.options.server || this.error('options.server not set');
},
bedrock() {
return this.options.bedrock === true;
},
statusTooltip() {
if (!this.status) {
return 'Loading...';
}
if (!this.online) {
return `${this.server} Offline`;
}
return `${this.onlinePlayers}/${this.maxPlayers} Online`;
},
showPlayers() {
return this.options.showPlayers && this.players.length > 0;
},
showMods() {
return this.options.showMods && this.mods.length > 0;
},
showPlugins() {
return this.options.showPlugins && this.plugins.length > 0;
},
endpoint() {
return `${widgetApiEndpoints.minecraftStatus}${this.bedrock ? 'bedrock/' : ''}3/${this.server}`;
},
serverLinkEndpoint() {
return `${widgetApiEndpoints.minecraftServerLink}${this.server}`;
},
},
methods: {
playerIconEndpoint(uuid) {
return `${widgetApiEndpoints.minecraftPlayerIcon}${uuid}/32.png`;
},
playerLinkEndpoint(uuid) {
return `${widgetApiEndpoints.minecraftPlayerLink}${uuid}`;
},
/* Make GET request to McSrvStat.US API endpoint */
fetchData() {
this.startLoading();
fetch(this.endpoint)
.then(response => {
if (!response.ok) {
this.error('Network response was not ok');
}
return response.json();
})
.then(data => {
this.processData(data);
})
.catch(dataFetchError => {
this.error('Unable to fetch data', dataFetchError);
})
.finally(() => {
this.finishLoading();
});
},
/* Assign data variables to the returned data */
processData(data) {
this.online = data.online;
this.ip = data.ip;
this.port = data.port;
this.hostname = data.hostname;
if (this.online) {
this.version = data.version;
this.iconData = data.icon;
this.software = data.software;
this.gamemode = data.gamemode;
this.motd = data.motd.clean || [];
this.players = data.players.list || [];
this.onlinePlayers = data.players.online;
this.maxPlayers = data.players.max;
this.mods = data.mods || [];
this.plugins = data.plugins || [];
}
this.status = true;
},
update() {
this.fetchData();
},
},
};
</script>

<style scoped lang="scss">

.minecraft-wrapper {
margin-top: -1em;
display: grid;
justify-content: center;
grid-template-columns: 64px 1fr;
color: var(--widget-text-color);
padding-top: 0.5rem;

.minecraft-link {
grid-column: 1 / span 2;
text-decoration: none;

.minecraft-title {
font-size: 1.2rem;
margin: 0.25rem auto;
border-bottom: 1px solid var(--widget-text-color);
color: var(--widget-text-color);
}
}

.minecraft-icon {
display: flex;
width: 100%;
max-width: 64px;
margin: 0.25rem auto 0;
padding-top: 0.5rem;
border-radius: var(--curve-factor);
}

.minecraft-content-wrapper {
position: relative;
padding: 0.5rem;

ul.minecraft-motd {
border-top: 1px dashed var(--widget-text-color);
list-style-type: none;
padding: 0.5rem 0;
margin: 0.5rem 0 0 0;
}

.player-list,
.mod-list,
.plugin-list {
span {
font-size: 1.2rem;
border-top: 1px dashed var(--widget-text-color);
padding: 0.25rem 0;
display: block;
}
ul {
list-style-type: '- ';
padding: 0;
margin: 0;
li {
padding: 1rem 0;
margin: 0;
}
}
}

.player-list {
ul {
li {
padding: 0;
list-style-type: none;
img {
width: 1rem;
height: 1rem;
float: left;
position: relative;
margin-right: 1em;
}
}
}
}
}
}
</style>
<style lang="scss">
.minecraft-alt-tt {
min-width: 20rem;
}
</style>
1 change: 1 addition & 0 deletions src/components/Widgets/WidgetBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const COMPAT = {
iframe: 'IframeWidget',
image: 'ImageWidget',
joke: 'Jokes',
'minecraft-status': 'MinecraftStatus',
'mullvad-status': 'MullvadStatus',
mvg: 'Mvg',
linkding: 'Linkding',
Expand Down
4 changes: 4 additions & 0 deletions src/utils/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ module.exports = {
holidays: 'https://kayaposoft.com/enrico/json/v2.0/?action=getHolidaysForDateRange',
jokes: 'https://v2.jokeapi.dev/joke/',
news: 'https://api.currentsapi.services/v1/latest-news',
minecraftPlayerIcon: 'https://mc-heads.net/avatar/',
minecraftPlayerLink: 'https://minecraftuuid.com/?search=',
minecraftServerLink: 'https://mcsrvstat.us/server/',
minecraftStatus: 'https://api.mcsrvstat.us/',
mullvad: 'https://am.i.mullvad.net/json',
mvg: 'https://www.mvg.de/api/fib/v2/',
publicIp: 'https://ipapi.co/json',
Expand Down