Compare commits

...

14 Commits

Author SHA1 Message Date
taizan-hokuto
f9480ea1eb Merge branch 'hotfix/cli_handle_live' 2020-08-21 22:25:48 +09:00
taizan-hokuto
6b924a88ef Increment version 2020-08-21 22:25:06 +09:00
taizan-hokuto
56294d6a67 Fix extracting video_id 2020-08-21 22:23:33 +09:00
taizan-hokuto
283443e374 Merge pull request #15 from EtianAM/patch-1
Fix videoinfo.py and CLI download
2020-08-21 19:34:19 +09:00
Etian Daniel Alavardo Mtz
89b51c420f Avoid changing the type of result.
However, if this argument is used elsewhere in the code it should be corrected.
2020-08-20 22:39:32 -05:00
Etian Daniel Alavardo Mtz
96474f10c6 Fix videoinfo.py
A bit ugly, but I couldn't solve it any other way. I'm bad with regex.
2020-08-20 22:29:59 -05:00
taizan-hokuto
78373bf45c Merge branch 'hotfix/exist_dir' 2020-08-06 00:32:06 +09:00
taizan-hokuto
3e11deed8f Increment version 2020-08-06 00:31:21 +09:00
taizan-hokuto
6daa375adf Handle exception when specified directory not found 2020-08-06 00:30:43 +09:00
taizan-hokuto
a90bda674d Merge pull request #12 from mark-ignacio/mit
Add LICENSE file
2020-07-27 00:22:56 +09:00
Mark Ignacio
48543b7866 add LICENSE file 2020-07-26 07:09:28 -07:00
taizan-hokuto
8df7062873 Merge branch 'hotfix/fix_color' 2020-07-24 22:43:09 +09:00
taizan-hokuto
b788f692ad Increment version 2020-07-24 22:42:26 +09:00
taizan-hokuto
713215f1d7 Fix supersticker bgColor 2020-07-24 22:41:07 +09:00
8 changed files with 46 additions and 9 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 taizan-hokuto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -2,7 +2,7 @@
pytchat is a lightweight python library to browse youtube livechat without Selenium or BeautifulSoup. pytchat is a lightweight python library to browse youtube livechat without Selenium or BeautifulSoup.
""" """
__copyright__ = 'Copyright (C) 2019 taizan-hokuto' __copyright__ = 'Copyright (C) 2019 taizan-hokuto'
__version__ = '0.1.1' __version__ = '0.1.4'
__license__ = 'MIT' __license__ = 'MIT'
__author__ = 'taizan-hokuto' __author__ = 'taizan-hokuto'
__author_email__ = '55448286+taizan-hokuto@users.noreply.github.com' __author_email__ = '55448286+taizan-hokuto@users.noreply.github.com'

View File

@@ -1,8 +1,9 @@
import argparse import argparse
import os
from pathlib import Path from pathlib import Path
from pytchat.util.extract_video_id import extract_video_id from pytchat.util.extract_video_id import extract_video_id
from .arguments import Arguments from .arguments import Arguments
from .. exceptions import InvalidVideoIdException, NoContents from .. exceptions import InvalidVideoIdException, NoContents, VideoInfoParseException
from .. processors.html_archiver import HTMLArchiver from .. processors.html_archiver import HTMLArchiver
from .. tool.extract.extractor import Extractor from .. tool.extract.extractor import Extractor
from .. tool.videoinfo import VideoInfo from .. tool.videoinfo import VideoInfo
@@ -21,7 +22,8 @@ def main():
# Arguments # Arguments
parser = argparse.ArgumentParser(description=f'pytchat v{__version__}') parser = argparse.ArgumentParser(description=f'pytchat v{__version__}')
parser.add_argument('-v', f'--{Arguments.Name.VIDEO_IDS}', type=str, parser.add_argument('-v', f'--{Arguments.Name.VIDEO_IDS}', type=str,
help='Video ID (or URL that includes Video ID). You can specify multiple video IDs by separating them with commas without spaces.\n' help='Video ID (or URL that includes Video ID). You can specify multiple video IDs by '
'separating them with commas without spaces.\n'
'If ID starts with a hyphen (-), enclose the ID in square brackets.') 'If ID starts with a hyphen (-), enclose the ID in square brackets.')
parser.add_argument('-o', f'--{Arguments.Name.OUTPUT}', type=str, parser.add_argument('-o', f'--{Arguments.Name.OUTPUT}', type=str,
help='Output directory (end with "/"). default="./"', default='./') help='Output directory (end with "/"). default="./"', default='./')
@@ -39,12 +41,16 @@ def main():
video_id = video_id.replace('[', '').replace(']', '') video_id = video_id.replace('[', '').replace(']', '')
try: try:
video_id = extract_video_id(video_id) video_id = extract_video_id(video_id)
if os.path.exists(Arguments().output):
path = Path(Arguments().output + video_id + '.html')
else:
raise FileNotFoundError
info = VideoInfo(video_id) info = VideoInfo(video_id)
print(f"Extracting...\n" print(f"Extracting...\n"
f" video_id: {video_id}\n" f" video_id: {video_id}\n"
f" channel: {info.get_channel_name()}\n" f" channel: {info.get_channel_name()}\n"
f" title: {info.get_title()}") f" title: {info.get_title()}")
path = Path(Arguments().output + video_id + '.html')
print(f" output path: {path.resolve()}") print(f" output path: {path.resolve()}")
Extractor(video_id, Extractor(video_id,
processor=HTMLArchiver( processor=HTMLArchiver(
@@ -56,6 +62,10 @@ def main():
print("Invalid Video ID or URL:", video_id) print("Invalid Video ID or URL:", video_id)
except (TypeError, NoContents) as e: except (TypeError, NoContents) as e:
print(e) print(e)
except FileNotFoundError:
print("The specified directory does not exist.:{}".format(Arguments().output))
except VideoInfoParseException:
print("Cannot parse video information.:{}".format(video_id))
return return
parser.print_help() parser.print_help()

View File

@@ -62,3 +62,9 @@ class ReceivedUnknownContinuation(ChatParseException):
class FailedExtractContinuation(ChatDataFinished): class FailedExtractContinuation(ChatDataFinished):
pass pass
class VideoInfoParseException(Exception):
'''
thrown when failed to parse video info
'''

View File

@@ -21,7 +21,7 @@ class LiveChatPaidStickerRenderer(BaseRenderer):
self.amountString = amountDisplayString self.amountString = amountDisplayString
self.currency = currency.symbols[symbol]["fxtext"] if currency.symbols.get( self.currency = currency.symbols[symbol]["fxtext"] if currency.symbols.get(
symbol) else symbol symbol) else symbol
self.bgColor = self.renderer.get("moneyChipBackgroundColor", 0) self.bgColor = self.renderer.get("backgroundColor", 0)
self.sticker = "".join(("https:", self.sticker = "".join(("https:",
self.renderer["sticker"]["thumbnails"][0]["url"])) self.renderer["sticker"]["thumbnails"][0]["url"]))
self.colors = self.get_colors() self.colors = self.get_colors()

View File

@@ -79,7 +79,7 @@ class Extractor:
def extract(self): def extract(self):
if self.duration == 0: if self.duration == 0:
print("video is not archived.") print("\nCannot extract chat data:\n The specified video has not yet been archived.")
return [] return []
data = self._execute_extract_operations() data = self._execute_extract_operations()
if self.processor is None: if self.processor is None:

View File

@@ -7,7 +7,7 @@ from ..util.extract_video_id import extract_video_id
headers = config.headers headers = config.headers
pattern = re.compile(r"yt\.setConfig\({'PLAYER_CONFIG': ({.*})}\);") pattern = re.compile(r"'PLAYER_CONFIG': ({.*}}})")
item_channel_id = [ item_channel_id = [
"videoDetails", "videoDetails",
@@ -91,7 +91,7 @@ class VideoInfo:
def _parse(self, text): def _parse(self, text):
result = re.search(pattern, text) result = re.search(pattern, text)
res = json.loads(result.group(1)) res = json.loads(result.group(1)[:-1])
response = self._get_item(res, item_response) response = self._get_item(res, item_response)
if response is None: if response is None:
self._check_video_is_private(res.get("args")) self._check_video_is_private(res.get("args"))

View File

@@ -136,7 +136,7 @@ def test_supersticker(mocker):
assert ret.amountValue == 200 assert ret.amountValue == 200
assert ret.amountString == "¥200" assert ret.amountString == "¥200"
assert ret.currency == "JPY" assert ret.currency == "JPY"
assert ret.bgColor == 4278248959 assert ret.bgColor == 4278237396
assert ret.sticker == "https://lh3.googleusercontent.com/param_s=s72-rp" assert ret.sticker == "https://lh3.googleusercontent.com/param_s=s72-rp"
assert ret.author.name == "author_name" assert ret.author.name == "author_name"
assert ret.author.channelId == "author_channel_id" assert ret.author.channelId == "author_channel_id"