Final v2 commit before launch?

Adds better logging and modifies README.md
This commit is contained in:
dmunozv04
2023-10-13 17:46:25 +02:00
parent aad6eea686
commit 143e5e4eff
6 changed files with 51 additions and 29 deletions

View File

@@ -31,9 +31,9 @@ jobs:
uses: docker/metadata-action@v4 uses: docker/metadata-action@v4
with: with:
images: ghcr.io/dmunozv04/isponsorblocktv, dmunozv04/isponsorblocktv images: ghcr.io/dmunozv04/isponsorblocktv, dmunozv04/isponsorblocktv
# tags: | tags: |
# type=raw,value=latest,priority=900,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} type=raw,value=develop,priority=900,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
# type=ref,enable=true,priority=600,prefix=pr-,suffix=,event=pr type=ref,enable=true,priority=600,prefix=pr-,suffix=,event=pr
# https://github.com/docker/setup-qemu-action # https://github.com/docker/setup-qemu-action
- name: Set up QEMU - name: Set up QEMU

2
.gitignore vendored
View File

@@ -155,7 +155,7 @@ cython_debug/
#config folder #config folder
data/ data/
config.json data/config.json
.DS_Store .DS_Store

View File

@@ -1,33 +1,49 @@
# iSponsorBlockTV # iSponsorBlockTV
Skip sponsor segments in YouTube videos playing on a YouTube TV device (see below for compatibility details).
Skip sponsor segments in YouTube videos playing on an Apple TV. Sponsor Block in YouTube for apple TV This project is written in asynchronous python and should be pretty quick.
This project is written in asycronous python and should be pretty quick. ## Installation
# Installation
Check the [wiki](https://github.com/dmunozv04/iSponsorBlockTV/wiki/Installation) Check the [wiki](https://github.com/dmunozv04/iSponsorBlockTV/wiki/Installation)
Warning: armv7 builds have been deprecated. Warning: docker armv7 builds have been deprecated. Amd64 and arm64 builds are still available.
# Usage ## Compatibility
Leyend: ✅ = Working, ❌ = Not working, ❔ = Not tested
Run iSponsorBLockTV on the same network as the Apple TV. Open an issue/pull request if you have tested a device that isn't listed here.
It connects to the Apple TV, watches its activity and skips any sponsor segment using the [SponsorBlock](https://sponsor.ajay.app/) API. | Device | Status |
|:-------------------|:------:|
| Apple TV | ✅ |
| Samsung TV (Tizen) | ✅ |
| LG TV (WebOS) | ✅ |
| Android TV | ❔ |
| Chromecast | ❔ |
| Roku | ❔ |
| Fire TV | ❔ |
| Nintendo Switch | ✅ |
| Xbox One/Series | ❔ |
| Playstation 4/5 | ❔ |
The last 5 videos' segments are cached to limit the number on queries on SponsorBlock and YouTube. ## Usage
Run iSponsorBlockTV on a computer that has network access.
Auto discovery will require the computer to be on the same network as the device during setup.
It connects to the device, watches its activity and skips any sponsor segment using the [SponsorBlock](https://sponsor.ajay.app/) API.
It can also skip/mute YouTube ads.
# Libraries used ## Libraries used
- [pyatv](https://github.com/postlund/pyatv) Used to connect to the Apple TV - [pyytlounge](https://github.com/FabioGNR/pyytlounge) Used to interact with the device
- asyncio and [aiohttp](https://github.com/aio-libs/aiohttp) - asyncio and [aiohttp](https://github.com/aio-libs/aiohttp)
- [async-cache](https://github.com/iamsinghrajat/async-cache) - [async-cache](https://github.com/iamsinghrajat/async-cache)
- [Textual](https://github.com/textualize/textual/) Used for the amazing new graphical configurator
- [ssdp](https://github.com/codingjoe/ssdp) Used for auto discovery
# Projects using this proect ## Projects using this project
- [Home Assistant Addon](https://github.com/bertybuttface/addons/tree/main/isponsorblocktv) - [Home Assistant Addon](https://github.com/bertybuttface/addons/tree/main/isponsorblocktv)
# Contributing ## Contributing
1. Fork it (<https://github.com/dmunozv04/iSponsorBlockTV/fork>) 1. Fork it (<https://github.com/dmunozv04/iSponsorBlockTV/fork>)
2. Create your feature branch (`git checkout -b my-new-feature`) 2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`) 3. Commit your changes (`git commit -am 'Add some feature'`)
@@ -35,9 +51,8 @@ The last 5 videos' segments are cached to limit the number on queries on Sponsor
5. Create a new Pull Request 5. Create a new Pull Request
## Contributors ## Contributors
- [dmunozv04](https://github.com/dmunozv04) - creator and maintainer - [dmunozv04](https://github.com/dmunozv04) - creator and maintainer
- [HaltCatchFire](https://github.com/HaltCatchFire) - updated dependencies and improved skip logic - [HaltCatchFire](https://github.com/HaltCatchFire) - updated dependencies and improved skip logic
- [Oxixes](https://github.com/oxixes) - added support for channel whitelist and minor improvements - [Oxixes](https://github.com/oxixes) - added support for channel whitelist and minor improvements
# License ## License
[![GNU GPLv3](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl-3.0.en.html) [![GNU GPLv3](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl-3.0.en.html)

View File

@@ -8,6 +8,7 @@ import traceback
class DeviceListener: class DeviceListener:
def __init__(self, api_helper, config, screen_id, offset): def __init__(self, api_helper, config, screen_id, offset):
self.task: asyncio.Task = None
self.api_helper = api_helper self.api_helper = api_helper
self.lounge_controller = ytlounge.YtLoungeApi(screen_id, config, api_helper) self.lounge_controller = ytlounge.YtLoungeApi(screen_id, config, api_helper)
self.offset = offset self.offset = offset
@@ -53,12 +54,12 @@ class DeviceListener:
await lounge_controller.connect() await lounge_controller.connect()
except: except:
pass pass
# print(f"Connected to device {lounge_controller.screen_name}") print(f"Connected to device {lounge_controller.screen_name}")
try: try:
print("Subscribing to lounge") #print("Subscribing to lounge")
sub = await lounge_controller.subscribe_monitored(self) sub = await lounge_controller.subscribe_monitored(self)
await sub await sub
print("Subscription ended") #print("Subscription ended")
except: except:
pass pass
@@ -77,8 +78,9 @@ class DeviceListener:
segments = [] segments = []
if state.videoId: if state.videoId:
segments = await self.api_helper.get_segments(state.videoId) segments = await self.api_helper.get_segments(state.videoId)
print(segments) if state.state.value == 1: # Playing
if state.state.value == 1 and segments: # Playing and has segments to skip print(f"Playing {state.videoId} with {len(segments)} segments")
if segments: # If there are segments
await self.time_to_segment(segments, state.currentTime, time_start) await self.time_to_segment(segments, state.currentTime, time_start)
# Finds the next segment to skip to and skips to it # Finds the next segment to skip to and skips to it
@@ -108,13 +110,14 @@ class DeviceListener:
self.api_helper.mark_viewed_segments(UUID) self.api_helper.mark_viewed_segments(UUID)
) # Don't wait for this to finish ) # Don't wait for this to finish
# Stops the connection to the device # Stops the connection to the device
async def cancel(self): async def cancel(self):
self.cancelled = True self.cancelled = True
try: try:
self.task.cancel() self.task.cancel()
except Exception as e: except Exception as e:
traceback.print_exc() pass
async def finish(devices): async def finish(devices):
@@ -141,7 +144,6 @@ def main(config, debug):
loop.run_forever() loop.run_forever()
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
print("Keyboard interrupt detected, cancelling tasks and exiting...") print("Keyboard interrupt detected, cancelling tasks and exiting...")
traceback.print_exc()
loop.run_until_complete(finish(devices)) loop.run_until_complete(finish(devices))
finally: finally:
loop.run_until_complete(web_session.close()) loop.run_until_complete(web_session.close())

View File

@@ -63,12 +63,15 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
self._update_state() self._update_state()
# Unmute when the video starts playing # Unmute when the video starts playing
if self.mute_ads and data.get("state", "0") == "1": if self.mute_ads and data.get("state", "0") == "1":
#print("Ad has ended, unmuting")
create_task(self.mute(False, override=True)) create_task(self.mute(False, override=True))
elif self.mute_ads and event_type == "onAdStateChange": elif self.mute_ads and event_type == "onAdStateChange":
data = args[0] data = args[0]
if data["adState"] == '0': # Ad is not playing if data["adState"] == '0': # Ad is not playing
#print("Ad has ended, unmuting")
create_task(self.mute(False, override=True)) create_task(self.mute(False, override=True))
else: # Seen multiple other adStates, assuming they are all ads else: # Seen multiple other adStates, assuming they are all ads
print("Ad has started, muting")
create_task(self.mute(True, override=True)) create_task(self.mute(True, override=True))
# Manages volume, useful since YouTube wants to know the volume when unmuting (even if they already have it) # Manages volume, useful since YouTube wants to know the volume when unmuting (even if they already have it)
elif event_type == "onVolumeChanged": elif event_type == "onVolumeChanged":
@@ -77,6 +80,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
# Gets segments for the next video before it starts playing # Gets segments for the next video before it starts playing
elif event_type == "autoplayUpNext": elif event_type == "autoplayUpNext":
if len(args) > 0 and (vid_id := args[0]["videoId"]): # if video id is not empty if len(args) > 0 and (vid_id := args[0]["videoId"]): # if video id is not empty
print(f"Getting segments for next video: {vid_id}")
create_task(self.api_helper.get_segments(vid_id)) create_task(self.api_helper.get_segments(vid_id))
# #Used to know if an ad is skippable or not # #Used to know if an ad is skippable or not
@@ -84,6 +88,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
data = args[0] data = args[0]
# Gets segments for the next video (after the ad) before it starts playing # Gets segments for the next video (after the ad) before it starts playing
if vid_id := data["contentVideoId"]: if vid_id := data["contentVideoId"]:
print(f"Getting segments for next video: {vid_id}")
create_task(self.api_helper.get_segments(vid_id)) create_task(self.api_helper.get_segments(vid_id))
if data["isSkippable"] == "true": # YouTube uses strings for booleans if data["isSkippable"] == "true": # YouTube uses strings for booleans

View File

@@ -1,5 +1,5 @@
from iSponsorBlockTV import setup_wizard from iSponsorBlockTV import setup_wizard
from iSponsorBlockTV.helpers import Config from iSponsorBlockTV.helpers import Config
config = Config("config.json") config = Config("data/config.json")
setup_wizard.main(config) setup_wizard.main(config)