From ce95b6dbf0e7c9423a8683e8ca3c46f9827e9470 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Sat, 27 Apr 2024 19:17:52 +0200 Subject: [PATCH 01/17] Update dependencies --- requirements.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 293b2ae..a090787 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -aiohttp==3.9.0 +aiohttp==3.9.5 appdirs==1.4.4 argparse==1.4.0 async-cache==1.1.1 -pyytlounge==1.6.3 -rich==13.6.0 +pyytlounge==2.0.0 +rich==13.7.1 ssdp==1.3.0 -textual==0.40.0 +textual==0.58.0 textual-slider==0.1.1 -xmltodict==0.13.0 +xmltodict==0.13.0 \ No newline at end of file From 582b9bf7254d5b7d9ee85b32fc598965bc7a7650 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Sat, 27 Apr 2024 19:26:55 +0200 Subject: [PATCH 02/17] Patch the main aiohttp.ClientSession() into YTlounge --- src/iSponsorBlockTV/config_setup.py | 42 ++++++++++++++++------------- src/iSponsorBlockTV/main.py | 9 ++++--- src/iSponsorBlockTV/setup_wizard.py | 4 +-- src/iSponsorBlockTV/ytlounge.py | 33 +++++++++++++++-------- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/iSponsorBlockTV/config_setup.py b/src/iSponsorBlockTV/config_setup.py index 51b0138..92a7dbb 100644 --- a/src/iSponsorBlockTV/config_setup.py +++ b/src/iSponsorBlockTV/config_setup.py @@ -5,9 +5,10 @@ import aiohttp from . import api_helpers, ytlounge -async def pair_device(): +async def pair_device(web_session): try: - lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV") + lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV", + web_session=web_session) pairing_code = input( "Enter pairing code (found in Settings - Link with TV code): " ) @@ -33,6 +34,7 @@ async def pair_device(): def main(config, debug: bool) -> None: print("Welcome to the iSponsorBlockTV cli setup wizard") loop = asyncio.get_event_loop_policy().get_event_loop() + web_session = aiohttp.ClientSession() if debug: loop.set_debug(True) asyncio.set_event_loop(loop) @@ -43,16 +45,17 @@ def main(config, debug: bool) -> None: " \nhttps://github.com/dmunozv04/iSponsorBlockTV/wiki/Migrate-from-V1-to-V2" ) if ( - input( - "Do you want to remove the legacy 'atvs' entry (the app won't start" - " with it present)? (y/n) " - ) - == "y" + input( + "Do you want to remove the legacy 'atvs' entry (the app won't start" + " with it present)? (y/n) " + ) + == "y" ): del config["atvs"] devices = config.devices - while not input(f"Paired with {len(devices)} Device(s). Add more? (y/n) ") == "n": - task = loop.create_task(pair_device()) + while not input( + f"Paired with {len(devices)} Device(s). Add more? (y/n) ") == "n": + task = loop.create_task(pair_device(web_session)) loop.run_until_complete(task) device = task.result() if device: @@ -65,10 +68,10 @@ def main(config, debug: bool) -> None: apikey = input("Enter your API key: ") else: if ( - input( - "API key only needed for the channel whitelist function. Add it? (y/n) " - ) - == "y" + input( + "API key only needed for the channel whitelist function. Add it? (y/n) " + ) + == "y" ): print( "Get youtube apikey here:" @@ -79,7 +82,8 @@ def main(config, debug: bool) -> None: skip_categories = config.skip_categories if skip_categories: - if input("Skip categories already specified. Change them? (y/n) ") == "y": + if input( + "Skip categories already specified. Change them? (y/n) ") == "y": categories = input( "Enter skip categories (space or comma sepparated) Options: [sponsor" " selfpromo exclusive_access interaction poi_highlight intro outro" @@ -103,8 +107,9 @@ def main(config, debug: bool) -> None: channel_whitelist = config.channel_whitelist if ( - input("Do you want to whitelist any channels from being ad-blocked? (y/n) ") - == "y" + input( + "Do you want to whitelist any channels from being ad-blocked? (y/n) ") + == "y" ): if not apikey: print( @@ -112,7 +117,6 @@ def main(config, debug: bool) -> None: " otherwise the program will fail to start.\nYou can add one by" " re-running this setup wizard." ) - web_session = aiohttp.ClientSession() api_helper = api_helpers.ApiHelper(config, web_session) while True: channel_info = {} @@ -152,7 +156,6 @@ def main(config, debug: bool) -> None: channel_info["name"] = results[int(choice)][1] channel_whitelist.append(channel_info) # Close web session asynchronously - loop.run_until_complete(web_session.close()) config.channel_whitelist = channel_whitelist @@ -161,7 +164,8 @@ def main(config, debug: bool) -> None: "Do you want to report skipped segments to sponsorblock. Only the segment" " UUID will be sent? (y/n) " ) - == "n" + == "n" ) print("Config finished") config.save() + loop.run_until_complete(web_session.close()) diff --git a/src/iSponsorBlockTV/main.py b/src/iSponsorBlockTV/main.py index 8cc6e9d..b624d00 100644 --- a/src/iSponsorBlockTV/main.py +++ b/src/iSponsorBlockTV/main.py @@ -10,13 +10,14 @@ from . import api_helpers, ytlounge class DeviceListener: - def __init__(self, api_helper, config, device, debug: bool): + def __init__(self, api_helper, config, device, debug: bool, web_session): self.task: Optional[asyncio.Task] = None self.api_helper = api_helper self.offset = device.offset self.name = device.name self.cancelled = False self.logger = logging.getLogger(f"iSponsorBlockTV-{device.screen_id}") + self.web_session = web_session if debug: self.logger.setLevel(logging.DEBUG) else: @@ -28,7 +29,7 @@ class DeviceListener: self.logger.addHandler(sh) self.logger.info(f"Starting device") self.lounge_controller = ytlounge.YtLoungeApi( - device.screen_id, config, api_helper, self.logger + device.screen_id, config, api_helper, self.logger, self.web_session ) # Ensures that we have a valid auth token @@ -155,7 +156,7 @@ def main(config, debug): web_session = aiohttp.ClientSession(loop=loop, connector=tcp_connector) api_helper = api_helpers.ApiHelper(config, web_session) for i in config.devices: - device = DeviceListener(api_helper, config, i, debug) + device = DeviceListener(api_helper, config, i, debug, web_session) devices.append(device) tasks.append(loop.create_task(device.loop())) tasks.append(loop.create_task(device.refresh_auth_loop())) @@ -165,3 +166,5 @@ def main(config, debug): print("Cancelling tasks and exiting...") loop.run_until_complete(finish(devices)) loop.run_until_complete(web_session.close()) + loop.run_until_complete(tcp_connector.close()) + loop.close() diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index e692abe..b111b63 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -234,7 +234,7 @@ class AddDevice(ModalWithClickExit): def __init__(self, config, **kwargs) -> None: super().__init__(**kwargs) self.config = config - web_session = aiohttp.ClientSession() + self.web_session = aiohttp.ClientSession() self.api_helper = api_helpers.ApiHelper(config, web_session) self.devices_discovered_dial = [] @@ -336,7 +336,7 @@ class AddDevice(ModalWithClickExit): @on(Button.Pressed, "#add-device-pin-add-button") async def handle_add_device_pin(self) -> None: self.query_one("#add-device-pin-add-button").disabled = True - lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV") + lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV", web_session=self.web_session) pairing_code = self.query_one("#pairing-code-input").value pairing_code = int( pairing_code.replace("-", "").replace(" ", "") diff --git a/src/iSponsorBlockTV/ytlounge.py b/src/iSponsorBlockTV/ytlounge.py index 18087f7..2cc2a1d 100644 --- a/src/iSponsorBlockTV/ytlounge.py +++ b/src/iSponsorBlockTV/ytlounge.py @@ -1,3 +1,4 @@ +from aiohttp import ClientSession import asyncio import json @@ -9,8 +10,13 @@ create_task = asyncio.create_task class YtLoungeApi(pyytlounge.YtLoungeApi): - def __init__(self, screen_id, config=None, api_helper=None, logger=None): + def __init__(self, screen_id, config=None, api_helper=None, logger=None, + web_session: ClientSession = None): super().__init__("iSponsorBlockTV", logger=logger) + if web_session is not None: + asyncio.get_event_loop().run_until_complete( + self.close()) # Close the default connection + self.session = web_session # And use the one we passed self.auth.screen_id = screen_id self.auth.lounge_id_token = None self.api_helper = api_helper @@ -75,13 +81,13 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): self.logger.info("Ad has ended, unmuting") create_task(self.mute(False, override=True)) elif ( - self.skip_ads and data["isSkipEnabled"] == "true" + self.skip_ads and data["isSkipEnabled"] == "true" ): # YouTube uses strings for booleans self.logger.info("Ad can be skipped, skipping") create_task(self.skip_ad()) create_task(self.mute(False, override=True)) elif ( - self.mute_ads + self.mute_ads ): # Seen multiple other adStates, assuming they are all ads self.logger.info("Ad has started, muting") create_task(self.mute(True, override=True)) @@ -92,7 +98,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): # Gets segments for the next video before it starts playing elif event_type == "autoplayUpNext": if len(args) > 0 and ( - vid_id := args[0]["videoId"] + vid_id := args[0]["videoId"] ): # if video id is not empty self.logger.info(f"Getting segments for next video: {vid_id}") create_task(self.api_helper.get_segments(vid_id)) @@ -105,13 +111,13 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): self.logger.info(f"Getting segments for next video: {vid_id}") create_task(self.api_helper.get_segments(vid_id)) elif ( - self.skip_ads and data["isSkipEnabled"] == "true" + self.skip_ads and data["isSkipEnabled"] == "true" ): # YouTube uses strings for booleans self.logger.info("Ad can be skipped, skipping") create_task(self.skip_ad()) create_task(self.mute(False, override=True)) elif ( - self.mute_ads + self.mute_ads ): # Seen multiple other adStates, assuming they are all ads self.logger.info("Ad has started, muting") create_task(self.mute(True, override=True)) @@ -122,7 +128,8 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): for device in devices: if device["type"] == "LOUNGE_SCREEN": device_info = json.loads(device.get("deviceInfo", "{}")) - if device_info.get("clientName", "") in youtube_client_blacklist: + if device_info.get("clientName", + "") in youtube_client_blacklist: self._sid = None self._gsession = None # Force disconnect @@ -134,7 +141,8 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): create_task(self.play_video(video_id_saved)) elif event_type == "loungeScreenDisconnected": data = args[0] - if data["reason"] == "disconnectedByUserScreenInitiated": # Short playing? + if data[ + "reason"] == "disconnectedByUserScreenInitiated": # Short playing? self.shorts_disconnected = True super()._process_event(event_id, event_type, args) @@ -152,17 +160,20 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): mute_str = "true" else: mute_str = "false" - if override or not (self.volume_state.get("muted", "false") == mute_str): + if override or not ( + self.volume_state.get("muted", "false") == mute_str): self.volume_state["muted"] = mute_str # YouTube wants the volume when unmuting, so we send it await super()._command( "setVolume", - {"volume": self.volume_state.get("volume", 100), "muted": mute_str}, + {"volume": self.volume_state.get("volume", 100), + "muted": mute_str}, ) async def set_auto_play_mode(self, enabled: bool): await super()._command( - "setAutoplayMode", {"autoplayMode": "ENABLED" if enabled else "DISABLED"} + "setAutoplayMode", + {"autoplayMode": "ENABLED" if enabled else "DISABLED"} ) async def play_video(self, video_id: str) -> bool: From 213ae97bf2a00154da7d59c6b5ce75bfd805e0e2 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Sun, 5 May 2024 19:07:03 +0200 Subject: [PATCH 03/17] Fix web_session --- src/iSponsorBlockTV/setup_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index b111b63..4411686 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -235,7 +235,7 @@ class AddDevice(ModalWithClickExit): super().__init__(**kwargs) self.config = config self.web_session = aiohttp.ClientSession() - self.api_helper = api_helpers.ApiHelper(config, web_session) + self.api_helper = api_helpers.ApiHelper(config, self.web_session) self.devices_discovered_dial = [] def compose(self) -> ComposeResult: From dd42e20dc48c40e9ad9745bbae25cb67ab7c70eb Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Sun, 5 May 2024 19:16:27 +0200 Subject: [PATCH 04/17] Remove session closer, it seems to break the config setup --- src/iSponsorBlockTV/ytlounge.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/iSponsorBlockTV/ytlounge.py b/src/iSponsorBlockTV/ytlounge.py index 2cc2a1d..56c7490 100644 --- a/src/iSponsorBlockTV/ytlounge.py +++ b/src/iSponsorBlockTV/ytlounge.py @@ -14,8 +14,6 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): web_session: ClientSession = None): super().__init__("iSponsorBlockTV", logger=logger) if web_session is not None: - asyncio.get_event_loop().run_until_complete( - self.close()) # Close the default connection self.session = web_session # And use the one we passed self.auth.screen_id = screen_id self.auth.lounge_id_token = None From d21bb6320f0c93940ebd4e3046b65e345216c4e8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 21:31:56 +0000 Subject: [PATCH 05/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- requirements.txt | 2 +- src/iSponsorBlockTV/config_setup.py | 36 +++++++++++++--------------- src/iSponsorBlockTV/setup_wizard.py | 4 +++- src/iSponsorBlockTV/ytlounge.py | 37 +++++++++++++++-------------- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/requirements.txt b/requirements.txt index a090787..e30c014 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ rich==13.7.1 ssdp==1.3.0 textual==0.58.0 textual-slider==0.1.1 -xmltodict==0.13.0 \ No newline at end of file +xmltodict==0.13.0 diff --git a/src/iSponsorBlockTV/config_setup.py b/src/iSponsorBlockTV/config_setup.py index 92a7dbb..3e3bb95 100644 --- a/src/iSponsorBlockTV/config_setup.py +++ b/src/iSponsorBlockTV/config_setup.py @@ -7,8 +7,9 @@ from . import api_helpers, ytlounge async def pair_device(web_session): try: - lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV", - web_session=web_session) + lounge_controller = ytlounge.YtLoungeApi( + "iSponsorBlockTV", web_session=web_session + ) pairing_code = input( "Enter pairing code (found in Settings - Link with TV code): " ) @@ -45,16 +46,15 @@ def main(config, debug: bool) -> None: " \nhttps://github.com/dmunozv04/iSponsorBlockTV/wiki/Migrate-from-V1-to-V2" ) if ( - input( - "Do you want to remove the legacy 'atvs' entry (the app won't start" - " with it present)? (y/n) " - ) - == "y" + input( + "Do you want to remove the legacy 'atvs' entry (the app won't start" + " with it present)? (y/n) " + ) + == "y" ): del config["atvs"] devices = config.devices - while not input( - f"Paired with {len(devices)} Device(s). Add more? (y/n) ") == "n": + while not input(f"Paired with {len(devices)} Device(s). Add more? (y/n) ") == "n": task = loop.create_task(pair_device(web_session)) loop.run_until_complete(task) device = task.result() @@ -68,10 +68,10 @@ def main(config, debug: bool) -> None: apikey = input("Enter your API key: ") else: if ( - input( - "API key only needed for the channel whitelist function. Add it? (y/n) " - ) - == "y" + input( + "API key only needed for the channel whitelist function. Add it? (y/n) " + ) + == "y" ): print( "Get youtube apikey here:" @@ -82,8 +82,7 @@ def main(config, debug: bool) -> None: skip_categories = config.skip_categories if skip_categories: - if input( - "Skip categories already specified. Change them? (y/n) ") == "y": + if input("Skip categories already specified. Change them? (y/n) ") == "y": categories = input( "Enter skip categories (space or comma sepparated) Options: [sponsor" " selfpromo exclusive_access interaction poi_highlight intro outro" @@ -107,9 +106,8 @@ def main(config, debug: bool) -> None: channel_whitelist = config.channel_whitelist if ( - input( - "Do you want to whitelist any channels from being ad-blocked? (y/n) ") - == "y" + input("Do you want to whitelist any channels from being ad-blocked? (y/n) ") + == "y" ): if not apikey: print( @@ -164,7 +162,7 @@ def main(config, debug: bool) -> None: "Do you want to report skipped segments to sponsorblock. Only the segment" " UUID will be sent? (y/n) " ) - == "n" + == "n" ) print("Config finished") config.save() diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index 4411686..da4d66f 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -336,7 +336,9 @@ class AddDevice(ModalWithClickExit): @on(Button.Pressed, "#add-device-pin-add-button") async def handle_add_device_pin(self) -> None: self.query_one("#add-device-pin-add-button").disabled = True - lounge_controller = ytlounge.YtLoungeApi("iSponsorBlockTV", web_session=self.web_session) + lounge_controller = ytlounge.YtLoungeApi( + "iSponsorBlockTV", web_session=self.web_session + ) pairing_code = self.query_one("#pairing-code-input").value pairing_code = int( pairing_code.replace("-", "").replace(" ", "") diff --git a/src/iSponsorBlockTV/ytlounge.py b/src/iSponsorBlockTV/ytlounge.py index 56c7490..625329f 100644 --- a/src/iSponsorBlockTV/ytlounge.py +++ b/src/iSponsorBlockTV/ytlounge.py @@ -1,8 +1,8 @@ -from aiohttp import ClientSession import asyncio import json import pyytlounge +from aiohttp import ClientSession from .constants import youtube_client_blacklist @@ -10,8 +10,14 @@ create_task = asyncio.create_task class YtLoungeApi(pyytlounge.YtLoungeApi): - def __init__(self, screen_id, config=None, api_helper=None, logger=None, - web_session: ClientSession = None): + def __init__( + self, + screen_id, + config=None, + api_helper=None, + logger=None, + web_session: ClientSession = None, + ): super().__init__("iSponsorBlockTV", logger=logger) if web_session is not None: self.session = web_session # And use the one we passed @@ -79,13 +85,13 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): self.logger.info("Ad has ended, unmuting") create_task(self.mute(False, override=True)) elif ( - self.skip_ads and data["isSkipEnabled"] == "true" + self.skip_ads and data["isSkipEnabled"] == "true" ): # YouTube uses strings for booleans self.logger.info("Ad can be skipped, skipping") create_task(self.skip_ad()) create_task(self.mute(False, override=True)) elif ( - self.mute_ads + self.mute_ads ): # Seen multiple other adStates, assuming they are all ads self.logger.info("Ad has started, muting") create_task(self.mute(True, override=True)) @@ -96,7 +102,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): # Gets segments for the next video before it starts playing elif event_type == "autoplayUpNext": if len(args) > 0 and ( - vid_id := args[0]["videoId"] + vid_id := args[0]["videoId"] ): # if video id is not empty self.logger.info(f"Getting segments for next video: {vid_id}") create_task(self.api_helper.get_segments(vid_id)) @@ -109,13 +115,13 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): self.logger.info(f"Getting segments for next video: {vid_id}") create_task(self.api_helper.get_segments(vid_id)) elif ( - self.skip_ads and data["isSkipEnabled"] == "true" + self.skip_ads and data["isSkipEnabled"] == "true" ): # YouTube uses strings for booleans self.logger.info("Ad can be skipped, skipping") create_task(self.skip_ad()) create_task(self.mute(False, override=True)) elif ( - self.mute_ads + self.mute_ads ): # Seen multiple other adStates, assuming they are all ads self.logger.info("Ad has started, muting") create_task(self.mute(True, override=True)) @@ -126,8 +132,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): for device in devices: if device["type"] == "LOUNGE_SCREEN": device_info = json.loads(device.get("deviceInfo", "{}")) - if device_info.get("clientName", - "") in youtube_client_blacklist: + if device_info.get("clientName", "") in youtube_client_blacklist: self._sid = None self._gsession = None # Force disconnect @@ -139,8 +144,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): create_task(self.play_video(video_id_saved)) elif event_type == "loungeScreenDisconnected": data = args[0] - if data[ - "reason"] == "disconnectedByUserScreenInitiated": # Short playing? + if data["reason"] == "disconnectedByUserScreenInitiated": # Short playing? self.shorts_disconnected = True super()._process_event(event_id, event_type, args) @@ -158,20 +162,17 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): mute_str = "true" else: mute_str = "false" - if override or not ( - self.volume_state.get("muted", "false") == mute_str): + if override or not (self.volume_state.get("muted", "false") == mute_str): self.volume_state["muted"] = mute_str # YouTube wants the volume when unmuting, so we send it await super()._command( "setVolume", - {"volume": self.volume_state.get("volume", 100), - "muted": mute_str}, + {"volume": self.volume_state.get("volume", 100), "muted": mute_str}, ) async def set_auto_play_mode(self, enabled: bool): await super()._command( - "setAutoplayMode", - {"autoplayMode": "ENABLED" if enabled else "DISABLED"} + "setAutoplayMode", {"autoplayMode": "ENABLED" if enabled else "DISABLED"} ) async def play_video(self, video_id: str) -> bool: From 1ab7e73b521acf3919816765031bb5ad85db97f3 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Wed, 29 May 2024 23:41:42 +0200 Subject: [PATCH 06/17] bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de6e83e..c497a20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "iSponsorBlockTV" -version = "2.0.6" +version = "2.0.7" authors = [ {"name" = "dmunozv04"} ] From fb3ed6b39a17bc3f2921af576990670a324508e6 Mon Sep 17 00:00:00 2001 From: Ravioli8235 Date: Thu, 30 May 2024 08:53:35 +0200 Subject: [PATCH 07/17] Implement autoplay --- config.json.template | 1 + src/iSponsorBlockTV/config_setup.py | 7 +++++++ src/iSponsorBlockTV/helpers.py | 1 + src/iSponsorBlockTV/setup_wizard.py | 31 +++++++++++++++++++++++++++++ src/iSponsorBlockTV/ytlounge.py | 4 ++++ 5 files changed, 44 insertions(+) diff --git a/config.json.template b/config.json.template index 59f2b9d..5e828f9 100644 --- a/config.json.template +++ b/config.json.template @@ -12,6 +12,7 @@ "skip_count_tracking": true, "mute_ads": true, "skip_ads": true, + "autoplay": true, "apikey": "", "channel_whitelist": [ {"id": "", diff --git a/src/iSponsorBlockTV/config_setup.py b/src/iSponsorBlockTV/config_setup.py index 51b0138..393d712 100644 --- a/src/iSponsorBlockTV/config_setup.py +++ b/src/iSponsorBlockTV/config_setup.py @@ -163,5 +163,12 @@ def main(config, debug: bool) -> None: ) == "n" ) + + config.auto_play = ( + not input( + "Do you want to enable autoplay? (y/n) " + ) + == "n" + ) print("Config finished") config.save() diff --git a/src/iSponsorBlockTV/helpers.py b/src/iSponsorBlockTV/helpers.py index 0627c29..3bce12c 100644 --- a/src/iSponsorBlockTV/helpers.py +++ b/src/iSponsorBlockTV/helpers.py @@ -41,6 +41,7 @@ class Config: self.skip_count_tracking = True self.mute_ads = False self.skip_ads = False + self.auto_play = True self.__load() def validate(self): diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index e692abe..e45a02e 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -848,6 +848,34 @@ class ChannelWhitelistManager(Vertical): self.app.push_screen(AddChannel(self.config), callback=self.new_channel) +class AutoPlayManager(Vertical): + """Manager for autoplay, allows enabling/disabling autoplay.""" + + def __init__(self, config, **kwargs) -> None: + super().__init__(**kwargs) + self.config = config + + def compose(self) -> ComposeResult: + yield Label("Autoplay", classes="title") + yield Label( + ( + "This feature allows you to enable/disable autoplay" + ), + classes="subtitle", + id="autoplay-subtitle", + ) + with Horizontal(id="autoplay-container"): + yield Checkbox( + value=self.config.auto_play, + id="autoplay-switch", + label="Enable autoplay", + ) + + @on(Checkbox.Changed, "#autoplay-switch") + def changed_skip(self, event: Checkbox.Changed): + self.config.auto_play = event.checkbox.value + + class ISponsorBlockTVSetupMainScreen(Screen): """Making this a separate screen to avoid a bug: https://github.com/Textualize/textual/issues/3221""" @@ -884,6 +912,9 @@ class ISponsorBlockTVSetupMainScreen(Screen): yield ApiKeyManager( config=self.config, id="api-key-manager", classes="container" ) + yield AutoPlayManager( + config=self.config, id="autoplay-manager", classes="container" + ) def on_mount(self) -> None: if self.check_for_old_config_entries(): diff --git a/src/iSponsorBlockTV/ytlounge.py b/src/iSponsorBlockTV/ytlounge.py index 18087f7..430021e 100644 --- a/src/iSponsorBlockTV/ytlounge.py +++ b/src/iSponsorBlockTV/ytlounge.py @@ -20,9 +20,11 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): self.callback = None self.logger = logger self.shorts_disconnected = False + self.auto_play = True if config: self.mute_ads = config.mute_ads self.skip_ads = config.skip_ads + self.auto_play = config.auto_play # Ensures that we still are subscribed to the lounge async def _watchdog(self): @@ -136,6 +138,8 @@ class YtLoungeApi(pyytlounge.YtLoungeApi): data = args[0] if data["reason"] == "disconnectedByUserScreenInitiated": # Short playing? self.shorts_disconnected = True + elif event_type == "onAutoplayModeChanged": + create_task(self.set_auto_play_mode(self.auto_play)) super()._process_event(event_id, event_type, args) From faa0379b8991ebc94b5908959637cf1151adcc29 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 07:03:27 +0000 Subject: [PATCH 08/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/iSponsorBlockTV/config_setup.py | 7 +------ src/iSponsorBlockTV/setup_wizard.py | 4 +--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/iSponsorBlockTV/config_setup.py b/src/iSponsorBlockTV/config_setup.py index 393d712..db5b30f 100644 --- a/src/iSponsorBlockTV/config_setup.py +++ b/src/iSponsorBlockTV/config_setup.py @@ -164,11 +164,6 @@ def main(config, debug: bool) -> None: == "n" ) - config.auto_play = ( - not input( - "Do you want to enable autoplay? (y/n) " - ) - == "n" - ) + config.auto_play = not input("Do you want to enable autoplay? (y/n) ") == "n" print("Config finished") config.save() diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index e45a02e..dcef224 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -858,9 +858,7 @@ class AutoPlayManager(Vertical): def compose(self) -> ComposeResult: yield Label("Autoplay", classes="title") yield Label( - ( - "This feature allows you to enable/disable autoplay" - ), + "This feature allows you to enable/disable autoplay", classes="subtitle", id="autoplay-subtitle", ) From adc0f5b95d9ed82e172aa3897311e369c3cee6ee Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Thu, 30 May 2024 12:26:55 +0200 Subject: [PATCH 09/17] enable building PR docker images --- .github/workflows/build_docker_images.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_docker_images.yml b/.github/workflows/build_docker_images.yml index ba8d1fc..62ffa26 100644 --- a/.github/workflows/build_docker_images.yml +++ b/.github/workflows/build_docker_images.yml @@ -49,14 +49,14 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - if: github.event_name != 'pull_request' + # if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR - if: github.event_name != 'pull_request' + # if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: registry: ghcr.io @@ -68,9 +68,10 @@ jobs: with: context: . platforms: linux/amd64, linux/arm64, linux/arm/v7 - push: ${{ github.event_name != 'pull_request' }} + # push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache # Only cache if it's not a pull request - cache-to: ${{ github.event_name != 'pull_request' && 'type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max' || '' }} + # cache-to: ${{ github.event_name != 'pull_request' && 'type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max' || '' }} + cache-to: type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max \ No newline at end of file From 5214190fd0cc8603759546a30e7d692d119e4c79 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Thu, 30 May 2024 12:35:59 +0200 Subject: [PATCH 10/17] revert last commit --- .github/workflows/build_docker_images.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_docker_images.yml b/.github/workflows/build_docker_images.yml index 62ffa26..ba8d1fc 100644 --- a/.github/workflows/build_docker_images.yml +++ b/.github/workflows/build_docker_images.yml @@ -49,14 +49,14 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - # if: github.event_name != 'pull_request' + if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR - # if: github.event_name != 'pull_request' + if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: registry: ghcr.io @@ -68,10 +68,9 @@ jobs: with: context: . platforms: linux/amd64, linux/arm64, linux/arm/v7 - # push: ${{ github.event_name != 'pull_request' }} + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache # Only cache if it's not a pull request - # cache-to: ${{ github.event_name != 'pull_request' && 'type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max' || '' }} - cache-to: type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max \ No newline at end of file + cache-to: ${{ github.event_name != 'pull_request' && 'type=registry,ref=ghcr.io/dmunozv04/isponsorblocktv:buildcache,mode=max' || '' }} From e92ba897c4b50b910cb9da892e2d3ad9ddb58600 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Fri, 31 May 2024 15:26:58 +0200 Subject: [PATCH 11/17] Refresh auth after every disconnect, ensuring there's a fresh token. Fixes Shorts aren't handled anymore #162 and maybe changes something related to Disable Autoplay #82 --- src/iSponsorBlockTV/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/iSponsorBlockTV/main.py b/src/iSponsorBlockTV/main.py index b624d00..bb8f1a2 100644 --- a/src/iSponsorBlockTV/main.py +++ b/src/iSponsorBlockTV/main.py @@ -52,13 +52,13 @@ class DeviceListener: # Main subscription loop async def loop(self): lounge_controller = self.lounge_controller - while not lounge_controller.linked(): - try: - self.logger.debug("Refreshing auth") - await lounge_controller.refresh_auth() - except: - await asyncio.sleep(10) while not self.cancelled: + while not lounge_controller.linked(): + try: + self.logger.debug("Refreshing auth") + await lounge_controller.refresh_auth() + except: + await asyncio.sleep(10) while not (await self.is_available()) and not self.cancelled: await asyncio.sleep(10) try: From 6e09db9994652e2a677f1ed4c55eebe59034e490 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Fri, 31 May 2024 15:35:16 +0200 Subject: [PATCH 12/17] bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c497a20..cd9e702 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "iSponsorBlockTV" -version = "2.0.7" +version = "2.0.8" authors = [ {"name" = "dmunozv04"} ] From 94ba642af1abefa8c7a172cbc891d1cda9bad53f Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:27:42 +0200 Subject: [PATCH 13/17] update actions versions to latest --- .github/workflows/build_docker_images.yml | 14 +++++++------- .github/workflows/release_pypi.yml | 4 ++-- .github/workflows/update_docker_readme.yml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_docker_images.yml b/.github/workflows/build_docker_images.yml index ba8d1fc..8bbb573 100644 --- a/.github/workflows/build_docker_images.yml +++ b/.github/workflows/build_docker_images.yml @@ -25,12 +25,12 @@ jobs: steps: # Get the repository's code - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Generate docker tags - name: Docker meta id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ghcr.io/dmunozv04/isponsorblocktv, dmunozv04/isponsorblocktv tags: | @@ -42,29 +42,29 @@ jobs: # https://github.com/docker/setup-qemu-action - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/setup-buildx-action - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64, linux/arm64, linux/arm/v7 diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml index 43c9298..180d5b9 100644 --- a/.github/workflows/release_pypi.yml +++ b/.github/workflows/release_pypi.yml @@ -22,9 +22,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install dependencies diff --git a/.github/workflows/update_docker_readme.yml b/.github/workflows/update_docker_readme.yml index ccf6c37..12a3e62 100644 --- a/.github/workflows/update_docker_readme.yml +++ b/.github/workflows/update_docker_readme.yml @@ -22,7 +22,7 @@ jobs: # Update description - name: Update repo description - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From dc72db06094a217deff392c92a5ce17f3e0ae092 Mon Sep 17 00:00:00 2001 From: Raymond Ha Date: Wed, 5 Jun 2024 16:05:07 -0700 Subject: [PATCH 14/17] Fix deps permissions in docker build --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5947838..e2067f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,12 +16,12 @@ COPY requirements.txt . RUN apk add --no-cache gcc musl-dev && \ pip install --upgrade pip wheel && \ - pip install --user -r requirements.txt && \ + pip install -r requirements.txt && \ pip uninstall -y pip wheel && \ apk del gcc musl-dev && \ - python3 -m compileall -b -f /root/.local/lib/python3.11/site-packages && \ - find /root/.local/lib/python3.11/site-packages -name "*.py" -type f -delete && \ - find /root/.local/lib/python3.11/ -name "__pycache__" -type d -exec rm -rf {} + + python3 -m compileall -b -f /usr/local/lib/python3.11/site-packages && \ + find /usr/local/lib/python3.11/site-packages -name "*.py" -type f -delete && \ + find /usr/local/lib/python3.11/ -name "__pycache__" -type d -exec rm -rf {} + FROM base @@ -29,7 +29,7 @@ ENV PIP_NO_CACHE_DIR=off iSPBTV_docker=True iSPBTV_data_dir=data TERM=xterm-256c COPY requirements.txt . -COPY --from=dep_installer /root/.local /root/.local +COPY --from=dep_installer /usr/local /usr/local WORKDIR /app From bfefa94a7bf18f1e1e71ff4026052fac9e985e1a Mon Sep 17 00:00:00 2001 From: Ravioli8235 Date: Fri, 21 Jun 2024 15:58:15 +0200 Subject: [PATCH 15/17] fix panel fill --- src/iSponsorBlockTV/setup_wizard.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index e45a02e..ede8bee 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -864,12 +864,11 @@ class AutoPlayManager(Vertical): classes="subtitle", id="autoplay-subtitle", ) - with Horizontal(id="autoplay-container"): - yield Checkbox( - value=self.config.auto_play, - id="autoplay-switch", - label="Enable autoplay", - ) + yield Checkbox( + value=self.config.auto_play, + id="autoplay-switch", + label="Enable autoplay", + ) @on(Checkbox.Changed, "#autoplay-switch") def changed_skip(self, event: Checkbox.Changed): From cfef219d3243c5d1e8094f52574e1470b524ff04 Mon Sep 17 00:00:00 2001 From: dmunozv04 <39565245+dmunozv04@users.noreply.github.com> Date: Fri, 21 Jun 2024 16:29:17 +0200 Subject: [PATCH 16/17] fix autoplay padding --- src/iSponsorBlockTV/setup-wizard-style.tcss | 6 ++++++ src/iSponsorBlockTV/setup_wizard.py | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/iSponsorBlockTV/setup-wizard-style.tcss b/src/iSponsorBlockTV/setup-wizard-style.tcss index e6dd886..e10f091 100644 --- a/src/iSponsorBlockTV/setup-wizard-style.tcss +++ b/src/iSponsorBlockTV/setup-wizard-style.tcss @@ -363,3 +363,9 @@ MigrationScreen { width: 1fr; content-align: center middle; } + +/* Autoplay */ +#autoplay-container{ + padding: 1; + height: auto; +} \ No newline at end of file diff --git a/src/iSponsorBlockTV/setup_wizard.py b/src/iSponsorBlockTV/setup_wizard.py index 083d062..669c581 100644 --- a/src/iSponsorBlockTV/setup_wizard.py +++ b/src/iSponsorBlockTV/setup_wizard.py @@ -864,11 +864,12 @@ class AutoPlayManager(Vertical): classes="subtitle", id="autoplay-subtitle", ) - yield Checkbox( - value=self.config.auto_play, - id="autoplay-switch", - label="Enable autoplay", - ) + with Horizontal(id="autoplay-container"): + yield Checkbox( + value=self.config.auto_play, + id="autoplay-switch", + label="Enable autoplay", + ) @on(Checkbox.Changed, "#autoplay-switch") def changed_skip(self, event: Checkbox.Changed): From b1333a2f6186648984ca6b9f7f0a1c620f6285f7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:29:34 +0000 Subject: [PATCH 17/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/iSponsorBlockTV/setup-wizard-style.tcss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iSponsorBlockTV/setup-wizard-style.tcss b/src/iSponsorBlockTV/setup-wizard-style.tcss index e10f091..4f6d25e 100644 --- a/src/iSponsorBlockTV/setup-wizard-style.tcss +++ b/src/iSponsorBlockTV/setup-wizard-style.tcss @@ -368,4 +368,4 @@ MigrationScreen { #autoplay-container{ padding: 1; height: auto; -} \ No newline at end of file +}