This commit is contained in:
SuperSonic 2023-03-04 11:44:41 +08:00
parent e137dd2256
commit 2caf3b7059
No known key found for this signature in database
GPG key ID: 9D3DE8DB7CF08BA3
36 changed files with 0 additions and 4909 deletions

View file

@ -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

View file

@ -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, ")

View file

@ -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, ")

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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)!

View file

@ -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!

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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`.

View file

@ -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)

View file

@ -1 +0,0 @@
(c) 2020 [Star Inc.](https://starinc.xyz) with its contributors.

View file

@ -1,2 +0,0 @@
Hey, are you finding the menu?
[Click Me](https://github.com/star-inc/star_yuuki_bot/wiki/Menu)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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}

View file

@ -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>

View file

@ -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()

View file

@ -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

View file

@ -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')

View file

@ -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,))

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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

View file

@ -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!")