update
This commit is contained in:
parent
ee12d11709
commit
28a9fdcdc8
|
|
@ -121,6 +121,5 @@ data/close.pl
|
|||
ssl/input.pl
|
||||
data/datadir.pl
|
||||
data/502Task.pl
|
||||
plugins/qbittorrent/
|
||||
data/default.pl
|
||||
data/backup.pl
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Mr Chen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# mw-qbittorrent
|
||||
mdserver-web|qbittorrent管理
|
||||
|
||||
|
||||
### 安装过程
|
||||
|
||||
```
|
||||
* 先进行压缩 `cd mw-qbittorrent && zip qbittorrent.zip -r ./* `
|
||||
* 在mdserver-web点击`添加插件`
|
||||
```
|
||||
|
||||
### 截图
|
||||
|
||||
[](/screenshot/ss1.jpg)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
[db]
|
||||
DB_HOST = 127.0.0.1
|
||||
DB_PORT = 3306
|
||||
DB_USER = qbittorrent
|
||||
DB_PASS = qbittorrent
|
||||
DB_NAME = qbittorrent
|
||||
|
||||
[qb]
|
||||
QB_HOST = 127.0.0.1
|
||||
QB_PORT = 8080
|
||||
QB_USER = admin
|
||||
QB_PWD = adminadmin
|
||||
|
||||
|
||||
[file]
|
||||
FILE_TO={$SERVER_PATH}/tmp
|
||||
FILE_TRANSFER_TO={$SERVER_PATH}/tmp
|
||||
FILE_OWN=www
|
||||
FILE_GROUP=www
|
||||
FILE_ENC_SWITCH=0
|
||||
FILE_API_URL=http://v.demo.com/api/key/id/{$KEY}
|
||||
FILE_ASYNC_SWITCH=0
|
||||
|
||||
[task]
|
||||
TASK_SIZE_LIMIT=1
|
||||
TASK_RATE=4
|
||||
TASK_COMPLETED_RATE=10
|
||||
TASK_DEBUG=0
|
||||
|
||||
[setting]
|
||||
QUEUE_SWITCH = 1
|
||||
MAX_ACTIVE_UPLOADS = 1
|
||||
MAX_ACTIVE_TORRENTS = 10
|
||||
MAX_ACTIVE_DOWNLOADS = 10
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
CREATE TABLE `pl_hash_list` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`name` text NOT NULL,
|
||||
`info_hash` varchar(40) NOT NULL,
|
||||
`length` bigint(20) NOT NULL,
|
||||
`status` char(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`create_time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `info_hash` (`info_hash`),
|
||||
KEY `create_time` (`create_time`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `pl_hash_file` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`pid` bigint(20) NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`m3u8` varchar(40) NOT NULL,
|
||||
`key` char(40) NULL DEFAULT '',
|
||||
`length` bigint(20) NULL DEFAULT 0,
|
||||
`create_time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `create_time` (`create_time`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `pl_hash_queue` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`info_hash` char(40) NOT NULL,
|
||||
`length` bigint(20) NOT NULL DEFAULT 0,
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `length`(`length`) USING BTREE,
|
||||
KEY `created_at` (`created_at`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1,23 @@
|
|||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('qbittorrent');">服务</p>
|
||||
<p onclick="pluginInitD('qbittorrent');">自启动</p>
|
||||
<p onclick="pluginConfig('qbittorrent', '','get_sql');" title="手动导入SQL">导入SQL</p>
|
||||
<p onclick="pluginConfig('qbittorrent');">配置</p>
|
||||
<p onclick="pluginConfig('qbittorrent', '','rsync_shell');" title="异步脚本">异步脚本</p>
|
||||
<p onclick="pluginLogs('qbittorrent','','get_run_Log', 25);">日志</p>
|
||||
<p onclick="qbList();">列表</p>
|
||||
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
pluginService('qbittorrent');
|
||||
$.getScript( "/plugins/file?name=qbittorrent&f=js/qbittorrent.js");
|
||||
</script>
|
||||
|
|
@ -0,0 +1,357 @@
|
|||
# coding: utf-8
|
||||
|
||||
import time
|
||||
import random
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import public
|
||||
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
|
||||
sys.path.append('/usr/local/lib/python2.7/site-packages')
|
||||
|
||||
|
||||
app_debug = False
|
||||
if public.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'qbittorrent'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return public.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return public.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
if app_debug:
|
||||
return '/tmp/' + getPluginName()
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, public.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, public.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getSqlFile():
|
||||
file = getPluginDir() + "/conf/qb.sql"
|
||||
return file
|
||||
|
||||
|
||||
def getRsyncShell():
|
||||
file = getServerDir() + "/workers/rsync.sh"
|
||||
return file
|
||||
|
||||
|
||||
def getConf():
|
||||
file = getServerDir() + "/qb.conf"
|
||||
return file
|
||||
|
||||
|
||||
def getRunLog():
|
||||
file = getServerDir() + "/logs.pl"
|
||||
return file
|
||||
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = public.getServerDir()
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
return content
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
ddir = getServerDir() + '/workers'
|
||||
if not os.path.exists(ddir):
|
||||
sdir = getPluginDir() + '/workers'
|
||||
public.execShell('cp -rf ' + sdir + ' ' + getServerDir())
|
||||
|
||||
cfg = getServerDir() + '/qb.conf'
|
||||
if not os.path.exists(cfg):
|
||||
cfg_tpl = getPluginDir() + '/conf/qb.conf'
|
||||
content = public.readFile(cfg_tpl)
|
||||
content = contentReplace(content)
|
||||
public.writeFile(cfg, content)
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = public.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
public.writeFile(file_bin, content)
|
||||
public.execShell('chmod +x ' + file_bin)
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def status():
|
||||
data = public.execShell(
|
||||
"ps -ef|grep qbittorrent_worker | grep -v grep | awk '{print $2}'")
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def start():
|
||||
|
||||
cmd = "ps -ef | grep qbittorrent-nox |grep -v grep |awk '{print $2}'"
|
||||
ret = public.execShell(cmd)
|
||||
if ret[0] == '':
|
||||
public.execShell('qbittorrent-nox -d')
|
||||
|
||||
file = initDreplace()
|
||||
|
||||
data = public.execShell(file + ' start')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def stop():
|
||||
file = initDreplace()
|
||||
data = public.execShell(file + ' stop')
|
||||
# cmd = "ps -ef | grep qbittorrent-nox |grep -v grep |awk '{print $2}' | xargs kill"
|
||||
# public.execShell(cmd)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def restart():
|
||||
file = initDreplace()
|
||||
data = public.execShell(file + ' restart')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def reload():
|
||||
file = initDreplace()
|
||||
data = public.execShell(file + ' reload')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if not app_debug:
|
||||
if public.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
import shutil
|
||||
if not app_debug:
|
||||
if public.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mysql_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(mysql_bin, initd_bin)
|
||||
public.execShell('chmod +x ' + initd_bin)
|
||||
public.execShell('chkconfig --add ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
if not app_debug:
|
||||
if public.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
public.execShell('chkconfig --del ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def matchData(reg, content):
|
||||
tmp = re.search(reg, content).groups()
|
||||
return tmp[0]
|
||||
|
||||
|
||||
def getDbConfInfo():
|
||||
cfg = getConf()
|
||||
content = public.readFile(cfg)
|
||||
data = {}
|
||||
data['DB_HOST'] = matchData("DB_HOST\s*=\s(.*)", content)
|
||||
data['DB_USER'] = matchData("DB_USER\s*=\s(.*)", content)
|
||||
data['DB_PORT'] = matchData("DB_PORT\s*=\s(.*)", content)
|
||||
data['DB_PASS'] = matchData("DB_PASS\s*=\s(.*)", content)
|
||||
data['DB_NAME'] = matchData("DB_NAME\s*=\s(.*)", content)
|
||||
return data
|
||||
|
||||
|
||||
def getQbConf():
|
||||
cfg = getConf()
|
||||
content = public.readFile(cfg)
|
||||
data = {}
|
||||
data['QB_HOST'] = matchData("QB_HOST\s*=\s(.*)", content)
|
||||
data['QB_PORT'] = matchData("QB_PORT\s*=\s(.*)", content)
|
||||
data['QB_USER'] = matchData("QB_USER\s*=\s(.*)", content)
|
||||
data['QB_PWD'] = matchData("QB_PWD\s*=\s(.*)", content)
|
||||
return data
|
||||
|
||||
|
||||
def pMysqlDb():
|
||||
data = getDbConfInfo()
|
||||
conn = mysql.mysql()
|
||||
conn.setHost(data['DB_HOST'])
|
||||
conn.setUser(data['DB_USER'])
|
||||
conn.setPwd(data['DB_PASS'])
|
||||
conn.setPort(int(data['DB_PORT']))
|
||||
conn.setDb(data['DB_NAME'])
|
||||
return conn
|
||||
|
||||
|
||||
def pQbClient():
|
||||
from qbittorrent import Client
|
||||
info = getQbConf()
|
||||
url = 'http://' + info['QB_HOST'] + ':' + info['QB_PORT'] + '/'
|
||||
qb = Client(url)
|
||||
qb.login(info['QB_USER'], info['QB_PWD'])
|
||||
return qb
|
||||
|
||||
|
||||
def getQbUrl():
|
||||
info = getQbConf()
|
||||
url = 'http://' + info['QB_HOST'] + ':' + info['QB_PORT'] + '/'
|
||||
return public.returnJson(True, 'ok', url)
|
||||
|
||||
|
||||
def qbList():
|
||||
args = getArgs()
|
||||
# data = checkArgs(args, ['type'])
|
||||
# if not data[0]:
|
||||
# return data[1]
|
||||
args_type = ''
|
||||
if 'type' in args:
|
||||
args_type = args['type']
|
||||
|
||||
f = ['downloading', 'completed']
|
||||
tfilter = ''
|
||||
if args_type in f:
|
||||
tfilter = args['type']
|
||||
try:
|
||||
qb = pQbClient()
|
||||
torrents = qb.torrents(filter=tfilter)
|
||||
data = {}
|
||||
data['type'] = tfilter
|
||||
data['torrents'] = torrents
|
||||
return public.returnJson(True, 'ok', data)
|
||||
except Exception as e:
|
||||
return public.returnJson(False, str(e))
|
||||
|
||||
|
||||
def qbDel():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['hash'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
qb = pQbClient()
|
||||
data = qb.delete(args['hash'])
|
||||
return public.returnJson(True, '操作成功!', data)
|
||||
|
||||
|
||||
def qbAdd():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['hash'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
url = 'magnet:?xt=urn:btih:' + args['hash']
|
||||
qb = pQbClient()
|
||||
data = qb.download_from_link(url)
|
||||
return public.returnJson(True, '操作成功!', data)
|
||||
|
||||
|
||||
def test():
|
||||
qb = pQbClient()
|
||||
# magnet_link = "magnet:?xt=urn:btih:57a0ec92a61c60585f1b7a206a75798aa69285a5"
|
||||
# print qb.download_from_link(magnet_link)
|
||||
torrents = qb.torrents(filter='downloading')
|
||||
for torrent in torrents:
|
||||
print public.returnJson(False, torrent)
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print status()
|
||||
elif func == 'start':
|
||||
print start()
|
||||
elif func == 'stop':
|
||||
print stop()
|
||||
elif func == 'restart':
|
||||
print restart()
|
||||
elif func == 'reload':
|
||||
print reload()
|
||||
elif func == 'initd_status':
|
||||
print initdStatus()
|
||||
elif func == 'initd_install':
|
||||
print initdInstall()
|
||||
elif func == 'initd_uninstall':
|
||||
print initdUinstall()
|
||||
elif func == 'get_sql':
|
||||
print getSqlFile()
|
||||
elif func == 'rsync_shell':
|
||||
print getRsyncShell()
|
||||
elif func == 'conf':
|
||||
print getConf()
|
||||
elif func == 'get_run_Log':
|
||||
print getRunLog()
|
||||
elif func == 'qb_list':
|
||||
print qbList()
|
||||
elif func == 'qb_del':
|
||||
print qbDel()
|
||||
elif func == 'qb_add':
|
||||
print qbAdd()
|
||||
elif func == 'qb_url':
|
||||
print getQbUrl()
|
||||
elif func == 'test':
|
||||
print test()
|
||||
else:
|
||||
print 'error'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"sort": 7,
|
||||
"ps": "一个新的轻量级BitTorrent客户端",
|
||||
"name": "qbittorrent",
|
||||
"title": "qBittorrent",
|
||||
"shell": "install.sh",
|
||||
"versions":["4.1.5"],
|
||||
"updates":["4.1.5"],
|
||||
"tip": "soft",
|
||||
"checks": "server/qbittorrent",
|
||||
"path": "server/qbittorrent",
|
||||
"display": 1,
|
||||
"author": "Zend",
|
||||
"date": "2017-04-01",
|
||||
"home": "https://www.qbittorrent.org",
|
||||
"type": 0,
|
||||
"pid": "5"
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/sh
|
||||
# chkconfig: 2345 55 25
|
||||
# description: qbittorrent Service
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: qbittorrent
|
||||
# Required-Start: $all
|
||||
# Required-Stop: $all
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: starts qbittorrent
|
||||
# Description: starts the MDW-Web
|
||||
### END INIT INFO
|
||||
|
||||
|
||||
qb_start(){
|
||||
cd {$SERVER_PATH}/qbittorrent/workers
|
||||
nohup python qbittorrent_worker.py > {$SERVER_PATH}/qbittorrent/logs.pl 2>&1 &
|
||||
echo "qbittorrent started"
|
||||
}
|
||||
|
||||
qb_stop(){
|
||||
echo "Stopping ..."
|
||||
#ps -ef | grep qbittorrent-nox-bin | grep -v grep | awk '{print $2}' | xargs kill -9
|
||||
ps -ef | grep "qbittorrent_worker.py" | grep -v grep | awk '{print $2}' | xargs kill -9
|
||||
echo "qbittorrent stopped"
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
qb_start
|
||||
;;
|
||||
stop)
|
||||
qb_stop
|
||||
;;
|
||||
restart|reload)
|
||||
qb_stop
|
||||
sleep 0.3
|
||||
qb_start
|
||||
;;
|
||||
*)
|
||||
echo "Please use start or stop as first argument"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/bt_install.pl
|
||||
|
||||
#https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
||||
|
||||
Install_mac_ffmpeg()
|
||||
{
|
||||
if [ ! -f $serverPath/source/ffmpeg-20180702-3c4af57-macos64-static.zip ];then
|
||||
wget -O $serverPath/source/ffmpeg-20180702-3c4af57-macos64-static.zip https://ffmpeg.zeranoe.com/builds/macos64/static/ffmpeg-20180702-3c4af57-macos64-static.zip
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/lib/ffmpeg ];then
|
||||
cd $serverPath/source && tar -xvf $serverPath/source/ffmpeg-20180702-3c4af57-macos64-static.zip
|
||||
mv ffmpeg-20180702-3c4af57-macos64-static $serverPath/lib/ffmpeg
|
||||
fi
|
||||
}
|
||||
|
||||
Install_linux_ffmpeg()
|
||||
{
|
||||
if [ ! -f $serverPath/source/ffmpeg-release-amd64-static.tar.xz ];then
|
||||
wget -O $serverPath/source/ffmpeg-release-amd64-static.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/lib/ffmpeg ];then
|
||||
cd $serverPath/source && tar -xvf $serverPath/source/ffmpeg-release-amd64-static.tar.xz
|
||||
mv ffmpeg-4.1.2-amd64-static $serverPath/lib/ffmpeg
|
||||
fi
|
||||
}
|
||||
|
||||
Install_qbittorrent()
|
||||
{
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
Install_mac_ffmpeg
|
||||
else
|
||||
yum -y install qbittorrent-nox
|
||||
#qbittorrent-nox -d
|
||||
|
||||
Install_linux_ffmpeg
|
||||
fi
|
||||
|
||||
pip install python-qbittorrent==0.2
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/qbittorrent
|
||||
|
||||
QB_DIR=${serverPath}/source/qbittorrent
|
||||
mkdir -p $QB_DIR
|
||||
|
||||
echo '4.1.5' > $serverPath/qbittorrent/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_qbittorrent()
|
||||
{
|
||||
rm -rf $serverPath/qbittorrent
|
||||
which yum && yum -y remove qbittorrent-nox
|
||||
echo "Uninstall_qbittorrent" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_qbittorrent
|
||||
else
|
||||
Uninstall_qbittorrent
|
||||
fi
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
function qbPostMin(method, args, callback){
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'qbittorrent';
|
||||
req_data['func'] = method;
|
||||
|
||||
if (typeof(args) != 'undefined' && args!=''){
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function qbPost(method, args, callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
qbPostMin(method,args,function(data){
|
||||
layer.close(loadT);
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showHideHash(obj){
|
||||
var a = "glyphicon-eye-open";
|
||||
var b = "glyphicon-eye-close";
|
||||
|
||||
if($(obj).hasClass(a)){
|
||||
$(obj).removeClass(a).addClass(b);
|
||||
$(obj).prev().text($(obj).prev().attr('data-pw'))
|
||||
} else{
|
||||
$(obj).removeClass(b).addClass(a);
|
||||
$(obj).prev().text($(obj).attr('data-pw'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function copyText(password){
|
||||
var clipboard = new ClipboardJS('#bt_copys');
|
||||
clipboard.on('success', function (e) {
|
||||
layer.msg('复制成功',{icon:1,time:2000});
|
||||
});
|
||||
|
||||
clipboard.on('error', function (e) {
|
||||
layer.msg('复制失败,浏览器不兼容!',{icon:2,time:2000});
|
||||
});
|
||||
$("#bt_copys").attr('data-clipboard-text',password);
|
||||
$("#bt_copys").click();
|
||||
}
|
||||
|
||||
function getLocalTime(nS) {
|
||||
return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/,' ');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function qbAdd(){
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '添加资源',
|
||||
area: '400px',
|
||||
content:"<div class='bt-form pd20 pb70 c6'>\
|
||||
<div class='version line'>\
|
||||
<div><input class='bt-input-text mr5 outline_no' type='text' id='qb_hash' name='qb_hash' style='height: 28px; border-radius: 3px;width: 350px;' placeholder='hash'></div>\
|
||||
</div>\
|
||||
<div class='bt-form-submit-btn'>\
|
||||
<button type='button' id='qb_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
|
||||
<button type='button' id='qb_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
|
||||
</div>\
|
||||
</div>"
|
||||
});
|
||||
|
||||
$('#qb_close').click(function(){
|
||||
layer.close(loadOpen);
|
||||
});
|
||||
|
||||
$('#qb_ok').click(function(){
|
||||
var hash = $('#qb_hash').val();
|
||||
qbPost('qb_add', {hash:hash}, function(data){
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
showMsg(rdata.msg, function(){
|
||||
qbList();
|
||||
},{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
layer.close(loadOpen);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function qbDel(hash){
|
||||
qbPost('qb_del', {hash:hash}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function qbListFind(){
|
||||
var qbs = $('#qb_selected').val();
|
||||
if ( qbs == '0' ){
|
||||
qbList();
|
||||
} else {
|
||||
qbList(qbs);
|
||||
}
|
||||
}
|
||||
|
||||
function openAdminUrl(){
|
||||
qbPost('qb_url', '', function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
window.open(rdata.data);
|
||||
});
|
||||
}
|
||||
|
||||
function qbList(search){
|
||||
var _data = {};
|
||||
_data['test'] ='yes';
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['type'] = search;
|
||||
}
|
||||
|
||||
qbPost('qb_list', _data, function(data){
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (!rdata['status']){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
content = '<select id="qb_selected" class="bt-input-text mr20" style="width:30%;margin-bottom: 3px;">'+
|
||||
'<option value="0">所有</option>' +
|
||||
'<option value="completed">已下载</option>' +
|
||||
'<option value="downloading">下载中</option>' +
|
||||
'</select>';
|
||||
content += '<button class="btn btn-success btn-sm" onclick="qbListFind();">查找</button></div>';
|
||||
|
||||
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
content += '<th>种子(hash)</th>';
|
||||
content += '<th>添加时间</th>';
|
||||
content += '<th>操作(<a class="btlink" onclick="qbAdd();">添加</a> | <a class="btlink" onclick="openAdminUrl();">管理</a>)</th>';
|
||||
content += '</tr></thead>';
|
||||
|
||||
content += '<tbody>';
|
||||
|
||||
ulist = rdata.data.torrents;
|
||||
for (i in ulist){
|
||||
content += '<tr><td>'+
|
||||
'<span class="password" data-pw="'+ulist[i]['hash']+'">'+ulist[i]['hash'].substr(0,3)+'</span>' +
|
||||
'<span onclick="showHideHash(this)" data-pw="'+ulist[i]['hash'].substr(0,3)+'" class="glyphicon glyphicon-eye-open cursor pw-ico" style="margin-left:10px"></span>'+
|
||||
'<span class="ico-copy cursor btcopy" style="margin-left:10px" title="复制种子hash" onclick="copyText(\''+ulist[i]['hash']+'\')"></span>'+
|
||||
'</td>'+
|
||||
'<td>'+getLocalTime(ulist[i]['added_on'])+'</td>'+
|
||||
'<td><a class="btlink" onclick="qbDel(\''+ulist[i]['hash']+'\')">删除</a></td></tr>';
|
||||
}
|
||||
|
||||
content += '</tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
|
||||
var type = rdata.data.type;
|
||||
if (type == ''){
|
||||
$("#qb_selected option[value='0']").attr("selected", true);
|
||||
} else {
|
||||
$("#qb_selected option[value='"+type+"']").attr("selected", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -0,0 +1,719 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""
|
||||
下载检测
|
||||
"""
|
||||
|
||||
'''
|
||||
pl_hash_list 表字段 status说明
|
||||
|
||||
0 视频资源 - 正常
|
||||
1 不含有视频资源
|
||||
2 3小时下载未反应
|
||||
4 3个月未下载完成
|
||||
'''
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import time
|
||||
import datetime
|
||||
import traceback
|
||||
import sys
|
||||
import json
|
||||
import socket
|
||||
import threading
|
||||
from hashlib import sha1
|
||||
from random import randint
|
||||
from struct import unpack
|
||||
from socket import inet_ntoa
|
||||
from threading import Timer, Thread
|
||||
from time import sleep
|
||||
|
||||
reload(sys)
|
||||
sys.setdefaultencoding("utf8")
|
||||
|
||||
sys.path.append('/usr/local/lib/python2.7/site-packages')
|
||||
|
||||
|
||||
def formatTime():
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||
|
||||
|
||||
def getRunDir():
|
||||
return os.getcwd()
|
||||
|
||||
|
||||
def getRootDir():
|
||||
return os.path.dirname(os.path.dirname(getRunDir()))
|
||||
|
||||
|
||||
def toSize(size):
|
||||
# 字节单位转换
|
||||
d = ('b', 'KB', 'MB', 'GB', 'TB')
|
||||
s = d[0]
|
||||
for b in d:
|
||||
if size < 1024:
|
||||
return str(round(size, 2)) + ' ' + b
|
||||
size = float(size) / 1024.0
|
||||
s = b
|
||||
return str(round(size, 2)) + ' ' + b
|
||||
|
||||
# import pygeoip
|
||||
import MySQLdb as mdb
|
||||
|
||||
from configparser import ConfigParser
|
||||
cp = ConfigParser()
|
||||
cp.read("../qb.conf")
|
||||
section_db = cp.sections()[0]
|
||||
DB_HOST = cp.get(section_db, "DB_HOST")
|
||||
DB_USER = cp.get(section_db, "DB_USER")
|
||||
DB_PORT = cp.getint(section_db, "DB_PORT")
|
||||
DB_PASS = cp.get(section_db, "DB_PASS")
|
||||
DB_NAME = cp.get(section_db, "DB_NAME")
|
||||
|
||||
|
||||
section_qb = cp.sections()[1]
|
||||
QB_HOST = cp.get(section_qb, "QB_HOST")
|
||||
QB_PORT = cp.get(section_qb, "QB_PORT")
|
||||
QB_USER = cp.get(section_qb, "QB_USER")
|
||||
QB_PWD = cp.get(section_qb, "QB_PWD")
|
||||
|
||||
section_file = cp.sections()[2]
|
||||
FILE_TO = cp.get(section_file, "FILE_TO")
|
||||
FILE_TRANSFER_TO = cp.get(section_file, "FILE_TRANSFER_TO")
|
||||
FILE_OWN = cp.get(section_file, "FILE_OWN")
|
||||
FILE_GROUP = cp.get(section_file, "FILE_GROUP")
|
||||
FILE_ENC_SWITCH = cp.get(section_file, "FILE_ENC_SWITCH")
|
||||
FILE_API_URL = cp.get(section_file, "FILE_API_URL")
|
||||
FILE_ASYNC_SWITCH = cp.get(section_file, "FILE_ASYNC_SWITCH")
|
||||
|
||||
|
||||
section_task = cp.sections()[3]
|
||||
TASK_SIZE_LIMIT = cp.get(section_task, "TASK_SIZE_LIMIT")
|
||||
TASK_RATE = cp.getint(section_task, "TASK_RATE")
|
||||
TASK_COMPLETED_RATE = cp.getint(section_task, "TASK_COMPLETED_RATE")
|
||||
TASK_DEBUG = cp.getint(section_task, "TASK_DEBUG")
|
||||
|
||||
section_setting = cp.sections()[4]
|
||||
QUEUE_SWITCH = cp.get(section_setting, "QUEUE_SWITCH")
|
||||
MAX_ACTIVE_UPLOADS = cp.getint(section_setting, "MAX_ACTIVE_UPLOADS")
|
||||
MAX_ACTIVE_TORRENTS = cp.getint(section_setting, "MAX_ACTIVE_TORRENTS")
|
||||
MAX_ACTIVE_DOWNLOADS = cp.getint(section_setting, "MAX_ACTIVE_DOWNLOADS")
|
||||
|
||||
rooDir = getRootDir()
|
||||
ffmpeg_cmd = rooDir + "/lib/ffmpeg/ffmpeg"
|
||||
if not os.path.exists(ffmpeg_cmd):
|
||||
ffmpeg_cmd = rooDir + "/lib/ffmpeg/bin/ffmpeg"
|
||||
|
||||
|
||||
class downloadBT(Thread):
|
||||
|
||||
__db_err = None
|
||||
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
self.setDaemon(True)
|
||||
self.qb = self.qb()
|
||||
|
||||
self.qb.set_preferences(max_active_uploads=MAX_ACTIVE_UPLOADS)
|
||||
self.qb.set_preferences(max_active_torrents=MAX_ACTIVE_TORRENTS)
|
||||
self.qb.set_preferences(max_active_downloads=MAX_ACTIVE_DOWNLOADS)
|
||||
|
||||
_has_suffix = ['mp4', 'rmvb', 'flv', 'avi',
|
||||
'mpg', 'mkv', 'wmv', 'avi', 'rm']
|
||||
has_suffix = []
|
||||
for x in range(len(_has_suffix)):
|
||||
has_suffix.append('.' + _has_suffix[x])
|
||||
has_suffix.append('.' + _has_suffix[x].upper())
|
||||
self.has_suffix = has_suffix
|
||||
|
||||
def __conn(self):
|
||||
try:
|
||||
self.dbconn = mdb.connect(
|
||||
DB_HOST, DB_USER, DB_PASS, DB_NAME, port=DB_PORT, charset='utf8')
|
||||
self.dbconn.autocommit(False)
|
||||
self.dbcurr = self.dbconn.cursor()
|
||||
self.dbcurr.execute('SET NAMES utf8')
|
||||
return True
|
||||
except Exception as e:
|
||||
self.__db_err = e
|
||||
return False
|
||||
|
||||
def __close(self):
|
||||
self.dbcurr.close()
|
||||
self.dbconn.close()
|
||||
|
||||
def query(self, sql):
|
||||
# 执行SQL语句返回数据集
|
||||
if not self.__conn():
|
||||
return self.__db_err
|
||||
try:
|
||||
self.dbcurr.execute(sql)
|
||||
result = self.dbcurr.fetchall()
|
||||
# print result
|
||||
# 将元组转换成列表
|
||||
data = map(list, result)
|
||||
self.__close()
|
||||
return data
|
||||
except Exception, ex:
|
||||
return ex
|
||||
|
||||
def execute(self, sql):
|
||||
if not self.__conn():
|
||||
return self.__db_err
|
||||
try:
|
||||
result = self.dbcurr.execute(sql)
|
||||
self.dbconn.commit()
|
||||
self.__close()
|
||||
return result
|
||||
except Exception, ex:
|
||||
return ex
|
||||
|
||||
def qb(self):
|
||||
from qbittorrent import Client
|
||||
url = 'http://' + QB_HOST + ':' + QB_PORT + '/'
|
||||
qb = Client(url)
|
||||
qb.login(QB_USER, QB_PWD)
|
||||
return qb
|
||||
|
||||
def execShell(self, cmdstring, cwd=None, timeout=None, shell=True):
|
||||
import subprocess
|
||||
if shell:
|
||||
cmdstring_list = cmdstring
|
||||
else:
|
||||
cmdstring_list = shlex.split(cmdstring)
|
||||
if timeout:
|
||||
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
||||
|
||||
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,
|
||||
shell=shell, bufsize=4096, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
if timeout:
|
||||
if end_time <= datetime.datetime.now():
|
||||
raise Exception("Timeout:%s" % cmdstring)
|
||||
|
||||
return sub.communicate()
|
||||
|
||||
def md5(self, str):
|
||||
# 生成MD5
|
||||
try:
|
||||
m = hashlib.md5()
|
||||
m.update(str)
|
||||
return m.hexdigest()
|
||||
except:
|
||||
return False
|
||||
|
||||
def readFile(self, filename):
|
||||
# 读文件内容
|
||||
try:
|
||||
fp = open(filename, 'r')
|
||||
fBody = fp.read()
|
||||
fp.close()
|
||||
return fBody
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_transfer_ts_file(self, to):
|
||||
return FILE_TRANSFER_TO + '/' + to + '.ts'
|
||||
|
||||
def get_transfer_mp4_file(self, to):
|
||||
return FILE_TRANSFER_TO + '/' + to + '.mp4'
|
||||
|
||||
def get_transfer_m3u5_dir(self, dirname, fname):
|
||||
return FILE_TO + '/m3u8/' + dirname + '/' + fname
|
||||
|
||||
def get_transfer_hash_dir(self, dirname):
|
||||
return FILE_TO + '/m3u8/' + dirname
|
||||
|
||||
def fg_transfer_mp4_cmd(self, sfile, dfile):
|
||||
cmd = ffmpeg_cmd + ' -y -i "' + sfile + \
|
||||
'" -threads 1 -preset veryslow -crf 28 -c:v libx264 -strict -2 ' + dfile
|
||||
return cmd
|
||||
|
||||
def fg_transfer_ts_cmd(self, file, to_file):
|
||||
cmd = ffmpeg_cmd + ' -y -i ' + file + \
|
||||
' -s 480x360 -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' + to_file
|
||||
return cmd
|
||||
|
||||
def fg_m3u8_cmd(self, ts_file, m3u8_file, to_file):
|
||||
cmd = ffmpeg_cmd + ' -y -i ' + ts_file + ' -c copy -map 0 -f segment -segment_list ' + \
|
||||
m3u8_file + ' -segment_time 3 ' + to_file
|
||||
return cmd
|
||||
|
||||
def fg_m3u8enc_cmd(self, ts_file, m3u8_file, to_file, enc_dir):
|
||||
cmd = ffmpeg_cmd + ' -y -i ' + ts_file + ' -threads 1 -strict -2 -hls_time 3 -hls_key_info_file ' + \
|
||||
enc_dir + '/enc.keyinfo.txt -hls_playlist_type vod -hls_segment_filename ' + \
|
||||
to_file + ' ' + m3u8_file
|
||||
return cmd
|
||||
|
||||
def debug(self, msg):
|
||||
return formatTime() + ":" + msg
|
||||
|
||||
def get_lock_file(self, to):
|
||||
return '/tmp/mdw_qb_' + to + '.lock'
|
||||
|
||||
def lock(self, sign):
|
||||
l = self.get_lock_file(sign)
|
||||
self.execShell('touch ' + l)
|
||||
|
||||
def unlock(self, sign):
|
||||
l = self.get_lock_file(sign)
|
||||
self.execShell('rm -rf ' + l)
|
||||
|
||||
def islock(self, sign):
|
||||
l = self.get_lock_file(sign)
|
||||
if os.path.exists(l):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ffmpeg_file_sync(self):
|
||||
if FILE_ASYNC_SWITCH == '1':
|
||||
runDir = getRunDir()
|
||||
sign = 'sync'
|
||||
|
||||
print 'file_sync... start'
|
||||
if self.islock(sign):
|
||||
print self.debug('sync doing,already lock it!!!')
|
||||
else:
|
||||
self.lock(sign)
|
||||
|
||||
r = self.execShell('sh -x ' + runDir + '/rsync.sh')
|
||||
print self.debug('file_sync:' + r[0])
|
||||
print self.debug('file_sync_error:' + r[1])
|
||||
self.unlock(sign)
|
||||
print 'file_sync... end'
|
||||
|
||||
def ffmpeg_del_file(self, mp4, ts, m3u8_dir):
|
||||
print self.debug('delete middle file ... start' + mp4)
|
||||
self.execShell('rm -rf ' + mp4)
|
||||
self.execShell('rm -rf ' + ts)
|
||||
|
||||
if os.path.exists(m3u8_dir):
|
||||
self.execShell('rm -rf ' + m3u8_dir)
|
||||
|
||||
print self.debug('delete middle file ... end' + ts)
|
||||
|
||||
def ffmpeg_del_hfile(self, shash_dir):
|
||||
print self.debug('delete middle hash dir ... start' + shash_dir)
|
||||
if os.path.exists(shash_dir):
|
||||
self.execShell('rm -rf ' + shash_dir)
|
||||
|
||||
print self.debug('delete middle hash dir ... end' + shash_dir)
|
||||
|
||||
def ffmpeg(self, file=''):
|
||||
if not os.path.exists(FILE_TRANSFER_TO):
|
||||
self.execShell('mkdir -p ' + FILE_TRANSFER_TO)
|
||||
|
||||
fname = os.path.basename(file)
|
||||
shash = self.sign_torrent['hash']
|
||||
md5file = self.md5(file)
|
||||
if not os.path.exists(file):
|
||||
print formatTime(), 'file not exists:', file
|
||||
return
|
||||
print self.debug('source file ' + file)
|
||||
|
||||
mp4file = self.get_transfer_mp4_file(md5file)
|
||||
cmd_mp4 = self.fg_transfer_mp4_cmd(file, mp4file)
|
||||
if not os.path.exists(mp4file):
|
||||
print self.debug('cmd_mp4:' + cmd_mp4)
|
||||
os.system(cmd_mp4)
|
||||
else:
|
||||
print self.debug('mp4 exists:' + mp4file)
|
||||
|
||||
if not os.path.exists(mp4file):
|
||||
print self.debug('mp4 not exists')
|
||||
return
|
||||
|
||||
tsfile = self.get_transfer_ts_file(md5file)
|
||||
cmd_ts = self.fg_transfer_ts_cmd(mp4file, tsfile)
|
||||
if not os.path.exists(tsfile):
|
||||
print self.debug('cmd_ts:' + cmd_ts)
|
||||
os.system(cmd_ts)
|
||||
else:
|
||||
print self.debug('data_ts exists:' + mp4file)
|
||||
|
||||
if not os.path.exists(tsfile):
|
||||
print self.debug('ts not exists')
|
||||
return
|
||||
|
||||
md5Fname = self.md5(fname)
|
||||
m3u8_dir = self.get_transfer_m3u5_dir(shash, md5Fname)
|
||||
if not os.path.exists(m3u8_dir):
|
||||
self.execShell('mkdir -p ' + m3u8_dir)
|
||||
|
||||
m3u8_file = m3u8_dir + '/index.m3u8'
|
||||
tofile = m3u8_dir + '/%010d.ts'
|
||||
print self.debug('tofile:' + tofile)
|
||||
# 加密m3u8
|
||||
if FILE_ENC_SWITCH != '0':
|
||||
enc_dir = '/tmp/qb_m3u8'
|
||||
cmd = self.fg_m3u8enc_cmd(tsfile, m3u8_file, tofile, enc_dir)
|
||||
if os.path.exists(m3u8_file):
|
||||
print self.debug('cmd_m3u8_enc exists:' + m3u8_file)
|
||||
print self.debug('cmd_m3u8_enc:' + cmd)
|
||||
self.ffmpeg_file_sync()
|
||||
self.ffmpeg_del_file(mp4file, tsfile, m3u8_dir)
|
||||
return
|
||||
|
||||
self.execShell('mkdir -p ' + enc_dir)
|
||||
self.execShell('openssl rand -base64 16 > ' +
|
||||
enc_dir + '/enc.key')
|
||||
self.execShell('rm -rf ' + enc_dir + '/enc.keyinfo.txt')
|
||||
|
||||
try:
|
||||
fid = self.add_hash(fname, md5Fname)
|
||||
except Exception as e:
|
||||
print 'add_hash_enc:' + str(e)
|
||||
return
|
||||
fid = self.add_hash(fname, md5Fname)
|
||||
key = self.readFile(enc_dir + '/enc.key').strip()
|
||||
self.set_hashfile_key(fid, key)
|
||||
|
||||
# FILE_API_URL
|
||||
url = FILE_API_URL.replace('{$KEY}', fid)
|
||||
enc_url = 'echo ' + url + ' >> ' + enc_dir + '/enc.keyinfo.txt'
|
||||
self.execShell(enc_url)
|
||||
enc_path = 'echo ' + enc_dir + '/enc.key >> ' + enc_dir + '/enc.keyinfo.txt'
|
||||
self.execShell(enc_path)
|
||||
enc_iv = 'openssl rand -hex 16 >> ' + enc_dir + '/enc.keyinfo.txt'
|
||||
self.execShell(enc_iv)
|
||||
|
||||
os.system(cmd)
|
||||
else:
|
||||
|
||||
if os.path.exists(m3u8_file):
|
||||
print self.debug('m3u8 exists:' + tofile)
|
||||
self.ffmpeg_file_sync()
|
||||
self.ffmpeg_del_file(mp4file, tsfile, m3u8_dir)
|
||||
return
|
||||
|
||||
cmd_m3u8 = self.fg_m3u8_cmd(tsfile, m3u8_file, tofile)
|
||||
print self.debug('cmd_m3u8:' + cmd_m3u8)
|
||||
os.system(cmd_m3u8)
|
||||
|
||||
try:
|
||||
self.add_hash(fname, md5Fname)
|
||||
except Exception as e:
|
||||
print 'add_hash', str(e)
|
||||
|
||||
self.execShell('chown -R ' + FILE_OWN + ':' +
|
||||
FILE_GROUP + ' ' + m3u8_dir)
|
||||
self.execShell('chmod -R 755 ' + m3u8_dir)
|
||||
|
||||
self.ffmpeg_file_sync()
|
||||
self.ffmpeg_del_file(mp4file, tsfile, m3u8_dir)
|
||||
|
||||
def get_bt_size(self, torrent):
|
||||
total_size = '0'
|
||||
if 'size' in torrent:
|
||||
total_size = str(torrent['size'])
|
||||
|
||||
if 'total_size' in torrent:
|
||||
total_size = str(torrent['total_size'])
|
||||
return total_size
|
||||
|
||||
def get_hashlist_id(self):
|
||||
ct = formatTime()
|
||||
|
||||
total_size = self.get_bt_size(self.sign_torrent)
|
||||
|
||||
shash = self.sign_torrent['hash']
|
||||
sname = self.sign_torrent['name']
|
||||
sname = mdb.escape_string(sname)
|
||||
|
||||
info = self.query(
|
||||
"select id from pl_hash_list where info_hash='" + shash + "'")
|
||||
if len(info) > 0:
|
||||
pid = str(info[0][0])
|
||||
else:
|
||||
print 'insert into pl_hash_list data'
|
||||
pid = self.execute("insert into pl_hash_list (`name`,`info_hash`,`length`,`create_time`) values('" +
|
||||
sname + "','" + shash + "','" + total_size + "','" + ct + "')")
|
||||
return pid
|
||||
|
||||
def set_hashlist_status(self, torrent, status):
|
||||
ct = formatTime()
|
||||
|
||||
shash = torrent['hash']
|
||||
|
||||
info = self.query(
|
||||
"select id from pl_hash_list where info_hash='" + shash + "'")
|
||||
if len(info) > 0:
|
||||
print 'set_hashlist_status update'
|
||||
usql = "update pl_hash_list set `status`='" + \
|
||||
str(status) + "' where info_hash='" + shash + "'"
|
||||
self.execute(usql)
|
||||
else:
|
||||
print 'set_hashlist_status insert'
|
||||
total_size = self.get_bt_size(torrent)
|
||||
sname = torrent['name']
|
||||
sname = mdb.escape_string(sname)
|
||||
return self.execute("insert into pl_hash_list (`name`,`info_hash`,`length`,`status`,`create_time`) values('" +
|
||||
sname + "','" + shash + "','" + total_size + "','" + str(status) + "','" + ct + "')")
|
||||
|
||||
def get_hashfile_id(self, fname, m3u8_name, pid):
|
||||
ct = formatTime()
|
||||
|
||||
info = self.query(
|
||||
"select id from pl_hash_file where name='" + fname + "' and pid='" + pid + "'")
|
||||
if len(info) == 0:
|
||||
print 'insert into pl_hash_file data !'
|
||||
fid = self.execute("insert into pl_hash_file (`pid`,`name`,`m3u8`,`create_time`) values('" +
|
||||
pid + "','" + fname + "','" + m3u8_name + "','" + ct + "')")
|
||||
else:
|
||||
print fname, ':', m3u8_name, 'already is exists!'
|
||||
fid = str(info[0][0])
|
||||
return fid
|
||||
|
||||
def set_hashfile_key(self, fid, key):
|
||||
self.execute("update pl_hash_file set `key`='" +
|
||||
mdb.escape_string(key) + "' where id=" + fid)
|
||||
|
||||
def add_queue(self, shash, size):
|
||||
ct = formatTime()
|
||||
|
||||
info = self.query(
|
||||
"select id from pl_hash_queue where info_hash='" + shash + "'")
|
||||
if len(info) == 0:
|
||||
sql = "insert into pl_hash_queue (`info_hash`,`length`,`created_at`,`updated_at`) values('" + \
|
||||
shash + "','" + str(size) + "','" + ct + "','" + ct + "')"
|
||||
return self.execute(sql)
|
||||
else:
|
||||
print 'queue:', shash, 'already is exists!'
|
||||
|
||||
def add_hash(self, fname, m3u8_name):
|
||||
print '-------------------------add_hash---start-----------------------'
|
||||
|
||||
pid = self.get_hashlist_id()
|
||||
fid = self.get_hashfile_id(fname, m3u8_name, pid)
|
||||
|
||||
print '-------------------------add_hash---end--------------------------'
|
||||
|
||||
return fid
|
||||
|
||||
def file_arr(self, path, filters=['.DS_Store']):
|
||||
file_list = []
|
||||
flist = os.listdir(path)
|
||||
|
||||
for i in range(len(flist)):
|
||||
# 下载缓存文件过滤
|
||||
if flist[i] == '.unwanted':
|
||||
continue
|
||||
|
||||
file_path = os.path.join(path, flist[i])
|
||||
if flist[i] in filters:
|
||||
continue
|
||||
if os.path.isdir(file_path):
|
||||
tmp = self.file_arr(file_path, filters)
|
||||
file_list.extend(tmp)
|
||||
else:
|
||||
file_list.append(file_path)
|
||||
return file_list
|
||||
|
||||
def find_dir_video(self, path):
|
||||
flist = self.file_arr(path)
|
||||
video = []
|
||||
for i in range(len(flist)):
|
||||
if self.is_video(flist[i]):
|
||||
video.append(flist[i])
|
||||
return video
|
||||
|
||||
def video_do(self, path):
|
||||
if os.path.isfile(path):
|
||||
if self.is_video(path):
|
||||
self.ffmpeg(path)
|
||||
else:
|
||||
vlist = self.find_dir_video(path)
|
||||
for v in vlist:
|
||||
self.ffmpeg(v)
|
||||
return ''
|
||||
|
||||
def is_video(self, path):
|
||||
t = os.path.splitext(path)
|
||||
if t[1] in self.has_suffix:
|
||||
return True
|
||||
return False
|
||||
|
||||
def non_download(self, torrent):
|
||||
flist = self.qb.get_torrent_files(torrent['hash'])
|
||||
is_video = False
|
||||
for pos in range(len(flist)):
|
||||
file = torrent['save_path'] + flist[pos]['name']
|
||||
if not self.is_video(file):
|
||||
self.qb.set_file_priority(torrent['hash'], pos, 0)
|
||||
else:
|
||||
is_video = True
|
||||
|
||||
# is video
|
||||
if not is_video:
|
||||
self.set_status(torrent, 1)
|
||||
|
||||
def set_status(self, torrent, status):
|
||||
self.set_hashlist_status(torrent, status)
|
||||
if TASK_DEBUG == 0 and status != 0:
|
||||
self.qb.delete_permanently(torrent['hash'])
|
||||
|
||||
def is_downloading(self, torrent):
|
||||
if torrent['name'] == torrent['hash']:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_nondownload_overtime(self, torrent, sec):
|
||||
ct = time.time()
|
||||
use_time = int(ct) - int(torrent['added_on'])
|
||||
|
||||
flist = self.qb.get_torrent_files(torrent['hash'])
|
||||
# print flist
|
||||
flist_len = len(flist)
|
||||
# 没有获取种子信息
|
||||
# print 'ddd:',flist_len,use_time,sec
|
||||
if flist_len == 0 and use_time > sec:
|
||||
self.set_status(torrent, 2)
|
||||
return True
|
||||
|
||||
is_video_download = False
|
||||
|
||||
# 获取了种子信息,但是没有下载
|
||||
for pos in range(len(flist)):
|
||||
file = torrent['save_path'] + flist[pos]['name']
|
||||
if self.is_video(file):
|
||||
if flist[pos]['progress'] != '0':
|
||||
is_video_download = True
|
||||
|
||||
if not is_video_download and use_time > sec:
|
||||
self.set_status(torrent, 3)
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_downloading_overtime(self, torrent, sec):
|
||||
ct = time.time()
|
||||
use_time = int(ct) - int(torrent['added_on'])
|
||||
if use_time > sec:
|
||||
self.set_status(torrent, 4)
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_downloading_overlimit(self, torrent):
|
||||
sz = self.get_bt_size(torrent)
|
||||
ct = formatTime()
|
||||
size_limit = float(TASK_SIZE_LIMIT) * 1024 * 1024 * 1024
|
||||
size_limit = int(size_limit)
|
||||
print 'is_downloading_overlimit:', toSize(sz), toSize(size_limit)
|
||||
if int(sz) > int(size_limit):
|
||||
print 'overlimit sz:' + sz
|
||||
self.add_queue(torrent['hash'], str(sz))
|
||||
self.qb.delete_permanently(torrent['hash'])
|
||||
|
||||
def check_task(self):
|
||||
while True:
|
||||
torrents = self.qb.torrents(filter='downloading')
|
||||
tlen = len(torrents)
|
||||
if tlen > 0:
|
||||
print "downloading torrents count:", tlen
|
||||
for torrent in torrents:
|
||||
if self.is_nondownload_overtime(torrent, 5 * 60):
|
||||
pass
|
||||
elif self.is_downloading_overtime(torrent, 7 * 24 * 60 * 60):
|
||||
pass
|
||||
elif self.is_downloading(torrent):
|
||||
pass
|
||||
elif self.is_downloading_overlimit(torrent):
|
||||
pass
|
||||
else:
|
||||
self.non_download(torrent)
|
||||
print torrent['name'], ' task downloading!'
|
||||
else:
|
||||
print self.debug("no downloading task!")
|
||||
time.sleep(TASK_RATE)
|
||||
|
||||
def completed(self):
|
||||
while True:
|
||||
|
||||
torrents = self.qb.torrents(filter='completed')
|
||||
tlen = len(torrents)
|
||||
print "completed torrents count:", tlen
|
||||
if tlen > 0:
|
||||
for torrent in torrents:
|
||||
self.sign_torrent = torrent
|
||||
path = torrent['save_path'] + torrent['name']
|
||||
path = path.encode()
|
||||
try:
|
||||
self.video_do(path)
|
||||
|
||||
hash_dir = self.get_transfer_hash_dir(torrent['hash'])
|
||||
self.ffmpeg_del_hfile(hash_dir)
|
||||
if TASK_DEBUG == 0:
|
||||
self.qb.delete_permanently(torrent['hash'])
|
||||
except Exception as e:
|
||||
print formatTime(), str(e)
|
||||
print self.debug("done task!")
|
||||
else:
|
||||
print self.debug("no completed task!")
|
||||
time.sleep(TASK_COMPLETED_RATE)
|
||||
|
||||
def add_hash_task(self, shash):
|
||||
url = 'magnet:?xt=urn:btih:' + shash
|
||||
self.qb.download_from_link(url)
|
||||
print self.debug('queue add_hash_task is ok ... ')
|
||||
|
||||
def queue(self):
|
||||
while True:
|
||||
if QUEUE_SWITCH == '1':
|
||||
print self.debug("------------ do queue task start! ---------------")
|
||||
|
||||
setting = self.qb.preferences()
|
||||
torrents = self.qb.torrents()
|
||||
tlen = len(torrents)
|
||||
# print tlen, setting['max_active_torrents']
|
||||
add = int(setting['max_active_torrents']) - tlen
|
||||
|
||||
if add == 0:
|
||||
print self.debug('the download queue is full ... ')
|
||||
else:
|
||||
size_limit = float(TASK_SIZE_LIMIT) * 1024 * 1024 * 1024
|
||||
size_limit = int(size_limit)
|
||||
size_sql_where = ''
|
||||
size_sql = ''
|
||||
if size_limit != 0:
|
||||
size_sql = ',`length` desc '
|
||||
size_sql_where = 'where `length`<=' + str(size_limit)
|
||||
|
||||
sql = "select * from pl_hash_queue " + size_sql_where + \
|
||||
" order by created_at desc " + \
|
||||
size_sql + " limit " + str(add)
|
||||
info = self.query(sql)
|
||||
info_len = len(info)
|
||||
|
||||
if info_len == 0:
|
||||
print self.debug('queue data is empty ... ')
|
||||
else:
|
||||
for x in range(info_len):
|
||||
self.add_hash_task(info[x][1])
|
||||
self.execute(
|
||||
'delete from pl_hash_queue where id=' + str(info[x][0]))
|
||||
print self.debug("------------ do queue task end ! ---------------")
|
||||
time.sleep(TASK_RATE)
|
||||
|
||||
|
||||
def test():
|
||||
while True:
|
||||
print self.debug("no download task!")
|
||||
time.sleep(1)
|
||||
test()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
dl = downloadBT()
|
||||
|
||||
import threading
|
||||
check_task = threading.Thread(target=dl.check_task)
|
||||
check_task.start()
|
||||
|
||||
completed = threading.Thread(target=dl.completed)
|
||||
completed.start()
|
||||
|
||||
queue = threading.Thread(target=dl.queue)
|
||||
queue.start()
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
echo 'hello world'
|
||||
Loading…
Reference in New Issue