-
Notifications
You must be signed in to change notification settings - Fork 0
Documentation
Just skip to the part where you want to get started.
Topic | Description |
---|---|
Client | Represents a LINE Official Acc... |
linelib.ext | Extensions for building your bot. |
linelib.notify | The LINE Notify extension. |
Resources | Linelib might include some wei... |
class Client(
self,
channel_secret: str,
channel_access_token: str,
*args, **options: Any
)
Represents a LINE Official Account (Client).
parameter | type | default | description |
---|---|---|---|
channel_secret | str |
required | Channel secret. |
channel_access_token | str |
required | Channel access token. |
*args, **options | Any |
() , {}
|
No usage provided. |
from linelib import Client
client = Client('channel secret', 'channel access token')
-
CS :
str
- Channel secret. -
CAT :
str
- Channel access token. -
app :
Flask
- (Running) Flask application. Note that it has been usedCORS(app)
-
headers :
dict
- Headers for requests. -
loop :
Loop
- Asyncio event loop. -
_EVENTS* :
dict
- Saved event handlers. -
_VALID_EVENTS* :
list
- Current valid events.
๐ข Notice! |
---|
* - These attributes should not be overwritten or deleted by the user. |
def createEvents(
self,
name: str,
obj: type
) -> None
Save the provided content to Client._EVENTS
.
parameter | type | default | description |
---|---|---|---|
name | str |
required | Event name. |
obj | type |
required | An event object. |
from linelib import Client
client = Client(...)
class ControlledEventObject:
def __init__(self, json: dict):
self.type = json['type'] # event type, REQUIRED
self.options = json['options'] # additional options, REQUIRED
async def emit(self, ctx):
await ctx.reply('Hello, World!')
obj = ControlledEventObject({
'type': 'text', # text message event
'options': () # Empty
})
client.createEvents('text', obj) # registers the event handler
def emitEvents(
self,
name: str,
*args: Any,
**kwargs: Any
) -> None
Runs the events inside Client._EVENTS
.
parameter | type | default | description |
---|---|---|---|
name | str |
required | The event name. |
*args, **kwargs | Any |
() , {}
|
Any arguments to add for the event handlers. |
from linelib import Client
client = Client(...)
@client.event('ready')
async def execute_me():
print("I just got executed!")
client.emitEvents('ready') # no arguments required
@event(
self,
listener: str,
*options
) -> EventObject
Registers an event handler. See Client._VALID_EVENTS
to see a list of valid events.
Decorator Parameters
parameter | type | default | description |
---|---|---|---|
listener | Union[str, Callable] |
FUNCTION_NAME_OR_LISTENER |
Listener name or leave blank. |
๐ Reference |
---|
FUNCTION_NAME_OR_LISTENER - You can pass in a valid function (Client._VALID_EVENTS ), or you can leave this blank and let linelib detect your function name. (Prefix: on_ + Event name) |
Handler Parameters
Handlers must be async (coroutine) functions.
parameter | type | description |
---|---|---|
ctx? None? |
Depends |
The specification depends on the event type. |
Depends: ctx? None?
event name | argument(s) | type | description |
---|---|---|---|
ready |
โ | โ | No arguments should be passed. |
text |
ctx | TextMessageEvent |
The text message context. |
postback |
ctx | PostbackEvent |
The postback context. |
sticker |
ctx | StickerMessageEvent |
The sticker message context. |
unsend |
ctx | UnsendEvent |
Message unsent. (Cannot reply) |
follow |
ctx | FollowEvent |
A user added your bot as friend or unblocked your bot. |
unfollow |
ctx | UnfollowEvent |
A user blocked your bot. |
join |
ctx | JoinEvent |
Occurs when your bot joins a group chat. |
leave |
ctx | LeaveEvent |
Occurs when your bot leaves a group chat. |
memberJoined |
ctx | MemberJoinEvent |
Occurs when a member joins the group chat. |
memberLeft |
ctx | MemberLeaveEvent |
Occurs when a member leaves the group chat. |
videoPlayComplete |
ctx | VideoViewingCompleteEvent |
The user finishes viewing a video for at least once. |
beacon |
ctx | BeaconEvent |
LINE beacon event (enter , stay , banner ) |
accountLink |
ctx | AccountLinkEvent |
The user has linked their LINE account with a provider's service account. |
image |
ctx | ImageMessageEvent |
The image message context. You can download them. |
video |
ctx | VideoMessageEvent |
The video message context. You can download them. |
audio |
ctx | AudioMessageEvent |
The audio message context. You can download them. |
file |
ctx | FileMessageEvent |
The file message context. You can download them. |
location |
ctx | LocationMessageEvent |
The location event context. |
from linelib import Client
client = Client(...)
# method 1
@client.event('ready')
async def ready(): # any name you want
print("WOW!")
# method 2
@client.event()
async def on_ready(): # on_{EVENT_NAME}
print("Wow, again -- wow!!")
@client.event('text')
async def on_text(ctx):
await ctx.reply('Good morning!')
client.run(...)
def load_cog(
self,
cog: type
)
Loads a Cog (extension).
parameter | type | default | description |
---|---|---|---|
cog | type |
required | The cog to load. |
def run(
self,
*args,
**options: Any
)
Runs the LINE bot.
parameter | type | default | description |
---|---|---|---|
**options | Any |
{} |
Configure run options. See Client Options โ |
option | type | description | example |
---|---|---|---|
log_level | level |
Sets the logger level of Flask. | log_level=logging.ERROR |
show_logs | bool |
Show linelib logs? | show_logs=False |
* | Any |
Unnamed for linelib, only for app.run options. |
threaded=True |
from linelib import Client
client = Client(...)
client.run(log_level=logging.ERROR, show_logs=False, threaded=True)
import linelib.ext
Extensions for building your bot.
class SocialPlugins
The LINE Social Plugins. (extension)
@staticmethod
def share(
url: str
) -> str
Returns a LINE Share Link. This is useful when you want a custom button.
from linelib.ext import SocialPlugins
print(SocialPlugins.share("https://example.com"))
constructed <_depends>: Depends
Represents something depends on the specification.
__bool__
def __bool__(self) -> bool
Returns False
.
__repr__
def __repr__(self) -> str
Returns "It Depends."
__hash__
def __hash__(self) -> int
Returns 0
.
__getitem__
def __getitem__(self, k) -> Any
Returns k
.
from linelib.ext import Depends
def my_function(arg: Depends[str] = None):
pass
from linelib.ext import commands
commands
module.
VALID_TYPES: list[type]
An array of valid typings for cog command arguments.
class Cog(self)
Represents a command cog.
The above represents an __init__
method, which is not recommended using until you've constructed with __init_subclass__
.
Useful Links |
---|
๐ฆ Properties โ โ๏ธ Methods โ โจ Loading Cogs โ |
def __init_subclass__(cls) -> None
Subclass initialization (highly recommended). This gathers valid linelib cog commands and store them into _ll_COMMANDS
โ for further usage.
Example
from linelib.ext import commands
class MyCog(commands.Cog):
...
async def emit(self, ctx: type) -> Depends[str]
Emits the commands inside the cog. (DO NOT TOUCH)
Returns "all-nf"
(str) if every command name cannot satisfy the condition (command not found).
async def not_found(self, ctx, command: str) -> Any
Emits when a command is not found. This coroutine function is overwritable.
Example
from linelib.ext import commands
class MyCog(commands.Cog):
async def not_found(self, ctx, command):
await ctx.reply(f"Command '{command}' not found.")
properties | default | description |
---|---|---|
name | "UnnamedCog" | The name of the cog. |
show_not_found_log | False | Whether to show command not found log or not. |
_ll_CONSTRUCTED* | False | Identification to check if this cog is constructed when using Client.load_cog . |
_ll_COMMANDS* | [] | Temporary list to store commands detected inside a cog class. |
๐ข Notice |
---|
* : Do not touch |
class CogCommandWrapper(
self,
cmd_name: str,
func,
rule: CommandRule | _dfr = DEFAULT_RULE
)
Represents a cog command.
parameters | type | default | description |
---|---|---|---|
cmd_name | str |
required | Command name. |
func | Callable |
required | Handler function. |
rule |
CommandRule | _dfr
|
DEFAULT_RULE |
Command rules. |
async def emit(self, o: Cog, ctx: type) -> Depends[str]
Event emitting for the handler. Returns "no"
(str) if this command does not equal to the context. (ctx.content
)
DO NOT TOUCH
parameters | type | default | description |
---|---|---|---|
o | Cog |
required | The Cog itself. |
ctx | type |
required | The context. |
@on_error(
self,
function: Callable
)
Event decorator when an error occurs.
The handler must be an async (coroutine) function.
type | parameters | description |
---|---|---|
@decorator | * | You do not need to add anything. |
handler | self, ctx, error |
error : The error message. |
Example
from linelib.ext import commands
class MyCog(commands.Cog):
@commands.cog_command() # returns CogCommandWrapper
async def my_command(self, ctx):
...
@my_command.on_error
async def my_error_handler(self, ctx, error):
print(error)
@rule_reject(
self,
function: Callable
) -> Callable
Event decorator once the rule function returned False
, which represents no pass.
The handler must be an async (coroutine) function.
type | parameters | description |
---|---|---|
@decorator | * | You do not need to add anything. |
handler | self, ctx | The context. |
Example
from linelib.ext import commands, rule
clas MyCog(commands.Cog):
@commands.cog_command(
name="hello",
rule=rule.CommandRule(
rule="cooldown",
seconds=10
)
) # returns CogCommandWrapper
async def hello(self, ctx):
...
@hello.rule_reject
async def rejected(self, ctx):
await ctx.reply("Rejected!")
@cog_command(
*,
name: String@CogCommandWrapper,
rule: CommandRule = DEFAULT_RULE
) -> CogCommandWrapper
Represents a command for cogs.
Returns: CogCommandWrapper
@decorator parameters
parameter | type | default | description | example |
---|---|---|---|---|
* | -- | -- | -- | You need to use named keywords. |
name | String@CogCommandWrapper | required | The command name. | name="hello" |
rule | CommandRule | required | Command rule. | See CommandRule |
Handler parameters
parameter | type | default | description |
---|---|---|---|
self | Cog | required | The cog itself. |
ctx | TextMessageEvent | required | The context. |
*: type | str | int | float | bool (keywordOnly?) | optional / assignable | The command parameter for the user to pass in. |
Get to know more about this kind of argument-passing condition!
Example
from linelib.ext import commands, rule
class MyCog(commands.Cog):
@commands.cog_command(
name="hello",
rule=rule.CommandRule(
rule="cooldown",
seconds=5
)
async def hello(self, ctx, number: int):
await ctx.reply(f"Your number was: {number}")
@hello.rule_reject
async def on_cooldown_now(self, ctx):
await ctx.send("You are in a cooldown.")
constructed <_str>: String
Represents any string.
def __matmul__(self, other) -> Any
Returns other
.
from typing import Any
from linelib.ext import commands
commands.String@Any
class DatabaseTable
A temporary database that helps you to store some information.
This old method is not recommended.
Example
# run_me.py
from linelib.ext import DatabaseTable as dbt
dbt.test = "My String"
dbt.cool = True
# main.py
import run_me # runs the 'run_me.py' file
from linelib.ext import DatabaseTable as dbt
print(dbt.test) # 'My String'
print(dbt.cool) # True
from linelib.ext import rule
Rules for cog commands. New in v2.2
VALID_RULES: dict
Returns valid rules and the additional arguments that are required.
Returns:
# RETURN VALUE
{
# RULE ARGUMENTS
"cooldown": ('seconds',),
"except": ('users',),
"for": ('users',),
"based.custom": (),
"usage_limit": ('times',)
}
constructed <_dfr>: DEFAULT_RULE
The default rule class. Always returns True
. (constructed)
Definition:
class _dfr:
def emit(self, *args, **kwargs) -> bool:
return True
class CommandRule(
self,
*,
rule: Literal["cooldown", "except", "for", "based.custom", "usage_limit"],
**variations
)
Represents a command rule. Example Usage
parameter | type | default | description |
---|---|---|---|
* | -- | -- | Please use keyword-only arguments. |
rule | str | required | The rule type. |
**variations | Depends[Any] | {} |
Additional arguments for the rule. The specification depends on the rule type. |
Depending on the rule type, there are several additional arguments you should pass in.
rule type | description | argument | argument description | example |
---|---|---|---|---|
cooldown | Command cooldown for a user. | seconds: int | Cooldown duration in seconds. | seconds=10 |
except | Run the command except for someone. | users: list[str] | A list of user IDs to prevent from using. | users=['id 1', 'id 2'] |
for | Run the command for some people. | users: list[str] | A list of user IDs that can use this command. | users=['id 1', 'id 2'] |
based.custom | Based on your custom rule. | Nothing. | See Custom Rules. | -- |
usage_limit | The user could only use the command for a limited amount of time. | times: int | Limited amount of time. | times=10 |
To build a custom rule, it requires the __init_subclass__
method.
In your custom class, note that it must contain the "handler" function, and it must NOT be a coroutine (async) function.
Your handler must return a bool
(Boolean).
return value | description |
---|---|
True | The user has passed the your check function, and could use the command. |
False | The user didn't pass your check function, and could NOT use the command. |
Example
from linelib.ext import commands, rule
class MyRule(rule.CommandRule):
def handler(self, ctx):
... # your code to detect something
return True # `True` for passing, `False` for denied!
class MyCog(commands.Cog):
@commands.cog_command(
name="test",
rule=MyRule(
rule="based.custom" # required
)
)
async def test_command(self, ctx):
... # rest of your code here
from linelib.ext import rule, commands
class MyCog(commands.Cog):
@commands.cog_command(
name="hello",
rule=rule.CommandRule(
rule="cooldown",
seconds=10
)
)
async def hello_cmd(self, ctx):
await ctx.send("You're not in a cooldown")
@hello_cmd.rule_reject
async def rejected(self, ctx):
await ctx.send("The cooldown is 10 seconds")
import linelib.notify
The LINE Notify extension.
class Notify(
self,
access_token: str
)
Represents a LINE Notify bot.
Useful Links |
---|
๐ฆ Register your service ๐ Create a token |
Parameters
parameter | type | default | description |
---|---|---|---|
access_token | str | required | Access token. |
async def notify(
self,
messages: str,
image_thumbnail: URL = "",
image_full_size: URL = "",
notification_disabled: bool = False
)
Sends a message. Note that this is a coroutine function.
parameter | type | default | description |
---|---|---|---|
messages | str | required | The message content. |
image_thumbnail | str | "" |
The image URL. (small size) |
image_full_size | str | "" |
Full size image URL. |
notification_disabled | bool | False | Whether disable the push notification or not. |
from linelib import Client
from linelib.notify import Notify
client = Client("channel secret", "channel access token")
notify_bot = Notify("access token")
@client.event('ready')
async def ready_event():
await notify_bot.notify("Hello, World!")
client.run()
Oh, boy! I love resources. They are nice and warm. Yes, no doubt.
Contents
Linelib might include some weird, and difficult-to-understand typings in the code.
However, the following descriptions could help you to get along with, or even be a real chad at them.
Linelib has a pretty unique cog command system, inspired by the discord.py module. However, it seems difficult to understand how it works by the type definition that I mentioned here.
This is how the type looks like: *: type
. The asterisk (*) represents Any
, and in this condition it represents any parameters. As well as the type
represents any type that is available (int
, float
, bool
, str
).
In addition, *: type
means that you should add parameters with type annotations to force Linelib convert it into a specific type.
Note that it is also possible to add keyword-only arguments. Keyword-only arguments should only have one, since it represents that any content left in the message (besides previous arguments & command name mentions) will be automatically passed into this single argument. Hard to understand? Let's break it down with a simple example, assuming the command name is /hi
, and the argument type annotations below:
# THIS IS NOT A VALID LINELIB CODE
# DEMONSTRATION PURPOSES ONLY
async def the_handler(ctx, arg1: int, *, arg2: str):
print(type(arg1))
print(arg2)
In this example (assuming this code works fine as a command cog), the user-sent messages will end up like this:
User: /hi 10 Good morning, sir!
The printed output:
<class 'int'>
Good morning, sir!
Linelib converted them with the same typing your annotation mentioned. In short, once the user send that message, the following is the result:
ctx: (The context)
arg1: 10 (int)
arg2: Good morning, sir! (str)
Let's see another example of not using the keyword-only asterisk.
async def handler_v2(ctx, arg1: int, arg2: str):
print(type(arg1))
print(arg2)
Message:
User: /hi 10 Good morning, sir!
The printed output:
<class 'int'>
Good
Now it's clear enough.
The argument arg2
did not return the value we expected, since we want the full sentence instead of just a single yet funny word.
In conclusion: The keyword-only asterisk (*) tells Linelib to put a full sentence into one argument, and type annotations force Linelib to convert the type of the original content (str) to the specified type.
Still don't understand? Feel free to take these FAQs as good advice ๐
Question 1: What if I add two keyword-only arguments?
It seems that it might cause a problem. However, Linelib processes the type annotations BEFORE starting your Bot application:
Program Start -> Process Arguments -> Process Type Annotations -> Raise An Error if "Multiple" keyword-only Arguments Found
In short: It is not possible to add two keyword-only arguments in this condition.
Question 2: What if I use my own type that's not on the list?
No, it's currently impossible for you to add your own types, since Linelib will raise an error which tells you to use the available types.
If you really hate the default types and would love us to add the feature, please consider submitting a feature request.
Question 3: I want more examples!!
Certainly! If you hate text descriptions like I do, feel free to understand in code ๐ง
Note that the following code examples are not valid Linelib cog commands, but you get the idea! ๐
async def drink(ctx, bottles: int):
print(f"Drank {bottles} bottles of water.")
async def say(ctx, *, text: str):
print(f"The user said: {text}")
async def eat(ctx, *, reason: str = "No reason provided"):
print(f"Eating, reason: {reason}")
async def kick(ctx, times: int, *, reason: str = "No reason provided"):
print(f"You kicked someone {times} times. Reason: {reason}")
Thanks for taking your time to read my awful documentation and guides.
Note that if you're interested, please also check out the Official LINE Documentation!
Hello! I am a cute sidebar that makes you to read this whole text with no doubt.
I was born in 1969 and collaborated with Gustavo Fring for my entire life, and my motto is: "Life is a career."
Actually, I have a more important announcement to make besides my profile.
My name is Sustavo Fring, but you can call me Sus.
I am the secondary owner of Los Pollos Hermanos that almost nobody knows.
Gustavo and I created an empire.
I AM THE DANGER.
My name is Walter Hartwell White. I live at-