Python library to receive live stream events like comments and gifts in realtime from TikTok LIVE.

Overview

TikTokLive

A python library to connect to and read events from TikTok's LIVE service

LinkedIn HitCount Downloads Issues Forks Stars Support Server

A python library to receive and decode livestream events such as comments and gifts in real-time from TikTok's LIVE service by connecting to TikTok's internal WebCast push service. This library includes a wrapper that connects to the WebCast service using only a user's unique_id and allows you to join your livestream as well as that of other streamers. No credentials are required to use TikTokLive.

This library a Python implementation of the Javascript TikTok-Live-Connector by @zerodytrash meant to serve as an alternative for users who feel more comfortable working in Python or require it for their specific dependancies.

This is not an official API. It's a reverse engineering and research project.

Join the support discord and visit the #support channel for questions, contributions and ideas. Feel free to make pull requests with missing/new features, fixes, etc.

Table of Contents

Primary Information

Resources & Guides

  1. David's Intro Tutorial
  2. Getting Started
  3. Params & Options
  4. Client Methods
  5. TikTok Events
  6. Usage Examples

💲 🖨 Thermal Printing Library 🖨 💲

Thermal printing is a very recent, very exciting trend on TikTok.

I developed an all-encompassing, multithreaded thermal printing program that does everything you could ever want with Thermal Printing. It even has its own YouTube Tutorial and comes with pre-made examples if your coding ability isn't very strong!

Print text, images, text-to-speech, play sounds, and much more. There is no subscription unlike virtual printer services. It's just a one-time, life-time purchase.

It's so easy, it can be installed in one command through pip. It's not just a "one-off" purchase, either. As the project is updated, you will have access to every new release as new features are added.

Here's a sample of what you can do with this library in less than 30 lines of code:

How to Purchase

First, read more about it on the public TikTokPrinter GitHub page.

Then, to buy this library, create a ticket in the #tickets channel in https://discord.gg/H8m3c6jSF4.

Type "Printer Magic" in the ticket to get started with your purchase.

Intro Tutorial

I cannot recommend this tutorial enough for people trying to get started. It is succinct, informative and easy to understand, created by David Teather, the creator of the Python TikTok-Api package. Click the thumbnail to warp.

David's Tutorial

Getting Started

  1. Install the module via pip
pip install TikTokLive
  1. Create your first chat connection
from TikTokLive import TikTokLiveClient
from TikTokLive.types.events import CommentEvent, ConnectEvent

# Instantiate the client with the user's username
client: TikTokLiveClient = TikTokLiveClient(unique_id="@isaackogz")


# Define how you want to handle specific events via decorator
@client.on("connect")
async def on_connect(_: ConnectEvent):
    print("Connected to Room ID:", client.room_id)


# Notice no decorator?
async def on_comment(event: CommentEvent):
    print(f"{event.user.nickname} -> {event.comment}")


# Define handling an event via "callback"
client.add_listener("comment", on_comment)

if __name__ == '__main__':
    # Run the client and block the main thread
    # await client.start() to run non-blocking
    client.run()

For more examples, see the examples folder provided in the tree.

Params & Options

To create a new TikTokLiveClient object the following parameter is required. You can optionally add configuration options to this via kwargs.

TikTokLiveClient(unique_id, **options)

Param Name Required Description
unique_id Yes The unique username of the broadcaster. You can find this name in the URL.
Example: https://www.tiktok.com/@officialgeilegisela/live => officialgeilegisela
debug No Whether to fire the "debug" event for receiving raw data
**options No Here you can set the following optional connection properties. If you do not specify a value, the default value will be used.

process_initial_data (default: true)
Define if you want to process the initial data which includes old messages of the last seconds.

fetch_room_info_on_connect (default: true)
Define if you want to fetch all room information on start. If this option is enabled, the connection to offline rooms will be prevented. If enabled, the connect result contains the room info via the room_info attribute. You can also manually retrieve the room info (even in an unconnected state) using the retrieve_room_info() method.

enable_extended_gift_info (default: false)
Define if you want to receive extended information about gifts like gift name, cost and images which you can retrieve via the available_gifts attribute.

polling_interval_ms (default: 1000)
Request polling interval.

client_params (default: {})
Custom client params for Webcast API.

headers (default: {})
Custom request headers passed to aiohttp.

timeout_ms (default: 1000)
How long to wait before a request should fail

loop (default: None)
Optionally supply your own asyncio event loop for usage by the client. When set to None, the client pulls the current active loop or creates a new one. This option is mostly useful for people trying to nest asyncio.

Example Options:

from TikTokLive import TikTokLiveClient

client: TikTokLiveClient = TikTokLiveClient(
    unique_id="@oldskoldj", **(
        {
            # Whether to process initial data (cached chats, etc.)
            "process_initial_data": True,

            # Connect info (viewers, stream status, etc.)
            "fetch_room_info_on_connect": True,

            # Whether to get extended gift info (Image URLs, etc.)
            "enable_extended_gift_info": True,

            # How frequently to poll Webcast API
            "polling_interval_ms": 1000,

            # Custom Client params
            "client_params": {},

            # Custom request headers
            "headers": {},

            # Custom timeout for Webcast API requests
            "timeout_ms": 1000,

            # Custom Asyncio event loop
            "loop": None,

            # Whether to trust environment variables that provide proxies to be used in aiohttp requests
            "trust_env": False,

            # A ProxyContainer object for proxied requests
            "proxy_container": None,

            # Set the language for Webcast responses (Changes extended_gift's language)
            "lang": "en-US"

        }
    )
)

client.run()

Methods

A TikTokLiveClient object contains the following methods.

Method Name Description
run Starts a connection to the live chat while blocking the main thread (sync)
start Connects to the live chat without blocking the main thread (async)
stop Turns off the connection to the live chat.
retrieve_room_info Gets the current room info from TikTok API
retrieve_available_gifts Retrieves a list of the available gifts for the room and adds it to the extended_gift attribute of the Gift object on the gift event, when enabled.
add_listener Adds an asynchronous listener function (or, you can decorate a function with @client.on()) and takes two parameters, an event name and the payload, an AbstractEvent
add_proxies Add proxies to the current list of proxies with a valid aiohttp proxy-url
get_proxies Get the current list of proxies by proxy-url
remove_proxies Remove proxies from the current list of proxies by proxy-url
set_proxies_enabled Set whether or not proxies are enabled (disabled by default)

Events

A TikTokLiveClient object has the following events. You can add events either by doing client.add_listener("event_name", callable) or by decorating a function with @client.on("event_name") that includes an event payload parameter.

connect

Triggered when the connection gets successfully established.

@client.on("connect")
async def on_connect(event: ConnectEvent):
    print("Connected")

disconnect

Triggered when the connection gets disconnected. You can call start() to have reconnect . Note that you should wait a little bit before attempting a reconnect to to avoid being rate-limited.

@client.on("disconnect")
async def on_disconnect(event: DisconnectEvent):
    print("Disconnected")

like

Triggered every time someone likes the stream.

@client.on("like")
async def on_like(event: LikeEvent):
    print("Someone liked the stream!")

join

Triggered every time a new person joins the stream.

@client.on("join")
async def on_join(event: JoinEvent):
    print("Someone joined the stream!")

gift

Triggered every time a gift arrives. Extra information can be gleamed off the available_gifts client attribute.

NOTE: Users have the capability to send gifts in a streak. This increases the data.gift.repeat_count value until the user terminates the streak. During this time new gift events are triggered again and again with an increased data.gift.repeat_count value. It should be noted that after the end of the streak, another gift event is triggered, which signals the end of the streak via data.gift.repeat_end:1. This applies only to gifts with data.gift.gift_type:1. This means that even if the user sends a gift_type:1 gift only once, you will receive the event twice. Once with repeat_end:0 and once with repeat_end:1. Therefore, the event should be handled as follows in one of TWO ways:

@client.on("gift")
async def on_gift(event: GiftEvent):
    # If it's type 1 and the streak is over
    if event.gift.gift_type == 1:
        if event.gift.repeat_end == 1:
            print(f"{event.user.uniqueId} sent {event.gift.repeat_count}x \"{event.gift.extended_gift.name}\"")

    # It's not type 1, which means it can't have a streak & is automatically over
    elif event.gift.gift_type != 1:
        print(f"{event.user.uniqueId} sent \"{event.gift.extended_gift.name}\"")
@client.on("gift")
async def on_gift(event: GiftEvent):
    # If it's type 1 and the streak is over
    if event.gift.streakable:
        if not event.gift.streaking:
            print(f"{event.user.uniqueId} sent {event.gift.repeat_count}x \"{event.gift.extended_gift.name}\"")

    # It's not type 1, which means it can't have a streak & is automatically over
    else:
        print(f"{event.user.uniqueId} sent \"{event.gift.extended_gift.name}\"")

follow

Triggered every time someone follows the streamer.

@client.on("follow")
async def on_follow(event: FollowEvent):
    print("Someone followed the streamer!")

share

Triggered every time someone shares the stream.

@client.on("share")
async def on_share(event: ShareEvent):
    print("Someone shared the streamer!")

viewer_count_update

Triggered every time the viewer count is updated. This event also updates the cached viewer count by default.

@client.on("viewer_count_update")
async def on_connect(event: ViewerCountUpdateEvent):
    print("Received a new viewer count:", event.viewCount)

comment

Triggered every time someone comments on the live

@client.on("comment")
async def on_connect(event: CommentEvent):
    print(f"{event.user.nickname} -> {event.comment}")

live_end

Triggered when the live stream gets terminated by the host.

@client.on("live_end")
async def on_connect(event: LiveEndEvent):
    print(f"Livestream ended :(")

unknown

Triggered when an unknown event is received that is not yet handled by this client

@client.on("live_end")
async def on_connect(event: UnknownEvent):
    print(event.as_dict, "<- This is my data as a dict!")

error

Triggered when there is an error in the client or in error handlers.

If this handler is not present in the code, an internal default handler will log errors in the console. If a handler is added, all error handling (including logging) is up to the individual.

Warning: If you listen for the error event and do not log errors, you will not see when an error occurs.

@client.on("error")
async def on_connect(error: Exception):
    # Handle the error
    if isinstance(error, SomeRandomError):
        print("Handle Some Error")
        return

    # Otherwise, log the error
    client._log_error(error)

Contributors

  • Isaac Kogan - Initial work & primary maintainer - isaackogan
  • Zerody - Reverse-Engineering & README.md file - Zerody
  • David Teather - TikTokLive Introduction Tutorial - davidteather

See the full list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Comments
  • Can't get the live broadcast barrage, no return failure

    Can't get the live broadcast barrage, no return failure

    Describe the bug Running the examples/gifts.py can't get the live broadcast information,

    Not sure if it has something to do with my network。

    Has tiktok modified the protocol?

    • OS: Ubuntu 20.04
    • Python: 3.8
    bug high priority 
    opened by wingceltis-c 13
  • InitialCursorMissing occurs In Version 4.3.3

    InitialCursorMissing occurs In Version 4.3.3

    In v4.3.3, running basic.py in exsample or simple code such as the following now causes an error.

    from TikTokLive import TikTokLiveClient
    from TikTokLive.types.events import CommentEvent, ConnectEvent
    
    # Cookies > sessionid
    sessionid = ""
    
    # Cookies > sid_guard
    sid_guard = ""
    
    client = TikTokLiveClient("@tv_asahi_news", **{
        "headers": {
            "Cookie": f"sessionid={sessionid}; sid_guard={sid_guard};"
        }
    })
    
    # Notice no decorator?
    async def on_comment(event: CommentEvent):
        print(f"{event.user.nickname} -> {event.comment}")
    
    
    if __name__ == '__main__':
        # Run the client and block the main thread
        # await client.start() to run non-blocking
        client.run(session_id=sessionid)
    
    Traceback (most recent call last):
      File "C:\Users\you-r\scoop\apps\python\current\lib\site-packages\TikTokLive\client\base.py", line 380, in _connect
        await self.__fetch_room_data(True)
      File "C:\Users\you-r\scoop\apps\python\current\lib\site-packages\TikTokLive\client\base.py", line 221, in __fetch_room_data
        raise InitialCursorMissing("Missing cursor in initial fetch response.")
    TikTokLive.types.errors.InitialCursorMissing: Missing cursor in initial fetch response.
    

    When I bring it down to v4.2.0, the error no longer occurs but it is not responsive. Two weeks ago it was working fine. Is there something I am missing?

    opened by you-ri 12
  • TikTokLive package ceased working on new connections 30 minutes ago

    TikTokLive package ceased working on new connections 30 minutes ago

    Dear team,

    The exact same code as previously worked, failed to initiate a connection.

    I upgraded TikTokLive to the latest version, and it still no longer connects.

    Here is the log.

    Any help or update will be useful. Thanks. S

    ERROR:root:Traceback (most recent call last): File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\base.py", line 114, in __fetch_room_info response = await self._http.get_json_object_from_webcast_api("room/info/", self._client_params) File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\http.py", line 144, in get_json_object_from_webcast_api response: dict = await self.__aiohttp_get_json(self.TIKTOK_URL_WEBCAST + path, params) File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\http.py", line 102, in __aiohttp_get_json async with session.get(request_url, headers=self.headers, timeout=self.timeout, proxy=self.proxy_container.get()) as request: File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\aiohttp\client.py", line 1138, in aenter self._resp = await self._coro File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\aiohttp\client.py", line 559, in _request await resp.start(conn) File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\aiohttp\client_reqrep.py", line 898, in start message, payload = await protocol.read() # type: ignore[union-attr] File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\aiohttp\streams.py", line 616, in read await self._waiter aiohttp.client_exceptions.ServerDisconnectedError: Server disconnected

    Failed to retrieve room info from webcast api Traceback (most recent call last): File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\base.py", line 215, in _connect if self.__room_info.get("status", 4) == 4: AttributeError: 'NoneType' object has no attribute 'get'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last): File "C:\Users\User\Desktop\t.py", line 25, in client.run() File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\base.py", line 293, in run self.loop.run_until_complete(self._connect()) File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.1264.0_x64__qbz5n2kfra8p0\lib\asyncio\base_events.py", line 646, in run_until_complete return future.result() File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\client.py", line 38, in _connect result: str = await super(TikTokLiveClient, self)._connect() File "C:\Users\User\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\TikTokLive\client\base.py", line 244, in _connect raise FailedConnection(message) TikTokLive.types.errors.FailedConnection: 'NoneType' object has no attribute 'get'

    opened by sjssjssjs 12
  • Websocket Disconnecting on windows with ver 4.2.6

    Websocket Disconnecting on windows with ver 4.2.6

    data transfer failed Traceback (most recent call last): File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 945, in transfer_data message = await self.read_message() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1015, in read_message frame = await self.read_data_frame(max_size=self.max_size) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1090, in read_data_frame frame = await self.read_frame(max_size) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1145, in read_frame frame = await Frame.read( File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\framing.py", line 100, in read data = await reader(length) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\streams.py", line 716, in readexactly self._maybe_resume_transport() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\streams.py", line 446, in _maybe_resume_transport self._transport.resume_reading() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\sslproto.py", line 343, in resume_reading self._ssl_protocol._transport.resume_reading() AttributeError: 'NoneType' object has no attribute 'resume_reading' Task exception was never retrieved future: <Task finished name='Task-9' coro=<WebcastWebsocket.connection_loop() done, defined at C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\TikTokLive\client\websocket.py:88> exception=ConnectionClosedError(None, Close(code=1011, reason=''), None)> Traceback (most recent call last): File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 945, in transfer_data message = await self.read_message() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1015, in read_message frame = await self.read_data_frame(max_size=self.max_size) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1090, in read_data_frame frame = await self.read_frame(max_size) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 1145, in read_frame frame = await Frame.read( File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\framing.py", line 100, in read data = await reader(length) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\streams.py", line 716, in readexactly self._maybe_resume_transport() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\streams.py", line 446, in _maybe_resume_transport self._transport.resume_reading() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\asyncio\sslproto.py", line 343, in resume_reading self._ssl_protocol._transport.resume_reading() AttributeError: 'NoneType' object has no attribute 'resume_reading'

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last): File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\TikTokLive\client\websocket.py", line 114, in connection_loop self.__client.emit("error", ex) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\pyee\base.py", line 179, in emit self._emit_handle_potential_error(event, args[0] if args else None) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\pyee\base.py", line 139, in _emit_handle_potential_error raise error File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\TikTokLive\client\websocket.py", line 104, in connection_loop await self.send_ack(decoded["id"]) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\TikTokLive\client\websocket.py", line 130, in send_ack await self._connection.send(message) File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 620, in send await self.ensure_open() File "C:\Users\GeneralKnow\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 930, in ensure_open raise self.connection_closed_exc() websockets.exceptions.ConnectionClosedError: sent 1011 (unexpected error); no close frame received

    Desktop (please complete the following information):

    • OS: win10
    • Browser: windows powershell
    • Version 4.2.6
    bug 
    opened by generalknow 9
  • To Do: v0.8.0

    To Do: v0.8.0

    • [x] Fix live count not working
    • [x] Proper library documentation
    • [x] Fix headers not being included in requests
    • [x] Remove double-quoted headers
    • [x] Enable trust-env, add proper proxy support
    • [x] Remove sessions or implement cookie saving
    • [x] Rebuild docs with updated pricelist
    new version 
    opened by isaackogan 9
  • Missing cursor in initial fetch response.

    Missing cursor in initial fetch response.

    Windows 10 Code: https://github.com/isaackogan/TikTokLive/blob/master/examples/basic.py Version 4,3.7

    Error: TikTokLive.types.errors.FailedConnection: Missing cursor in initial fetch response.

    bug 
    opened by xSoczek 8
  • error when running on a new thread

    error when running on a new thread

    Hi I'm a newbie who just started exploring TikTok world and thank you for developing this great toolkit! I found a weird behavior as below. Could you confirm it as expected or not? Thanks!

    Describe the bug When I execute TikTokLiveClient.run on a newly created thread, it crashes.

    To Reproduce Run the code below:

    import threading
    import time
    import asyncio
    from TikTokLive import TikTokLiveClient
    
    def start_tiktok():
        # loop = asyncio.new_event_loop()
        # asyncio.set_event_loop(loop)
        client = TikTokLiveClient(unique_id='@isaackogz')
        client.run()
    
    thread = threading.Thread(target=start_tiktok)
    thread.daemon = True
    thread.start()
    
    time.sleep(10)
    

    and we get this error:

    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/home/ec2-user/.local/lib/python3.7/site-packages/TikTokLive/client/base.py", line 73, in __init__
        self.loop: AbstractEventLoop = asyncio.get_event_loop()
      File "/usr/lib64/python3.7/asyncio/events.py", line 644, in get_event_loop
        % threading.current_thread().name)
    RuntimeError: There is no current event loop in thread 'Thread-1'.
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/lib64/python3.7/threading.py", line 926, in _bootstrap_inner
        self.run()
      File "/usr/lib64/python3.7/threading.py", line 870, in run
        self._target(*self._args, **self._kwargs)
      File "repro.py", line 9, in start_tiktok
        subscription = TikTokLiveClient(unique_id='@tv_asahi_news')
      File "/home/ec2-user/.local/lib/python3.7/site-packages/TikTokLive/client/client.py", line 31, in __init__
        BaseClient.__init__(self, unique_id, **options)
      File "/home/ec2-user/.local/lib/python3.7/site-packages/TikTokLive/client/base.py", line 75, in __init__
        self.loop: AbstractEventLoop = asyncio.get_running_loop()
    RuntimeError: no running event loop
    

    If I uncomment the two lines, it works without problem.

         loop = asyncio.new_event_loop()
         asyncio.set_event_loop(loop)
    

    Shouldn't this be handled inside the library? I saw the following description in README.md

    Optionally supply your own asyncio event loop for usage by the client. When set to None, the client pulls the current active loop or creates a new one. This option is mostly useful for people trying to nest asyncio.

    Expected behavior Code runs without problem.

    Additional context Add any other context about the problem here.

    bug 
    opened by tmokmss 8
  • I have upgraded to the latest version! I have encountered such a problem and how should I solve it

    I have upgraded to the latest version! I have encountered such a problem and how should I solve it

    ERROR:root:Traceback (most recent call last): File "F:\Programs\Python\Python310\lib\site-packages\TikTokLive\client\base.py", line 253, in __try_websocket_upgrade connection: WebSocketClientConnection = await websocket_connect( tornado.websocket.WebSocketError: Non-websocket response

    opened by kevinyasuo 8
  • To Do: v0.8.2

    To Do: v0.8.2

    • [x] Hide that ClientSession warning about not being closed when error/program exits (honestly, I'm probably misusing the ClientSession- let's look into that)
    • [x] Add a separate table for TikTokLive Printing. Should range from $30 base to $60 max & include a ton of customization options.
    • [x] Implement new Gift proto structure
    • [x] Add aliases to maintain backwards compatibility with old Gift structure
    • [x] Release a PyPi package fork of python-escpos under "python-escpos-win" with modified Windows support
    • [x] Fix Invalid JSON for Gifts

    Cancelled "Transpose method from GoTikTokLive for fetching current prices of coins" because I can't find out how to get a valid response after checking out https://github.com/Davincible/gotiktoklive/blob/master/tiktok.go. Assistance appreciated for the next version! Don't have time to do more debugging, need this new version out with the breaking gift change.

    Also couldn't find the whole discovering new streams thing. @davincible any help appreciated!

    {
    	"data": [],
    	"extra": {
    		"apple_pay_hint_url": "",
    		"badge_icon": "",
    		"channel": "",
    		"channel_id": 0,
    		"currency_list": [],
    		"customized_ids": [],
    		"default_currency": "",
    		"default_packet_id": 0,
    		"deprecated1": "",
    		"deprecated2": [],
    		"deprecated3": false,
    		"extra_diamond_list": [],
    		"first_charge_packet_id": 0,
    		"is_default": false,
    		"is_recommend": false,
    		"large_pay_url": "",
    		"max_customized_diamond_cnt": 2500000,
    		"merchant_id": "",
    		"min_customized_diamond_cnt": 30,
    		"need_auth": 0,
    		"now": 1649801498036,
    		"ploy_trace_id": 0,
    		"recently_purchased_packet_id": 0,
    		"recommended_packet_id": 0,
    		"should_display_customized_web_recharge": false,
    		"show_hint": 0,
    		"sign_infos": [],
    		"total_signed": 0
    	},
    	"status_code": 0
    }
    
    new version 
    opened by isaackogan 8
  • No bug display. No error output. Just randomly misses a few gifts and comments. Sometimes nothing displays at all.

    No bug display. No error output. Just randomly misses a few gifts and comments. Sometimes nothing displays at all.

    Describe the bug It doesn't get all comments and gifts.

    To Reproduce Steps to reproduce the behavior:

    1. Compile python code
    2. Run exe on CMD, "TikTokMonitor.exe (username)" without the parenthesis

    Expected behavior To catch all gifts and comments

    Code `from TikTokLive import TikTokLiveClient from TikTokLive.types.events import GiftEvent, ShareEvent, LikeEvent, FollowEvent, ConnectEvent, CommentEvent

    client = TikTokLiveClient(sys.argv[1])

    @client.on("gift") async def on_gift(event: GiftEvent): if event.gift.gift_type == 1 and event.gift.repeat_end == 1: output = (f"Gift,{event.user.profilePicture.avatar_url},{event.user.uniqueId},{event.gift.repeat_count},{event.gift.extended_gift.name},{event.gift.giftDetails.giftImage.giftPictureUrl},{event.gift.giftDetails.diamondCount}") print(output.encode("utf-8"),flush=True)

    elif event.gift.gift_type != 1:
        output = (f"Gift,{event.user.profilePicture.avatar_url},{event.user.uniqueId},1,{event.gift.extended_gift.name},{event.gift.giftDetails.giftImage.giftPictureUrl},{event.gift.giftDetails.diamondCount}")
        print(output.encode("utf-8"),flush=True)
    

    @client.on("like") async def on_like(event: LikeEvent): if event.likeCount > 10: output = (f"Like,{event.user.profilePicture.avatar_url},{event.user.uniqueId},{event.likeCount}") print(output.encode("utf-8"),flush=True)

    @client.on("share") async def on_share(event: ShareEvent): output = (f"Share,{event.user.profilePicture.avatar_url},{event.user.uniqueId}") print(output.encode("utf-8"),flush=True)

    @client.on("follow") async def on_follow(event: FollowEvent): output = (f"Follow,{event.user.profilePicture.avatar_url},{event.user.uniqueId}") print(output.encode("utf-8"),flush=True)

    @client.on("comment") async def on_follow(event: CommentEvent): output = (f"Comment,{event.user.profilePicture.avatar_url},{event.user.uniqueId},{event.comment}") print(output.encode("utf-8"),flush=True)

    client.run()`

    Desktop (please complete the following information):

    • OS: Windows 10

    Additional context I also noticed that some gifts and comments misses out on browser (chrome)

    bug 
    opened by kosmicforger 7
  • TikTokLive - Patch Report for October 3rd, 2022

    TikTokLive - Patch Report for October 3rd, 2022

    TikTokLive - Patch Report for October 3rd, 2022

    As per usual, here's a brief explanation as to why the library broke and what we did to fix it.

    TikTokLive works by connecting you, the user, to TikTok's internal API via Websocket. When TikTokLive and TikTok-Live-Connector came out earlier this year, TikTok were not too thrilled. They added authentication to their Webcast API to prevent users from using our projects.

    Our response was to reverse-engineer their authentication. Zerody figured out how to do this, and together we hid the method behind an API, known as the "Signing API" which signs the requests and returns valid tokens. This way, TikTok would not be able to see what we were doing to reverse engineer their authentication and we could continue without them trying to block us.

    Timeline of Changes

    Friday, September 30th

    TikTok released an update with the intention of completely stopping the library in its tracks. They essentially added a bunch of hidden checks, that, if caught in, would make our generated signatures fail. They even added checks to make it harder to see what checks they added.

    Saturday, October 1st

    We investigated what was going wrong. A fix wash pushed out. The fix managed to get around some issues, but was still being detected.

    Sunday, October 2nd

    Today, I am happy to say TikTokLive is once again operational, as is TikTok-Live-Connector.

    Monday, October 3rd

    TikTok are starting to block the library's usage again. We are trying out new signing methods. It may be working for you right now.

    Wednesday, October 5th

    We're back. Again. With the new Signing API version, we made a change to stop spammers from being able to abuse the service by no longer providing any tokens to the end-user. This way our platform cannot be misused. We've also added checks to prevent spam of the TikTok platform in general. The hope is that if TikTokLive cannot be misused, TikTok will not have incentive to put developer time towards blocking it.

    Thanks for your patience throughout all of this. If TikTok don't block us again, it should be smooth sailing hereon out, for the next little while anyways.

    Supporting Development

    TikTokLive has always been free to use and free for Zerody and I to run. Zerody is busy with a full-time job, and I am writing my first-ever midterm in University tomorrow. We both took a lot of time to fix this, for free. Time I did not have.

    As of this most recent fix, it now also costs us money to run this library, thanks to our new method of token generation.

    If you enjoy this library (and perhaps even made a coin or two from it), consider supporting its development with a donation to me at https://www.paypal.me/isaackogan or, Zerody, the other developer responsible for running this project & TikTok-Live-Connector at https://www.paypal.com/paypalme/dalixz .

    patch report 
    opened by isaackogan 6
Releases(v4.5.1)
  • v4.5.1(Oct 14, 2022)

    Version 4.5.1

    • [x] Fix issue in 4.5.0 release where proxies property was asynchronous

    Signing API

    • Additional logging
    • Methods to block spammers
    • Limit to approved use-cases to prevent misuse (ByteDance, leave us alone <3_<3)

    There are plenty of breaking changes:

    1. set_proxies was replaced with client.proxies = foobar
    2. SignatureSigningError was removed
    3. send_message function was modified to require additional parameters

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/84 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/80, https://github.com/isaackogan/TikTokLive/issues/79

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.5.0(Oct 14, 2022)

    Version 4.5.0

    • [x] Add support for new version of TikTok Signing Server (and deprecate old endpoint usage)
    • [x] Add websocket headers param
    • [x] Replace set_proxies with proxies setter method
    • [x] Modify send_message to require you to provide your own signatures and headers
    • [x] Remove SignatureSigningError error
    • [x] Add rate limit information on SignatureRateLimitReached error

    Signing API

    • Additional logging
    • Methods to block spammers
    • Limit to approved use-cases to prevent misuse (ByteDance, leave us alone <3_<3)

    There are plenty of breaking changes:

    1. set_proxies was replaced with client.proxies = foobar
    2. SignatureSigningError was removed
    3. send_message function was modified to require additional parameters

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/84 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/80, https://github.com/isaackogan/TikTokLive/issues/79

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.8(Oct 6, 2022)

    Version 4.3.8

    • [x] Add support for new version of TikTok Signing Server

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/77 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/76, https://github.com/isaackogan/TikTokLive/issues/74, https://github.com/zerodytrash/TikTok-Live-Connector/issues/69

    There are no breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.7(Sep 19, 2022)

    Version 4.3.7

    • [x] Add quality parameter to client.download

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/73 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/71

    There are no breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.6(Sep 4, 2022)

    Version 4.3.6

    • [x] Fix is_subscriber User attribute

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/69 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/68

    There are no breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.5(Aug 26, 2022)

    Version 4.3.5

    • [x] Replace get_proxies method with proxies attribute
    • [x] Replace old subscribe event logic with new detection logic
    • [x] Add sign_api_key parameter for clients requiring bulk access to TikTokLive

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/67 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/65, https://github.com/isaackogan/TikTokLive/issues/64, https://github.com/isaackogan/TikTokLive/issues/63

    client.get_proxies() becomes client.proxies. There are no other breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.3(Aug 3, 2022)

    • [x] Everything from https://github.com/isaackogan/TikTokLive/releases/tag/v4.3.2
    • [x] Remove websocket_timeout_ms
    • [x] Add ping loop

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/57 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/56

    client.stop() is no longer asynchronous. Remove await when using. There are no other breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.2(Aug 2, 2022)

    • [x] Add error message if websocket connection lost.
    • [x] Set websocket timeout to 15 seconds
    • [x] Remove 0.5s delay between websocket queries
    • [x] client.stop is no-longer an asynchronous method

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/57 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/56

    client.stop() is no longer asynchronous. Remove await when using. There are no other breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.3.0(Jul 29, 2022)

    • [x] Redo Websocket support
    • [x] Update Documentation

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/53 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/50

    There are no breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.2.6(Jul 23, 2022)

    • [x] Fix websocket connection dropping after ~3 minutes
    • [x] Make failed html parsing error more user-friendly to read & understand
    • [x] Update Documentation

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/49

    There are no breaking changes at this time.

    Upgrade with pip install TikTokLive --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v4.2.5(Jul 22, 2022)

    Changelog Summary

    • [x] Add Web-socket support
    • [x] Remove ProxyContainer in favour over regular proxying
    • [x] Migrate from aiohttp to httpx for requests
    • [x] Only allow long polling if a sessionid is provided
    • [x] Refactor project entirely for readability, functionality

    If you were using the ProxyContainer API, you must switch to the new proxy handling system. There are no other breaking changes.

    See full release changelog here: https://github.com/isaackogan/TikTokLive/issues/41 See referenced issue(s) here: https://github.com/isaackogan/TikTokLive/issues/34, https://github.com/isaackogan/TikTokLive/issues/35, https://github.com/isaackogan/TikTokLive/issues/37, https://github.com/isaackogan/TikTokLive/issues/38, https://github.com/isaackogan/TikTokLive/issues/39

    Source code(tar.gz)
    Source code(zip)
  • v4.2.0(Jul 12, 2022)

    • [x] Implement subscriber badges (image badges) ⭐
    • [x] Implement subscriber emotes ⭐
    • [x] Implement envelope event (sending treasure boxes)
    • [x] Repair is_moderator "User" attribute with new proto
    • [x] Add is_new_gifter "User" attribute
    • [x] Add is_subscriber "User" attribute
    • [x] Add "through_share" attribute to JoinEvent
    • [x] Add MoreShareEvent when a user shares to more than 5, 10 TikTok users
    • [x] Update HTTP Parameters
    • [x] Add "subscribe" event ⭐
    • [x] Add weekly rankings events
    • [x] Add support for TikTok Battles
    • [x] Add the ability to download streams including the "download" and "stop_download" methods on the BaseClient class ⭐
    • [x] Add the stream download example
    • [x] Updated documentation & README.md

    There are no breaking changes at this time. ⭐'s represent important/large changes

    See release here: https://github.com/isaackogan/TikTokLive/issues/33 See referenced suggestion(s) here: https://github.com/isaackogan/TikTokLive/issues/32, https://github.com/isaackogan/TikTokLive/issues/29

    Release Stats

    +2298 additions +123 deletions

    Source code(tar.gz)
    Source code(zip)
  • v0.8.9(May 5, 2022)

    • [x] Advanced error handling via the "error" event. If a custom handler is not added, runtime errors will be automatically logged in the console. If a handler is added, handling (and logging) is fully up to the user. If client.connected is False, handlers will NOT be used.
    • [x] Update documentation

    There are no breaking changes at this time.

    See release here: https://github.com/isaackogan/TikTokLive/issues/26 See fixed issue(s) here: https://github.com/isaackogan/TikTokLive/issues/25

    Source code(tar.gz)
    Source code(zip)
  • v0.8.6(Apr 22, 2022)

    • [x] Address issue with package failure to retrieve Room ID due to poor Room ID parsing: https://github.com/isaackogan/TikTokLive/issues/23

    Hotfix release. No new additional features included, no breaking changes.

    Source code(tar.gz)
    Source code(zip)
  • v0.8.5(Apr 16, 2022)

    • [x] Implement GiftExtra attribute
    • [x] Implement chat sending functionality & related errors
    • [x] Language Change Option
    • [x] New examples
    • [x] Additional Documentation
    Source code(tar.gz)
    Source code(zip)
  • v0.8.2(Apr 12, 2022)

    • [x] Revert ClientSession creation to old method
    • [x] Add a separate table for TikTokLive Printing
    • [x] Update Documentation
    • [x] Implement new Gift proto structure
    • [x] Add aliases to maintain backwards compatibility with old Gift structure
    • [x] Release a PyPi package fork of python-escpos under "python-escpos-win" with modified Windows support
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Mar 23, 2022)

    Update release tracking at https://github.com/isaackogan/TikTokLive/issues/14 containing:

    • [x] Fix live count not working
    • [x] Proper library documentation
    • [x] Fix headers not being included in requests
    • [x] Remove double-quoted headers
    • [x] Enable trust-env, add proper proxy support
    • [x] Remove sessions or implement cookie saving
    • [x] Rebuild docs with updated pricelist
    Source code(tar.gz)
    Source code(zip)
  • v0.7.5(Mar 8, 2022)

    Update release tracking at https://github.com/isaackogan/TikTokLive/issues/10 containing:

    • [x] Parsing for **kwargs in client constructor https://github.com/isaackogan/TikTokLive/issues/8
    • [x] Update documentation https://github.com/isaackogan/TikTokLive/issues/8
    • [x] Catch the ssl.SSLCertVerificationError and direct users to upgrade their certificates with dynamic information based on their python location https://cdn.discordapp.com/attachments/946228281059975189/948675757499088916/B2ED3006-893D-476C-AB43-ED7F704E744F.jpg
    • [x] Fix gift URLs not being shown in extended_gift https://github.com/isaackogan/TikTokLive/issues/9

    Full Changelog: https://github.com/isaackogan/TikTokLive/compare/v0.7.0...v0.7.5

    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Mar 1, 2022)

    Update https://github.com/isaackogan/TikTokLive/issues/2 containing:

    • [x] Debug option "on_debug"
    • [x] Add is_friend and is_following attributes on User object
    • [x] Add is_moderator attribute on User object
    • [x] Add extended gift info
    • [x] Look into missing gift info
    • [x] Fix chat repitition
    Source code(tar.gz)
    Source code(zip)
  • v0.6.9(Feb 24, 2022)

Owner
Isaac Kogan
Biology Major with Computer Science on the side, making messes & breaking codebases.
Isaac Kogan
Python implementation of 3D facial mesh exaggeration using the techniques described in the paper: Computational Caricaturization of Surfaces.

Python implementation of 3D facial mesh exaggeration using the techniques described in the paper: Computational Caricaturization of Surfaces.

Wonjong Jang 8 Nov 01, 2022
The final project of "Applying AI to 3D Medical Imaging Data" from "AI for Healthcare" nanodegree - Udacity.

Quantifying Hippocampus Volume for Alzheimer's Progression Background Alzheimer's disease (AD) is a progressive neurodegenerative disorder that result

Omar Laham 1 Jan 14, 2022
Rethinking Semantic Segmentation from a Sequence-to-Sequence Perspective with Transformers

Segmentation Transformer Implementation of Segmentation Transformer in PyTorch, a new model to achieve SOTA in semantic segmentation while using trans

Abhay Gupta 161 Dec 08, 2022
Black box hyperparameter optimization made easy.

BBopt BBopt aims to provide the easiest hyperparameter optimization you'll ever do. Think of BBopt like Keras (back when Theano was still a thing) for

Evan Hubinger 70 Nov 03, 2022
Official Implementation for "ReStyle: A Residual-Based StyleGAN Encoder via Iterative Refinement" https://arxiv.org/abs/2104.02699

ReStyle: A Residual-Based StyleGAN Encoder via Iterative Refinement Recently, the power of unconditional image synthesis has significantly advanced th

967 Jan 04, 2023
A Learning-based Camera Calibration Toolbox

Learning-based Camera Calibration A Learning-based Camera Calibration Toolbox Paper The pdf file can be found here. @misc{zhang2022learningbased,

Eason 14 Dec 21, 2022
Real-Time and Accurate Full-Body Multi-Person Pose Estimation&Tracking System

News! Aug 2020: v0.4.0 version of AlphaPose is released! Stronger tracking! Include whole body(face,hand,foot) keypoints! Colab now available. Dec 201

Machine Vision and Intelligence Group @ SJTU 6.7k Dec 28, 2022
A library for preparing, training, and evaluating scalable deep learning hybrid recommender systems using PyTorch.

collie Collie is a library for preparing, training, and evaluating implicit deep learning hybrid recommender systems, named after the Border Collie do

ShopRunner 96 Dec 29, 2022
[TOG 2021] PyTorch implementation for the paper: SofGAN: A Portrait Image Generator with Dynamic Styling.

This repository contains the official PyTorch implementation for the paper: SofGAN: A Portrait Image Generator with Dynamic Styling. We propose a SofGAN image generator to decouple the latent space o

Anpei Chen 694 Dec 23, 2022
PyTorch implementation code for the paper MixCo: Mix-up Contrastive Learning for Visual Representation

How to Reproduce our Results This repository contains PyTorch implementation code for the paper MixCo: Mix-up Contrastive Learning for Visual Represen

opcrisis 46 Dec 15, 2022
This is an official implementation for "SimMIM: A Simple Framework for Masked Image Modeling".

SimMIM By Zhenda Xie*, Zheng Zhang*, Yue Cao*, Yutong Lin, Jianmin Bao, Zhuliang Yao, Qi Dai and Han Hu*. This repo is the official implementation of

Microsoft 674 Dec 26, 2022
pytorch implementation of ABC : Auxiliary Balanced Classifier for Class-imbalanced Semi-supervised Learning

ABC:Auxiliary Balanced Classifier for Class-imbalanced Semi-supervised Learning, NeurIPS 2021 pytorch implementation of ABC : Auxiliary Balanced Class

Hyuck Lee 25 Dec 22, 2022
Object recognition using Azure Custom Vision AI and Azure Functions

Step by Step on how to create an object recognition model using Custom Vision, export the model and run the model in an Azure Function

El Bruno 11 Jul 08, 2022
Simple torch.nn.module implementation of Alias-Free-GAN style filter and resample

Alias-Free-Torch Simple torch module implementation of Alias-Free GAN. This repository including Alias-Free GAN style lowpass sinc filter @filter.py A

이준혁(Junhyeok Lee) 64 Dec 22, 2022
[EMNLP 2021] MuVER: Improving First-Stage Entity Retrieval with Multi-View Entity Representations

MuVER This repo contains the code and pre-trained model for our EMNLP 2021 paper: MuVER: Improving First-Stage Entity Retrieval with Multi-View Entity

24 May 30, 2022
GLaRA: Graph-based Labeling Rule Augmentation for Weakly Supervised Named Entity Recognition

GLaRA: Graph-based Labeling Rule Augmentation for Weakly Supervised Named Entity Recognition

Xinyan Zhao 29 Dec 26, 2022
🐥A PyTorch implementation of OpenAI's finetuned transformer language model with a script to import the weights pre-trained by OpenAI

PyTorch implementation of OpenAI's Finetuned Transformer Language Model This is a PyTorch implementation of the TensorFlow code provided with OpenAI's

Hugging Face 1.4k Jan 05, 2023
Supervised & unsupervised machine-learning techniques are applied to the database of weighted P4s which admit Calabi-Yau hypersurfaces.

Weighted Projective Spaces ML Description: The database of 5-vectors describing 4d weighted projective spaces which admit Calabi-Yau hypersurfaces are

Ed Hirst 3 Sep 08, 2022
[ECE NTUA] 👁 Computer Vision - Lab Projects & Theoretical Problem Sets (2020-2021)

Computer Vision - NTUA (2020-2021) This repository hosts the lab projects and theoretical problem sets of the Computer Vision course held by ECE NTUA

Dimitris Dimos 6 Jul 21, 2022
Computer Vision Paper Reviews with Key Summary of paper, End to End Code Practice and Jupyter Notebook converted papers

Computer-Vision-Paper-Reviews Computer Vision Paper Reviews with Key Summary along Papers & Codes. Jonathan Choi 2021 The repository provides 100+ Pap

Jonathan Choi 2 Mar 17, 2022