From 26e7018912f9c142f6394031c1bf5d17a999ba4f Mon Sep 17 00:00:00 2001 From: Pelle Date: Wed, 7 Apr 2021 12:22:28 +0200 Subject: [PATCH 01/11] Created new working branch for new features and updated README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1d9f17a..eb2fe65 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # twitch-highlights +[![GitHub](https://img.shields.io/github/license/pelledrijver/twitch-highlights)](https://github.com/pelledrijver/twitch-highlights/blob/master/LICENSE) +[![PyPI](https://img.shields.io/pypi/v/twitch-highlights)](https://pypi.org/project/twitch-highlights/) +[![GitHub Repo stars](https://img.shields.io/github/stars/pelledrijver/twitch-highlights)](https://github.com/pelledrijver/twitch-highlights/stargazers) +[![Discord](https://img.shields.io/discord/829297778324537384?color=%237289da&label=discord)](https://discord.gg/SPCj7TURj7) + An OS-independent and easy-to-use module for creating highlight videos from trending Twitch clips. Twitch highlight videos can be created by either specifying a category or a list of streamer names. ## Getting started From fa46f59277d395b34b1aa8a19cd01008f870b511 Mon Sep 17 00:00:00 2001 From: Pelle Date: Thu, 8 Apr 2021 12:25:51 +0200 Subject: [PATCH 02/11] Added custom logger for writing videofiles and added render_settings parameter --- requirements.txt | 3 +- setup.py | 5 +- src/twitch_highlights.py | 103 +++++++++++++++++++++++++++++++++------ 3 files changed, 92 insertions(+), 19 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c1dee2..6b21196 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ DateTime==4.3 moviepy==1.0.3 -requests==2.25.1 \ No newline at end of file +requests==2.25.1 +proglog==0.1.9 \ No newline at end of file diff --git a/setup.py b/setup.py index 16bfcd9..d304e5a 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ author_email='pelledrijver@gmail.com', url='https://github.com/pelledrijver/twitch-highlights', name='twitch-highlights', - version='0.0.1', + version='1.0.0', long_description=long_description, long_description_content_type="text/markdown", description = "An OS-independent and easy-to-use module for creating highlight videos from trending Twitch clips. Twitch highlight videos can be created by either specifying a category or a list of streamer names.", @@ -16,7 +16,8 @@ install_requires = [ 'requests', 'datetime', - 'moviepy>=1.0.3' + 'moviepy>=1.0.3', + 'proglog<=1.0.0' ], package_dir={'':'src'}, packages=find_packages(), diff --git a/src/twitch_highlights.py b/src/twitch_highlights.py index 4fdc393..9805d31 100644 --- a/src/twitch_highlights.py +++ b/src/twitch_highlights.py @@ -4,6 +4,12 @@ import shutil from datetime import datetime, timedelta from moviepy.editor import VideoFileClip, concatenate_videoclips +import random +import proglog + +#added sort_by +#remember proglog dependency +#todo: add logger? def _sort_clips_chronologically(clips): clips.sort(key=lambda k : k["created_at"]) @@ -13,21 +19,69 @@ def _sort_clips_popularity(clips): clips.sort(key=lambda k : k["view_count"]) -def _merge_videos(clip_list, output_name): +def _sort_clips_randomly(clips): + clips.sort(random.shuffle(clips)) + + +def _add_clip(clip_list, file_path, render_settings): + #TODO: Add transition + intro/outro functionality + + newVideoFileClip = VideoFileClip(file_path, target_resolution=render_settings["target_resolution"]) + clip_list.append(newVideoFileClip) + +def _combined_video_length(clip_list): + sum = 0 + for clip in clip_list: + sum += clip.duration + return sum + +def _check_render_settings(render_settings): + if render_settings is None: + render_settings = dict() + render_settings["fps"] = 60 + render_settings["target_resolution"] = (1920, 1080) + return render_settings + + if 'intro_path' in render_settings: + pass #check if path is valid + + if 'outro_path' in render_settings: + pass #check if path is valid + + if 'transition_path' in render_settings: + pass #check if path is valid + + if 'fps' not in render_settings: + render_settings['fps'] = 60 + + if 'target_resolution' not in render_settings: + render_settings['target_resolution'] = (1920, 1080) + + return render_settings + +def _merge_videos(clip_list, output_name, render_settings): + + #TODO: add outro? + merged_video = concatenate_videoclips(clip_list, method="compose") + print(f"Writing video file to {output_name}.mp4") + merged_video.write_videofile( f"{output_name}.mp4", codec="libx264", - fps=60, + fps=render_settings['fps'], temp_audiofile="temp-audio.m4a", remove_temp=True, - audio_codec="aac") + audio_codec="aac", + logger=proglog.TqdmProgressBarLogger(print_messages=False)) merged_video.close() for clip in clip_list: clip.close() - + + print(f'Succesfully generated highlight clip {output_name}!') + class TwitchHighlights: _TWITCH_OAUTH_ENDPOINT = "https://id.twitch.tv/oauth2/token" @@ -50,6 +104,10 @@ def login_twitch(self, twitch_credentials): query_parameters = f'?client_id={twitch_client_id}&client_secret={twitch_client_secret}&grant_type=client_credentials' response = requests.post(self._TWITCH_OAUTH_ENDPOINT + query_parameters) + + if(response.status_code != 200): + raise Exception(response.json()) + twitch_token = response.json()['access_token'] self.twitch_oauth_header = {"Client-ID": twitch_client_id, @@ -66,40 +124,50 @@ def get_top_categories(self, amount = 20): return categories - def make_video_by_category(self, category, output_name = "output_video", language = None, video_length = 300, started_at = datetime.utcnow() - timedelta(days=1), ended_at = datetime.utcnow(), target_resolution=(1080,1920)): + def make_video_by_category(self, category, output_name = "output_video", language = None, video_length = 300, started_at = datetime.utcnow() - timedelta(days=1), ended_at = datetime.utcnow(), render_settings = None, sort_by = "popularity"): clips = self._get_clips_by_category(category, started_at, ended_at) - self._create_video_from_json(clips, output_name, language, video_length, target_resolution) + self._create_video_from_json(clips, output_name, language, video_length, render_settings, sort_by) - def make_video_by_streamer(self, streamers, output_name = "output_video", language = None, video_length = 300, started_at = datetime.utcnow() - timedelta(days=1), ended_at = datetime.utcnow(), target_resolution=(1080,1920)): + def make_video_by_streamer(self, streamers, output_name = "output_video", language = None, video_length = 300, started_at = datetime.utcnow() - timedelta(days=1), ended_at = datetime.utcnow(), render_settings = None, sort_by = "popularity"): clips = [] for streamer in streamers: clips += self._get_clips_by_streamer(streamer, started_at, ended_at) _sort_clips_popularity(clips) - self._create_video_from_json(clips, output_name, language, video_length, target_resolution) + self._create_video_from_json(clips, output_name, language, video_length, render_settings, sort_by) + + def _create_video_from_json(self, clips, output_name, language, video_length, render_settings, sort_by): + print("Succesfully fetched clip data") - def _create_video_from_json(self, clips, output_name, language, video_length, target_resolution): - print("Succesfully fetched clip data") self._preprocess_clips(clips, language) + render_settings = _check_render_settings(render_settings) + + if sort_by == "random": + _sort_clips_randomly(clips) + elif sort_by == "popularity": + _sort_clips_popularity(clips) + elif sort_by == "chronologically": + _sort_clips_chronologically(clips) + else: + Exception(f'Sorting method {sort_by} not recognized.') + clip_list = [] - combined_length = 0 with requests.Session() as s: for i, clip in enumerate(clips): - if combined_length >= video_length: + if _combined_video_length(clip_list) >= video_length: break print(f'Downloading clip: {clip["broadcaster_name"]} - {clip["title"]}') file_path = self._download_clip(s, clip, i) - newVideoFileClip = VideoFileClip(file_path, target_resolution=target_resolution) - clip_list.append(newVideoFileClip) - combined_length += newVideoFileClip.duration - _merge_videos(clip_list, output_name) + _add_clip(clip_list, file_path, render_settings) + + _merge_videos(clip_list, output_name, render_settings) for file in os.listdir(self.tmpdir.name): os.remove(os.path.join(self.tmpdir.name, file)) @@ -115,6 +183,9 @@ def _get_request(self, endpoint_url, query_parameters, error_message = "An error response = requests.get(endpoint_url + query_parameters, headers=self.twitch_oauth_header) + if(response.status_code != 200): + raise Exception(response.json()) + if response.json()["data"] == None: raise Exception(error_message) From 800ef3b35905c6ff4f9df3c88ac1d998106824c4 Mon Sep 17 00:00:00 2001 From: Pelle Date: Thu, 8 Apr 2021 16:49:28 +0200 Subject: [PATCH 03/11] Implemented intro, outro, and transition, added download bar for downloading clips, downloaded clips are now removed when system crashes. --- requirements.txt | 3 +- setup.py | 3 +- src/twitch_highlights.py | 78 ++++++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/requirements.txt b/requirements.txt index 6b21196..7c1dee2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ DateTime==4.3 moviepy==1.0.3 -requests==2.25.1 -proglog==0.1.9 \ No newline at end of file +requests==2.25.1 \ No newline at end of file diff --git a/setup.py b/setup.py index d304e5a..0dc116b 100644 --- a/setup.py +++ b/setup.py @@ -16,8 +16,7 @@ install_requires = [ 'requests', 'datetime', - 'moviepy>=1.0.3', - 'proglog<=1.0.0' + 'moviepy>=1.0.3' ], package_dir={'':'src'}, packages=find_packages(), diff --git a/src/twitch_highlights.py b/src/twitch_highlights.py index 9805d31..0bb14a9 100644 --- a/src/twitch_highlights.py +++ b/src/twitch_highlights.py @@ -1,15 +1,13 @@ +from datetime import datetime, timedelta +from moviepy.editor import VideoFileClip, concatenate_videoclips import tempfile -import os import requests import shutil -from datetime import datetime, timedelta -from moviepy.editor import VideoFileClip, concatenate_videoclips import random import proglog +import os +from tqdm import tqdm -#added sort_by -#remember proglog dependency -#todo: add logger? def _sort_clips_chronologically(clips): clips.sort(key=lambda k : k["created_at"]) @@ -24,12 +22,14 @@ def _sort_clips_randomly(clips): def _add_clip(clip_list, file_path, render_settings): - #TODO: Add transition + intro/outro functionality + if len(clip_list) == 0 and 'intro_path' in render_settings: + clip_list.append(VideoFileClip(render_settings['intro_path'], target_resolution=render_settings["target_resolution"])) + elif 'transition_path' in render_settings: + clip_list.append(render_settings['transition_path'], target_resolution=render_settings["target_resolution"]) - newVideoFileClip = VideoFileClip(file_path, target_resolution=render_settings["target_resolution"]) - clip_list.append(newVideoFileClip) + clip_list.append(VideoFileClip(file_path, target_resolution=render_settings["target_resolution"])) -def _combined_video_length(clip_list): +def _get_combined_video_length(clip_list): sum = 0 for clip in clip_list: sum += clip.duration @@ -42,31 +42,34 @@ def _check_render_settings(render_settings): render_settings["target_resolution"] = (1920, 1080) return render_settings + if 'fps' not in render_settings: + render_settings['fps'] = 60 + + if 'target_resolution' not in render_settings: + render_settings['target_resolution'] = (1920, 1080) + if 'intro_path' in render_settings: - pass #check if path is valid + temp = VideoFileClip(render_settings['intro_path'], target_resolution=render_settings["target_resolution"]) + temp.close() if 'outro_path' in render_settings: - pass #check if path is valid + temp = VideoFileClip(render_settings['outro_path'], target_resolution=render_settings["target_resolution"]) + temp.close() if 'transition_path' in render_settings: - pass #check if path is valid - - if 'fps' not in render_settings: - render_settings['fps'] = 60 - - if 'target_resolution' not in render_settings: - render_settings['target_resolution'] = (1920, 1080) + temp = VideoFileClip(render_settings['transition_path'], target_resolution=render_settings["target_resolution"]) + temp.close() return render_settings def _merge_videos(clip_list, output_name, render_settings): - - #TODO: add outro? + if 'outro_path' in render_settings: + clip_list.append(VideoFileClip(render_settings['outro_path'], target_resolution=render_settings["target_resolution"])) merged_video = concatenate_videoclips(clip_list, method="compose") print(f"Writing video file to {output_name}.mp4") - + merged_video.write_videofile( f"{output_name}.mp4", codec="libx264", @@ -92,11 +95,18 @@ class TwitchHighlights: def __init__(self, twitch_credentials = None): - self.tmpdir = tempfile.TemporaryDirectory() + self.tmpdir = tempfile.mkdtemp() + print(self.tmpdir) if(twitch_credentials): self.login_twitch(twitch_credentials) + def __del__(self): + if hasattr(self, "clip_list"): + for clip in self.clip_list: + clip.close() + + shutil.rmtree(self.tmpdir) def login_twitch(self, twitch_credentials): twitch_client_id = twitch_credentials["client_id"] @@ -135,7 +145,6 @@ def make_video_by_streamer(self, streamers, output_name = "output_video", langua for streamer in streamers: clips += self._get_clips_by_streamer(streamer, started_at, ended_at) - _sort_clips_popularity(clips) self._create_video_from_json(clips, output_name, language, video_length, render_settings, sort_by) @@ -143,7 +152,6 @@ def _create_video_from_json(self, clips, output_name, language, video_length, re print("Succesfully fetched clip data") self._preprocess_clips(clips, language) - render_settings = _check_render_settings(render_settings) if sort_by == "random": @@ -156,10 +164,11 @@ def _create_video_from_json(self, clips, output_name, language, video_length, re Exception(f'Sorting method {sort_by} not recognized.') clip_list = [] + self.clip_list = clip_list with requests.Session() as s: for i, clip in enumerate(clips): - if _combined_video_length(clip_list) >= video_length: + if _get_combined_video_length(clip_list) >= video_length: break print(f'Downloading clip: {clip["broadcaster_name"]} - {clip["title"]}') @@ -169,8 +178,8 @@ def _create_video_from_json(self, clips, output_name, language, video_length, re _merge_videos(clip_list, output_name, render_settings) - for file in os.listdir(self.tmpdir.name): - os.remove(os.path.join(self.tmpdir.name, file)) + for file in os.listdir(self.tmpdir): + os.remove(os.path.join(self.tmpdir, file)) def _check_twitch_authentication(self): @@ -204,19 +213,20 @@ def _preprocess_clips(self, clips, language): def _download_clip(self, session, clip, id): - if not hasattr(self, "tmpdir"): - raise Exception("No temporary file storage available for downloaded clips.") - video_url = clip["video_url"] + file_path = f'{self.tmpdir}/{id}.mp4' - file_path = f'{self.tmpdir.name}/{id}.mp4' + response = session.get(video_url, stream=True) + total_size_in_bytes= int(response.headers.get('content-length', 0)) + progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True) - r=session.get(video_url) f=open(file_path,'wb') - for chunk in r.iter_content(chunk_size=1024*1024): + for chunk in response.iter_content(chunk_size=1024*1024): if chunk: + progress_bar.update(len(chunk)) f.write(chunk) f.close() + progress_bar.close() return file_path From 4c41bf889b9f2ec2223a67ff28d1469534a8d338 Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 16:54:29 +0200 Subject: [PATCH 04/11] Added Github Actions releasing automation --- .github/workflows/publish-to-test-pypi.yml | 42 +++++++++++++ .github/workflows/test.yml | 21 +++++++ src/twitch_highlights.py | 69 +++++++++++----------- 3 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/publish-to-test-pypi.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml new file mode 100644 index 0000000..bbf71fb --- /dev/null +++ b/.github/workflows/publish-to-test-pypi.yml @@ -0,0 +1,42 @@ +name: Publish Python 🐍 distributions 📦 to PyPI + +on: release + +jobs: + build-n-publish: + name: Build and publish Python 🐍 distributions 📦 to PyPI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel + - name: Build distributions + run: | + python setup.py sdist bdist_wheel + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{ secrets.PYPI_API_TOKEN }} + + discord-notification: + name: Send an announcement to the Discord community channel 💬 + runs-on: ubuntu-latest + steps: + - name: Discord notification + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + uses: Ilshidur/action-discord@master + with: + args: > + :rust: Server Announcement! :rust: + Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot + + + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4d1ad91 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,21 @@ +name: Test! + +on: commit + +jobs: + discord-notification: + name: Send an announcement to the Discord community channel 💬 + runs-on: ubuntu-latest + steps: + - name: Discord notification + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + uses: Ilshidur/action-discord@master + with: + args: > + :rust: Server Announcement! :rust: + Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot + + + diff --git a/src/twitch_highlights.py b/src/twitch_highlights.py index 0bb14a9..40bef0e 100644 --- a/src/twitch_highlights.py +++ b/src/twitch_highlights.py @@ -1,12 +1,12 @@ -from datetime import datetime, timedelta from moviepy.editor import VideoFileClip, concatenate_videoclips +from datetime import datetime, timedelta import tempfile import requests import shutil -import random -import proglog import os from tqdm import tqdm +import random +import proglog def _sort_clips_chronologically(clips): @@ -14,7 +14,7 @@ def _sort_clips_chronologically(clips): def _sort_clips_popularity(clips): - clips.sort(key=lambda k : k["view_count"]) + clips.sort(key=lambda k : k["view_count"], reverse = True) def _sort_clips_randomly(clips): @@ -24,8 +24,9 @@ def _sort_clips_randomly(clips): def _add_clip(clip_list, file_path, render_settings): if len(clip_list) == 0 and 'intro_path' in render_settings: clip_list.append(VideoFileClip(render_settings['intro_path'], target_resolution=render_settings["target_resolution"])) - elif 'transition_path' in render_settings: - clip_list.append(render_settings['transition_path'], target_resolution=render_settings["target_resolution"]) + + if 'transition_path' in render_settings and len(clip_list) != 0: + clip_list.append(VideoFileClip(render_settings['transition_path'], target_resolution=render_settings["target_resolution"])) clip_list.append(VideoFileClip(file_path, target_resolution=render_settings["target_resolution"])) @@ -35,18 +36,44 @@ def _get_combined_video_length(clip_list): sum += clip.duration return sum + +def _merge_videos(clip_list, output_name, render_settings): + if 'outro_path' in render_settings: + clip_list.append(VideoFileClip(render_settings['outro_path'], target_resolution=render_settings["target_resolution"])) + + merged_video = concatenate_videoclips(clip_list, method="compose") + + print(f"Writing video file to {output_name}.mp4") + + merged_video.write_videofile( + f"{output_name}.mp4", + codec="libx264", + fps=render_settings['fps'], + temp_audiofile="temp-audio.m4a", + remove_temp=True, + audio_codec="aac", + logger=proglog.TqdmProgressBarLogger(print_messages=False)) + + merged_video.close() + for clip in clip_list: + clip.close() + + print(f'Succesfully generated highlight video {output_name}!') + + + def _check_render_settings(render_settings): if render_settings is None: render_settings = dict() render_settings["fps"] = 60 - render_settings["target_resolution"] = (1920, 1080) + render_settings["target_resolution"] = (1080, 1920) return render_settings if 'fps' not in render_settings: render_settings['fps'] = 60 if 'target_resolution' not in render_settings: - render_settings['target_resolution'] = (1920, 1080) + render_settings['target_resolution'] = (1080, 1920) if 'intro_path' in render_settings: temp = VideoFileClip(render_settings['intro_path'], target_resolution=render_settings["target_resolution"]) @@ -62,29 +89,6 @@ def _check_render_settings(render_settings): return render_settings -def _merge_videos(clip_list, output_name, render_settings): - if 'outro_path' in render_settings: - clip_list.append(VideoFileClip(render_settings['outro_path'], target_resolution=render_settings["target_resolution"])) - - merged_video = concatenate_videoclips(clip_list, method="compose") - - print(f"Writing video file to {output_name}.mp4") - - merged_video.write_videofile( - f"{output_name}.mp4", - codec="libx264", - fps=render_settings['fps'], - temp_audiofile="temp-audio.m4a", - remove_temp=True, - audio_codec="aac", - logger=proglog.TqdmProgressBarLogger(print_messages=False)) - - merged_video.close() - for clip in clip_list: - clip.close() - - print(f'Succesfully generated highlight clip {output_name}!') - class TwitchHighlights: _TWITCH_OAUTH_ENDPOINT = "https://id.twitch.tv/oauth2/token" @@ -96,7 +100,6 @@ class TwitchHighlights: def __init__(self, twitch_credentials = None): self.tmpdir = tempfile.mkdtemp() - print(self.tmpdir) if(twitch_credentials): self.login_twitch(twitch_credentials) @@ -184,7 +187,7 @@ def _create_video_from_json(self, clips, output_name, language, video_length, re def _check_twitch_authentication(self): if not hasattr(self, "twitch_oauth_header"): - raise Exception("Twitch authentication incomplete. Please authenticate using the login() method.") + raise Exception("Twitch authentication incomplete. Please authenticate using the login_twitch() method.") def _get_request(self, endpoint_url, query_parameters, error_message = "An error occurred"): From 5763652036d86dc45f45824e0648ddf6ae4fb402 Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 16:56:16 +0200 Subject: [PATCH 05/11] changed workflows --- .github/workflows/publish-to-test-pypi.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index bbf71fb..fbf113e 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -34,7 +34,7 @@ jobs: uses: Ilshidur/action-discord@master with: args: > - :rust: Server Announcement! :rust: + *Server Announcement!* \n Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d1ad91..7fb3c72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: uses: Ilshidur/action-discord@master with: args: > - :rust: Server Announcement! :rust: + *Server Announcement!* \n Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot From e0d50b2c169d9a62cb5b5b73e8566c8fdf9f2332 Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 16:59:30 +0200 Subject: [PATCH 06/11] changed workflows --- .github/workflows/publish-to-test-pypi.yml | 18 +++++++++--------- .github/workflows/test.yml | 22 +++++++++++----------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index fbf113e..2f36fd7 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -29,14 +29,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Discord notification - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - uses: Ilshidur/action-discord@master - with: - args: > - *Server Announcement!* \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n - Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot - + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + uses: Ilshidur/action-discord@master + with: + args: > + Server Announcement! \n + Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7fb3c72..af9b4e7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: Test! -on: commit +on: push jobs: discord-notification: @@ -8,14 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Discord notification - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - uses: Ilshidur/action-discord@master - with: - args: > - *Server Announcement!* \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n - Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot - - + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + uses: Ilshidur/action-discord@master + with: + args: > + Server Announcement! \n + Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot + + From 635ae2223fd6a7baee6988b753cf7943aca1120c Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 17:09:00 +0200 Subject: [PATCH 07/11] changed workflows --- .github/workflows/publish-to-test-pypi.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index 2f36fd7..1969575 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -35,7 +35,7 @@ jobs: with: args: > Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Hi everyone! A new version of the twitch-highlights package has been released: {{ github.event.action }} 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af9b4e7..2989d36 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: with: args: > Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ EVENT_PAYLOAD.release.tag_name }} 📦 \n\n + Hi everyone! A new version of the twitch-highlights package has been released: {{ github.event.action }} 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot From 25df7a5ed0051413a37ae7746ac3134cc441c18f Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 17:10:11 +0200 Subject: [PATCH 08/11] changed workflows --- .github/workflows/publish-to-test-pypi.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index 1969575..7b16182 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -35,7 +35,7 @@ jobs: with: args: > Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ github.event.action }} 📦 \n\n + Hi everyone! A new version of the twitch-highlights package has been released: v1 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2989d36..28e3fc0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: with: args: > Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: {{ github.event.action }} 📦 \n\n + Hi everyone! A new version of the twitch-highlights package has been released: v1 📦 \n\n Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot From 6ad535f8f215accb6e8b4a59b8c4d37375a4f20c Mon Sep 17 00:00:00 2001 From: Pelle Date: Fri, 9 Apr 2021 17:24:47 +0200 Subject: [PATCH 09/11] changed workflows --- .github/workflows/publish-to-test-pypi.yml | 7 ++++--- .github/workflows/test.yml | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index 7b16182..d4e386f 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -33,9 +33,10 @@ jobs: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@master with: - args: > - Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: v1 📦 \n\n + args: |+ + :loudspeaker: **Release Alert!** :loudspeaker: + Hi everyone! A new version of the twitch-highlights package has been released: ${{ github.event.release.tag_name }} 📦 + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 28e3fc0..b2b722d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,9 +12,10 @@ jobs: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@master with: - args: > - Server Announcement! \n - Hi everyone! A new version of the twitch-highlights package has been released: v1 📦 \n\n + args: |+ + :loudspeaker: **Release Alert!** :loudspeaker: + Hi everyone! A new version of the twitch-highlights package has been released: ${{ github.event }} 📦 + Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot From 3dc57a7dc969e9c9cd1ecf0bea2c04ba237fac1d Mon Sep 17 00:00:00 2001 From: Pelle Date: Sat, 10 Apr 2021 15:30:57 +0200 Subject: [PATCH 10/11] Updated README.md and workflows --- ...sh-to-test-pypi.yml => python-publish.yml} | 10 +++--- .github/workflows/test.yml | 22 ------------- README.md | 33 +++++++++++++------ 3 files changed, 29 insertions(+), 36 deletions(-) rename .github/workflows/{publish-to-test-pypi.yml => python-publish.yml} (82%) delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/python-publish.yml similarity index 82% rename from .github/workflows/publish-to-test-pypi.yml rename to .github/workflows/python-publish.yml index d4e386f..f13d0a0 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/python-publish.yml @@ -1,6 +1,8 @@ -name: Publish Python 🐍 distributions 📦 to PyPI +name: Publish Python 🐍 distribution 📦 to PyPI and inform the Discord community -on: release +on: + release: + types: [created] jobs: build-n-publish: @@ -36,8 +38,8 @@ jobs: args: |+ :loudspeaker: **Release Alert!** :loudspeaker: Hi everyone! A new version of the twitch-highlights package has been released: ${{ github.event.release.tag_name }} 📦 - - Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot + + Take a look at the new features and the updated documentation at: https://github.com/pelledrijver/highlights-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index b2b722d..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Test! - -on: push - -jobs: - discord-notification: - name: Send an announcement to the Discord community channel 💬 - runs-on: ubuntu-latest - steps: - - name: Discord notification - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - uses: Ilshidur/action-discord@master - with: - args: |+ - :loudspeaker: **Release Alert!** :loudspeaker: - Hi everyone! A new version of the twitch-highlights package has been released: ${{ github.event }} 📦 - - Take a look at the new features and their documentation at: https://github.com/pelledrijver/highlights-bot - - - diff --git a/README.md b/README.md index eb2fe65..a67bd23 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Arguments: - **twitch_credentials**: *(optional)* Dictionary storing the *client_id* and *client_sectet* keys. ### login_twitch -Performs the proper authentication steps using Twitch's OAuth procedure to get access to its API. This method must be called before any other methods on the TwitchHighlights object are called. +Performs the proper authentication steps using Twitch's OAuth procedure to get access to its API. This method must be called before any other methods on the *TwitchHighlights* object are called. Information on how to obtain these credentials can be found [here](https://dev.twitch.tv/docs/authentication). ```python highlight_generator = TwitchHighlights() @@ -53,10 +53,12 @@ Arguments: - **category**: Name of the category from which the clips are gathered (case-insensitive). - **output_name**: Name of the generated output mp4 file. Defaults to "*output_video*". - **language**: Preferred language of the clips to be included in the video. Note that the clip's language tag might not actually match the language spoken in the clip. Defaults to *None*, which means that no clips are removed. -- **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to 300. +- **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to *300*. - **started_at**: Starting date/time for included clips as a datetime object in the UTC standard. Defaults to exactly one day before the time at which the method is called. - **ended_at**: Ending date/time for included clips as a datetime object in the UTC standard. Defaults to the time at which the method is called. -- **target_resolution**: Tuple containing (*desired_height*, *desired_width*) to which the resolution is resized. Defaults to (1080, 1920) +- **render_settings**: Dictionary containing information used for rendering and combining the clips. More information [here](#render_settings). Defaults to *None*. +- **sort_by**: Preferred ordering of clips (*"popularity", "chronologically", or "random"*). Defaults to *"popularity"*. + ### make_video_by_streamer Creates a highlight video consisting of trending clip from the provided category in the current directory. @@ -67,10 +69,12 @@ Arguments: - **streamers**: List of streamer names to gather clips from. - **output_name**: Name of the generated output mp4 file. Defaults to "*output_video*". - **language**: Preferred language of the clips to be included in the video. Note that the clip's language tag might not actually match the language spoken in the clip. Defaults to *None*, which means that no clips are removed. -- **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to 300. +- **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to *300*. - **started_at**: Starting date/time for included clips as a datetime object in the UTC standard. Defaults to exactly one day before the time at which the method is called. - **ended_at**: Ending date/time for included clips as a datetime object in the UTC standard. Defaults to the time at which the method is called. -- **target_resolution**: Tuple containing (*desired_height*, *desired_width*) to which the resolution is resized. Defaults to (1080, 1920) +- **render_settings**: Dictionary containing information used for rendering and combining the clips. More information [here](#render_settings). Defaults to *None*. +- **sort_by**: Preferred ordering of clips (*"popularity", "chronologically", or "random"*). Defaults to *"popularity"*. + ### get_top_categories Returns a list of the names of the most trending categories on Twitch at that moment. @@ -78,14 +82,23 @@ Returns a list of the names of the most trending categories on Twitch at that mo highlight_generator.get_top_categories(5) ``` Arguments: -- **amount**: Maximum number of categories to return. Maximum: 100. Defaults to 20. +- **amount**: Maximum number of categories to return. Maximum: 100. Defaults to *20*. + + +### render_settings +Dictionary containing information used for rendering and combining the clips. When None is passed or any of the keys are missing, the default values are used. + +Keys: +- **intro_path**: Path to the file containing the intro video that has to be added to the start of the generated video. If not specified, no intro is added. +- **transition_path**: Path to the file containing the transition video that has to be added between each of the clips in the generated video. If not specified, no transitions are added. +- **outro_path**: Path to the file containing the outro video that has to be added to the end of the generated video. If not specified, no outro is added. +- **target_resolution**: Tuple containing (desired_height, desired_width) to which the resolution is resized. Defaults to *(1080, 1920)*. +- **fps**: Number of frames per second. Defaults to *60*. ## License Apache-2.0 ## Contributing -So far, I have been the only one who has worked on the project and it would be great if I could get an extra pair of hands. Feel free to contact me if you have any great ideas and would like contribute to this project. New features I'm currently working on are: +So far, I have been the only one who has worked on the project and it would be great if I could get an extra pair of hands. Feel free to contact me if you have any great ideas and would like to contribute to this project. New features I'm currently working on are: - Copyright music detection -- Adding an intro/outro to the generated video -- Uploading the created video directly to YouTube -- An extra ordering feature in which the user can specify a specific ordering of clips (by number of views, chronological order, etc) +- Uploading the created video directly to YouTube \ No newline at end of file From b467b6774e1514f3d3769ff7316590a713f5eaaf Mon Sep 17 00:00:00 2001 From: Pelle Date: Sat, 10 Apr 2021 15:33:06 +0200 Subject: [PATCH 11/11] Final touches --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a67bd23..59502f2 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ highlight_generator.make_video_by_category(category = "Just Chatting", language ``` Arguments: - **category**: Name of the category from which the clips are gathered (case-insensitive). -- **output_name**: Name of the generated output mp4 file. Defaults to "*output_video*". +- **output_name**: Name of the generated output mp4 file. Defaults to *"output_video"*. - **language**: Preferred language of the clips to be included in the video. Note that the clip's language tag might not actually match the language spoken in the clip. Defaults to *None*, which means that no clips are removed. - **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to *300*. - **started_at**: Starting date/time for included clips as a datetime object in the UTC standard. Defaults to exactly one day before the time at which the method is called. @@ -67,7 +67,7 @@ highlight_generator.make_video_by_streamer(streamers = ["Ninja", "Myth"]) ``` Arguments: - **streamers**: List of streamer names to gather clips from. -- **output_name**: Name of the generated output mp4 file. Defaults to "*output_video*". +- **output_name**: Name of the generated output mp4 file. Defaults to *"output_video"*. - **language**: Preferred language of the clips to be included in the video. Note that the clip's language tag might not actually match the language spoken in the clip. Defaults to *None*, which means that no clips are removed. - **video_length**: Minimum length of the video to be created in seconds. Clips are added to the combined video until this length is reached. Defaults to *300*. - **started_at**: Starting date/time for included clips as a datetime object in the UTC standard. Defaults to exactly one day before the time at which the method is called. @@ -96,7 +96,7 @@ Keys: - **fps**: Number of frames per second. Defaults to *60*. ## License -Apache-2.0 +[Apache-2.0](https://github.com/pelledrijver/twitch-highlights/blob/dev/LICENSE) ## Contributing So far, I have been the only one who has worked on the project and it would be great if I could get an extra pair of hands. Feel free to contact me if you have any great ideas and would like to contribute to this project. New features I'm currently working on are: