Merge remote-tracking branch 'origin' into pr/ryankupk/150

This commit is contained in:
dmunozv04
2024-06-21 17:01:45 +02:00
13 changed files with 95 additions and 36 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -12,6 +12,7 @@
"skip_count_tracking": true,
"mute_ads": true,
"skip_ads": true,
"autoplay": true,
"apikey": "",
"channel_whitelist": [
{"id": "",

View File

@@ -1,6 +1,6 @@
[project]
name = "iSponsorBlockTV"
version = "2.0.6"
version = "2.0.8"
authors = [
{"name" = "dmunozv04"}
]

View File

@@ -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

View File

@@ -35,7 +35,7 @@ REPORT_SKIPPED_SEGMENTS_PROMPT = (
)
MUTE_ADS_PROMPT = "Do you want to mute native YouTube ads automatically? (y/n) "
SKIP_ADS_PROMPT = "Do you want to skip native YouTube ads automatically? (y/n) "
AUTOPLAY_PROMPT = "Do you want to enable autoplay? (y/n) "
def get_yn_input(prompt):
while choice := input(prompt):
@@ -70,6 +70,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)
@@ -135,7 +136,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 = {}
@@ -174,7 +174,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
@@ -187,5 +186,9 @@ def main(config, debug: bool) -> None:
choice = get_yn_input(SKIP_ADS_PROMPT)
config.skip_ads = choice == "y"
choice = get_yn_input(AUTOPLAY_PROMPT)
config.auto_play = choice == "y"
print("Config finished")
config.save()
loop.run_until_complete(web_session.close())

View File

@@ -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):

View File

@@ -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
@@ -51,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:
@@ -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()

View File

@@ -363,3 +363,9 @@ MigrationScreen {
width: 1fr;
content-align: center middle;
}
/* Autoplay */
#autoplay-container{
padding: 1;
height: auto;
}

View File

@@ -234,8 +234,8 @@ class AddDevice(ModalWithClickExit):
def __init__(self, config, **kwargs) -> None:
super().__init__(**kwargs)
self.config = config
web_session = aiohttp.ClientSession()
self.api_helper = api_helpers.ApiHelper(config, web_session)
self.web_session = aiohttp.ClientSession()
self.api_helper = api_helpers.ApiHelper(config, self.web_session)
self.devices_discovered_dial = []
def compose(self) -> ComposeResult:
@@ -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")
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(" ", "")
@@ -848,6 +850,32 @@ 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():

View File

@@ -2,6 +2,7 @@ import asyncio
import json
import pyytlounge
from aiohttp import ClientSession
from .constants import youtube_client_blacklist
@@ -9,8 +10,17 @@ 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:
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
@@ -20,9 +30,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 +148,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)