Metadata-Version: 2.1
Name: pytchat
Version: 0.2.2
Summary: a python library for fetching youtube live chat.
Home-page: https://github.com/taizan-hokuto/pytchat
Author: taizan-hokuto
Author-email: 55448286+taizan-hokuto@users.noreply.github.com
License: MIT
Keywords: youtube livechat asyncio
Platform: UNKNOWN
Classifier: Natural Language :: Japanese
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: License :: OSI Approved :: MIT License
Description-Content-Type: text/markdown
Requires-Dist: httpx[http2] (==0.14.1)
Requires-Dist: protobuf (==3.13.0)
Requires-Dist: pytz
Requires-Dist: urllib3

pytchat
=======

pytchat is a python library for fetching youtube live chat.

## Description
pytchat is a python library for fetching youtube live chat
without using youtube api, Selenium or BeautifulSoup.

pytchatは、YouTubeチャットを閲覧するためのpythonライブラリです。

Other features:
+ Customizable [chat data processors](https://github.com/taizan-hokuto/pytchat/wiki/ChatProcessor) including youtube api compatible one.
+ Available on asyncio context. 
+ Quick fetching of initial chat data by generating continuation params
instead of web scraping.

For more detailed information, see [wiki](https://github.com/taizan-hokuto/pytchat/wiki). <br>
より詳細な解説は[wiki](https://github.com/taizan-hokuto/pytchat/wiki/Home_jp)を参照してください。

## Install
```python
pip install pytchat
```
## Examples

### CLI

One-liner command.
Save chat data to html, with embedded custom emojis.

```bash
$ pytchat -v https://www.youtube.com/watch?v=ZJ6Q4U_Vg6s -o "c:/temp/"
# options:
#  -v : Video ID or URL that includes ID
#  -o : output directory (default path: './')
# saved filename is [video_id].html
```


### on-demand mode
```python
from pytchat import LiveChat
livechat = LiveChat(video_id = "Zvp1pJpie4I")
# It is also possible to specify a URL that includes the video ID:
# livechat = LiveChat("https://www.youtube.com/watch?v=Zvp1pJpie4I")
while livechat.is_alive():
  try:
    chatdata = livechat.get()
    for c in chatdata.items:
        print(f"{c.datetime} [{c.author.name}]- {c.message}")
        chatdata.tick()
  except KeyboardInterrupt:
    livechat.terminate()
    break
```

### callback mode
```python
from pytchat import LiveChat
import time

def main():
  livechat = LiveChat(video_id = "Zvp1pJpie4I", callback = disp)
  while livechat.is_alive():
    #other background operation.
    time.sleep(1)
  livechat.terminate()

#callback function (automatically called)
def disp(chatdata):
    for c in chatdata.items:
        print(f"{c.datetime} [{c.author.name}]- {c.message}")
        chatdata.tick()

if __name__ == '__main__':
  main()

```

### asyncio context:
```python
from pytchat import LiveChatAsync
from concurrent.futures import CancelledError
import asyncio

async def main():
  livechat = LiveChatAsync("Zvp1pJpie4I", callback = func)
  while livechat.is_alive():
    #other background operation.
    await asyncio.sleep(3)

#callback function is automatically called.
async def func(chatdata):
  for c in chatdata.items:
    print(f"{c.datetime} [{c.author.name}]-{c.message} {c.amountString}")
    await chatdata.tick_async()

if __name__ == '__main__':
  try:
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
  except CancelledError:
    pass
```


### youtube api compatible processor:
```python
from pytchat import LiveChat, CompatibleProcessor
import time

chat = LiveChat("Zvp1pJpie4I", 
  processor = CompatibleProcessor() )

while chat.is_alive():
  try:
    data = chat.get()
    polling = data['pollingIntervalMillis']/1000
    for c in data['items']:
      if c.get('snippet'):
        print(f"[{c['authorDetails']['displayName']}]"
              f"-{c['snippet']['displayMessage']}")
        time.sleep(polling/len(data['items']))
  except KeyboardInterrupt:
    chat.terminate()
```
### replay: 
If specified video is not live,
automatically try to fetch archived chat data.

```python
from pytchat import LiveChat

def main():
  #seektime (seconds): start position of chat.
  chat = LiveChat("ojes5ULOqhc", seektime = 60*30)
  print('Replay from 30:00')
  try:
    while chat.is_alive():
      data = chat.get()
      for c in data.items:
        print(f"{c.elapsedTime} [{c.author.name}]-{c.message} {c.amountString}")
        data.tick()
  except KeyboardInterrupt:
    chat.terminate()

if __name__ == '__main__':
  main()
```
### Extract archived chat data as [HTML](https://github.com/taizan-hokuto/pytchat/wiki/HTMLArchiver) or [tab separated values](https://github.com/taizan-hokuto/pytchat/wiki/TSVArchiver).
```python
from pytchat import HTMLArchiver, Extractor

video_id = "*******"
ex = Extractor(
    video_id,
    div=10,
    processor=HTMLArchiver("c:/test.html")
)

ex.extract()
print("finished.")
```

## Structure of Default Processor
Each item can be got with `items` function.
<table>
  <tr>
    <th>name</th>
    <th>type</th>
    <th>remarks</th>
  </tr>
  <tr>
    <td>type</td>
    <td>str</td>
    <td>"superChat","textMessage","superSticker","newSponsor"</td>
  </tr>
  <tr>
    <td>id</td>
    <td>str</td>
    <td></td>
  </tr>
  <tr>
    <td>message</td>
    <td>str</td>
    <td>emojis are represented by ":(shortcut text):"</td>
  </tr>
  <tr>
    <td>messageEx</td>
    <td>str</td>
    <td>list of message texts and emoji dicts(id, txt, url).</td>
  </tr>
  <tr>
    <td>timestamp</td>
    <td>int</td>
    <td>unixtime milliseconds</td>
  </tr>
  <tr>
    <td>datetime</td>
    <td>str</td>
    <td>e.g. "2019-10-10 12:34:56"</td>
  </tr>
    <td>elapsedTime</td>
    <td>str</td>
    <td>elapsed time. (e.g. "1:02:27") *Replay Only.</td>
  </tr>
  <tr>
    <td>amountValue</td>
    <td>float</td>
    <td>e.g. 1,234.0</td>
  </tr>
  <tr>
    <td>amountString</td>
    <td>str</td>
    <td>e.g. "$ 1,234"</td>
  </tr>
  <tr>
    <td>currency</td>
    <td>str</td>
    <td><a href="https://en.wikipedia.org/wiki/ISO_4217">ISO 4217 currency codes</a> (e.g. "USD")</td>
  </tr>
  <tr>
    <td>bgColor</td>
    <td>int</td>
    <td>RGB Int</td>
  </tr>
  <tr>
    <td>author</td>
    <td>object</td>
    <td>see below</td>
  </tr>
</table>

Structure of author object.
<table>
  <tr>
    <th>name</th>
    <th>type</th>
    <th>remarks</th>
  </tr>
  <tr>
    <td>name</td>
    <td>str</td>
    <td></td>
  </tr>
  <tr>
    <td>channelId</td>
    <td>str</td>
    <td>*chatter's channel ID.</td>
  </tr>
  <tr>
    <td>channelUrl</td>
    <td>str</td>
    <td></td>
  </tr>
  <tr>
    <td>imageUrl</td>
    <td>str</td>
    <td></td>
  </tr>
  <tr>
    <td>badgeUrl</td>
    <td>str</td>
    <td></td>
  </tr>
  <tr>
    <td>isVerified</td>
    <td>bool</td>
    <td></td>
  </tr>
  <tr>
    <td>isChatOwner</td>
    <td>bool</td>
    <td></td>
  </tr>
  <tr>
    <td>isChatSponsor</td>
    <td>bool</td>
    <td></td>
  </tr>
  <tr>
    <td>isChatModerator</td>
    <td>bool</td>
    <td></td>
  </tr>
</table>

## Licence

[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)


## Contributes
Great thanks:

Most of source code of CLI refer to:

[PetterKraabol / Twitch-Chat-Downloader](https://github.com/PetterKraabol/Twitch-Chat-Downloader)


## Author

[taizan-hokuto](https://github.com/taizan-hokuto)

[twitter:@taizan205](https://twitter.com/taizan205)


