Initial commit
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* 让流量消失
|
||||
*/
|
||||
|
||||
namespace plugin\fun\bandwidth_waste;
|
||||
|
||||
use app\Plugin;
|
||||
|
||||
class App extends Plugin
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
return $this->view();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
{extend name="common/plugin_layout" /}
|
||||
{block name="title"}{$plugin.title} - {:config_get('title')}{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
.stat {
|
||||
width: 100%;
|
||||
column-gap: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
.stat-title {
|
||||
white-space: nowrap;
|
||||
opacity: .6;
|
||||
}
|
||||
.stat-value {
|
||||
white-space: nowrap;
|
||||
grid-column-start: 1;
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
line-height: 2.5rem
|
||||
}
|
||||
</style>
|
||||
<div class="container-xl" id="app">
|
||||
<div class="col-sm-12 col-md-10 col-xl-8 center-block">
|
||||
<div class="card card-preview">
|
||||
<div class="card-inner mt-3">
|
||||
<div class="nya-title nk-ibx-action-item progress-rating">
|
||||
<span class="nk-menu-text font-weight-bold">让流量消失</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">下载链接</label>
|
||||
<div class="form-control-wrap">
|
||||
<input type="text" v-model="set.input" placeholder="下载链接" class="form-control" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">线程</label>
|
||||
<div class="form-control-wrap number-spinner-wrap">
|
||||
<button class="btn btn-icon btn-outline-primary number-spinner-btn number-minus" @click="if(set.thread>1)set.thread--"><em class="icon ni ni-minus"></em></button>
|
||||
<input type="number" class="form-control number-spinner" min="1" max="32" v-model="set.thread">
|
||||
<button class="btn btn-icon btn-outline-primary number-spinner-btn number-plus"><em class="icon ni ni-plus" @click="if(set.thread<32)set.thread++"></em></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="preview-block">
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" v-model="set.infinite" id="customSwitch2">
|
||||
<label class="custom-control-label" for="customSwitch2">无限循环</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-dim btn-outline-secondary btn-block card-link" @click="run">
|
||||
{{set.status?'停止':'开始'}}
|
||||
</button>
|
||||
<div class="row mt-4">
|
||||
<div class="col-sm-12 col-md-4 border stat">
|
||||
<div class="text-dark"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-15 w-15 float-right pt-3"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path></svg></div>
|
||||
<div class="stat-title">已消失的流量</div>
|
||||
<div class="stat-value">{{changeFilesize(waste)}}</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-4 border stat">
|
||||
<div class="text-info"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-15 w-15 float-right pt-3"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg></div>
|
||||
<div class="stat-title">每秒实时流量</div>
|
||||
<div class="stat-value text-info">{{speed}}</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-4 border stat">
|
||||
<div class="text-dark"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-15 w-15 float-right pt-3"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg></div>
|
||||
<div class="stat-title">运行时长</div>
|
||||
<div class="stat-value">{{secToTime(spend)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card card-preview">
|
||||
<div class="card-inner">
|
||||
<h6><em class="icon ni ni-info"></em> 工具说明</h6>
|
||||
<div class="accordion-inner">
|
||||
<p>此工具可以以浪费的形式消耗你的流量</p>
|
||||
<p>注意:无法请求跨域链接</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdn_cdnjs}vue/2.6.14/vue.min.js"></script>
|
||||
<script src="{$cdn_cdnjs}axios/0.26.0/axios.min.js"></script>
|
||||
<script>
|
||||
var errors = null
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
set: {
|
||||
input: 'https://cachefly.cachefly.net/100mb.test',
|
||||
output: '',
|
||||
infinite: true,
|
||||
status: false,
|
||||
thread: 1,
|
||||
},
|
||||
tasks: [],
|
||||
speed: '0.00B/s',
|
||||
spend: 0,
|
||||
waste: 0,
|
||||
timer: null,
|
||||
cancelSource: axios.CancelToken.source()
|
||||
},
|
||||
watch: {
|
||||
async 'set.status'(newVal) {
|
||||
if (newVal) {
|
||||
this.cancelSource = axios.CancelToken.source()
|
||||
this.timer = setInterval(() => {
|
||||
this.speed = this.changeDownloadSpeed(this.tasks.reduce(function (prev, curr) {
|
||||
return prev + curr;
|
||||
}, 0));
|
||||
this.spend++
|
||||
}, 1000)
|
||||
do {
|
||||
await new Promise(resolve => {
|
||||
let task = []
|
||||
for (let i = 0; i < this.set.thread; i++) {
|
||||
task.push(this.download(Math.random().toString(36).substr(2, 10)))
|
||||
}
|
||||
Promise.all(task).finally(resolve)
|
||||
})
|
||||
} while (this.set.status && this.set.infinite)
|
||||
} else {
|
||||
clearInterval(this.timer)
|
||||
this.cancelSource.cancel()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
run() {
|
||||
this.set.status = !this.set.status
|
||||
},
|
||||
download(id) {
|
||||
let loaded = 0
|
||||
let speed = 0
|
||||
let timestamp = new Date().getTime()
|
||||
let that = this
|
||||
const index = this.tasks.push(speed) - 1
|
||||
return axios.request({
|
||||
url: this.set.input,
|
||||
params: {
|
||||
[id]: id,
|
||||
},
|
||||
cancelToken: this.cancelSource.token,
|
||||
onDownloadProgress: function (progressEvent) {
|
||||
// 处理原生进度事件
|
||||
const now = new Date().getTime();
|
||||
speed = (progressEvent.loaded - loaded) / (now - timestamp) * 1000
|
||||
that.tasks[index] = speed
|
||||
that.waste += progressEvent.loaded - loaded
|
||||
loaded = progressEvent.loaded
|
||||
timestamp = now
|
||||
},
|
||||
}).catch(e => {
|
||||
if (!axios.isCancel(e)) {
|
||||
layer.msg(e.message, {icon:2})
|
||||
this.set.status = false
|
||||
}
|
||||
}).finally(() => {
|
||||
delete that.tasks[index]
|
||||
})
|
||||
},
|
||||
secToTime(s) {
|
||||
let t = '';
|
||||
if (s > -1) {
|
||||
let hour = Math.floor(s / 3600)
|
||||
let min = Math.floor(s / 60) % 60
|
||||
let sec = s % 60
|
||||
if (hour > 0) {
|
||||
if (hour < 10) {
|
||||
t += '0'
|
||||
}
|
||||
t = hour + "h"
|
||||
}
|
||||
if (hour > 0 || min > 0) {
|
||||
if (min < 10) {
|
||||
t += '0'
|
||||
}
|
||||
t += min + "m"
|
||||
}
|
||||
if (sec < 10) {
|
||||
t += '0'
|
||||
}
|
||||
t += sec + 's'
|
||||
}
|
||||
return t
|
||||
},
|
||||
changeFilesize: (filesize) => {
|
||||
filesize = parseInt(filesize);
|
||||
let size = "";
|
||||
if (filesize === 0) {
|
||||
size = "0.00 B"
|
||||
} else if (filesize < 1024) { //小于1KB,则转化成B
|
||||
size = filesize.toFixed(2) + " B"
|
||||
} else if (filesize < 1024 * 1024) { //小于1MB,则转化成KB
|
||||
size = (filesize / 1024).toFixed(2) + " KB"
|
||||
} else if (filesize < 1024 * 1024 * 1024) { //小于1GB,则转化成MB
|
||||
size = (filesize / (1024 * 1024)).toFixed(2) + " MB"
|
||||
} else { //其他转化成GB
|
||||
size = (filesize / (1024 * 1024 * 1024)).toFixed(2) + " GB"
|
||||
}
|
||||
return size;
|
||||
},
|
||||
changeDownloadSpeed(filesize) {
|
||||
filesize = this.changeFilesize(filesize);
|
||||
return filesize.replace(/\s([K|M|G|B]*)B{0,1}/, '$1/s')
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
{/block}
|
||||
Reference in New Issue
Block a user