mirror of
https://github.com/star-inc/star_yuuki_bot.git
synced 2024-09-20 06:46:17 +08:00
reset v8
This commit is contained in:
parent
e137dd2256
commit
2caf3b7059
67
README.md
67
README.md
|
@ -1,12 +1,6 @@
|
|||
# Star Yuuki(pYthon) BOT - Yuuki
|
||||
|
||||
<<<<<<< HEAD
|
||||
![Version](https://img.shields.io/badge/v8-OpenSource-FF0033.svg)
|
||||
=======
|
||||
> v6 receives security updates only, no feature will be added.
|
||||
|
||||
![Version](https://img.shields.io/badge/v6.5.3-OpenSource-FF0033.svg)
|
||||
>>>>>>> v6
|
||||
![Series](https://img.shields.io/badge/syb-Series-7700FF.svg)
|
||||
![License](https://img.shields.io/badge/license-MPL--2.0-FF6600.svg)
|
||||
![Python](https://img.shields.io/badge/python-3.x-0066FF.svg)
|
||||
|
@ -29,68 +23,7 @@ Since 2018, it turns to be an opensource software.
|
|||
|
||||
## Introduction
|
||||
|
||||
<<<<<<< HEAD
|
||||
Version `v8` is not ready.
|
||||
=======
|
||||
This is a LINE Group Security BOT, to solve the problem that prevent from someone who is not the management but trying to destroy the group.
|
||||
|
||||
As know as the group feature of LINE has a major issue, everyone own the permission to modify the member list.
|
||||
|
||||
It's a good idea to be fair, but causes a communicated risk if one of member kick everyone maliciously.
|
||||
|
||||
So a protective solution is necessary, especially for corporation, organization, or education.
|
||||
|
||||
Since 2015, we start to design and provide several solutions to the market and public, Star Yuuki BOT is one of the success cases.
|
||||
|
||||
To protect Internet Security is our duty, and open source is romantic, that is why we are here.
|
||||
|
||||
> Star Yuuki BOT is designed to be a completed BOT, don't use the software as a "Self BOT", it might damage your account.
|
||||
|
||||
## License
|
||||
|
||||
The software is licensed under [Mozilla Public License 2.0](LICENSE.md) with [COPYING.md](COPYING.md).
|
||||
|
||||
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fstar-inc%2Fstar_yuuki_bot.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fstar-inc%2Fstar_yuuki_bot?ref=badge_large)
|
||||
|
||||
## Features
|
||||
|
||||
It's a powerful software, not only a BOT, even to be your secretary.
|
||||
|
||||
| Feature | Status | Note |
|
||||
|---|---|---|
|
||||
| Login for authorizing | X | [Read the document](https://github.com/star-inc/star_yuuki_bot/wiki/Configure) |
|
||||
| Basic Group Protection | O |
|
||||
| Specify the Vice Administrators of a Group | O |
|
||||
| Multiprocessing Support | O |
|
||||
| Advanced Group Protection | O |
|
||||
| [WebAdmin](#WebAdmin) | O |
|
||||
| General [Manual](https://line.starinc.xyz/yuuki_manual/) for Users | O |
|
||||
| [Documentation](#Documents) for Developers | O |
|
||||
| 100% [OpenSource](https://github.com/star-inc/star_yuuki_bot) and Free | O | [Licensed](#License) |
|
||||
|
||||
## WebAdmin
|
||||
|
||||
This is a magic feature since `v6.5.3` that you can control your BOT with GUI.
|
||||
|
||||
| Feature | Status | Note |
|
||||
|---|---|---|
|
||||
| Broadcast | O | Group only currently |
|
||||
| Events Viewer | O |
|
||||
| Profile Modify | O |
|
||||
| Groups Management | O |
|
||||
| Helper Management | O |
|
||||
| Yuuki Configure | X | Will be available in v8 |
|
||||
|
||||
![WebAdmin](WebAdmin.png)
|
||||
|
||||
## Documents
|
||||
|
||||
Are you finding how to set up, configure, and use it, or extend its features?
|
||||
|
||||
The documentation for developers is available on [GitHub Wiki](https://github.com/star-inc/star_yuuki_bot/wiki).
|
||||
|
||||
Welcome to help us for improving and making `Yuuki` better!
|
||||
>>>>>>> v6
|
||||
|
||||
## Logo Copyright
|
||||
|
||||
|
|
125
archived/v5.0.py
125
archived/v5.0.py
|
@ -1,125 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
import api.mu
|
||||
import time, os
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
ss=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password)
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
print 'Login OK'
|
||||
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
if "Error, Error, Error, Error, Error, Error, Error, Error," in open(".error-log","r").read():
|
||||
syb.getContactById(king).sendMessage("SafeMode On")
|
||||
time.sleep(180)
|
||||
if len(syb._getGroupIdsInvited()) >= 45:
|
||||
syb.getContactById(king).sendMessage("Security!")
|
||||
while True:
|
||||
if len(syb._getGroupIdsInvited()) >= 7:
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
else:
|
||||
time.sleep(90)
|
||||
else:
|
||||
syb.getContactById(king).sendMessage("Program Off")
|
||||
os.system('~/k')
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
except:
|
||||
pass
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
if len(syb._getGroupIdsInvited()) >= 1:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb.refreshGroups()
|
||||
syb.refreshContacts()
|
||||
gg=syb.getGroupById(gi)
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
log = open("yuuki-status", "a+")
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(ts) + ": ReJoin: " + gg.name + " ->Members/Invites :" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb.getContactById(king).name or len(syb.getGroupById(gi).members) >= 50:
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Members/Invites :" + str(len(gm)) + "/" + str(len(ge)))
|
||||
gg.sendMessage('安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO')
|
||||
#gg.sendMessage('((如果要我離開,請管理員直接踢我就可以了0.0\n##千萬不能踢我的姐姐\n##千萬不能踢我的姐姐\n##千萬不能踢我的姐姐\n不然我會請你出去XD')
|
||||
if gg.creator:
|
||||
gc=gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
syb.getGroupById(gi).sendMessage('本群組管理員:'+gc.name)
|
||||
if not ss in gg.getMemberIds():
|
||||
#syb._inviteIntoGroup(gi,[ss])
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(ts) + ": NoJoin: " + gg.name + " ->Members/Invites :" + str(len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log = open("yuuki-status", "a+")
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb.getGroupById(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.id
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.id
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
else:
|
||||
kgroup.sendMessage('除非管理員,否則不可以踢人呦^^')
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
try:
|
||||
syb._findAndAddContactsByMid(kcontact)
|
||||
syb._inviteIntoGroup(kgroupid, [kcontact])
|
||||
bist='Back'
|
||||
except:
|
||||
kcgurl=api.mu.get(kcontact)
|
||||
if kcgurl == None:
|
||||
kcaurl='加入好友網址取得失敗'
|
||||
else:
|
||||
kcaurl=kcgurl
|
||||
kgroup.sendMessage("邀請受到官方限制,請自行邀回@@\n被踢者:"+kcaurl)
|
||||
bist='NoBack'
|
||||
log.write("<br>" + str(ts) + ": Save: " + kgroup.name + "<br> ->Kicker/Kicked/Admin :" + kuser+ "/" + kcontact +"("+bist+")" + "/" +k.name+"("+ka+")")
|
||||
except:
|
||||
syb = LineClient(account,password)
|
||||
log = open("./.error-log", "a+")
|
||||
log.write("Error, ")
|
150
archived/v5.1.py
150
archived/v5.1.py
|
@ -1,150 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import api.mu
|
||||
import time, os
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
if "Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, Error, " in open(".error-log","r").read():
|
||||
syb.getContactById(king).sendMessage("SafeMode On")
|
||||
time.sleep(120)
|
||||
if len(syb._getGroupIdsInvited()) >= 15:
|
||||
syb.getContactById(king).sendMessage("Security!")
|
||||
while True:
|
||||
if len(syb._getGroupIdsInvited()) >= 7:
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
else:
|
||||
time.sleep(90)
|
||||
else:
|
||||
syb.getContactById(king).sendMessage("Program Off")
|
||||
#os.system('~/k')
|
||||
os.system('sh ~/.ss/syb/restart.sh')
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
except:
|
||||
pass
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
log = open("yuuki-status", "a+")
|
||||
if len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gg = syb._getGroups([gi])[0]
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 50:
|
||||
syb.refreshGroups()
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
# syb.sendMessage(0, Message(to=gi, contentType=0, text=msg))
|
||||
syb.getGroupById(gi).sendMessage(msg)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
# syb.sendMessage(0, Message(to=gi, contentType=0, text=msg))
|
||||
syb.getGroupById(gi).sendMessage(msg)
|
||||
if not ss in gg.getMemberIds():
|
||||
# syb._inviteIntoGroup(gi,[ss])
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
#log.write("<br>" + str(ts) + ": NotJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
#try:
|
||||
#syb._leaveGroup(gi)
|
||||
#except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb.getGroupById(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.id
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.id
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
kgroup.sendMessage('除非管理員,否則不可以踢人呦^^')
|
||||
kgroup.sendMessage('被踢者在封鎖名單內!故無法邀請\n如有需要,請自行邀回:')
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
kgroup.sendMessage('除非管理員,否則不可以踢人呦^^')
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
except:
|
||||
kgroup.sendMessage('緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人==')
|
||||
try:
|
||||
syb._findAndAddContactsByMid(kcontact)
|
||||
syb._inviteIntoGroup(kgroupid, [kcontact])
|
||||
bist='Back'
|
||||
except:
|
||||
kgroup.sendMessage("邀請受到官方限制,請自行邀回@@\n被踢者:")
|
||||
kgroup.sendUser(kcontact)
|
||||
bist='NoBack'
|
||||
log.write("<br>" + str(ts) + ": Save: " + kgroup.name + "<br> ->Kicker/Kicked/Admin :" + kuser+ "/" + kcontact +"("+bist+")" + "/" +k.name+"("+ka+")")
|
||||
except:
|
||||
try:
|
||||
syb = LineClient(authToken=syb.authToken)
|
||||
except:
|
||||
syb.updateAuthToken()
|
||||
syb = LineClient(authToken=syb.authToken)
|
||||
log = open("./.error-log", "a+")
|
||||
log.write("Error, ")
|
119
archived/v5.2.py
119
archived/v5.2.py
|
@ -1,119 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import api.mu
|
||||
import time, os
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
log = open("yuuki-status", "a+")
|
||||
if len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gg = syb._getGroups([gi])[0]
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 50:
|
||||
syb.refreshGroups()
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
syb.getGroupById(gi).sendMessage(msg)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
syb.getGroupById(gi).sendMessage(msg)
|
||||
if not ss in gg.getMemberIds():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb.getGroupById(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.id
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.id
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
kgroup.sendMessage('除非管理員,否則不可以踢人呦^^')
|
||||
kgroup.sendMessage('被踢者在封鎖名單內!故無法邀請\n如有需要,請自行邀回:')
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
kgroup.sendMessage('除非管理員,否則不可以踢人呦^^')
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
kist = 'Kick'
|
||||
except:
|
||||
kgroup.sendMessage('緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人==')
|
||||
kist = 'NoKick'
|
||||
kgroup.sendMessage("請自行邀回0.0\n被踢者:")
|
||||
kgroup.sendUser(kcontact)
|
||||
if syb._getGroup(kgroupid).preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(kgroupid, False)
|
||||
ust = 'Yes'
|
||||
else:
|
||||
usr = 'No'
|
||||
log.write("<br>%s: Save: %s<br> ->Kicker/Kicked/Admin/Url :%s(%s)/%s/%s(%s)/%s") % (ts, kgroup.name, kuser, kist, kcontact, k.name, ka, ust)
|
||||
except:
|
||||
syb.login()
|
140
archived/v6.0.py
140
archived/v6.0.py
|
@ -1,140 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
if len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
gg = syb._getGroup(gi)
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 100:
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if not ss in gg.getMemberIds():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb._getGroup(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.mid
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.mid
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg='被踢者在封鎖名單內!\n如有需要,請自行邀回:'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
kist = 'Kick'
|
||||
except:
|
||||
msg='緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'NoKick'
|
||||
if kcontact == ka or kcontact == king or kcontact == ss:
|
||||
try:
|
||||
syb._inviteIntoGroup(kgroupid, kcontact)
|
||||
except:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
else:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
if kgroup.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(kgroupid, False)
|
||||
ust = 'Yes'
|
||||
else:
|
||||
ust = 'No'
|
||||
if not kgroupid == None:
|
||||
log.write("<br>%s: Save: %s<br> ->Kicker/Kicked/Admin/Url :%s(%s)/%s/%s(%s)/%s" % (ts, kgroup.name, kuser, kist, kcontact, k.name, ka, ust))
|
||||
except:
|
||||
syb.login()
|
140
archived/v6.1.py
140
archived/v6.1.py
|
@ -1,140 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
if len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
gg = syb._getGroup(gi)
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 100:
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if not ss in gg.getMemberIds():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb._getGroup(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.mid
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.mid
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg='被踢者在封鎖名單內!\n如有需要,請自行邀回:'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
kist = 'Kick'
|
||||
except:
|
||||
msg='緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'NoKick'
|
||||
if kcontact == ka or kcontact == king or kcontact == ss:
|
||||
try:
|
||||
syb._inviteIntoGroup(kgroupid, kcontact)
|
||||
except:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
else:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
if kgroup.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(kgroupid, False)
|
||||
ust = 'Yes'
|
||||
else:
|
||||
ust = 'No'
|
||||
if not kgroupid == None:
|
||||
log.write("<br>%s: Save: %s<br> ->Kicker/Kicked/Admin/Url :%s(%s)/%s/%s(%s)/%s" % (ts, kgroup.name, kuser, kist, kcontact, k.name, ka, ust))
|
||||
except:
|
||||
syb.login()
|
|
@ -1,177 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
kicktimes=0
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
if syb.revision == -1:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
else:
|
||||
syb.revision = gc.revision
|
||||
urljoin=open('../talk/yuuki-join','r')
|
||||
uread = urljoin.read()
|
||||
if uread != "":
|
||||
try:
|
||||
if '\n' in uread:
|
||||
ouread = uread.replace('\n','')
|
||||
else:
|
||||
ouread = uread
|
||||
gg = syb._client.findGroupByTicket(ouread)
|
||||
syb._client.acceptGroupInvitationByTicket(0, gg.id, ouread)
|
||||
syb._changeGroupUrlStatus(gg.id, False)
|
||||
urljoin.close()
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
except:
|
||||
pass
|
||||
elif time.localtime().tm_min == 55:
|
||||
kicktimes=0
|
||||
elif len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
gg = syb._getGroup(gi)
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 100:
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if not ss in gg.getMemberIds():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
urljoin.close()
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb._getGroup(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.mid
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.mid
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg='被踢者在封鎖名單內!\n如有需要,請自行邀回:'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if kicktimes <= 45:
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
kist = 'Kick'
|
||||
kicktimes=kicktimes+1
|
||||
except:
|
||||
msg='緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'NoKick'
|
||||
else:
|
||||
msg = '緊告!有人正在踢人!請進入群組檢查!\n##次數已達程序上限無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'SYBNoKick'
|
||||
if kcontact == ka or kcontact == king or kcontact == ss:
|
||||
if kcontact == ss:
|
||||
ull=syb._renewGroupUrl(kgroupid)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(kgroupid, True)
|
||||
urljoin.write(ull)
|
||||
urljoin.close()
|
||||
else:
|
||||
try:
|
||||
syb._inviteIntoGroup(kgroupid, kcontact)
|
||||
except:
|
||||
msg = "請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='',
|
||||
contentMetadata={'mid': kcontact, 'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
else:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
if kgroup.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(kgroupid, False)
|
||||
ust = 'Yes'
|
||||
else:
|
||||
ust = 'No'
|
||||
if not kgroupid == None:
|
||||
log.write("<br>%s: Save: %s<br> ->Kicker/Kicked/Admin/Url :%s(%s)/%s/%s(%s)/%s" % (ts, kgroup.name, kuser, kist, kcontact, k.name, ka, ust))
|
||||
except:
|
||||
syb.login()
|
174
archived/v6.2.py
174
archived/v6.2.py
|
@ -1,174 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Neptune Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
|
||||
Star pYthon Bot = Star Yuuki Bot = SYB
|
||||
|
||||
:copyright: (c) 2016 Star Inc.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
gi=''
|
||||
gg=''
|
||||
gm=''
|
||||
ge=''
|
||||
kgroupid = ''
|
||||
kgroup = ''
|
||||
kuser = ''
|
||||
kcontact = ''
|
||||
kicktimes=0
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
try:
|
||||
gc=syb.sybKcheck()
|
||||
if gc==None or gc.param1 == kgroupid and gc.param2 == kuser and gc.param3 == kcontact:
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
urljoin=open('../talk/yuuki-join','r')
|
||||
uread = urljoin.read()
|
||||
if uread != "":
|
||||
try:
|
||||
if '\n' in uread:
|
||||
ouread = uread.replace('\n','')
|
||||
else:
|
||||
ouread = uread
|
||||
gg = syb._client.findGroupByTicket(ouread)
|
||||
syb._client.acceptGroupInvitationByTicket(0, gg.id, ouread)
|
||||
syb._changeGroupUrlStatus(gg.id, False)
|
||||
urljoin.close()
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
except:
|
||||
pass
|
||||
elif time.localtime().tm_min == 55:
|
||||
kicktimes=0
|
||||
elif len(syb._getGroupIdsInvited()) >= 1:
|
||||
try:
|
||||
gi = syb._getGroupIdsInvited()[0]
|
||||
gg = syb._getGroup(gi)
|
||||
syb._acceptGroupInvitation(gi)
|
||||
gm = gg.members
|
||||
ge = gg.invitee
|
||||
if gg.creator:
|
||||
gc = gg.creator
|
||||
else:
|
||||
gc = gg.members[0]
|
||||
if gi == kgroupid:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": ReJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
elif "✘" in syb._getContacts([king])[0].displayName or len(gg.members) >= 100:
|
||||
log.write("<br>" + str(ts) + ": Join: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(len(gm)) + "/" + str(len(ge)))
|
||||
msg = '安安^^\n我是刀劍神域的絕劍呦><\n我叫作友紀,請多多指教OwO'
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg = '使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n本群組管理員:' + gc.displayName
|
||||
text = Message(to=gi, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if not ss in gg.getMemberIds():
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
log.write("<br>" + str(
|
||||
ts) + ": NoJoin: " + gg.name + " ->Admin/Members/Invites :" + gc.displayName + "(" + gc.mid + ")" + "/" + str(
|
||||
len(gm)) + "/" + str(len(ge)))
|
||||
syb._leaveGroup(gi)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
urljoin.close()
|
||||
else:
|
||||
kgroupid=gc.param1
|
||||
kgroup=syb._getGroup(kgroupid)
|
||||
kuser=gc.param2
|
||||
kcontact=gc.param3
|
||||
if kgroup.creator != None:
|
||||
k=kgroup.creator
|
||||
ka=k.mid
|
||||
else:
|
||||
k=kgroup.members[0]
|
||||
ka=k.mid
|
||||
if kuser in [ka,king,nc]:
|
||||
pass
|
||||
elif kcontact in syb._getBlockedContactIds():
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
msg='被踢者在封鎖名單內!\n如有需要,請自行邀回:'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kgroup.sendUser(kcontact)
|
||||
else:
|
||||
msg='除非管理員,否則不可以踢人呦^^'
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
if kicktimes <= 45:
|
||||
try:
|
||||
syb._kickoutFromGroup(kgroupid, [kuser])
|
||||
kist = 'Kick'
|
||||
kicktimes=kicktimes+1
|
||||
except:
|
||||
msg='緊告!有人正在踢人!請進入群組檢查!\n##系統因限制無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'NoKick'
|
||||
else:
|
||||
msg = '緊告!有人正在踢人!請進入群組檢查!\n##次數已達程序上限無法踢人=='
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
kist = 'SYBNoKick'
|
||||
if kcontact == ka or kcontact == king or kcontact == ss:
|
||||
if kcontact == ss:
|
||||
ull=syb._renewGroupUrl(kgroupid)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(kgroupid, True)
|
||||
urljoin.write(ull)
|
||||
urljoin.close()
|
||||
else:
|
||||
try:
|
||||
syb._inviteIntoGroup(kgroupid, kcontact)
|
||||
except:
|
||||
msg = "請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='',
|
||||
contentMetadata={'mid': kcontact, 'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
else:
|
||||
msg="請自行邀回0.0\n被踢者:"
|
||||
text = Message(to=kgroupid, text=msg.encode('utf-8'))
|
||||
syb.sendMessage(text)
|
||||
text = Message(contentType=13, text='', contentMetadata = {'mid': kcontact,'displayName': 'Line User',}, to=kgroupid)
|
||||
syb.sendMessage(text)
|
||||
if kgroup.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(kgroupid, False)
|
||||
ust = 'Yes'
|
||||
else:
|
||||
ust = 'No'
|
||||
if not kgroupid == None:
|
||||
log.write("<br>%s: Save: %s<br> ->Kicker/Kicked/Admin/Url :%s(%s)/%s/%s(%s)/%s" % (ts, kgroup.name, kuser, kist, kcontact, k.name, ka, ust))
|
||||
except:
|
||||
syb.login()
|
|
@ -1,320 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Yuuki Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
This is a main program in SYB.
|
||||
It`s belong to Star Yuuki(pYthon) Bot Project of Star Neptune Bot
|
||||
Version: v6.3.0
|
||||
Copyright(c) 2017 Star Inc. All Rights Reserved.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time, sys
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
lastrev=0
|
||||
errortimes=0
|
||||
allerrortimes=0
|
||||
botkick=0
|
||||
ked=''
|
||||
kued=[]
|
||||
kced=0
|
||||
urljoined=''
|
||||
works=[]
|
||||
partblock=[]
|
||||
partblocknew=0
|
||||
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
bk=open('.blocklist','r')
|
||||
blocklist = syb._getBlockedContactIds()
|
||||
for x in eval("[%s]" % (bk.read(),)):
|
||||
blocklist.append(x)
|
||||
bk=open('.blocklist','a+')
|
||||
|
||||
pb=open('.partblock','r')
|
||||
for x in eval("[%s]" % (pb.read(),)):
|
||||
partblock.append(x)
|
||||
blocklist.append(x)
|
||||
pb.close()
|
||||
|
||||
bt=open('.botlist','r')
|
||||
botlist = eval("[%s]" % (bt.read(),))
|
||||
bt=open('.botlist','a+')
|
||||
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
|
||||
def sendMessage(self, toid, msg):
|
||||
text = Message(to=toid, text=msg.encode('utf-8'))
|
||||
self._sendMessage(text)
|
||||
|
||||
def sendUser(self, toid, mid):
|
||||
text = Message(contentType=13, text='',contentMetadata={'mid': mid, 'displayName': 'Line User',}, to=toid)
|
||||
self._sendMessage(text)
|
||||
|
||||
def sybGetGroupCreator(group):
|
||||
if group.creator == None:
|
||||
contact = group.members[0]
|
||||
else:
|
||||
contact = group.creator
|
||||
return contact
|
||||
|
||||
def newSybLog(self, when, logcode, gid, who, whoseid):
|
||||
self.write("<br>%s: %s: %s ->%s :%s" % (when,logcode,gid,who,whoseid))
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
if allerrortimes == 29:
|
||||
try:
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
sys.exit(0)
|
||||
elif errortimes == 1:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
errortimes = 0
|
||||
allerrortimes = allerrortimes +1
|
||||
try:
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
if allerrortimes != 1:
|
||||
time.sleep(60)
|
||||
if over != None:
|
||||
works.remove(over)
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
try:
|
||||
if works == []:
|
||||
ncover = syb._fetchOperations(syb.revision,50)
|
||||
else:
|
||||
ncover=None
|
||||
logcode = None
|
||||
glist = None
|
||||
over = None
|
||||
if ncover != None:
|
||||
if ncover != []:
|
||||
if ncover[-1].revision == -1:
|
||||
lastrev = ncover[-2].revision
|
||||
else:
|
||||
lastrev = ncover[-1].revision
|
||||
for nc in ncover:
|
||||
if nc.type == 11 or nc.type == 13 or nc.type == 17 or nc.type == 19:
|
||||
works.append(nc)
|
||||
if partblocknew == 1:
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.write(str(partblock))
|
||||
pb.close()
|
||||
if time.localtime(time.time()).tm_min == 0:
|
||||
for x in partblock:
|
||||
blocklist.remove(x)
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.close()
|
||||
if kced == 2:
|
||||
kued = []
|
||||
else:
|
||||
kced=kced+1
|
||||
if works != []:
|
||||
over=works[0]
|
||||
urljoin=open('../talk/yuuki-join','r')
|
||||
uread = urljoin.read()
|
||||
if uread != "":
|
||||
try:
|
||||
if '\n' in uread:
|
||||
ouread = uread.replace('\n','')
|
||||
else:
|
||||
ouread = uread
|
||||
gg = syb._client.findGroupByTicket(ouread)
|
||||
syb._client.acceptGroupInvitationByTicket(0, gg.id, ouread)
|
||||
syb._changeGroupUrlStatus(gg.id, False)
|
||||
newSybLog(log, ts, 'Join',over.param1,'Inviter','UrlJoin')
|
||||
urljoin.close()
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
except:
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
elif over == None:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 17:
|
||||
kued=[over.param1,over.param2]
|
||||
kced=0
|
||||
if over.param2 in blocklist:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Blocked',over.param2)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 11:
|
||||
if over.param3 == '1':
|
||||
gg=syb._getGroup(over.param1)
|
||||
if gg.name == 'Yuuki OFF' and syb.profile.id in [x.mid for x in gg.members]:
|
||||
if over.param2 != sybGetGroupCreator(gg).mid:
|
||||
syb._changeGroupName(over.param1,'No way!')
|
||||
else:
|
||||
newSybLog(log, ts, 'OFF',over.param1,'Changer',over.param2)
|
||||
sendMessage(syb,over.param1,'所有功能已關閉,可放心移除任何成員(包含我QAQQ)')
|
||||
if gg.name == 'Yuuki SC' or gg.name == 'SA Kingdom':
|
||||
if over.param2 != sybGetGroupCreator(gg).mid and gg.name == 'Yuuki SC':
|
||||
syb._changeGroupName(over.param1,'Group`s Admin Only!')
|
||||
else:
|
||||
ull=syb._renewGroupUrl(over.param1)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(over.param1, True)
|
||||
urljoin.write(ull)
|
||||
urljoin.close()
|
||||
newSybLog(log, ts, 'SC',over.param1,'Changer',over.param2)
|
||||
urljoined=over.param1
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 19:
|
||||
if [over.param1,over.param2] == kued or over.param2 in botlist:
|
||||
ogn = 'Yuuki OFF'
|
||||
if botkick == 0:
|
||||
syb._client.send_kickoutFromGroup(0, over.param1, [over.param2])
|
||||
if over.param2 not in botlist:
|
||||
bt.write('"%s",' % (over.param2,))
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb, over.param2, '您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Bot',over.param2)
|
||||
botkick=botkick+1
|
||||
else:
|
||||
botkick=0
|
||||
gg=syb._getGroup(over.param1)
|
||||
ogn=gg.name
|
||||
if ogn == 'Yuuki OFF' or over.param2 == king or over.param2 == nc or over.param2 ==sss or over.param2 == ss or over.param2 == s:
|
||||
pass
|
||||
else:
|
||||
if over.param3 == syb.profile.id:
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Blocked',over.param2)
|
||||
elif over.param3 == ss:
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
syb._client.send_kickoutFromGroup(0, over.param1, [over.param2])
|
||||
ull=syb._renewGroupUrl(over.param1)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(over.param1, True)
|
||||
urljoin.write(ull)
|
||||
urljoin.close()
|
||||
newSybLog(log, ts, 'SCBlock',over.param1,'Blocked',over.param2)
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.members]:
|
||||
sendMessage(syb,over.param1,'如果你是系統認定的群組管理員,請先停用我\nP.S.把群名改成(區分大小寫):Yuuki OFF\n反正,掰掰囉><\nhttp://line.me/ti/p/@niq6886v')
|
||||
sendUser(syb,over.param1,over.param2)
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
sendMessage(syb,over.param1,'被踢者:')
|
||||
sendUser(syb,over.param1,over.param3)
|
||||
if gg.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(gg.id, False)
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Kicker/Kicked','%s/%s' % (over.param2,over.param3,))
|
||||
ked=over.param1
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 13:
|
||||
inlist = False
|
||||
if over.param3 == syb.profile.id:
|
||||
inlist = True
|
||||
elif "\x1e" in over.param3:
|
||||
glist = over.param3.split("\x1e")
|
||||
if syb.profile.id in glist:
|
||||
inlist = True
|
||||
if glist != None or over.param3 in botlist:
|
||||
blocked = []
|
||||
if glist != None:
|
||||
if syb.profile.id not in glist:
|
||||
for x in glist:
|
||||
if x in botlist:
|
||||
blocked=glist
|
||||
break
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
inlist = False
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1, blocked)
|
||||
for x in blocked:syb._client.send_kickoutFromGroup(0,over.param1,[x])
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
if over.param2 not in blocklist:
|
||||
partblock.append(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.append(over.param2)
|
||||
sendMessage(syb,over.param2,'由於您疑似邀請到了惡意解散群組程式\n您目前已被本程序暫時性封鎖\n請耐心等候至整點,名單會自動移除\n\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
newSybLog(log, ts, 'Cancel', over.param1, 'BOT_Inviter', over.param2)
|
||||
if inlist == True:
|
||||
try:
|
||||
gg=syb._getGroup(over.param1)
|
||||
if over.param1 == ked:
|
||||
pass
|
||||
elif len(gg.members) <= 100:
|
||||
if king in [x.mid for x in gg.members]:
|
||||
for x in gg.members:
|
||||
if x.mid == king:
|
||||
kingname=x.displayName
|
||||
if "✘" not in kingname:
|
||||
inlist = False
|
||||
else:
|
||||
inlist = False
|
||||
except:
|
||||
inlist=False
|
||||
try:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee] and inlist == True:
|
||||
syb._acceptGroupInvitation(over.param1)
|
||||
newSybLog(log, ts, 'Join',over.param1,'Inviter',over.param2)
|
||||
sendMessage(syb,over.param1,'安安^^\n我是絕劍呦><\n請多多指教OwO')
|
||||
sendMessage(syb,over.param1,'我隸屬於千本桜帝国(TW)呦\n使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n也歡迎造訪千本桜帝国(TW)官網\nhttp://sa-kingdom.ml/tw\n本群組管理員:\n%s' % (sybGetGroupCreator(gg).displayName,))
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee]:
|
||||
syb._acceptGroupInvitation(over.param1)
|
||||
sendMessage(syb,over.param1,'不好意思...\n此群組人數未滿100人')
|
||||
syb._leaveGroup(over.param1)
|
||||
newSybLog(log, ts, 'NoJoin',over.param1,'Inviter',over.param2)
|
||||
except:
|
||||
newSybLog(log, ts, 'NoJoin(E)',over.param1,'Inviter',over.param2)
|
||||
if glist != None or over.param3 in blocklist:
|
||||
blocked=[]
|
||||
if glist != None:
|
||||
for x in glist:
|
||||
if x in blocklist:
|
||||
blocked.append(x)
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1,blocked)
|
||||
newSybLog(log, ts, 'Cancel',over.param1,'Blocked',over.param2)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
else:
|
||||
if over != None:
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
except EOFError:
|
||||
pass
|
||||
except:
|
||||
errortimes = errortimes + 1
|
||||
err1, err2, err3 = sys.exc_info()
|
|
@ -1,362 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Yuuki Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
This is a main program in SYB.
|
||||
It`s belong to Star Yuuki(pYthon) Bot Project of Star Neptune Bot
|
||||
Version: v6.3.1
|
||||
Copyright(c) 2017 Star Inc. All Rights Reserved.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time, sys
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
lastrev=0
|
||||
errortimes=0
|
||||
allerrortimes=0
|
||||
botkick=0
|
||||
ks=0
|
||||
kickban = 45
|
||||
ked=''
|
||||
kued=[]
|
||||
kced=0
|
||||
urljoined=''
|
||||
works=[]
|
||||
partblock=[]
|
||||
partblocknew=0
|
||||
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
lks=open('.kicks','r')
|
||||
ks = len(lks.read())
|
||||
lks.close()
|
||||
lks=open('.kicks','w+')
|
||||
|
||||
bk=open('.blocklist','r')
|
||||
blocklist = syb._getBlockedContactIds()
|
||||
for x in eval("[%s]" % (bk.read(),)):
|
||||
blocklist.append(x)
|
||||
bk=open('.blocklist','a+')
|
||||
|
||||
pb=open('.partblock','r')
|
||||
for x in eval("[%s]" % (pb.read(),)):
|
||||
partblock.append(x)
|
||||
blocklist.append(x)
|
||||
pb.close()
|
||||
|
||||
bt=open('.botlist','r')
|
||||
botlist = eval("[%s]" % (bt.read(),))
|
||||
bt=open('.botlist','a+')
|
||||
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
|
||||
def SNB4sybURL(key='',gid='',url='',gki='',glv=''):
|
||||
urlworks = {"key":key,"gid":gid,"gur":url,"gki":gki,"glv":glv}
|
||||
urlover = requests.post(' ',urlworks)
|
||||
return urlover.text
|
||||
|
||||
def sendMessage(self, toid, msg):
|
||||
text = Message(to=toid, text=msg.encode('utf-8'))
|
||||
self._client.send_sendMessage(0, text)
|
||||
|
||||
def sendUser(self, toid, mid):
|
||||
text = Message(contentType=13, text='',contentMetadata={'mid': mid, 'displayName': 'Line User',}, to=toid)
|
||||
self._client.send_sendMessage(0, text)
|
||||
|
||||
def sybGetGroupCreator(group):
|
||||
if group.creator == None:
|
||||
contact = group.members[0]
|
||||
else:
|
||||
contact = group.creator
|
||||
return contact
|
||||
|
||||
def newSybLog(self, when, logcode, gid, who, whoseid):
|
||||
self.write("<br>%s: %s: %s ->%s :%s" % (when,logcode,gid,who,whoseid))
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
if allerrortimes == 229:
|
||||
try:
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
sys.exit(0)
|
||||
elif errortimes == 1:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
errortimes = 0
|
||||
allerrortimes = allerrortimes +1
|
||||
try:
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
if allerrortimes != 1:
|
||||
time.sleep(60)
|
||||
if over != None and works != []:
|
||||
works.remove(over)
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
try:
|
||||
if works == []:
|
||||
ncover = syb._fetchOperations(syb.revision,50)
|
||||
else:
|
||||
ncover=None
|
||||
logcode = None
|
||||
glist = None
|
||||
over = None
|
||||
if ncover != None:
|
||||
if ncover != []:
|
||||
if ncover[-1].revision == -1:
|
||||
lastrev = ncover[-2].revision
|
||||
else:
|
||||
lastrev = ncover[-1].revision
|
||||
for nc in ncover:
|
||||
if nc.type == 11 or nc.type == 13 or nc.type == 17 or nc.type == 19:
|
||||
works.append(nc)
|
||||
if partblocknew == 1:
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.write(str(partblock))
|
||||
pb.close()
|
||||
if time.localtime(time.time()).tm_min == 0:
|
||||
if partblock != []:
|
||||
for x in partblock:
|
||||
blocklist.remove(x)
|
||||
partblock = []
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.close()
|
||||
lks.close()
|
||||
ks=0
|
||||
lks = open('.kicks', 'w+')
|
||||
if kced == 2:
|
||||
kued = []
|
||||
else:
|
||||
kced=kced+1
|
||||
if works != []:
|
||||
over=works[0]
|
||||
urljoin=open('../talk/yuuki-join','r')
|
||||
uread = urljoin.read()
|
||||
if uread != "":
|
||||
try:
|
||||
ouread = uread.split('\n')
|
||||
syb._client.send_acceptGroupInvitationByTicket(0, ouread[0], ouread[1])
|
||||
syb._changeGroupUrlStatus(ouread[0], False)
|
||||
newSybLog(log, ts, 'Join',ouread[0],'Inviter','UrlJoin')
|
||||
urljoin.close()
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
except:
|
||||
urljoin=open('../talk/yuuki-join','w')
|
||||
elif over == None:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 17:
|
||||
kued=[over.param1,over.param2]
|
||||
kced=0
|
||||
if over.param2 in blocklist:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有遭系統封鎖之人員進入!\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Blocked',over.param2)
|
||||
syb._changeGroupUrlStatus(over.param1,False)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 11:
|
||||
if over.param3 == '1':
|
||||
gg=syb._getGroup(over.param1)
|
||||
if gg.name == 'Yuuki OFF' and syb.profile.id in [x.mid for x in gg.members]:
|
||||
if over.param2 != sybGetGroupCreator(gg).mid:
|
||||
syb._changeGroupName(over.param1,'No way!')
|
||||
else:
|
||||
newSybLog(log, ts, 'OFF',over.param1,'Changer',over.param2)
|
||||
sendMessage(syb,over.param1,'所有功能已關閉,可放心移除任何成員(包含我QAQQ)')
|
||||
if gg.name == 'Yuuki SC' or gg.name == 'SA Kingdom':
|
||||
if over.param2 != sybGetGroupCreator(gg).mid and gg.name == 'Yuuki SC':
|
||||
syb._changeGroupName(over.param1,'Group`s Admin Only!')
|
||||
else:
|
||||
ull=syb._renewGroupUrl(over.param1)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(over.param1, True)
|
||||
urljoin.write(over.param1+"\n"+ull)
|
||||
urljoin.close()
|
||||
newSybLog(log, ts, 'SC',over.param1,'Changer',over.param2)
|
||||
urljoined=over.param1
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 19:
|
||||
if [over.param1,over.param2] == kued or over.param2 in botlist:
|
||||
ogn = 'Yuuki OFF'
|
||||
if botkick == 2:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有新加入者正在移除成員\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in botlist:
|
||||
bt.write('"%s",' % (over.param2,))
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb, over.param2, '您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Bot',over.param2)
|
||||
botkick=botkick+1
|
||||
else:
|
||||
botkick=0
|
||||
gg=syb._getGroup(over.param1)
|
||||
ogn=gg.name
|
||||
if ogn == 'Yuuki OFF' or over.param2 == king or over.param2 == nc or over.param2 ==sss or over.param2 == ss or over.param2 == s:
|
||||
pass
|
||||
else:
|
||||
if over.param3 == syb.profile.id:
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Blocked',over.param2)
|
||||
elif over.param3 == ss:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
ull=syb._renewGroupUrl(over.param1)
|
||||
urljoin = open('../talk/sc-join','w')
|
||||
syb._changeGroupUrlStatus(over.param1, True)
|
||||
urljoin.write(over.param1+"\n"+ull)
|
||||
urljoin.close()
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'SCBlock',over.param1,'Blocked',over.param2)
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.members]:
|
||||
if ks <= kickban:
|
||||
sendMessage(syb,over.param1,'如果你是系統認定的群組管理員,請先停用我\nP.S.把群名改成(區分大小寫):Yuuki OFF\n反正,掰掰囉><\nhttp://line.me/ti/p/@niq6886v')
|
||||
sendUser(syb,over.param1,over.param2)
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
sendMessage(syb,over.param1,'被踢者:')
|
||||
sendUser(syb,over.param1,over.param3)
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有人正在移除成員\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
if gg.preventJoinByTicket == False:
|
||||
syb._changeGroupUrlStatus(gg.id, False)
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Kicker/Kicked','%s/%s' % (over.param2,over.param3,))
|
||||
ked=over.param1
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 13:
|
||||
inlist = False
|
||||
if over.param3 == syb.profile.id:
|
||||
inlist = True
|
||||
elif "\x1e" in over.param3:
|
||||
glist = over.param3.split("\x1e")
|
||||
if syb.profile.id in glist:
|
||||
inlist = True
|
||||
if glist != None or over.param3 in botlist:
|
||||
blocked = []
|
||||
if glist != None:
|
||||
if syb.profile.id not in glist:
|
||||
for x in glist:
|
||||
if x in botlist:
|
||||
blocked=glist
|
||||
break
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
inlist = False
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1, blocked)
|
||||
if over.param2 not in blocklist:
|
||||
partblock.append(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.append(over.param2)
|
||||
sendMessage(syb,over.param2,'由於您疑似邀請到了惡意解散群組程式\n您目前已被本程序暫時性封鎖\n請耐心等候至整點,名單會自動移除\n\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
newSybLog(log, ts, 'Cancel', over.param1, 'BOT_Inviter', over.param2)
|
||||
if inlist == True:
|
||||
try:
|
||||
gg=syb._getGroup(over.param1)
|
||||
if over.param1 == ked:
|
||||
pass
|
||||
elif len(gg.members) <= 100:
|
||||
if king in [x.mid for x in gg.members]:
|
||||
for x in gg.members:
|
||||
if x.mid == king:
|
||||
kingname=x.displayName
|
||||
if "✘" not in kingname:
|
||||
inlist = False
|
||||
else:
|
||||
inlist = False
|
||||
except:
|
||||
inlist=False
|
||||
try:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee] and inlist == True:
|
||||
syb._client.send_acceptGroupInvitation(0,over.param1)
|
||||
newSybLog(log, ts, 'Join',over.param1,'Inviter',over.param2)
|
||||
sendMessage(syb,over.param1,'安安^^\n我是絕劍呦><\n請多多指教OwO')
|
||||
sendMessage(syb,over.param1,'我隸屬於千本桜帝国(TW)呦\n使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n也歡迎造訪千本桜帝国(TW)官網\nhttp://sa-kingdom.ml/tw\n本群組管理員:\n%s' % (sybGetGroupCreator(gg).displayName,))
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee]:
|
||||
syb._client.send_acceptGroupInvitation(0,over.param1)
|
||||
sendMessage(syb,over.param1,'不好意思...\n此群組人數未滿100人')
|
||||
syb._client.send_leaveGroup(0,over.param1)
|
||||
newSybLog(log, ts, 'NoJoin',over.param1,'Inviter',over.param2)
|
||||
except:
|
||||
newSybLog(log, ts, 'NoJoin(E)',over.param1,'Inviter',over.param2)
|
||||
if glist != None or over.param3 in blocklist:
|
||||
blocked=[]
|
||||
if glist != None:
|
||||
for x in glist:
|
||||
if x in blocklist:
|
||||
blocked.append(x)
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1,blocked)
|
||||
newSybLog(log, ts, 'Cancel',over.param1,'Blocked',over.param2)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
else:
|
||||
if over != None:
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
except EOFError:
|
||||
pass
|
||||
except:
|
||||
errortimes = errortimes + 1
|
||||
err1, err2, err3 = sys.exc_info()
|
|
@ -1,463 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Yuuki Bot - Yuuki
|
||||
~~~~~~~~~~~
|
||||
This is a main program in SYB.
|
||||
It`s belong to Star Yuuki(pYthon) Bot Project of Star Neptune Bot
|
||||
Version: v6.3.2
|
||||
Copyright(c) 2017 Star Inc. All Rights Reserved.
|
||||
"""
|
||||
from api import *
|
||||
from api.core.ttypes import Message
|
||||
import time, sys, requests
|
||||
|
||||
account=''
|
||||
password=''
|
||||
king=''
|
||||
nc=''
|
||||
sss=''
|
||||
ss=''
|
||||
s=''
|
||||
forsyb=''
|
||||
|
||||
try:
|
||||
syb = LineClient(account,password,refreshCacheDatas=False)
|
||||
print 'Login OK'
|
||||
except:
|
||||
print "Login Failed"
|
||||
|
||||
lastrev=0
|
||||
errortimes=0
|
||||
allerrortimes=0
|
||||
botkick=0
|
||||
ks=0
|
||||
kickban = 30
|
||||
ked=''
|
||||
kedcheck=0
|
||||
kked=[]
|
||||
kued=[]
|
||||
kced=0
|
||||
urljoined=''
|
||||
works=[]
|
||||
partblock=[]
|
||||
partblocknew=0
|
||||
ksreg=0
|
||||
notKick=[]
|
||||
|
||||
localtime = time.asctime(time.localtime(time.time()))
|
||||
log=open("yuuki-status","a+")
|
||||
log.write("<br>"+localtime+": Start")
|
||||
for gi in syb._getGroupIdsInvited():
|
||||
syb._acceptGroupInvitation(gi)
|
||||
syb._leaveGroup(gi)
|
||||
|
||||
authKey=open('../talk/yuuki-join','w')
|
||||
authKey.write(syb.authToken)
|
||||
authKey.close()
|
||||
time.sleep(3)
|
||||
authKey=open('../talk/sc-join','r')
|
||||
key=authKey.read()
|
||||
authKey.close()
|
||||
time.sleep(3)
|
||||
authKey=open('../../www/star_nep/4syb/.key','r')
|
||||
kirito=authKey.read()
|
||||
authKey.close()
|
||||
|
||||
lk=open('.lastkick','r')
|
||||
strlk=lk.read()
|
||||
if strlk != '':
|
||||
lastkick=int(strlk)
|
||||
else:
|
||||
lastkick=0
|
||||
lk.close()
|
||||
|
||||
lks=open('.kicks','r')
|
||||
ks = len(lks.read())
|
||||
lks.close()
|
||||
lks=open('.kicks','w+')
|
||||
|
||||
ng=open('.ng','r')
|
||||
notKick = ng.read().split("\n")
|
||||
ng.close()
|
||||
ng=open('.ng','w+')
|
||||
|
||||
bk=open('.blocklist','r')
|
||||
blocklist = syb._getBlockedContactIds()
|
||||
for x in eval("[%s]" % (bk.read(),)):
|
||||
blocklist.append(x)
|
||||
bk=open('.blocklist','a+')
|
||||
|
||||
pb=open('.partblock','r')
|
||||
for x in eval("[%s]" % (pb.read(),)):
|
||||
partblock.append(x)
|
||||
blocklist.append(x)
|
||||
pb.close()
|
||||
|
||||
bt=open('.botlist','r')
|
||||
botlist = eval("[%s]" % (bt.read(),))
|
||||
bt=open('.botlist','a+')
|
||||
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
|
||||
def SNB4sybURL(key='',gid='',url='',gki='',glv=''):
|
||||
urlworks = {"key":key,"gid":gid,"gur":url,"gki":gki,"glv":glv}
|
||||
urlover = requests.post(' ',urlworks)
|
||||
return urlover.text
|
||||
|
||||
def changeGroupUrlStatusByData(self, data, status):
|
||||
if status == True:
|
||||
msg=False
|
||||
else:
|
||||
msg=True
|
||||
message=data
|
||||
message.preventJoinByTicket=msg
|
||||
message.invitee=None
|
||||
message.members=None
|
||||
return self._client.send_updateGroup(0, message)
|
||||
|
||||
def sendMessage(self, toid, msg):
|
||||
text = Message(to=toid, text=msg.encode('utf-8'))
|
||||
self._client.send_sendMessage(0, text)
|
||||
|
||||
def sendUser(self, toid, mid):
|
||||
text = Message(contentType=13, text='',contentMetadata={'mid': mid, 'displayName': 'Line User',}, to=toid)
|
||||
self._client.send_sendMessage(0, text)
|
||||
|
||||
def sybGetGroupCreator(group):
|
||||
if group.creator == None:
|
||||
contact = group.members[0]
|
||||
else:
|
||||
contact = group.creator
|
||||
return contact
|
||||
|
||||
def newSybLog(self, when, logcode, gid, who, whoseid):
|
||||
self.write("<br>%s: %s: %s ->%s :%s" % (when,logcode,gid,who,whoseid))
|
||||
|
||||
while True:
|
||||
ts=time.asctime( time.localtime(time.time()) )
|
||||
if allerrortimes == 229:
|
||||
try:
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"Safe Mode Start!\nError:\n%s\n%s\n%s" % (err1,err2,err3))
|
||||
sys.exit(0)
|
||||
elif errortimes == 1:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
errortimes = 0
|
||||
allerrortimes = allerrortimes +1
|
||||
try:
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
except:
|
||||
syb.login()
|
||||
sendMessage(syb,king,"System Error\nTimes: %s\n\nError:\n%s\n%s\n%s" % (allerrortimes,err1,err2,err3))
|
||||
if allerrortimes != 1:
|
||||
time.sleep(60)
|
||||
if over != None and works != []:
|
||||
works.remove(over)
|
||||
syb.revision = syb._getLastOpRevision()
|
||||
try:
|
||||
if works == []:
|
||||
ncover = syb._fetchOperations(syb.revision,50)
|
||||
else:
|
||||
ncover=None
|
||||
logcode = None
|
||||
glist = None
|
||||
over = None
|
||||
if ncover != None:
|
||||
if ncover != []:
|
||||
if ncover[-1].revision == -1:
|
||||
lastrev = ncover[-2].revision
|
||||
else:
|
||||
lastrev = ncover[-1].revision
|
||||
for nc in ncover:
|
||||
if nc.type == 19:
|
||||
works.append(nc)
|
||||
if kedcheck == 1:
|
||||
if over.param2 == sss:
|
||||
kedcheck = 0
|
||||
elif nc.type == 11 or nc.type == 13 or nc.type == 17:
|
||||
works.append(nc)
|
||||
if kedcheck == 1:
|
||||
kedcheck = 2
|
||||
if kedcheck == 2:
|
||||
if ks == 0:
|
||||
ks = 1
|
||||
ksreg = 0
|
||||
else:
|
||||
ks = 99
|
||||
kedcheck = 0
|
||||
if partblocknew == 1:
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.write(str(partblock))
|
||||
pb.close()
|
||||
if ks == 1 and ksreg == 0:
|
||||
x=time.localtime(time.time()).tm_min
|
||||
lk=open('.lastkick','w+')
|
||||
lastkick=x
|
||||
lk.write(str(x))
|
||||
lk.close()
|
||||
ksreg=1
|
||||
if time.localtime(time.time()).tm_min == lastkick:
|
||||
lks.close()
|
||||
ksreg=0
|
||||
ks=0
|
||||
lks = open('.kicks', 'w+')
|
||||
if time.localtime(time.time()).tm_min == 0:
|
||||
if partblock != []:
|
||||
for x in partblock:
|
||||
blocklist.remove(x)
|
||||
partblock = []
|
||||
pb = open('.partblocklist', 'w')
|
||||
pb.close()
|
||||
notKick=[]
|
||||
ng.close()
|
||||
ng = open('.ng', 'w+')
|
||||
if kced == 5:
|
||||
kued = []
|
||||
else:
|
||||
kced=kced+1
|
||||
if works != []:
|
||||
over=works[0]
|
||||
if over == None:
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 17:
|
||||
if over.param2 != forsyb:
|
||||
kued=[over.param1,over.param2]
|
||||
kced=0
|
||||
if over.param2 in blocklist:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
kedcheck=1
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有遭系統封鎖之人員進入!\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Blocked',over.param2)
|
||||
syb._changeGroupUrlStatus(over.param1,False)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 11:
|
||||
if over.param3 == '1':
|
||||
gg=syb._getGroup(over.param1)
|
||||
if gg.name == 'Yuuki OFF' and syb.profile.id in [x.mid for x in gg.members]:
|
||||
if over.param2 != sybGetGroupCreator(gg).mid:
|
||||
syb._changeGroupName(over.param1,'No way!')
|
||||
else:
|
||||
newSybLog(log, ts, 'OFF',over.param1,'Changer',over.param2)
|
||||
sendMessage(syb,over.param1,'所有功能已關閉,可放心移除任何成員(包含我QAQQ)')
|
||||
if gg.name == 'Yuuki SC' or gg.name == 'SA Kingdom':
|
||||
if over.param2 != sybGetGroupCreator(gg).mid and gg.name == 'Yuuki SC':
|
||||
syb._changeGroupName(over.param1,'Group`s Admin Only!')
|
||||
else:
|
||||
if gg.preventJoinByTicket == True:
|
||||
changeGroupUrlStatusByData(syb,gg,True)
|
||||
SNB4sybURL(key=key,gid=over.param1,url=syb._renewGroupUrl(over.param1))
|
||||
changeGroupUrlStatusByData(syb,gg,False)
|
||||
newSybLog(log, ts, 'SC',over.param1,'Changer',over.param2)
|
||||
urljoined=over.param1
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 19:
|
||||
if [over.param1,over.param2] == kued or over.param2 in botlist:
|
||||
ogn = 'Yuuki OFF'
|
||||
if botkick == 2:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
kedcheck=1
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
else:
|
||||
BotKickE=BotKickE+1
|
||||
if BotKickE == 2:
|
||||
if gg.preventJoinByTicket == True:
|
||||
changeGroupUrlStatusByData(syb,gg,True)
|
||||
SNB4sybURL(key=kirito,gid=over.param1,url=syb._renewGroupUrl(over.param1),glv='yes')
|
||||
changeGroupUrlStatusByData(syb,gg,False)
|
||||
BotKickE=0
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有新加入者正在移除成員\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in botlist:
|
||||
bt.write('"%s",' % (over.param2,))
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb, over.param2, '您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Bot',over.param2)
|
||||
botkick=botkick+1
|
||||
else:
|
||||
botkick=0
|
||||
gg=syb._getGroup(over.param1)
|
||||
ogn=gg.name
|
||||
if ogn == 'Yuuki OFF' or over.param2 == king or over.param2 == nc or over.param2 == sss or over.param2 == ss or over.param2 == s or over.param2 == forsyb:
|
||||
pass
|
||||
else:
|
||||
if over.param3 == syb.profile.id:
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Blocked',over.param2)
|
||||
elif over.param3 == ss:
|
||||
if ks <= kickban:
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
kedcheck=1
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
gki=''
|
||||
else:
|
||||
gki=over.param2
|
||||
if gg.preventJoinByTicket == True:
|
||||
gg.preventJoinByTicket = False
|
||||
changeGroupUrlStatusByData(syb,gg,True)
|
||||
SNB4sybURL(key=key,gid=over.param1,url=syb._renewGroupUrl(over.param1),gki=gki)
|
||||
if over.param2 in partblock:
|
||||
partblock.remove(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.remove(over.param2)
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'SCBlock',over.param1,'Blocked',over.param2)
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.members]:
|
||||
if ks <= kickban:
|
||||
sendMessage(syb,over.param1,'如果你是系統認定的群組管理員,請先停用我\nP.S.把群名改成(區分大小寫):Yuuki OFF\n反正,掰掰囉><\nhttp://line.me/ti/p/@niq6886v')
|
||||
sendUser(syb,over.param1,over.param2)
|
||||
syb._client.send_kickoutFromGroup(0,over.param1,[over.param2])
|
||||
kedcheck=1
|
||||
ks=ks+1
|
||||
lks.write("+")
|
||||
sendMessage(syb,over.param1,'被踢者:')
|
||||
sendUser(syb,over.param1,over.param3)
|
||||
else:
|
||||
sendMessage(syb,over.param1,'請注意!目前有人正在移除成員\n程序由於Line Corp.限制\n目前無法踢人!請注意此群組!\nhttp://line.me/ti/p/@niq6886v')
|
||||
if [over.param1,over.param2] != kked:
|
||||
sendMessage(syb,over.param1,'以下分別為:\n踢人者/被踢者')
|
||||
sendUser(syb,over.param1,over.param2)
|
||||
sendUser(syb,over.param1,over.param3)
|
||||
else:
|
||||
sendMessage(syb,over.param1,'以下為被踢者')
|
||||
sendUser(syb,over.param1,over.param3)
|
||||
notKick.append(over.param1)
|
||||
ng.write(over.param1+'\n')
|
||||
inElist=0
|
||||
for x in notKick:
|
||||
if x == over.param1:
|
||||
inElist=inElist+1
|
||||
if inElist == 10:
|
||||
if gg.preventJoinByTicket == True:
|
||||
gg.preventJoinByTicket = False
|
||||
changeGroupUrlStatusByData(syb,gg,True)
|
||||
sendMessage(syb,over.param1,'警戒!目前此群組已進入管制模式\n嚴禁執行任何有關成員名單更變之動作\nP.S.整點時解除\nhttp://line.me/ti/p/@niq6886v')
|
||||
SNB4sybURL(key=kirito,gid=over.param1,url=syb._renewGroupUrl(over.param1),gki=over.param2,glv='yes')
|
||||
sendMessage(syb,over.param2,'此功能尚未啟用...\nhttp://line.me/ti/p/@niq6886v')
|
||||
if over.param2 not in blocklist:
|
||||
sendMessage(syb,over.param2,'您目前已被本程序封鎖\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
syb._blockContact(over.param2)
|
||||
blocklist.append(over.param2)
|
||||
bk.write('"%s",' % (over.param2,))
|
||||
newSybLog(log, ts, 'Block',over.param1,'Warning',over.param2)
|
||||
for x in notKick:
|
||||
if x == over.param1:
|
||||
notKick.remove(x)
|
||||
elif inElist == 5:
|
||||
sendMessage(syb,over.param1,'警告!目前此群組即將進入管制模式\n將嚴禁任何人員踢人、邀請等相關動作\n請勿再嘗試剔除任何成員\nhttp://line.me/ti/p/@niq6886v')
|
||||
if gg.preventJoinByTicket == False:
|
||||
changeGroupUrlStatusByData(syb,gg,False)
|
||||
newSybLog(log, ts, 'Kick',over.param1,'Kicker/Kicked','%s/%s' % (over.param2,over.param3,))
|
||||
ked=over.param1
|
||||
kked=[over.param1,over.param2]
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
elif over.type == 13:
|
||||
inlist = False
|
||||
if over.param3 == syb.profile.id:
|
||||
inlist = True
|
||||
elif "\x1e" in over.param3:
|
||||
glist = over.param3.split("\x1e")
|
||||
if syb.profile.id in glist:
|
||||
inlist = True
|
||||
if glist != None or over.param3 in botlist:
|
||||
blocked = []
|
||||
if glist != None:
|
||||
if syb.profile.id not in glist:
|
||||
for x in glist:
|
||||
if x in botlist:
|
||||
blocked=glist
|
||||
break
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
inlist = False
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1, blocked)
|
||||
if over.param2 not in blocklist:
|
||||
partblock.append(over.param2)
|
||||
partblocknew=1
|
||||
blocklist.append(over.param2)
|
||||
sendMessage(syb,over.param2,'由於您疑似邀請到了惡意解散群組程式\n您目前已被本程序暫時性封鎖\n請耐心等候至整點,名單會自動移除\n\n如有任何問題,請洽詢\nhttp://line.me/ti/p/@niq6886v')
|
||||
newSybLog(log, ts, 'Cancel', over.param1, 'BOT_Inviter', over.param2)
|
||||
if inlist == True:
|
||||
try:
|
||||
gg=syb._getGroup(over.param1)
|
||||
if over.param1 == ked:
|
||||
pass
|
||||
elif len(gg.members) <= 100:
|
||||
if king in [x.mid for x in gg.members]:
|
||||
for x in gg.members:
|
||||
if x.mid == king:
|
||||
kingname=x.displayName
|
||||
if "✘" not in kingname:
|
||||
inlist = False
|
||||
else:
|
||||
inlist = False
|
||||
except:
|
||||
inlist=False
|
||||
try:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee] and inlist == True:
|
||||
syb._client.send_acceptGroupInvitation(0,over.param1)
|
||||
newSybLog(log, ts, 'Join',over.param1,'Inviter',over.param2)
|
||||
sendMessage(syb,over.param1,'安安^^\n我是絕劍呦><\n請多多指教OwO')
|
||||
sendMessage(syb,over.param1,'我隸屬於千本桜帝国(TW)呦\n使用說明及最新消息請至\nhttp://line.me/ti/p/@niq6886v\n之主頁瀏覽,謝謝^^\n也歡迎造訪千本桜帝国(TW)官網\nhttp://sa-kingdom.ml/tw\n本群組管理員:\n%s' % (sybGetGroupCreator(gg).displayName,))
|
||||
else:
|
||||
if syb.profile.id in [x.mid for x in gg.invitee]:
|
||||
syb._client.send_acceptGroupInvitation(0,over.param1)
|
||||
sendMessage(syb,over.param1,'不好意思...\n此群組人數未滿100人')
|
||||
syb._client.send_leaveGroup(0,over.param1)
|
||||
newSybLog(log, ts, 'NoJoin',over.param1,'Inviter',over.param2)
|
||||
except:
|
||||
newSybLog(log, ts, 'NoJoin(E)',over.param1,'Inviter',over.param2)
|
||||
if glist != None or over.param3 in blocklist:
|
||||
blocked=[]
|
||||
if glist != None:
|
||||
for x in glist:
|
||||
if x in blocklist:
|
||||
blocked.append(x)
|
||||
else:
|
||||
blocked=[over.param3]
|
||||
if blocked != []:
|
||||
syb._client.send_cancelGroupInvitation(0,over.param1,blocked)
|
||||
newSybLog(log, ts, 'Cancel',over.param1,'Blocked',over.param2)
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
else:
|
||||
if over != None:
|
||||
works.remove(over)
|
||||
syb.revision = max(syb.revision,lastrev)
|
||||
except EOFError:
|
||||
pass
|
||||
except:
|
||||
errortimes = errortimes + 1
|
||||
err1, err2, err3 = sys.exc_info()
|
|
@ -1,109 +0,0 @@
|
|||
> :warning: Warning
|
||||
>
|
||||
> Due to protect the talk service of LINE, the software **never** provides any login method, for raising the development threshold.
|
||||
>
|
||||
> If you are the developer, we hope you have the sincere spirit only, for improving the Internet, and respect for their hard. :pray:
|
||||
|
||||
## Preparing
|
||||
|
||||
+ Copying `config.yaml` from `config.sample.yaml`
|
||||
|
||||
+ Following the [guide](#configuring), configure your settings and environment in `config.yaml`.
|
||||
|
||||
## Configuring
|
||||
|
||||
Star Yuuki BOT never provides any login method for connecting LINE talk service, you need to collect the information required, for continuing.
|
||||
|
||||
The config file format is [YAML](https://yaml.org), please understanding the syntax, documents, tutorials, and how to write that for configuring.
|
||||
|
||||
### Sample Config File
|
||||
|
||||
This is the required information to boot the software for working correctly, and optional settings can be set by override as `config.py` listed.
|
||||
|
||||
```yaml
|
||||
# Sample Config File for star_yuuki_bot
|
||||
# Please replace setting options from `libs/config.py`
|
||||
|
||||
Yuuki:
|
||||
SecurityService: True
|
||||
Default_Language: en
|
||||
|
||||
LINE:
|
||||
Server:
|
||||
Host: https://example.com
|
||||
Command_Path: /example_path
|
||||
LongPoll_path: /example_path
|
||||
|
||||
Account:
|
||||
X-Line-Application: LINE_Application_Identification
|
||||
X-Line-Access: LINE_Application_AccessKey
|
||||
User-Agent: LINE_Application_User-Agent
|
||||
```
|
||||
|
||||
Please make sure all of information above are filled correctly.
|
||||
|
||||
### Optional Settings
|
||||
|
||||
The guide will lead you to override the settings of `config.py`.
|
||||
|
||||
The config file is separated as two major parts, [`Yuuki`](#Yuuki) and [`LINE`](#LINE).
|
||||
|
||||
#### Yuuki
|
||||
|
||||
| In `config.py` | Converting to `config.yaml` |
|
||||
|---|---|
|
||||
| systemConfig | Yuuki |
|
||||
|
||||
The part is used for configuring how the software works and computes.
|
||||
|
||||
Taking the optional setting, `Advanced`, for example, it belongs to `systemConfig -> Advanced` as `Python dict` default in `config.py`.
|
||||
|
||||
So if you hope to set the option to `True`, according the converting table, the config file should be
|
||||
|
||||
```yaml
|
||||
Yuuki:
|
||||
Advanced: True
|
||||
```
|
||||
|
||||
The feature, `Advanced`, will be active as you set.
|
||||
|
||||
As the result, the new config file will be
|
||||
|
||||
```yaml
|
||||
Yuuki:
|
||||
SecurityService: True
|
||||
Default_Language: en
|
||||
Advanced: True
|
||||
|
||||
LINE:
|
||||
Server:
|
||||
Host: https://example.com
|
||||
Command_Path: /example_path
|
||||
LongPoll_path: /example_path
|
||||
|
||||
Account:
|
||||
X-Line-Application: LINE_Application_Identification
|
||||
X-Line-Access: LINE_Application_AccessKey
|
||||
User-Agent: LINE_Application_User-Agent
|
||||
```
|
||||
|
||||
That is the way to config the software correctly without any programming modification.
|
||||
|
||||
#### LINE
|
||||
|
||||
| In `config.py` | Converting to `config.yaml` |
|
||||
|---|---|
|
||||
| connectInfo | LINE -> Server |
|
||||
| connectHeader | LINE -> Account |
|
||||
|
||||
- X-Line-Application: `LINE_Application_Identification` means the Product ID for LINE server to identify the client.
|
||||
- X-Line-Access: `LINE_Application_AccessKey` as known as an access token of LINE user.
|
||||
- User-Agent: `LINE_Application_User-Agent` is the field to be used as HTTP header to connect LINE server.
|
||||
|
||||
These are the required config for connecting LINE server, that you should collect them by yourself.
|
||||
|
||||
As the guide part [`Yuuki`](#Yuuki) did, overriding settings as needing.
|
||||
|
||||
## Next
|
||||
|
||||
If you are ready, let's [run it up](https://github.com/star-inc/star_yuuki_bot/wiki/Execute-and-Maintain)!
|
|
@ -1,35 +0,0 @@
|
|||
> Hey! Developer! 🙌
|
||||
>
|
||||
> This is the last step for you to execute the software! 👋
|
||||
>
|
||||
> After the guide, if you have anything interested else, welcome to visit [our team blog](https://snb.starinc.xyz) to get more information!
|
||||
|
||||
## Install the dependencies
|
||||
|
||||
To install the modules the software required, just need to type
|
||||
|
||||
pip install -Ur requirements.txt
|
||||
|
||||
The command will install its requirements automatically.
|
||||
|
||||
## Execute
|
||||
|
||||
It's simple that you have only a command to do
|
||||
|
||||
python main.py
|
||||
|
||||
If the configuration have no fault, [Star Yuuki BOT](https://line.starinc.xyz/star-yuuki-bot) will boot successfully!
|
||||
|
||||
## Maintain
|
||||
|
||||
You may do some programming modification, for extending some feature by creating on your own, but `Star Yuuki BOT` while suffering a major updated, it might be making you annoyed.
|
||||
|
||||
Please trying to good use of [`git diff`](https://git-scm.com/docs/git-diff) or something similar, for comparing between the new one and the one you edited, merging the best snippets to you product.
|
||||
|
||||
The software built-in a feature, checking the update automatically, will check `git` while booting everytime!
|
||||
|
||||
You may turn it off, but doing version control is necessary to a service for ensuring it stability.
|
||||
|
||||
Last but not least, DO NOT MAKE THE SOFTWARE AS `SELF BOT`, it is not acceptable, some features will not work, and may damage your account.
|
||||
|
||||
> Thanks for your using, developing, even contributing!
|
|
@ -1,33 +0,0 @@
|
|||
Hey! Are you a new developer for LINE Unofficial Engineering?
|
||||
Due to LINE Messenger API having a lot of restricts, we choose this way to create the security services for LINE.
|
||||
|
||||
You must understand that you will have the risk because you are using an unofficial method to connect their server.
|
||||
You may receive `warning`, `request`, `ban`, even `legal action` from LINE Corporation while you taking too far.
|
||||
|
||||
Anyway, welcome to join us. Let's improving the Internet experience for public!
|
||||
|
||||
## History
|
||||
|
||||
[Star Yuuki BOT](https://line.starinc.xyz/star-yuuki-bot/) was a commerce service in the past, end in 2017.
|
||||
|
||||
Since 2018, the source code has been released on [GitHub](https://github.com/star-inc/star_yuuki_bot) as an OSS.
|
||||
|
||||
2019, the software was rewritten base on [`NightCrazy`](https://www.facebook.com/star.nightcrazy/) programming structure and improving its performance.
|
||||
|
||||
## Start Development
|
||||
|
||||
Before beginning, you should read all of the [Technical Information](https://github.com/star-inc/star_yuuki_bot/wiki/Technical-Information) and [Setup Environment](https://github.com/star-inc/star_yuuki_bot/wiki/Setup-Environment) at first.
|
||||
|
||||
Generally, the software is compatible with the latest version of `Python 3` on any `Unix-like` system.
|
||||
|
||||
If you're suffering anything strange, Yuuki `v6.5` is designed by `Python 3.7`, please install it instead and checking your runtime environment sure.
|
||||
|
||||
### Get Source Code
|
||||
|
||||
git clone https://github.com/star-inc/star_yuuki_bot.git
|
||||
|
||||
### Next
|
||||
|
||||
[Configure](https://github.com/star-inc/star_yuuki_bot/wiki/Configure)
|
||||
|
||||
[Execute and Maintain](https://github.com/star-inc/star_yuuki_bot/wiki/Execute-and-Maintain)
|
|
@ -1,7 +0,0 @@
|
|||
This is the developer documentation for Star Yuuki BOT.
|
||||
|
||||
Originally, these documents will should be placed at the [Developer Center of Star Inc.](https://developer.starinc.xyz), but we confused that Star Yuuki BOT is an opensource software, which is one of the repositories on GitHub, the documents should be freedom and could be modify by its community, eventually, we upload them to GitHub Wiki.
|
||||
|
||||
Anyway, welcome for choosing the perfectest LINE Group Protective BOT as your helper in your life. :smiley:
|
||||
|
||||
[**Get Started**](https://github.com/star-inc/star_yuuki_bot/wiki/Get-Started)
|
11
docs/Menu.md
11
docs/Menu.md
|
@ -1,11 +0,0 @@
|
|||
> Are you new from here? ✋
|
||||
>
|
||||
> Please read all of [Get Started](https://github.com/star-inc/star_yuuki_bot/wiki/Get-Started) first. 🙏
|
||||
|
||||
+ [Setup Environment](https://github.com/star-inc/star_yuuki_bot/wiki/Setup-Environment)
|
||||
|
||||
+ [Configure](https://github.com/star-inc/star_yuuki_bot/wiki/Configure)
|
||||
|
||||
+ [Execute and Maintain](https://github.com/star-inc/star_yuuki_bot/wiki/Execute-and-Maintain)
|
||||
|
||||
+ [Technical Information](https://github.com/star-inc/star_yuuki_bot/wiki/Technical-Information)
|
|
@ -1,5 +0,0 @@
|
|||
+ Check your system environment
|
||||
|
||||
- According to our test, the software is incompatible with `Microsoft Windows`.
|
||||
- We recommend to choosing `Python 3.7` as the runtime environment for executing.
|
||||
- Please install `pip` and `git`.
|
|
@ -1,26 +0,0 @@
|
|||
Star Yuuki BOT is the software to deploy an automated management service of group for [LINE](http://line.me) platform via their private API with `Apache Thrift Compact Protocol`.
|
||||
|
||||
The new programming structure since the version `v6.5` is based on `NightCrazy`, supporting multiprocessing, and getting flexiable for extending.
|
||||
|
||||
There are two modes, choosing the compatible one for your environment.
|
||||
|
||||
- [Legacy](#legacy-mode) is used for some old or performance losing devices.
|
||||
- [Advanced](#advanced-mode) will enable multiprocessing for improving the compute speed.
|
||||
|
||||
To configure the mode for executing, please read [`Configure`](https://github.com/star-inc/star_yuuki_bot/wiki/Configure) for getting how to set it up.
|
||||
|
||||
## Legacy Mode
|
||||
|
||||
The mode takes only one thread for running, and [WebAmin](https://github.com/star-inc/star_yuuki_bot#webadmin) or any extra features will be shutdown automatically, no matter if you already turn them on.
|
||||
|
||||
### Flow Chart
|
||||
|
||||
![Legacy Mode](https://line.starinc.xyz/wp-content/uploads/2020/11/Legacy.png)
|
||||
|
||||
## Advanced Mode
|
||||
|
||||
This is used as multiprocessing support for improving performance while computing, and provides some extra features.
|
||||
|
||||
### Flow Chart
|
||||
|
||||
![Advanced Mode](https://line.starinc.xyz/wp-content/uploads/2020/11/Advanced.png)
|
|
@ -1 +0,0 @@
|
|||
(c) 2020 [Star Inc.](https://starinc.xyz) with its contributors.
|
|
@ -1,2 +0,0 @@
|
|||
Hey, are you finding the menu?
|
||||
[Click Me](https://github.com/star-inc/star_yuuki_bot/wiki/Menu)
|
262
libs/data.py
262
libs/data.py
|
@ -1,262 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
from tornado.httpclient import HTTPClient, HTTPRequest
|
||||
from yuuki_core.ttypes import OpType
|
||||
|
||||
from .mds import PythonMDS
|
||||
from .thread import Yuuki_Multiprocess
|
||||
from .thread import Yuuki_Thread
|
||||
|
||||
|
||||
class Yuuki_Data:
|
||||
# Data Struct Define
|
||||
|
||||
Data = {}
|
||||
|
||||
DataType = {
|
||||
"Global": {
|
||||
"LastResetLimitTime": None,
|
||||
},
|
||||
"Group": {},
|
||||
"LimitInfo": {},
|
||||
"BlackList": []
|
||||
}
|
||||
|
||||
GroupType = {
|
||||
"SEGroup": None,
|
||||
"Ext_Admin": [],
|
||||
"GroupTicket": {}
|
||||
}
|
||||
|
||||
LimitType = {
|
||||
"KickLimit": {},
|
||||
"CancelLimit": {}
|
||||
}
|
||||
|
||||
SEGrouptype = {
|
||||
OpType.NOTIFIED_UPDATE_GROUP: False,
|
||||
OpType.NOTIFIED_INVITE_INTO_GROUP: False,
|
||||
OpType.NOTIFIED_ACCEPT_GROUP_INVITATION: False,
|
||||
OpType.NOTIFIED_KICKOUT_FROM_GROUP: False
|
||||
}
|
||||
|
||||
DataPath = "data/"
|
||||
DataName = "{}.json"
|
||||
|
||||
# Log Struct Define
|
||||
|
||||
LogType = {
|
||||
"JoinGroup": "<li>%s: %s(%s) -> Inviter: %s</li>",
|
||||
"KickEvent": "<li>%s: %s(%s) -(%s)> Kicker: %s | Kicked: %s | Status: %s</li>",
|
||||
"CancelEvent": "<li>%s: %s(%s) -(%s)> Inviter: %s | Canceled: %s</li>",
|
||||
"BlackList": "<li>%s: %s(%s)</li>"
|
||||
}
|
||||
|
||||
LogPath = "logs/"
|
||||
LogName = "{}.html"
|
||||
|
||||
initHeader = "<title>{} - SYB</title>" \
|
||||
"<meta charset='utf-8' />"
|
||||
|
||||
def __init__(self, threading, mds_port):
|
||||
self.threading = threading
|
||||
self.mds_port = mds_port
|
||||
self.ThreadControl = Yuuki_Thread()
|
||||
self.MdsThreadControl = Yuuki_Multiprocess()
|
||||
self._Data_Initialize()
|
||||
|
||||
def _Data_Initialize(self):
|
||||
if not os.path.isdir(self.DataPath):
|
||||
os.mkdir(self.DataPath)
|
||||
|
||||
for data_type in self.DataType:
|
||||
name = self.DataPath + self.DataName.format(data_type)
|
||||
|
||||
if not os.path.isfile(name):
|
||||
with open(name, "w") as f:
|
||||
self.Data[data_type] = self.DataType[data_type]
|
||||
json.dump(self.Data[data_type], f)
|
||||
else:
|
||||
with open(name, "r") as f:
|
||||
try:
|
||||
self.Data[data_type] = json.load(f)
|
||||
except ValueError:
|
||||
assert "{}\nJson Test Error".format(name)
|
||||
|
||||
return self._MDS_Initialize()
|
||||
|
||||
def _MDS_Initialize(self):
|
||||
if self.threading:
|
||||
mds = PythonMDS(self.mds_port)
|
||||
self.mdsHost = "http://localhost:{}/".format(self.mds_port)
|
||||
self.mdsCode = "{}.{}".format(random.random(), time.time())
|
||||
self.MdsThreadControl.add(mds.mds_listen, (self.mdsCode,))
|
||||
|
||||
# MDS Sync
|
||||
|
||||
time.sleep(1)
|
||||
self.mdsShake("SYC", self.Data)
|
||||
return self._Log_Initialize()
|
||||
|
||||
def _Log_Initialize(self):
|
||||
if not os.path.isdir(self.LogPath):
|
||||
os.mkdir(self.LogPath)
|
||||
|
||||
for Type in self.LogType:
|
||||
name = self.LogPath + self.LogName.format(Type)
|
||||
if not os.path.isfile(name):
|
||||
with open(name, "w") as f:
|
||||
f.write(self.initHeader.format(Type))
|
||||
|
||||
def ThreadExec(self, Function, args):
|
||||
if self.threading:
|
||||
self.ThreadControl.lock.acquire()
|
||||
self.ThreadControl.add(Function, args)
|
||||
self.ThreadControl.lock.release()
|
||||
else:
|
||||
Function(*args)
|
||||
|
||||
def mdsShake(self, do, path, data=None):
|
||||
status = 0
|
||||
if self.threading:
|
||||
http_client = HTTPClient()
|
||||
http_request = HTTPRequest(
|
||||
url=self.mdsHost,
|
||||
method="POST",
|
||||
body=json.dumps({
|
||||
"code": self.mdsCode,
|
||||
"do": do,
|
||||
"path": path,
|
||||
"data": data
|
||||
})
|
||||
)
|
||||
response = http_client.fetch(http_request)
|
||||
over = json.loads(response.body)
|
||||
if "status" in over:
|
||||
status = over["status"]
|
||||
assert_result = "mds - ERROR {}\n{} on {}".format(status, do, path)
|
||||
assert status == 200, assert_result
|
||||
return over
|
||||
else:
|
||||
status = {"status": status}
|
||||
return json.dumps(status)
|
||||
|
||||
def _local_query(self, query_data):
|
||||
if type(query_data) is list:
|
||||
result = self.Data
|
||||
query_len = len(query_data) - 1
|
||||
for count, key in enumerate(query_data):
|
||||
if key in result:
|
||||
if count < query_len:
|
||||
if type(result.get(key)) is not dict:
|
||||
result = 1
|
||||
break
|
||||
result = result.get(key)
|
||||
else:
|
||||
result = 2
|
||||
break
|
||||
|
||||
return result
|
||||
return 0
|
||||
|
||||
def _local_update(self, path, data):
|
||||
over = self._local_query(path)
|
||||
if not str(over).isnumeric():
|
||||
over.update(data)
|
||||
return False
|
||||
|
||||
def file(self, Type, Mode, Format):
|
||||
if Format == "Data":
|
||||
return open(self.DataPath + self.DataName.format(Type), Mode)
|
||||
elif Format == "Log":
|
||||
return open(self.LogPath + self.LogName.format(Type), Mode)
|
||||
|
||||
def syncData(self):
|
||||
if self.threading:
|
||||
self.Data = self.getData([])
|
||||
for Type in self.DataType:
|
||||
with self.file(Type, "w", "Data") as f:
|
||||
json.dump(self.Data[Type], f)
|
||||
return self.getData(["Global", "Power"])
|
||||
|
||||
def updateData(self, path, data):
|
||||
if self.threading:
|
||||
self.ThreadExec(self._updateData, (path, data))
|
||||
else:
|
||||
self._updateData(path, data)
|
||||
|
||||
def _updateData(self, path, data):
|
||||
assert path and type(path) is list, "Empty path - updateData"
|
||||
if len(path) == 1:
|
||||
origin_data = self.getData([])
|
||||
assert type(origin_data) is dict, "Error origin data type (1) - updateData"
|
||||
origin = origin_data.copy()
|
||||
origin[path[0]] = data
|
||||
path = []
|
||||
else:
|
||||
origin_data = self.getData(path[:-1])
|
||||
assert type(origin_data) is dict, "Error origin data type (2) - updateData"
|
||||
origin = origin_data.copy()
|
||||
origin[path[-1]] = data
|
||||
path = path[:-1]
|
||||
assert type(origin) is dict, "Error request data type - updateData"
|
||||
if self.threading:
|
||||
self.mdsShake("UPT", path, origin)
|
||||
else:
|
||||
self._local_update(path, origin)
|
||||
|
||||
def updateLog(self, Type, Data):
|
||||
if self.threading:
|
||||
self.ThreadExec(self._updateLog, (Type, Data))
|
||||
else:
|
||||
self._updateLog(Type, Data)
|
||||
|
||||
def _updateLog(self, Type, Data):
|
||||
with self.file(Type, "a", "Log") as f:
|
||||
f.write(self.LogType[Type] % Data)
|
||||
|
||||
@staticmethod
|
||||
def getTime(time_format="%b %d %Y %H:%M:%S %Z"):
|
||||
Time = time.localtime(time.time())
|
||||
return time.strftime(time_format, Time)
|
||||
|
||||
def getData(self, path):
|
||||
if self.threading:
|
||||
return self.mdsShake("GET", path).get("data")
|
||||
else:
|
||||
return self._local_query(path)
|
||||
|
||||
def getGroup(self, GroupID):
|
||||
Groups = self.getData(["Group"])
|
||||
if GroupID not in Groups:
|
||||
self.updateData(["Group", GroupID], self.GroupType)
|
||||
return self.GroupType
|
||||
return Groups.get(GroupID)
|
||||
|
||||
def getSEGroup(self, GroupID):
|
||||
GroupData = self.getGroup(GroupID)
|
||||
SEMode = GroupData.get("SEGroup")
|
||||
if SEMode is None:
|
||||
return None
|
||||
SEMode_ = {}
|
||||
for Mode in SEMode:
|
||||
Num_Mode = int(Mode)
|
||||
SEMode_[Num_Mode] = SEMode[Mode]
|
||||
return SEMode_
|
||||
|
||||
def limitDecrease(self, limit_type, userId):
|
||||
if self.threading:
|
||||
self.mdsShake("YLD", limit_type, userId)
|
||||
else:
|
||||
self.Data["LimitInfo"][limit_type][userId] -= 1
|
|
@ -1,45 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import time
|
||||
|
||||
from yuuki_core.ttypes import ContentType
|
||||
|
||||
from ..utils import Yuuki_DynamicTools
|
||||
|
||||
|
||||
class Yuuki_Callback:
|
||||
def __init__(self, Yuuki):
|
||||
"""
|
||||
Event Type:
|
||||
SEND_MESSAGE(25)
|
||||
"""
|
||||
self.Yuuki = Yuuki
|
||||
self.Yuuki_DynamicTools = Yuuki_DynamicTools(self.Yuuki)
|
||||
|
||||
def _shutdown(self, ncMessage):
|
||||
self.Yuuki.Thread_Control.add(self._shutdown_reply, (ncMessage,))
|
||||
self.Yuuki.exit()
|
||||
|
||||
def _shutdown_reply(self, ncMessage):
|
||||
time.sleep(1)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
ncMessage.message.to,
|
||||
self.Yuuki.get_text("Exit.")
|
||||
)
|
||||
|
||||
def _text(self, ncMessage):
|
||||
actions = {
|
||||
'[Yuuki] Remote Shutdown': self._shutdown,
|
||||
}
|
||||
if ncMessage.message.text in actions:
|
||||
actions[ncMessage.message.text](ncMessage)
|
||||
|
||||
def action(self, ncMessage):
|
||||
if ncMessage.message.contentType == ContentType.NONE:
|
||||
self._text(ncMessage)
|
|
@ -1,382 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from yuuki_core.ttypes import MIDType, ContentType, OpType
|
||||
|
||||
from ..utils import Yuuki_StaticTools, Yuuki_DynamicTools
|
||||
|
||||
|
||||
class Yuuki_Command:
|
||||
def __init__(self, Yuuki):
|
||||
"""
|
||||
Event Type:
|
||||
RECEIVE_MESSAGE (26)
|
||||
"""
|
||||
self.Yuuki = Yuuki
|
||||
self.Yuuki_DynamicTools = Yuuki_DynamicTools(self.Yuuki)
|
||||
|
||||
def _Help(self, ncMessage):
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text(
|
||||
"%s\n\t%s\n\nCommands Info:\n%s\n\nPrivacy:\n%s\n\nMore Information:\n%s\n\n%s") %
|
||||
(
|
||||
self.Yuuki.YuukiConfigs["name"],
|
||||
self.Yuuki.YuukiConfigs["version"],
|
||||
self.Yuuki.YuukiConfigs["man_page"],
|
||||
self.Yuuki.YuukiConfigs["privacy_page"],
|
||||
self.Yuuki.YuukiConfigs["project_url"],
|
||||
self.Yuuki.YuukiConfigs["copyright"],
|
||||
)
|
||||
)
|
||||
|
||||
def _Version(self, ncMessage):
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.YuukiConfigs["version"])
|
||||
|
||||
def _UserID(self, ncMessage):
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("LINE System UserID:\n") + ncMessage.message.from_)
|
||||
|
||||
def _GetAllHelper(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid,
|
||||
*self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]
|
||||
]
|
||||
if ncMessage.message.from_ in GroupPrivilege:
|
||||
for userId in self.Yuuki.Connect.helper:
|
||||
self.Yuuki_DynamicTools.sendUser(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
userId)
|
||||
|
||||
def _Speed(self, ncMessage):
|
||||
Time1 = time.time()
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Testing..."))
|
||||
Time2 = time.time()
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Speed:\n %s com/s") % (Time2 - Time1,))
|
||||
|
||||
def _SecurityMode(self, ncMessage):
|
||||
msgSep = ncMessage.message.text.split(" ")
|
||||
if ncMessage.message.from_ in self.Yuuki.Admin:
|
||||
if len(msgSep) == 2:
|
||||
if msgSep[1].isdigit() and 1 >= int(msgSep[1]) >= 0:
|
||||
self.Yuuki.data.updateData(
|
||||
["Global", "SecurityService"], bool(msgSep[1]))
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Okay"))
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Enable(True): 1\nDisable(False): 0"))
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
str(bool(
|
||||
self.Yuuki.data.getData(["Global", "SecurityService"]))))
|
||||
|
||||
def _Switch(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid,
|
||||
*self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]
|
||||
]
|
||||
if not self.Yuuki.data.getData(["Global", "SecurityService"]):
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("SecurityService of %s was disable") % (self.Yuuki.YuukiConfigs["name"],)
|
||||
)
|
||||
elif ncMessage.message.from_ in GroupPrivilege:
|
||||
self._Switch_action(ncMessage)
|
||||
|
||||
def _Switch_action(self, ncMessage):
|
||||
msgSep = ncMessage.message.text.split(" ")
|
||||
status = []
|
||||
unknown_msg = []
|
||||
unknown_msgtext = ""
|
||||
for count, code in enumerate(msgSep):
|
||||
if code.isdigit() and 3 >= int(code) >= 0:
|
||||
status.append(int(code))
|
||||
elif count != 0:
|
||||
unknown_msg.append(code.strip())
|
||||
self.Yuuki_DynamicTools.configSecurityStatus(
|
||||
ncMessage.message.to, status)
|
||||
if unknown_msg:
|
||||
unknown_msgtext = ", ".join(unknown_msg)
|
||||
if status:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Okay"))
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Not Found"))
|
||||
if unknown_msgtext != "":
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text(
|
||||
"Notice: Unknown command line argument(s)") + "\n({})".format(unknown_msgtext)
|
||||
)
|
||||
|
||||
def _DisableAll(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid,
|
||||
*self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]
|
||||
]
|
||||
if not self.Yuuki.data.getData(["Global", "SecurityService"]):
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("SecurityService of %s was disable") % (self.Yuuki.YuukiConfigs["name"],)
|
||||
)
|
||||
elif ncMessage.message.from_ in GroupPrivilege:
|
||||
self.Yuuki_DynamicTools.configSecurityStatus(
|
||||
ncMessage.message.to, [])
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Okay"))
|
||||
|
||||
def _ExtAdmin(self, ncMessage):
|
||||
msgSep = ncMessage.message.text.split(" ")
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid
|
||||
]
|
||||
if len(msgSep) == 3:
|
||||
if ncMessage.message.from_ in GroupPrivilege:
|
||||
if msgSep[1] == "add":
|
||||
self._ExtAdmin_Add(ncMessage, msgSep, GroupInfo)
|
||||
elif msgSep[1] == "delete":
|
||||
self._ExtAdmin_Delete(ncMessage, msgSep, GroupInfo)
|
||||
else:
|
||||
self._ExtAdmin_Query(ncMessage, GroupInfo)
|
||||
|
||||
def _ExtAdmin_Add(self, ncMessage, msgSep, GroupInfo):
|
||||
if msgSep[2] in [Member.mid for Member in GroupInfo.members]:
|
||||
if msgSep[2] in self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]:
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("Added")
|
||||
)
|
||||
elif msgSep[2] not in self.Yuuki.data.getData(["BlackList"]):
|
||||
origin = self.Yuuki.data.getData(
|
||||
["Group", GroupInfo.id, "Ext_Admin"])
|
||||
ext_admin_list = origin.copy()
|
||||
ext_admin_list.append(msgSep[2])
|
||||
self.Yuuki.data.updateData(
|
||||
["Group", GroupInfo.id, "Ext_Admin"], ext_admin_list)
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Okay"))
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text(
|
||||
"The User(s) was in our blacklist database."))
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text(
|
||||
"Wrong UserID or the guy is not in Group"))
|
||||
|
||||
def _ExtAdmin_Delete(self, ncMessage, msgSep, GroupInfo):
|
||||
if msgSep[2] in self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]:
|
||||
origin = self.Yuuki.data.getData(["Group", GroupInfo.id, "Ext_Admin"])
|
||||
ext_admin_list = origin.copy()
|
||||
ext_admin_list.remove(msgSep[2])
|
||||
self.Yuuki.data.updateData(
|
||||
["Group", GroupInfo.id, "Ext_Admin"], ext_admin_list)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("Okay")
|
||||
)
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Not Found"))
|
||||
|
||||
def _ExtAdmin_Query(self, ncMessage, GroupInfo):
|
||||
if self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]:
|
||||
status = ""
|
||||
status_added = []
|
||||
for member in GroupInfo.members:
|
||||
if member.mid in self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]:
|
||||
status += "{}\n".format(member.displayName)
|
||||
status_added.append(member.mid)
|
||||
for userId in self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]:
|
||||
if userId not in status_added:
|
||||
status += "{}: {}\n".format(
|
||||
self.Yuuki.get_text("Unknown"),
|
||||
userId
|
||||
)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
status + self.Yuuki.get_text("\nExtend Administrator(s)")
|
||||
)
|
||||
else:
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(
|
||||
ncMessage), self.Yuuki.get_text("Not Found"))
|
||||
|
||||
def _Status(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
group_status = self.Yuuki.data.getSEGroup(
|
||||
ncMessage.message.to)
|
||||
if not self.Yuuki.data.getData(["Global", "SecurityService"]):
|
||||
status = self.Yuuki.get_text("SecurityService of %s was disable") % (
|
||||
self.Yuuki.YuukiConfigs["name"],
|
||||
)
|
||||
elif group_status is None:
|
||||
status = self.Yuuki.get_text("Default without Initialize\nMain Admin of the Group:\n%s") % (
|
||||
Yuuki_StaticTools.sybGetGroupCreator(
|
||||
GroupInfo).displayName,
|
||||
)
|
||||
else:
|
||||
status = self.Yuuki.get_text(
|
||||
"SecurityService is Listening on\n"
|
||||
"\nURL:%s\nInvite:%s\nJoin:%s\nMembers:%s\n"
|
||||
"\nMain Admin of the Group:\n%s") % (
|
||||
group_status[OpType.NOTIFIED_UPDATE_GROUP],
|
||||
group_status[OpType.NOTIFIED_INVITE_INTO_GROUP],
|
||||
group_status[OpType.NOTIFIED_ACCEPT_GROUP_INVITATION],
|
||||
group_status[OpType.NOTIFIED_KICKOUT_FROM_GROUP],
|
||||
Yuuki_StaticTools.sybGetGroupCreator(
|
||||
GroupInfo).displayName,
|
||||
)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage), status)
|
||||
|
||||
def _GroupBackup(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid,
|
||||
*self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]
|
||||
]
|
||||
if ncMessage.message.from_ in GroupPrivilege:
|
||||
GroupMembers = [User.mid for User in GroupInfo.members]
|
||||
GroupInvites = None
|
||||
if GroupInfo.invitee:
|
||||
GroupInvites = [
|
||||
User.mid for User in GroupInfo.invitee]
|
||||
LayoutInfo = {
|
||||
"OriginID": GroupInfo.id,
|
||||
"Members": GroupMembers,
|
||||
"Invites": GroupInvites
|
||||
}
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
ncMessage.message.from_, GroupInfo.name)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
ncMessage.message.from_, json.dumps(LayoutInfo))
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
ncMessage.message.to, self.Yuuki.get_text("Okay"))
|
||||
|
||||
def _Quit(self, ncMessage):
|
||||
if ncMessage.message.toType == MIDType.GROUP:
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID
|
||||
).getGroup(ncMessage.message.to)
|
||||
GroupPrivilege = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid
|
||||
]
|
||||
if ncMessage.message.from_ in GroupPrivilege:
|
||||
self.Yuuki_DynamicTools.leaveGroup(GroupInfo)
|
||||
|
||||
def _Exit(self, ncMessage):
|
||||
if ncMessage.message.from_ in self.Yuuki.Admin:
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("Exit.")
|
||||
)
|
||||
self.Yuuki.exit()
|
||||
|
||||
def _SystemCall(self, ncMessage):
|
||||
msgSep = ncMessage.message.text.split(" ")
|
||||
if ncMessage.message.from_ in self.Yuuki.Admin:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
ComMsg = Yuuki_StaticTools.readCommandLine(msgSep[1:len(msgSep)])
|
||||
Report = str(eval(ComMsg))
|
||||
except:
|
||||
(err1, err2, err3, ErrorInfo) = Yuuki_StaticTools.errorReport()
|
||||
Report = "Star Yuuki BOT - Eval Error:\n%s\n%s\n%s\n\n%s" % (err1, err2, err3, ErrorInfo)
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(ncMessage), Report)
|
||||
|
||||
def _text(self, ncMessage):
|
||||
Yuuki_Name = self.Yuuki.YuukiConfigs["name"]
|
||||
msgSep = ncMessage.message.text.split(" ")[0].split("/")
|
||||
actions = {
|
||||
'Help': self._Help,
|
||||
'Version': self._Version,
|
||||
'UserID': self._UserID,
|
||||
'GetAllHelper': self._GetAllHelper,
|
||||
'Speed': self._Speed,
|
||||
'SecurityMode': self._SecurityMode,
|
||||
'Switch': self._Switch,
|
||||
'DisableAll': self._DisableAll,
|
||||
'ExtAdmin': self._ExtAdmin,
|
||||
'Status': self._Status,
|
||||
'GroupBackup': self._GroupBackup,
|
||||
'Quit': self._Quit,
|
||||
'Exit': self._Exit,
|
||||
'SystemCall': self._SystemCall,
|
||||
}
|
||||
if Yuuki_Name == msgSep[0]:
|
||||
if len(msgSep) > 1 and msgSep[1] in actions:
|
||||
return actions[msgSep[1]](ncMessage)
|
||||
return self.Yuuki_DynamicTools.sendText(
|
||||
Yuuki_StaticTools.sendToWho(ncMessage),
|
||||
self.Yuuki.get_text("Helllo^^\nMy name is %s ><\nNice to meet you OwO") % (Yuuki_Name,)
|
||||
)
|
||||
|
||||
def _contact(self, ncMessage):
|
||||
cache = ncMessage.message.contentMetadata["mid"]
|
||||
contactInfo = self.Yuuki_DynamicTools.getContact(cache)
|
||||
if not contactInfo:
|
||||
msg = self.Yuuki.get_text("Not Found")
|
||||
elif contactInfo.mid in self.Yuuki.data.getData(["BlackList"]):
|
||||
msg = "{}\n{}".format(self.Yuuki.get_text(
|
||||
"The User(s) was in our blacklist database."), contactInfo.mid)
|
||||
else:
|
||||
msg = self.Yuuki.get_text("Name:%s\nPicture URL:%s/%s\nStatusMessage:\n%s\nLINE System UserID:%s") % \
|
||||
(contactInfo.displayName, self.Yuuki.LINE_Media_server, contactInfo.pictureStatus,
|
||||
contactInfo.statusMessage, contactInfo.mid)
|
||||
self.Yuuki_DynamicTools.sendText(Yuuki_StaticTools.sendToWho(ncMessage), msg)
|
||||
|
||||
def action(self, ncMessage):
|
||||
BlockedIgnore = (ncMessage.message.to in self.Yuuki.data.getData(["BlackList"])) or \
|
||||
(ncMessage.message.from_ in self.Yuuki.data.getData(["BlackList"]))
|
||||
|
||||
if ('BOT_CHECK' in ncMessage.message.contentMetadata) or BlockedIgnore:
|
||||
pass
|
||||
|
||||
elif ncMessage.message.toType == MIDType.ROOM:
|
||||
self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID
|
||||
).leaveRoom(
|
||||
self.Yuuki.Seq, ncMessage.message.to
|
||||
)
|
||||
|
||||
elif ncMessage.message.contentType == ContentType.NONE:
|
||||
self._text(ncMessage)
|
||||
|
||||
elif ncMessage.message.contentType == ContentType.CONTACT:
|
||||
self._contact(ncMessage)
|
|
@ -1,91 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
|
||||
from ..utils import Yuuki_StaticTools, Yuuki_DynamicTools
|
||||
|
||||
|
||||
class Yuuki_JoinGroup:
|
||||
def __init__(self, Yuuki):
|
||||
"""
|
||||
Event Type:
|
||||
NOTIFIED_INVITE_INTO_GROUP (13)
|
||||
"""
|
||||
self.Yuuki = Yuuki
|
||||
self.Yuuki_DynamicTools = Yuuki_DynamicTools(self.Yuuki)
|
||||
|
||||
def _accept(self, GroupID, GroupInfo, Inviter):
|
||||
GroupList = self.Yuuki.data.getData(["Global", "GroupJoined"])
|
||||
NewGroupList = GroupList.copy()
|
||||
NewGroupList.append(GroupID)
|
||||
self.Yuuki.data.updateData(
|
||||
["Global", "GroupJoined"], NewGroupList)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
GroupID,
|
||||
self.Yuuki.get_text("Helllo^^\nMy name is %s ><\nNice to meet you OwO") %
|
||||
(self.Yuuki.YuukiConfigs["name"],)
|
||||
)
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
GroupID,
|
||||
self.Yuuki.get_text("Type:\n\t%s/Help\nto get more information\n\nMain Admin of the Group:\n%s") %
|
||||
(
|
||||
self.Yuuki.YuukiConfigs["name"],
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).displayName,
|
||||
)
|
||||
)
|
||||
self.Yuuki_DynamicTools.getGroupTicket(GroupID, self.Yuuki.MyMID, True)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog(
|
||||
"JoinGroup", (self.Yuuki.data.getTime(), GroupInfo.name, GroupID, Inviter))
|
||||
|
||||
def _reject(self, GroupID, Inviter):
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
GroupID,
|
||||
self.Yuuki.get_text("Sorry...\nThe number of members is not satisfied (%s needed)") %
|
||||
(self.Yuuki.YuukiConfigs["GroupMebers_Demand"],)
|
||||
)
|
||||
self.Yuuki_DynamicTools.getClient(self.Yuuki.MyMID).leaveGroup(self.Yuuki.Seq, GroupID)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog(
|
||||
"JoinGroup", (self.Yuuki.data.getTime(), GroupID, "Not Join", Inviter))
|
||||
|
||||
def _helper_check(self, ncMessage, GroupInvite, BlockedIgnore):
|
||||
if ncMessage.param1 in self.Yuuki.data.getData(["Global", "GroupJoined"]) and not BlockedIgnore:
|
||||
for userId in self.Yuuki.Connect.helper:
|
||||
if self.Yuuki_DynamicTools.checkInInvitationList(ncMessage, userId) or userId in GroupInvite:
|
||||
self.Yuuki_DynamicTools.getClient(userId).acceptGroupInvitation(self.Yuuki.Seq, ncMessage.param1)
|
||||
self.Yuuki_DynamicTools.getGroupTicket(ncMessage.param1, userId, True)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("JoinGroup", (
|
||||
self.Yuuki.data.getTime(),
|
||||
ncMessage.param1,
|
||||
userId,
|
||||
ncMessage.param2
|
||||
))
|
||||
|
||||
def action(self, ncMessage):
|
||||
GroupInvite = []
|
||||
BlockedIgnore = ncMessage.param2 in self.Yuuki.data.getData(["BlackList"])
|
||||
if self.Yuuki_DynamicTools.checkInInvitationList(ncMessage) and not BlockedIgnore:
|
||||
GroupID = ncMessage.param1
|
||||
Inviter = ncMessage.param2
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(
|
||||
self.Yuuki.MyMID).getGroup(GroupID)
|
||||
if GroupInfo.members:
|
||||
GroupMember = [Catched.mid for Catched in GroupInfo.members]
|
||||
GroupInfo.invitee = []
|
||||
if GroupInfo.invitee:
|
||||
GroupInvite = [
|
||||
Catched.mid for Catched in GroupInfo.invitee]
|
||||
self.Yuuki_DynamicTools.getClient(self.Yuuki.MyMID).acceptGroupInvitation(self.Yuuki.Seq, GroupID)
|
||||
if len(GroupMember) >= self.Yuuki.YuukiConfigs["GroupMebers_Demand"]:
|
||||
self._accept(GroupID, GroupInfo, Inviter)
|
||||
else:
|
||||
self._reject(GroupID, Inviter)
|
||||
self._helper_check(ncMessage, GroupInvite, BlockedIgnore)
|
||||
self.Yuuki.Security(ncMessage)
|
|
@ -1,308 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
|
||||
from yuuki_core.ttypes import OpType
|
||||
|
||||
from ..utils import Yuuki_StaticTools, Yuuki_DynamicTools
|
||||
|
||||
|
||||
def security_access_checker(function):
|
||||
def wrapper(*args):
|
||||
if not args[2].get("Security_Access"):
|
||||
return
|
||||
return function(*args)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class Yuuki_Security:
|
||||
def __init__(self, Yuuki):
|
||||
"""
|
||||
Event Type:
|
||||
NOTIFIED_UPDATE_GROUP (11)
|
||||
NOTIFIED_INVITE_INTO_GROUP (13)
|
||||
NOTIFIED_ACCEPT_GROUP_INVITATION (17)
|
||||
NOTIFIED_KICKOUT_FROM_GROUP (19)
|
||||
"""
|
||||
self.Yuuki = Yuuki
|
||||
|
||||
self.Yuuki_DynamicTools = Yuuki_DynamicTools(self.Yuuki)
|
||||
|
||||
@security_access_checker
|
||||
def _NOTIFIED_UPDATE_GROUP(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
if SecurityInfo["Another"] == '4':
|
||||
if not GroupInfo.preventJoinByTicket and SecurityInfo["Action"] not in self.Yuuki.Connect.helper:
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.changeGroupUrlStatus,
|
||||
(GroupInfo, False)
|
||||
)
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.sendText,
|
||||
(SecurityInfo["GroupID"], self.Yuuki.get_text("DO NOT ENABLE THE GROUP URL STATUS, see you..."))
|
||||
)
|
||||
Kicker = self.Yuuki_DynamicTools.modifyGroupMemberList(1, GroupInfo, SecurityInfo["Action"])
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Kicker,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type
|
||||
))
|
||||
|
||||
@security_access_checker
|
||||
def _NOTIFIED_INVITE_INTO_GROUP(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
Canceler = "None"
|
||||
if "\x1e" in SecurityInfo["Another"]:
|
||||
Canceler = self._NOTIFIED_INVITE_INTO_GROUP_list(GroupInfo, SecurityInfo, ncMessage, Canceler)
|
||||
elif SecurityInfo["Another"] not in self.Yuuki.AllAccountIds + SecurityInfo["GroupPrivilege"]:
|
||||
Canceler = self._NOTIFIED_INVITE_INTO_GROUP_single(GroupInfo, SecurityInfo, ncMessage)
|
||||
if Canceler != "None":
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
SecurityInfo["GroupID"],
|
||||
self.Yuuki.get_text("Do not invite anyone...thanks")
|
||||
)
|
||||
|
||||
def _NOTIFIED_INVITE_INTO_GROUP_list(self, GroupInfo, SecurityInfo, ncMessage, Canceler):
|
||||
for userId in SecurityInfo["Another"].split("\x1e"):
|
||||
if userId not in self.Yuuki.AllAccountIds + SecurityInfo["GroupPrivilege"]:
|
||||
if GroupInfo.invitee and userId in [user.mid for user in GroupInfo.invitee]:
|
||||
Canceler = self.Yuuki_DynamicTools.modifyGroupMemberList(2, GroupInfo, userId)
|
||||
else:
|
||||
Canceler = self.Yuuki_DynamicTools.modifyGroupMemberList(1, GroupInfo, userId)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Canceler,
|
||||
SecurityInfo["Action"],
|
||||
userId,
|
||||
ncMessage.type * 10
|
||||
))
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("CancelEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Canceler,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"].replace("\x1e", ",")
|
||||
))
|
||||
return Canceler
|
||||
|
||||
def _NOTIFIED_INVITE_INTO_GROUP_single(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
if GroupInfo.invitee and SecurityInfo["Another"] in [user.mid for user in GroupInfo.invitee]:
|
||||
Canceler = self.Yuuki_DynamicTools.modifyGroupMemberList(2, GroupInfo, SecurityInfo["Another"])
|
||||
else:
|
||||
Canceler = self.Yuuki_DynamicTools.modifyGroupMemberList(1, GroupInfo, SecurityInfo["Another"])
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name, SecurityInfo["GroupID"],
|
||||
Canceler, SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type * 10
|
||||
))
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("CancelEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Canceler,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"]
|
||||
))
|
||||
return Canceler
|
||||
|
||||
@security_access_checker
|
||||
def _NOTIFIED_ACCEPT_GROUP_INVITATION(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
for userId in self.Yuuki.data.getData(["BlackList"]):
|
||||
if userId == SecurityInfo["Action"]:
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.sendText,
|
||||
(SecurityInfo["GroupID"], self.Yuuki.get_text("You are our blacklist. Bye~"))
|
||||
)
|
||||
Kicker = self.Yuuki_DynamicTools.modifyGroupMemberList(1, GroupInfo, SecurityInfo["Action"])
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Kicker,
|
||||
Kicker,
|
||||
SecurityInfo["Action"],
|
||||
ncMessage.type
|
||||
))
|
||||
|
||||
def _NOTIFIED_KICKOUT_FROM_GROUP(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
if SecurityInfo["Action"] in self.Yuuki.Connect.helper:
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type * 10 + 1
|
||||
))
|
||||
elif SecurityInfo["Another"] in self.Yuuki.AllAccountIds:
|
||||
Kicker = "None"
|
||||
try:
|
||||
Kicker = self.Yuuki_DynamicTools.modifyGroupMemberList(
|
||||
1,
|
||||
GroupInfo,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"]
|
||||
)
|
||||
self._NOTIFIED_KICKOUT_FROM_GROUP_rescue(GroupInfo, SecurityInfo, ncMessage, Kicker)
|
||||
except:
|
||||
self._NOTIFIED_KICKOUT_FROM_GROUP_rescue_failure(GroupInfo, SecurityInfo, ncMessage, Kicker)
|
||||
BlackList = self.Yuuki.data.getData(["BlackList"])
|
||||
if SecurityInfo["Action"] not in BlackList:
|
||||
NewBlackList = BlackList.copy()
|
||||
NewBlackList.append(SecurityInfo["Action"])
|
||||
self.Yuuki.data.updateData(["BlackList"], NewBlackList)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("BlackList", (
|
||||
self.Yuuki.data.getTime(),
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["GroupID"]
|
||||
))
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.sendText,
|
||||
(
|
||||
SecurityInfo["Action"],
|
||||
self.Yuuki.get_text("You had been blocked by our database.")
|
||||
)
|
||||
)
|
||||
elif SecurityInfo["Security_Access"]:
|
||||
self._NOTIFIED_KICKOUT_FROM_GROUP_normal(GroupInfo, SecurityInfo, ncMessage)
|
||||
|
||||
def _NOTIFIED_KICKOUT_FROM_GROUP_rescue(self, GroupInfo, SecurityInfo, ncMessage, Kicker):
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Kicker,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type * 10 + 2
|
||||
))
|
||||
assert Kicker != "None", "No Helper Found"
|
||||
if GroupInfo.preventJoinByTicket:
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.changeGroupUrlStatus,
|
||||
(GroupInfo, True, Kicker)
|
||||
)
|
||||
GroupTicket = self.Yuuki_DynamicTools.getGroupTicket(
|
||||
SecurityInfo["GroupID"], Kicker)
|
||||
try:
|
||||
self.Yuuki_DynamicTools.getClient(SecurityInfo["Another"]).acceptGroupInvitationByTicket(
|
||||
self.Yuuki.Seq,
|
||||
SecurityInfo["GroupID"],
|
||||
GroupTicket
|
||||
)
|
||||
except:
|
||||
if GroupInfo.preventJoinByTicket:
|
||||
self.Yuuki_DynamicTools.changeGroupUrlStatus(
|
||||
GroupInfo,
|
||||
True,
|
||||
Kicker
|
||||
)
|
||||
GroupTicket = self.Yuuki_DynamicTools.getGroupTicket(
|
||||
SecurityInfo["GroupID"], Kicker, True)
|
||||
self.Yuuki_DynamicTools.getClient(SecurityInfo["Another"]).acceptGroupInvitationByTicket(
|
||||
self.Yuuki.Seq,
|
||||
SecurityInfo["GroupID"],
|
||||
GroupTicket
|
||||
)
|
||||
if GroupInfo.preventJoinByTicket:
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.changeGroupUrlStatus, (GroupInfo, False, SecurityInfo["Another"]))
|
||||
self.Yuuki_DynamicTools.getGroupTicket(
|
||||
SecurityInfo["GroupID"], SecurityInfo["Another"], True)
|
||||
|
||||
def _NOTIFIED_KICKOUT_FROM_GROUP_rescue_failure(self, GroupInfo, SecurityInfo, ncMessage, Kicker):
|
||||
(err1, err2, err3, ErrorInfo) = Yuuki_StaticTools.errorReport()
|
||||
for Root in self.Yuuki.Admin:
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Root,
|
||||
"Star Yuuki BOT - SecurityService Failure\n\n%s\n%s\n%s\n\n%s" % (err1, err2, err3, ErrorInfo)
|
||||
)
|
||||
if SecurityInfo["Another"] == self.Yuuki.MyMID:
|
||||
GroupList = self.Yuuki.data.getData(["Global", "GroupJoined"])
|
||||
NewGroupList = GroupList.copy()
|
||||
NewGroupList.remove(SecurityInfo["GroupID"])
|
||||
self.Yuuki.data.updateData(["Global", "GroupJoined"], NewGroupList)
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Kicker,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type * 10 + 3
|
||||
))
|
||||
|
||||
def _NOTIFIED_KICKOUT_FROM_GROUP_normal(self, GroupInfo, SecurityInfo, ncMessage):
|
||||
self.Yuuki.threadExec(self.Yuuki_DynamicTools.sendText, (
|
||||
SecurityInfo["GroupID"], self.Yuuki.get_text("DO NOT KICK, thank you ^^")))
|
||||
Kicker = self.Yuuki_DynamicTools.modifyGroupMemberList(1, GroupInfo, SecurityInfo["Action"])
|
||||
# Log
|
||||
self.Yuuki.data.updateLog("KickEvent", (
|
||||
self.Yuuki.data.getTime(),
|
||||
GroupInfo.name,
|
||||
SecurityInfo["GroupID"],
|
||||
Kicker,
|
||||
SecurityInfo["Action"],
|
||||
SecurityInfo["Another"],
|
||||
ncMessage.type
|
||||
))
|
||||
self.Yuuki.threadExec(self.Yuuki_DynamicTools.sendText, (SecurityInfo["GroupID"], self.Yuuki.get_text(
|
||||
"The one who was been kicked:")))
|
||||
self.Yuuki.threadExec(
|
||||
self.Yuuki_DynamicTools.sendUser, (SecurityInfo["GroupID"], SecurityInfo["Another"]))
|
||||
|
||||
def action(self, ncMessage):
|
||||
SecurityInfo = Yuuki_StaticTools.securityForWhere(ncMessage)
|
||||
|
||||
GroupInfo = self.Yuuki_DynamicTools.getClient(self.Yuuki.MyMID).getGroup(SecurityInfo["GroupID"])
|
||||
SecurityInfo["GroupPrivilege"] = [
|
||||
*self.Yuuki.Admin,
|
||||
Yuuki_StaticTools.sybGetGroupCreator(GroupInfo).mid,
|
||||
*self.Yuuki.data.getGroup(GroupInfo.id)["Ext_Admin"]
|
||||
]
|
||||
if SecurityInfo["Action"] in SecurityInfo["GroupPrivilege"] or \
|
||||
SecurityInfo["Another"] in SecurityInfo["GroupPrivilege"]:
|
||||
if ncMessage.type != OpType.NOTIFIED_KICKOUT_FROM_GROUP:
|
||||
return
|
||||
elif SecurityInfo["Action"] in SecurityInfo["GroupPrivilege"]:
|
||||
return
|
||||
|
||||
SEGroup = self.Yuuki.data.getSEGroup(SecurityInfo["GroupID"])
|
||||
if SEGroup is None:
|
||||
SecurityInfo["Security_Access"] = self.Yuuki.data.getData(["Global", "SecurityService"])
|
||||
elif SEGroup[ncMessage.type]:
|
||||
SecurityInfo["Security_Access"] = SEGroup[ncMessage.type]
|
||||
else:
|
||||
SecurityInfo["Security_Access"] = False
|
||||
|
||||
if self.Yuuki.data.getData(["Global", "SecurityService"]):
|
||||
{
|
||||
OpType.NOTIFIED_UPDATE_GROUP: self._NOTIFIED_UPDATE_GROUP,
|
||||
OpType.NOTIFIED_INVITE_INTO_GROUP: self._NOTIFIED_INVITE_INTO_GROUP,
|
||||
OpType.NOTIFIED_ACCEPT_GROUP_INVITATION: self._NOTIFIED_ACCEPT_GROUP_INVITATION,
|
||||
OpType.NOTIFIED_KICKOUT_FROM_GROUP: self._NOTIFIED_KICKOUT_FROM_GROUP
|
||||
}[ncMessage.type](GroupInfo, SecurityInfo, ncMessage)
|
|
@ -1,258 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
from functools import wraps
|
||||
|
||||
from flask import Flask, render_template, request, redirect, jsonify
|
||||
from flask_bootstrap import Bootstrap
|
||||
from gevent.pywsgi import WSGIServer
|
||||
|
||||
from .reader import Yuuki_WebDataReader
|
||||
from ..utils import Yuuki_DynamicTools
|
||||
|
||||
wa_app = Flask(__name__)
|
||||
|
||||
Yuuki_Handle = None
|
||||
Yuuki_Handle_Data = None
|
||||
Yuuki_APIHandle_Data = None
|
||||
|
||||
passports = []
|
||||
password = str(hash(random.random()))
|
||||
|
||||
|
||||
def authorized_response(function):
|
||||
@wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
if "yuuki_admin" in request.cookies \
|
||||
and request.cookies["yuuki_admin"] in passports:
|
||||
return jsonify(function(*args, **kwargs))
|
||||
response = jsonify({"status": 403})
|
||||
response.set_cookie(
|
||||
key='yuuki_admin',
|
||||
value='',
|
||||
expires=0
|
||||
)
|
||||
return response
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class Yuuki_WebAdmin:
|
||||
Bootstrap(wa_app)
|
||||
http_server = None
|
||||
|
||||
def __init__(self, Yuuki, port):
|
||||
global Yuuki_Handle, Yuuki_Handle_Data, Yuuki_APIHandle_Data
|
||||
Yuuki_Handle = Yuuki
|
||||
Yuuki_Handle_Data = Yuuki.data
|
||||
Yuuki_APIHandle_Data = Yuuki_WebDataReader(Yuuki_Handle_Data)
|
||||
self.port = port
|
||||
|
||||
@staticmethod
|
||||
def set_password(code):
|
||||
global password
|
||||
password = code
|
||||
|
||||
def wa_listen(self):
|
||||
self.http_server = WSGIServer(('', self.port), wa_app)
|
||||
self.http_server.serve_forever()
|
||||
|
||||
# HTML Server
|
||||
@staticmethod
|
||||
@wa_app.route("/")
|
||||
def index():
|
||||
status = False
|
||||
if "yuuki_admin" in request.cookies \
|
||||
and request.cookies["yuuki_admin"] in passports:
|
||||
status = True
|
||||
return render_template(
|
||||
'/index.html',
|
||||
name=Yuuki_Handle.YuukiConfigs["name"],
|
||||
authorized=status
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/logout")
|
||||
def logout():
|
||||
response = redirect("/")
|
||||
if "yuuki_admin" in request.cookies:
|
||||
if request.cookies.get("yuuki_admin") in passports:
|
||||
passports.remove(request.cookies.get("yuuki_admin"))
|
||||
response.set_cookie(
|
||||
key='yuuki_admin',
|
||||
value='',
|
||||
expires=0
|
||||
)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/logo")
|
||||
def logo():
|
||||
default_logo_path = os.path.abspath(os.path.join(__file__, "../../../logo.png"))
|
||||
online_logo_path = "https://raw.githubusercontent.com/star-inc/star_yuuki_bot/master/logo.png"
|
||||
if os.path.isfile(default_logo_path):
|
||||
with open(default_logo_path, "rb") as f:
|
||||
return f"data:image/png;base64, {base64.b64encode(f.read()).decode('utf-8')}"
|
||||
return online_logo_path
|
||||
|
||||
# API Points
|
||||
@staticmethod
|
||||
@wa_app.route("/api/verify", methods=['POST'])
|
||||
def verify():
|
||||
if "code" in request.values:
|
||||
if request.values["code"] == password:
|
||||
seed = hash(random.random() + time.time())
|
||||
seed = str(seed).encode('utf-8')
|
||||
session_key = hashlib.sha256(seed).hexdigest()
|
||||
passports.append(session_key)
|
||||
result = jsonify({"status": 200, "session": session_key})
|
||||
result.set_cookie(
|
||||
key='yuuki_admin',
|
||||
value=session_key
|
||||
)
|
||||
return result
|
||||
return jsonify({"status": 401})
|
||||
return jsonify({"status": 403})
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/profile", methods=["GET", "PUT"])
|
||||
@authorized_response
|
||||
def profile():
|
||||
if request.method == "GET":
|
||||
return {
|
||||
"id": Yuuki_Handle.profile.mid,
|
||||
"version": Yuuki_Handle.YuukiConfigs["version"],
|
||||
"name": Yuuki_Handle.profile.displayName,
|
||||
"status": Yuuki_Handle.profile.statusMessage,
|
||||
"picture": f"{Yuuki_Handle.LINE_Media_server}/{Yuuki_Handle.profile.pictureStatus}"
|
||||
if Yuuki_Handle.profile.pictureStatus is not None else None,
|
||||
}
|
||||
if request.method == "PUT" and "name" in request.values and "status" in request.values:
|
||||
Yuuki_Handle.profile.displayName = request.values["name"]
|
||||
Yuuki_Handle.profile.statusMessage = request.values["status"]
|
||||
Yuuki_DynamicTools(Yuuki_Handle).getClient(Yuuki_Handle.MyMID).updateProfile(
|
||||
Yuuki_Handle.Seq, Yuuki_Handle.profile
|
||||
)
|
||||
return {"status": 200}
|
||||
return {"status": 400}
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/groups", methods=["GET", "POST", "DELETE"])
|
||||
@authorized_response
|
||||
def groups():
|
||||
if request.method == "GET":
|
||||
return Yuuki_Handle_Data.getData(["Global", "GroupJoined"])
|
||||
if request.method == "POST" and "id" in request.values:
|
||||
return Yuuki_DynamicTools(Yuuki_Handle).getClient(Yuuki_Handle.MyMID).acceptGroupInvitation(
|
||||
Yuuki_Handle.Seq, request.values["id"]
|
||||
)
|
||||
if request.method == "DELETE" and "id" in request.values:
|
||||
group_information = Yuuki_DynamicTools(Yuuki_Handle).getClient(
|
||||
Yuuki_Handle.MyMID
|
||||
).getGroup(request.values["id"])
|
||||
return Yuuki_DynamicTools(Yuuki_Handle).leaveGroup(group_information)
|
||||
return {"status": 400}
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/group/ticket", methods=["POST"])
|
||||
@authorized_response
|
||||
def group_ticket():
|
||||
if "id" in request.values and "ticket" in request.values:
|
||||
return Yuuki_DynamicTools(Yuuki_Handle).getClient(Yuuki_Handle.MyMID).acceptGroupInvitationByTicket(
|
||||
Yuuki_Handle.Seq, request.values["id"], request.values["ticket"]
|
||||
)
|
||||
return {"status": 400}
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/groups/<id_list>")
|
||||
@authorized_response
|
||||
def groups_information(id_list=None):
|
||||
read_id_list = id_list.split(",")
|
||||
if isinstance(read_id_list, list) and len(read_id_list) > 0:
|
||||
def type_handle(obj):
|
||||
for key in obj.__dict__:
|
||||
if key == "pictureStatus" and obj.__dict__[key] is not None:
|
||||
obj.__dict__[
|
||||
key] = f"{Yuuki_Handle.LINE_Media_server}/{obj.__dict__[key]}"
|
||||
if isinstance(obj.__dict__[key], list):
|
||||
obj.__dict__[key] = list(
|
||||
map(type_handle, obj.__dict__[key]))
|
||||
if hasattr(obj.__dict__[key], '__dict__'):
|
||||
obj.__dict__[key] = obj.__dict__[key].__dict__
|
||||
return obj.__dict__
|
||||
|
||||
return [
|
||||
type_handle(obj)
|
||||
for obj in Yuuki_DynamicTools(Yuuki_Handle).getClient(Yuuki_Handle.MyMID).getGroups(read_id_list)
|
||||
]
|
||||
return {"status": 400}
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/helpers")
|
||||
@authorized_response
|
||||
def helpers():
|
||||
def info_handle(profile):
|
||||
return {
|
||||
"id": profile.mid,
|
||||
"name": profile.displayName,
|
||||
"status": profile.statusMessage,
|
||||
"picture": f"{Yuuki_Handle.LINE_Media_server}/{profile.pictureStatus}"
|
||||
if profile.pictureStatus is not None else None,
|
||||
}
|
||||
|
||||
return [
|
||||
info_handle(Yuuki_Handle.Connect.helper[userId].get("profile"))
|
||||
for userId in Yuuki_Handle.Connect.helper
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/settings")
|
||||
@authorized_response
|
||||
def settings():
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/events/<doctype>")
|
||||
@authorized_response
|
||||
def get_logs(doctype):
|
||||
return Yuuki_APIHandle_Data.get_logs(doctype)
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/broadcast", methods=["POST"])
|
||||
@authorized_response
|
||||
def broadcast():
|
||||
if "message" in request.values and "audience" in request.values and request.values["message"]:
|
||||
audience_ids = {
|
||||
"groups": lambda: Yuuki_Handle_Data.getData(
|
||||
["Global", "GroupJoined"]
|
||||
)
|
||||
}
|
||||
if request.values["audience"] not in audience_ids:
|
||||
return {"status": "404"}
|
||||
return [
|
||||
Yuuki_DynamicTools(Yuuki_Handle).sendText(target_id, request.values["message"])
|
||||
for target_id in audience_ids[request.values["audience"]]()
|
||||
]
|
||||
return {"status": 400}
|
||||
|
||||
@staticmethod
|
||||
@wa_app.route("/api/shutdown")
|
||||
@authorized_response
|
||||
def shutdown():
|
||||
LINE_ACCOUNT_SECURITY_NOTIFY_ID = "u085311ecd9e3e3d74ae4c9f5437cbcb5"
|
||||
# The ID belongs to an official account, which is controlled by SysOp of LINE.
|
||||
Yuuki_DynamicTools(Yuuki_Handle).sendText(
|
||||
LINE_ACCOUNT_SECURITY_NOTIFY_ID,
|
||||
"[Yuuki] Remote Shutdown"
|
||||
)
|
||||
return {"status": 200}
|
|
@ -1,47 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
{{ bootstrap.load_css() }}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"/>
|
||||
|
||||
<title>Star Yuuki BOT - WebAdmin</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{% from 'bootstrap/nav.html' import render_nav_item %}
|
||||
|
||||
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
|
||||
<a class="navbar-brand" href="/">{{ name }} - WebAdmin</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
|
||||
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
{{ render_nav_item('index') }}
|
||||
</ul>
|
||||
{% if authorized %}
|
||||
<a class="navbar-brand" href="/logout">
|
||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Logout</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main id="app"></main>
|
||||
|
||||
<!-- Optional JavaScript -->
|
||||
{{ bootstrap.load_js() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.min.js"></script>
|
||||
<script type="module" src="{{ url_for('static', filename='js/index.js') }}"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
183
libs/yuuki.py
183
libs/yuuki.py
|
@ -1,183 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
|
||||
from git import Repo
|
||||
from yuuki_core.ttypes import OpType
|
||||
|
||||
from .connector import Yuuki_Connect
|
||||
from .data import Yuuki_Data
|
||||
from .events import Yuuki_Command, Yuuki_JoinGroup, Yuuki_Security, Yuuki_Callback
|
||||
from .i18n import Yuuki_LangSetting
|
||||
from .polling import Yuuki_Poll
|
||||
from .thread import Yuuki_Multiprocess
|
||||
from .webadmin.server import Yuuki_WebAdmin
|
||||
|
||||
|
||||
class Yuuki:
|
||||
def __init__(self, Yuuki_Settings):
|
||||
|
||||
self.Connect = Yuuki_Connect(Yuuki_Settings)
|
||||
self.YuukiConfigs = Yuuki_Settings.systemConfig
|
||||
|
||||
# Static_Variable
|
||||
self.Thread_Control = Yuuki_Multiprocess()
|
||||
|
||||
self.Seq = self.YuukiConfigs["Seq"]
|
||||
self.Admin = self.YuukiConfigs["Admin"]
|
||||
self.Threading = self.YuukiConfigs["Advanced"]
|
||||
self.KickLimit = self.YuukiConfigs["Hour_KickLimit"]
|
||||
self.CancelLimit = self.YuukiConfigs["Hour_CancelLimit"]
|
||||
self.i18n = Yuuki_LangSetting(self.YuukiConfigs["Default_Language"])
|
||||
|
||||
self.LINE_Media_server = "https://obs.line-apps.com"
|
||||
|
||||
self._Version_Check()
|
||||
|
||||
def _Version_Check(self):
|
||||
git_result = "Unknown"
|
||||
origin_url = "https://github.com/star-inc/star_yuuki_bot.git"
|
||||
|
||||
if self.YuukiConfigs["version_check"]:
|
||||
git_remote = Repo('.').remote()
|
||||
update_status = git_remote.fetch()[0]
|
||||
if update_status.flags == 64:
|
||||
git_result = "New version found."
|
||||
elif update_status.flags == 4:
|
||||
git_result = "This is the latest version."
|
||||
origin_url = "\n".join(git_remote.urls)
|
||||
|
||||
return self._Announce_Dog(git_result, origin_url)
|
||||
|
||||
def _Announce_Dog(self, git_result, origin_url):
|
||||
print(
|
||||
"\n{} {}\n"
|
||||
"\t===\n\n"
|
||||
"<*> {}\n\n"
|
||||
"Update Origin:\n"
|
||||
"\t{}\n\n\t\t\t\t\t"
|
||||
"{}\n\t{}\n".format(
|
||||
self.YuukiConfigs["name"],
|
||||
self.YuukiConfigs["version"],
|
||||
git_result,
|
||||
origin_url,
|
||||
self.YuukiConfigs["copyright"],
|
||||
"\t==" * 5
|
||||
)
|
||||
)
|
||||
self._LINE_Login()
|
||||
|
||||
def _LINE_Login(self):
|
||||
(self.client, self.listen) = self.Connect.connect()
|
||||
|
||||
if self.YuukiConfigs.get("helper_LINE_ACCESS_KEYs"):
|
||||
for access in self.YuukiConfigs["helper_LINE_ACCESS_KEYs"]:
|
||||
self.Connect.helperConnect(access)
|
||||
|
||||
# Dynamic Variable
|
||||
self.get_text = self.i18n.gettext
|
||||
|
||||
self.JoinGroup = Yuuki_JoinGroup(self).action
|
||||
self.Command = Yuuki_Command(self).action
|
||||
self.Security = Yuuki_Security(self).action
|
||||
self.Callback = Yuuki_Callback(self).action
|
||||
|
||||
mds_port = self.YuukiConfigs["MDS_Port"]
|
||||
self.data = Yuuki_Data(self.Threading, mds_port)
|
||||
|
||||
self.data.updateData(["Global", "GroupJoined"], self.client.getGroupIdsJoined())
|
||||
self.data.updateData(["Global", "SecurityService"], self.YuukiConfigs["SecurityService"])
|
||||
self._Initialize()
|
||||
|
||||
def _Initialize(self):
|
||||
self.profile = self.client.getProfile()
|
||||
self.MyMID = self.profile.mid
|
||||
self.revision = self.client.getLastOpRevision()
|
||||
|
||||
self.AllAccountIds = [self.MyMID]
|
||||
|
||||
for userId in self.Connect.helper:
|
||||
self.AllAccountIds.append(userId)
|
||||
|
||||
if len(self.data.getData(["LimitInfo"])) != 2:
|
||||
self.data.updateData(["LimitInfo"], self.data.LimitType)
|
||||
self._Setup_WebAdmin()
|
||||
|
||||
def _Setup_WebAdmin(self):
|
||||
if self.Threading and self.YuukiConfigs.get("WebAdmin"):
|
||||
wa_port = self.YuukiConfigs["WebAdmin_Port"]
|
||||
password = str(hash(random.random()))
|
||||
self.web_admin = Yuuki_WebAdmin(self, wa_port)
|
||||
self.web_admin.set_password(password)
|
||||
self.Thread_Control.add(self.web_admin.wa_listen)
|
||||
print(
|
||||
"<*> Yuuki WebAdmin - Enable\n"
|
||||
"<*> http://localhost:{}\n"
|
||||
"<*> Password: {}\n".format(wa_port, password)
|
||||
)
|
||||
else:
|
||||
print("<*> Yuuki WebAdmin - Disable\n")
|
||||
|
||||
def exit(self, restart=False):
|
||||
print("System Exit")
|
||||
while self.data.syncData():
|
||||
self.data.updateData(["Global", "Power"], False)
|
||||
if self.Threading:
|
||||
self.data.mdsShake("EXT", None, None)
|
||||
time.sleep(1)
|
||||
self.data.MdsThreadControl.stop("mds_listen")
|
||||
if self.YuukiConfigs.get("WebAdmin"):
|
||||
self.data.MdsThreadControl.stop("wa_listen")
|
||||
if restart:
|
||||
self.__restart()
|
||||
sys.exit(0)
|
||||
|
||||
@staticmethod
|
||||
def __restart():
|
||||
if platform.system() == "Windows":
|
||||
with open("cache.bat", "w") as c:
|
||||
c.write(sys.executable + " ./main.py")
|
||||
os.system("cache.bat")
|
||||
os.system("del cache.bat")
|
||||
elif platform.system() == "Linux":
|
||||
with open(".cache.sh", "w") as c:
|
||||
c.write(sys.executable + " ./main.py")
|
||||
os.system("sh .cache.sh")
|
||||
os.system("rm .cache.sh")
|
||||
else:
|
||||
print("Star Yuuki BOT - Restart Error\n\nUnknown Platform")
|
||||
|
||||
def threadExec(self, function, args):
|
||||
if self.Threading:
|
||||
self.Thread_Control.add(function, args)
|
||||
else:
|
||||
function(*args)
|
||||
|
||||
def taskDemux(self, catched_news):
|
||||
for ncMessage in catched_news:
|
||||
if ncMessage.type == OpType.NOTIFIED_INVITE_INTO_GROUP:
|
||||
self.threadExec(self.JoinGroup, (ncMessage,))
|
||||
elif ncMessage.type == OpType.NOTIFIED_KICKOUT_FROM_GROUP:
|
||||
self.threadExec(self.Security, (ncMessage,))
|
||||
elif ncMessage.type == OpType.NOTIFIED_ACCEPT_GROUP_INVITATION:
|
||||
self.threadExec(self.Security, (ncMessage,))
|
||||
elif ncMessage.type == OpType.NOTIFIED_UPDATE_GROUP:
|
||||
self.threadExec(self.Security, (ncMessage,))
|
||||
elif ncMessage.type == OpType.RECEIVE_MESSAGE:
|
||||
self.threadExec(self.Command, (ncMessage,))
|
||||
elif ncMessage.type == OpType.SEND_MESSAGE:
|
||||
self.threadExec(self.Callback, (ncMessage,))
|
||||
|
||||
def main(self):
|
||||
handle = Yuuki_Poll(self)
|
||||
handle.init()
|
|
@ -1,27 +0,0 @@
|
|||
<<<<<<< HEAD
|
||||
=======
|
||||
beautifulsoup4==4.9.3
|
||||
Bootstrap-Flask==1.5
|
||||
certifi==2020.6.20
|
||||
chardet==3.0.4
|
||||
click==7.1.2
|
||||
Flask==1.1.2
|
||||
gevent==20.9.0
|
||||
gitdb2==4.0.2
|
||||
GitPython==3.1.9
|
||||
greenlet==0.4.17
|
||||
idna==2.10
|
||||
itsdangerous==1.1.0
|
||||
PyYAML==5.4
|
||||
requests==2.24.0
|
||||
six==1.15.0
|
||||
smmap2==3.0.1
|
||||
soupsieve==2.0.1
|
||||
thrift==0.13.0
|
||||
tornado==6.0.4
|
||||
urllib3==1.26.5
|
||||
Werkzeug==1.0.1
|
||||
yuuki-core==6.5.2
|
||||
zope.event==4.5.0
|
||||
zope.interface==5.1.2
|
||||
>>>>>>> v6
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import Cookies from 'https://cdn.jsdelivr.net/npm/js-cookie@rc/dist/js.cookie.min.mjs';
|
||||
|
||||
import Login from "./views/Login.js";
|
||||
import Dashboard from "./views/Dashboard.js";
|
||||
import Groups from "./views/Groups.js";
|
||||
import Helpers from "./views/Helpers.js";
|
||||
import Settings from "./views/Settings.js";
|
||||
import Profile from "./views/Profile.js";
|
||||
import Events from "./views/Events.js";
|
||||
import About from "./views/About.js";
|
||||
import NotFound from "./views/NotFound.js";
|
||||
|
||||
const router = new VueRouter({
|
||||
routes: [{
|
||||
path: '/',
|
||||
component: Login
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
path: '/groups',
|
||||
component: Groups
|
||||
},
|
||||
{
|
||||
path: '/helpers',
|
||||
component: Helpers
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
component: Settings,
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
component: Profile,
|
||||
},
|
||||
{
|
||||
path: '/events/:doctype',
|
||||
component: Events,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
component: About,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
component: NotFound
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
new Vue({
|
||||
template: `
|
||||
<div>
|
||||
<div v-if="accessStatus" class="nav-scroller bg-white shadow-sm pt-1 pb-1">
|
||||
<nav class="nav nav-underline">
|
||||
<router-link
|
||||
v-for="(item, target, itemId) in pageList"
|
||||
:key="itemId"
|
||||
class="nav-link"
|
||||
data-transition-enter="slideleft"
|
||||
:to="target">{{item}}</router-link>
|
||||
</nav>
|
||||
</div>
|
||||
<main id="app" role="main" class="container">
|
||||
<router-view></router-view>
|
||||
</main>
|
||||
<div class="text-center m-5">
|
||||
<a title="About SYB" @click.prevent="about" href="#">
|
||||
<svg width="25px" height="25px" viewBox="0 0 16 16" class="bi bi-info-circle" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588z"/>
|
||||
<circle cx="8" cy="4.5" r="1"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
router,
|
||||
methods: {
|
||||
about() {
|
||||
if (this.$router.currentRoute.path === "/about") {
|
||||
this.$router.push({path: "/"})
|
||||
} else {
|
||||
this.$router.push({path: "/about"})
|
||||
}
|
||||
},
|
||||
verifyAccess() {
|
||||
if (this.$router.currentRoute.path === "/about") return;
|
||||
if (Cookies.get('yuuki_admin')) {
|
||||
if (this.$router.currentRoute.path === "/") {
|
||||
this.$router.push({
|
||||
path: "/dashboard"
|
||||
});
|
||||
}
|
||||
this.accessStatus = true;
|
||||
} else {
|
||||
if (this.$router.currentRoute.path !== "/") {
|
||||
this.$router.push({
|
||||
path: "/"
|
||||
});
|
||||
}
|
||||
this.accessStatus = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.verifyAccess();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.verifyAccess();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accessStatus: false,
|
||||
pageList: {
|
||||
"/dashboard": "Dashboard",
|
||||
"/groups": "Groups",
|
||||
"/helpers": "Helpers",
|
||||
"/settings": "Settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount('#app')
|
|
@ -1,71 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
from thrift.protocol import TCompactProtocol
|
||||
from thrift.transport import THttpClient
|
||||
|
||||
from yuuki_core.TalkService import Client, TalkException
|
||||
|
||||
# NC HighSpeed Library
|
||||
try:
|
||||
from thrift.protocol import fastbinary
|
||||
except ImportError:
|
||||
print("[No fast_binary using]")
|
||||
|
||||
|
||||
class Yuuki_Connect:
|
||||
def __init__(self, Yuuki_Configs):
|
||||
|
||||
self.helper = {}
|
||||
|
||||
self.host = Yuuki_Configs.connectInfo["Host"]
|
||||
self.com_path = Yuuki_Configs.connectInfo["Command_Path"]
|
||||
self.poll_path = Yuuki_Configs.connectInfo["LongPoll_path"]
|
||||
|
||||
self.con_header = Yuuki_Configs.connectHeader
|
||||
|
||||
def connect(self, listen_timeout=600000):
|
||||
transport = THttpClient.THttpClient(self.host + self.com_path)
|
||||
transport_in = THttpClient.THttpClient(self.host + self.poll_path)
|
||||
|
||||
transport_in.setTimeout(listen_timeout)
|
||||
|
||||
transport.setCustomHeaders(self.con_header)
|
||||
transport_in.setCustomHeaders(self.con_header)
|
||||
|
||||
protocol = TCompactProtocol.TCompactProtocol(transport)
|
||||
protocol_in = TCompactProtocol.TCompactProtocol(transport_in)
|
||||
|
||||
client = Client(protocol)
|
||||
listen = Client(protocol_in)
|
||||
|
||||
transport.open()
|
||||
transport_in.open()
|
||||
|
||||
return client, listen
|
||||
|
||||
def helperConnect(self, auth_token):
|
||||
helper_connect_header = self.con_header.copy()
|
||||
helper_connect_header["X-Line-Access"] = auth_token
|
||||
|
||||
transport = THttpClient.THttpClient(self.host + self.com_path)
|
||||
transport.setCustomHeaders(helper_connect_header)
|
||||
protocol = TCompactProtocol.TCompactProtocol(transport)
|
||||
client = Client(protocol)
|
||||
transport.open()
|
||||
|
||||
try:
|
||||
profile = client.getProfile()
|
||||
self.helper[profile.mid] = {
|
||||
"client": client,
|
||||
"profile": profile
|
||||
}
|
||||
return True
|
||||
|
||||
except TalkException:
|
||||
print("Error:\n%s\nNot Acceptable\n" % (auth_token,))
|
124
src/model/mds.py
124
src/model/mds.py
|
@ -1,124 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Star Inc. multiprocessing data switching
|
||||
===
|
||||
To switch data in multiprocessing.
|
||||
|
||||
LICENSE: MPL 2.0
|
||||
(c)2020 Star Inc.
|
||||
"""
|
||||
|
||||
# Initializing
|
||||
import json
|
||||
import types
|
||||
from abc import ABC
|
||||
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.web import Application, RequestHandler
|
||||
|
||||
# Works
|
||||
_work = {}
|
||||
auth_code = 0
|
||||
|
||||
|
||||
class IndexHandler(RequestHandler, ABC):
|
||||
def get(self):
|
||||
self.write('''
|
||||
<b>Python MDS Server</b><br>
|
||||
To switch data in multiprocessing.<hr>
|
||||
(c)2020 <a href="https://starinc.xyz">Star Inc.</a>
|
||||
''')
|
||||
|
||||
def post(self):
|
||||
global auth_code
|
||||
req_body = self.request.body
|
||||
req_str = req_body.decode('utf8')
|
||||
req_res = json.loads(req_str)
|
||||
if req_res.get("code") == auth_code:
|
||||
result = _work[req_res.get("do")](
|
||||
{
|
||||
"path": req_res.get("path"),
|
||||
"data": req_res.get("data")
|
||||
}
|
||||
)
|
||||
else:
|
||||
result = {"status": 401}
|
||||
if isinstance(result, types.GeneratorType):
|
||||
result = {"status": 200}
|
||||
self.write(json.dumps(result))
|
||||
|
||||
|
||||
class PythonMDS:
|
||||
switch_data = {}
|
||||
|
||||
# Main
|
||||
app = Application([
|
||||
('/', IndexHandler)
|
||||
])
|
||||
server = HTTPServer(app)
|
||||
async_lock = IOLoop.current()
|
||||
|
||||
def __init__(self, port):
|
||||
_work["UPT"] = self._update
|
||||
_work["DEL"] = self._delete
|
||||
_work["GET"] = self._query
|
||||
_work["SYC"] = self._sync
|
||||
_work["YLD"] = self._yuuki_limit_decrease
|
||||
_work["EXT"] = self._shutdown
|
||||
self.port = port
|
||||
|
||||
def _query(self, data):
|
||||
query_data = data["path"]
|
||||
if type(self.switch_data) is dict and type(query_data) is list:
|
||||
result = self.switch_data
|
||||
query_len = len(query_data) - 1
|
||||
for count, key in enumerate(query_data):
|
||||
if key in result:
|
||||
if count < query_len:
|
||||
if type(result.get(key)) is not dict:
|
||||
result = 1 # "unknown_type" + type(source_data.get(key))
|
||||
break
|
||||
result = result.get(key)
|
||||
else:
|
||||
result = 2 # "unknown_key"
|
||||
break
|
||||
|
||||
return {"status": 200, "data": result}
|
||||
return {"status": 400}
|
||||
|
||||
def _update(self, data):
|
||||
if type(data["path"]) is list:
|
||||
over = self._query({"path": data["path"]})
|
||||
over.get("data").update(data["data"])
|
||||
return {"status": 200}
|
||||
return {"status": 400}
|
||||
|
||||
def _delete(self, data):
|
||||
if type(data["path"]) is list:
|
||||
over = self._query({"path": data["path"]})
|
||||
over.get("data").pop(data["data"])
|
||||
return {"status": 200}
|
||||
return {"status": 400}
|
||||
|
||||
def _sync(self, data):
|
||||
self.switch_data = data["path"]
|
||||
return {"status": 200}
|
||||
|
||||
def _yuuki_limit_decrease(self, data):
|
||||
self.switch_data["LimitInfo"][data["path"]][data["data"]] -= 1
|
||||
return {"status": 200}
|
||||
|
||||
def _shutdown(self, data):
|
||||
if data:
|
||||
pass
|
||||
self.server.stop()
|
||||
yield True
|
||||
self.async_lock.stop()
|
||||
self.async_lock.close()
|
||||
|
||||
def mds_listen(self, code):
|
||||
global auth_code
|
||||
auth_code = code
|
||||
self.server.listen(self.port)
|
||||
self.async_lock.start()
|
|
@ -1,105 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import socket
|
||||
import time
|
||||
|
||||
from yuuki_core.ttypes import Operation
|
||||
|
||||
from .utils import Yuuki_StaticTools, Yuuki_DynamicTools
|
||||
|
||||
|
||||
class Yuuki_Poll:
|
||||
Power = True
|
||||
|
||||
NoWork = 0
|
||||
NoWorkLimit = 5
|
||||
|
||||
fetchNum = 50
|
||||
cacheOperations = []
|
||||
|
||||
def __init__(self, Yuuki):
|
||||
self.Yuuki = Yuuki
|
||||
self.Yuuki_DynamicTools = Yuuki_DynamicTools(self.Yuuki)
|
||||
|
||||
def _action(self):
|
||||
ncMessage = Operation()
|
||||
|
||||
if time.localtime().tm_hour != self.Yuuki.data.getData(["Global", "LastResetLimitTime"]):
|
||||
self.Yuuki_DynamicTools.limitReset()
|
||||
self.Yuuki.data.updateData(["Global", "LastResetLimitTime"], time.localtime().tm_hour)
|
||||
|
||||
if self.NoWork >= self.NoWorkLimit:
|
||||
self.NoWork = 0
|
||||
for ncMessage in self.cacheOperations:
|
||||
if ncMessage.reqSeq != -1 and ncMessage.revision > self.Yuuki.revision:
|
||||
self.Yuuki.revision = ncMessage.revision
|
||||
break
|
||||
if ncMessage.revision != self.Yuuki.revision:
|
||||
self.Yuuki.revision = self.Yuuki.client.getLastOpRevision()
|
||||
|
||||
try:
|
||||
self.cacheOperations = self.Yuuki.listen.fetchOperations(self.Yuuki.revision, self.fetchNum)
|
||||
except socket.timeout:
|
||||
self.NoWork += 1
|
||||
|
||||
if self.cacheOperations:
|
||||
self.NoWork = 0
|
||||
self.Yuuki.threadExec(self.Yuuki.taskDemux, (self.cacheOperations,))
|
||||
if len(self.cacheOperations) > 1:
|
||||
self.Yuuki.revision = max(self.cacheOperations[-1].revision, self.cacheOperations[-2].revision)
|
||||
|
||||
def _exception(self):
|
||||
(err1, err2, err3, ErrorInfo) = Yuuki_StaticTools.errorReport()
|
||||
|
||||
ncMessage = Operation()
|
||||
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
for ncMessage in self.cacheOperations:
|
||||
if ncMessage.reqSeq != -1 and ncMessage.revision > self.Yuuki.revision:
|
||||
self.Yuuki.revision = ncMessage.revision
|
||||
break
|
||||
if ncMessage.revision != self.Yuuki.revision:
|
||||
self.Yuuki.revision = self.Yuuki.client.getLastOpRevision()
|
||||
for Root in self.Yuuki.Admin:
|
||||
self.Yuuki_DynamicTools.sendText(
|
||||
Root,
|
||||
"Star Yuuki BOT - Something was wrong...\nError:\n%s\n%s\n%s\n\n%s" %
|
||||
(err1, err2, err3, ErrorInfo)
|
||||
)
|
||||
except:
|
||||
print("Star Yuuki BOT - Damage!\nError:\n%s\n%s\n%s\n\n%s" % (err1, err2, err3, ErrorInfo))
|
||||
self.Yuuki.exit()
|
||||
|
||||
def init(self):
|
||||
self.Yuuki.data.updateData(["Global", "Power"], self.Power)
|
||||
|
||||
if "LastResetLimitTime" not in self.Yuuki.data.getData(["Global"]):
|
||||
self.Yuuki.data.updateData(["Global", "LastResetLimitTime"], None)
|
||||
|
||||
while self.Power:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
self._action()
|
||||
try:
|
||||
self.Power = self.Yuuki.data.syncData()
|
||||
except ConnectionRefusedError:
|
||||
self.Power = False
|
||||
|
||||
except SystemExit:
|
||||
self.Power = False
|
||||
|
||||
except KeyboardInterrupt:
|
||||
self.Yuuki.exit()
|
||||
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
except:
|
||||
self._exception()
|
|
@ -1,39 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import multiprocessing
|
||||
import threading
|
||||
|
||||
|
||||
class Yuuki_Thread:
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
|
||||
@staticmethod
|
||||
def add(function, args=()):
|
||||
added_thread = threading.Thread(name=function.__name__, target=function, args=args)
|
||||
added_thread.start()
|
||||
|
||||
@staticmethod
|
||||
def getThreadInfo():
|
||||
print(threading.active_count())
|
||||
print(threading.enumerate())
|
||||
print("{} add Threading\n".format(threading.current_thread()))
|
||||
|
||||
|
||||
class Yuuki_Multiprocess:
|
||||
multiprocess_list = {}
|
||||
|
||||
def add(self, function, args=()):
|
||||
added_multiprocess = multiprocessing.Process(name=function.__name__, target=function, args=args)
|
||||
self.multiprocess_list[function.__name__] = added_multiprocess
|
||||
added_multiprocess.start()
|
||||
|
||||
def stop(self, function_name):
|
||||
assert function_name in self.multiprocess_list
|
||||
self.multiprocess_list[function_name].terminate()
|
|
@ -7,13 +7,9 @@ License, v. 2.0. If a copy of the MPL was not distributed with this
|
|||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
|
||||
<<<<<<< HEAD:src/model/user.py
|
||||
from yuuki_core.ttypes import Contact as Prototype
|
||||
|
||||
|
||||
class User(Prototype):
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super(User, self).__init__(kwargs)
|
||||
=======
|
||||
__all__ = ['connector.py', 'data', 'mds.py', 'thread.py', 'Yuuki', 'Yuuki_Config']
|
||||
>>>>>>> v6:libs/__init__.py
|
||||
|
|
|
@ -1,360 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Yuuki_Libs
|
||||
(c) 2020 Star Inc.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
import json
|
||||
import ntpath
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import requests
|
||||
from yuuki_core.ttypes import OpType, MIDType, ContentType, Group, Message
|
||||
|
||||
|
||||
class Yuuki_StaticTools:
|
||||
@staticmethod
|
||||
def sybGetGroupCreator(groupInfo):
|
||||
"""
|
||||
Get the LINE Group Creator
|
||||
:param groupInfo: LINE Group
|
||||
:return: LINE Contact
|
||||
"""
|
||||
if groupInfo.creator is None:
|
||||
contact = groupInfo.members[0]
|
||||
else:
|
||||
contact = groupInfo.creator
|
||||
return contact
|
||||
|
||||
@staticmethod
|
||||
def readCommandLine(msgs):
|
||||
"""
|
||||
Read string list as a command line
|
||||
:param msgs: List of strings
|
||||
:return: string
|
||||
"""
|
||||
reply_msg = " ".join(msgs).lstrip()
|
||||
return reply_msg
|
||||
|
||||
@staticmethod
|
||||
def errorReport():
|
||||
"""
|
||||
Report errors as tuple
|
||||
:return: tuple
|
||||
"""
|
||||
err1, err2, err3 = sys.exc_info()
|
||||
traceback.print_tb(err3)
|
||||
tb_info = traceback.extract_tb(err3)
|
||||
filename, line, func, text = tb_info[-1]
|
||||
ErrorInfo = "occurred in\n{}\n\non line {}\nin statement {}".format(filename, line, text)
|
||||
return err1, err2, err3, ErrorInfo
|
||||
|
||||
@staticmethod
|
||||
def securityForWhere(ncMessage):
|
||||
"""
|
||||
Return arguments for security tasks
|
||||
:param ncMessage: Operation
|
||||
:return: tuple
|
||||
"""
|
||||
if ncMessage.type == OpType.NOTIFIED_UPDATE_GROUP or \
|
||||
ncMessage.type == OpType.NOTIFIED_INVITE_INTO_GROUP or \
|
||||
ncMessage.type == OpType.NOTIFIED_ACCEPT_GROUP_INVITATION or \
|
||||
ncMessage.type == OpType.NOTIFIED_KICKOUT_FROM_GROUP:
|
||||
return {
|
||||
"GroupID": ncMessage.param1,
|
||||
"Action": ncMessage.param2,
|
||||
"Another": ncMessage.param3,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def dictShuffle(dict_object, requirement=None):
|
||||
"""
|
||||
Shuffle dicts
|
||||
:param dict_object: dict
|
||||
:param requirement: list
|
||||
:return: dict
|
||||
"""
|
||||
dict_key = [key for key in dict_object]
|
||||
random.shuffle(dict_key)
|
||||
result = {}
|
||||
for key in dict_key:
|
||||
if requirement is None:
|
||||
result[key] = dict_object[key]
|
||||
else:
|
||||
if key in requirement:
|
||||
result[key] = dict_object[key]
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def sendToWho(ncMessage):
|
||||
"""
|
||||
Get who to send with Operation
|
||||
:param ncMessage: Operation
|
||||
:return: string
|
||||
"""
|
||||
if ncMessage.message.toType == MIDType.USER:
|
||||
return ncMessage.message.from_
|
||||
elif ncMessage.message.toType == MIDType.ROOM:
|
||||
return ncMessage.message.to
|
||||
elif ncMessage.message.toType == MIDType.GROUP:
|
||||
return ncMessage.message.to
|
||||
|
||||
|
||||
class Yuuki_DynamicTools:
|
||||
def __init__(self, Yuuki):
|
||||
self.Yuuki = Yuuki
|
||||
|
||||
def getClient(self, userId):
|
||||
"""
|
||||
Get client by account userId
|
||||
:param userId: string
|
||||
:return: TalkServiceClient
|
||||
"""
|
||||
if userId == self.Yuuki.MyMID:
|
||||
return self.Yuuki.client
|
||||
return self.Yuuki.Connect.helper[userId].get("client")
|
||||
|
||||
def checkInInvitationList(self, ncMessage, userId=None):
|
||||
"""
|
||||
Check If userId in Invitation List
|
||||
:param ncMessage: Operation
|
||||
:param userId: string
|
||||
:return: boolean
|
||||
"""
|
||||
if userId is None:
|
||||
userId = self.Yuuki.MyMID
|
||||
if ncMessage.param3 == userId:
|
||||
return True
|
||||
elif "\x1e" in ncMessage.param3:
|
||||
if userId in ncMessage.param3.split("\x1e"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def changeGroupUrlStatus(self, groupInfo, status, handlerId=None):
|
||||
"""
|
||||
Change LINE Group URL Status
|
||||
:param groupInfo: Line Group
|
||||
:param status: boolean
|
||||
:param handlerId: string
|
||||
:return: None
|
||||
"""
|
||||
result = Group()
|
||||
for key in groupInfo.__dict__:
|
||||
if key != "members" or key != "invitee":
|
||||
result.__dict__[key] = groupInfo.__dict__[key]
|
||||
result.preventJoinByTicket = not status
|
||||
handler = self.Yuuki.MyMID if handlerId is None else handlerId
|
||||
self.getClient(handler).updateGroup(self.Yuuki.Seq, result)
|
||||
|
||||
def configSecurityStatus(self, groupId, status):
|
||||
"""
|
||||
Configure LINE Group Security Status for Yuuki
|
||||
:param groupId: string
|
||||
:param status: boolean
|
||||
:return: None
|
||||
"""
|
||||
group_status = self.Yuuki.data.SEGrouptype
|
||||
if 0 in status:
|
||||
group_status[OpType.NOTIFIED_UPDATE_GROUP] = True
|
||||
if 1 in status:
|
||||
group_status[OpType.NOTIFIED_INVITE_INTO_GROUP] = True
|
||||
if 2 in status:
|
||||
group_status[OpType.NOTIFIED_ACCEPT_GROUP_INVITATION] = True
|
||||
if 3 in status:
|
||||
group_status[OpType.NOTIFIED_KICKOUT_FROM_GROUP] = True
|
||||
|
||||
self.Yuuki.data.updateData(["Group", groupId, "SEGroup"], group_status)
|
||||
|
||||
def cleanMyGroupInvitations(self):
|
||||
"""
|
||||
Clean personal group invitations for LINE account
|
||||
:return: None
|
||||
"""
|
||||
for client in [self.getClient(userId) for userId in self.Yuuki.MyMID + self.Yuuki.Connect.helper.keys()]:
|
||||
for cleanInvitations in client.getGroupIdsInvited():
|
||||
client.acceptGroupInvitation(self.Yuuki.Seq, cleanInvitations)
|
||||
client.leaveGroup(self.Yuuki.Seq, cleanInvitations)
|
||||
|
||||
def leaveGroup(self, groupInfo):
|
||||
"""
|
||||
Leave a group by its group information object
|
||||
:param groupInfo: Line Group
|
||||
:return: None
|
||||
"""
|
||||
self.sendText(groupInfo.id, self.Yuuki.get_text("Bye Bye"))
|
||||
self.getClient(self.Yuuki.MyMID).leaveGroup(self.Yuuki.Seq, groupInfo.id)
|
||||
for userId in self.Yuuki.Connect.helper:
|
||||
if userId in [member.mid for member in groupInfo.members]:
|
||||
self.getClient(userId).leaveGroup(self.Yuuki.Seq, groupInfo.id)
|
||||
GroupList = self.Yuuki.data.getData(["Global", "GroupJoined"])
|
||||
NewGroupList = GroupList.copy()
|
||||
NewGroupList.remove(groupInfo.id)
|
||||
self.Yuuki.data.updateData(["Global", "GroupJoined"], NewGroupList)
|
||||
|
||||
def getContact(self, userId):
|
||||
"""
|
||||
Get LINE Contact information with userId
|
||||
:param userId: string
|
||||
:return: LINE Contact
|
||||
"""
|
||||
if len(userId) == len(self.Yuuki.MyMID) and userId[0] == "u":
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
contactInfo = self.getClient(self.Yuuki.MyMID).getContact(userId)
|
||||
except:
|
||||
contactInfo = False
|
||||
else:
|
||||
contactInfo = False
|
||||
return contactInfo
|
||||
|
||||
def getGroupTicket(self, groupId, userId, renew=False):
|
||||
"""
|
||||
Get LINE Group Ticket with groupId and userId
|
||||
:param groupId: string
|
||||
:param userId: string
|
||||
:param renew: boolean
|
||||
:return: string
|
||||
"""
|
||||
GroupTicket = ""
|
||||
GroupData = self.Yuuki.data.getGroup(groupId)
|
||||
if "GroupTicket" in GroupData:
|
||||
if GroupData["GroupTicket"].get(userId) is not None:
|
||||
GroupTicket = GroupData["GroupTicket"].get(userId)
|
||||
else:
|
||||
assert "Error JSON data type - GroupTicket"
|
||||
if GroupTicket == "" or renew:
|
||||
GroupTicket = self.getClient(userId).reissueGroupTicket(groupId)
|
||||
self.Yuuki.data.updateData(
|
||||
["Group", groupId, "GroupTicket", userId], GroupTicket)
|
||||
return GroupTicket
|
||||
|
||||
def limitReset(self):
|
||||
"""
|
||||
Reset Yuuki modify LINE Group Member List limits
|
||||
:return: None
|
||||
"""
|
||||
for userId in self.Yuuki.AllAccountIds:
|
||||
self.Yuuki.data.updateData(
|
||||
["LimitInfo", "KickLimit", userId], self.Yuuki.KickLimit)
|
||||
self.Yuuki.data.updateData(
|
||||
["LimitInfo", "CancelLimit", userId], self.Yuuki.CancelLimit)
|
||||
|
||||
def modifyGroupMemberList(self, action, groupInfo, userId, exceptUserId=None):
|
||||
"""
|
||||
Modify LINE Group Member List
|
||||
:param action: integer (1->kick 2->cancel)
|
||||
:param groupInfo: LINE Group
|
||||
:param userId: string
|
||||
:param exceptUserId: List of userId
|
||||
:return: string
|
||||
"""
|
||||
actions = {
|
||||
1: {
|
||||
"command": "KickLimit",
|
||||
"message": "Kick Limit.",
|
||||
"function": lambda handlerId: self.getClient(handlerId).kickoutFromGroup
|
||||
},
|
||||
2: {
|
||||
"command": "CancelLimit",
|
||||
"message": "Cancel Limit.",
|
||||
"function": lambda handlerId: self.getClient(handlerId).cancelGroupInvitation
|
||||
}
|
||||
}
|
||||
assert action in actions, "Invalid action code"
|
||||
if len(self.Yuuki.Connect.helper) >= 1:
|
||||
members = [member.mid for member in groupInfo.members if member.mid in self.Yuuki.AllAccountIds]
|
||||
accounts = Yuuki_StaticTools.dictShuffle(
|
||||
self.Yuuki.data.getData(["LimitInfo", actions[action].get("command")]), members)
|
||||
if len(accounts) == 0:
|
||||
return "None"
|
||||
if exceptUserId:
|
||||
accounts[exceptUserId] = -1
|
||||
helper = max(accounts, key=accounts.get)
|
||||
else:
|
||||
if exceptUserId == self.Yuuki.MyMID:
|
||||
return "None"
|
||||
helper = self.Yuuki.MyMID
|
||||
Limit = self.Yuuki.data.getData(["LimitInfo", actions[action].get("command"), helper])
|
||||
if Limit > 0:
|
||||
actions[action].get("function")(helper)(self.Yuuki.Seq, groupInfo.id, [userId])
|
||||
self.Yuuki.data.limitDecrease(actions[action].get("command"), helper)
|
||||
else:
|
||||
self.sendText(groupInfo.id, self.Yuuki.get_text(actions[action].get("message")), helper)
|
||||
return helper
|
||||
|
||||
def sendText(self, send_to, msg, senderId=None):
|
||||
"""
|
||||
Send text to LINE Chat
|
||||
:param send_to: The target to received
|
||||
:param msg: The message hope to send
|
||||
:param senderId: The client specified to send the message
|
||||
:return: None
|
||||
"""
|
||||
message = Message(to=send_to, text=msg)
|
||||
sender = self.Yuuki.MyMID if senderId is None else senderId
|
||||
self.getClient(sender).sendMessage(self.Yuuki.Seq, message)
|
||||
|
||||
def sendUser(self, send_to, userId):
|
||||
"""
|
||||
Send LINE contact to LINE Chat
|
||||
:param send_to: string
|
||||
:param userId: string
|
||||
:return: None
|
||||
"""
|
||||
message = Message(
|
||||
contentType=ContentType.CONTACT,
|
||||
text='',
|
||||
contentMetadata={
|
||||
'mid': userId,
|
||||
'displayName': 'LINE User',
|
||||
},
|
||||
to=send_to
|
||||
)
|
||||
self.getClient(self.Yuuki.MyMID).sendMessage(self.Yuuki.Seq, message)
|
||||
|
||||
def sendMedia(self, send_to, send_type, path):
|
||||
"""
|
||||
Send media file to LINE Chat
|
||||
:param send_to: string
|
||||
:param send_type: string
|
||||
:param path: string
|
||||
:return: None
|
||||
"""
|
||||
if os.path.exists(path):
|
||||
file_name = ntpath.basename(path)
|
||||
file_size = len(open(path, 'rb').read())
|
||||
message = Message(to=send_to, text=None)
|
||||
message.contentType = send_type
|
||||
message.contentPreview = None
|
||||
message.contentMetadata = {
|
||||
'FILE_NAME': str(file_name),
|
||||
'FILE_SIZE': str(file_size),
|
||||
}
|
||||
if send_type == ContentType.FILE:
|
||||
media_name = file_name
|
||||
else:
|
||||
media_name = 'media'
|
||||
message_id = self.getClient(self.Yuuki.MyMID).sendMessage(
|
||||
self.Yuuki.Seq, message).id
|
||||
files = {
|
||||
'file': open(path, 'rb'),
|
||||
}
|
||||
params = {
|
||||
'name': media_name,
|
||||
'oid': message_id,
|
||||
'size': file_size,
|
||||
'type': ContentType._VALUES_TO_NAMES[send_type].lower(),
|
||||
'ver': '1.0',
|
||||
}
|
||||
data = {
|
||||
'params': json.dumps(params)
|
||||
}
|
||||
url = self.Yuuki.LINE_Media_server + '/talk/m/upload.nhn'
|
||||
r = requests.post(url, headers=self.Yuuki.connectHeader, data=data, files=files)
|
||||
if r.status_code != 201:
|
||||
self.sendText(send_to, "Error!")
|
Loading…
Reference in a new issue