diff --git a/Dockerfile b/Dockerfile index 3f362c9..acd4cff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,6 @@ COPY requirements.txt . WORKDIR /app -COPY main.py . +COPY *.py . ENTRYPOINT ["/opt/venv/bin/python3", "-u", "main.py"] diff --git a/README.md b/README.md index e6ddcc7..5f8ce65 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,18 @@ Skip sponsor segments in YouTube videos playing on an Apple TV. This project is written in asycronous python and should be pretty quick. -## Installation +# Installation -### Docker -## Setup +## Docker +### Setup -You need to retrieve airplay keys to be able to connect to the Apple TV. (It will be made simpler in the future) -For now, use `atvremote`, a script included in pyatv: -1. ```docker run --rm -it --network=host --entrypoint /bin/bash ghcr.io/dmunozv04/isponsorblocktv``` -2. atvremote scan -3. atvremote pair --protocol airplay --id `identifier you got on the previous step` -4. ```exit``` the container - -Get [YouTube api key](https://developers.google.com/youtube/registering_an_application) - -Edit config.json.template and save it as config.json (this is the /PATH_TO_YOUR_CONFIG.json file) +You need to set up several things before you can run the project. +1. Create blank config file: ```touch config.json``` +2. ```docker run --rm -it \ +--network=host \ +--entrypoint /opt/venv/bin/python3 /app/create_config.py \ +-v /PATH_TO_YOUR_CONFIG.json:/app/config.json \ +ghcr.io/dmunozv04/isponsorblocktv``` ## Run ```sh docker pull ghcr.io/dmunozv04/isponsorblocktv @@ -29,14 +26,14 @@ docker run -d \ -v /PATH_TO_YOUR_CONFIG.json:/app/config.json \ ghcr.io/dmunozv04/isponsorblocktv ``` -### From source +## From source You need to install [python](https://www.python.org/downloads/) first, and to make it available in your PATH. After, clone the repo. Then you need to download the dependencies with pip: ```python3 -m pip install -r requirements.txt``` Lastly, run ```main.py``` -## Setup +### Setup You need to retrieve airplay keys to be able to connect to the Apple TV. (It will be made simpler in the future) For now, use `atvremote`, a script included in pyatv: @@ -46,7 +43,7 @@ For now, use `atvremote`, a script included in pyatv: Get [YouTube api key](https://developers.google.com/youtube/registering_an_application) Edit config.json.template and save it as config.json -## Usage +# Usage Run iSponsorBLockTV in the same network as the Apple TV. @@ -54,15 +51,14 @@ It connect to the Apple TV, watch its activity and skip any sponsor segment usin The last 5 videos' segments are cached to limit the number on queries on SponsorBlock and YouTube. -To exit press ENTER -## Libraries used +# Libraries used - [pyatv](https://github.com/postlund/pyatv) Used to connect to the Apple TV - [asyncio] and [aiohttp] - [async_lru] - [json] -## Contributing +# Contributing 1. Fork it () 2. Create your feature branch (`git checkout -b my-new-feature`) @@ -74,5 +70,5 @@ To exit press ENTER - [dmunozv04](https://github.com/dmunozv04) - creator and maintainer - [HaltCatchFire](https://github.com/HaltCatchFire) - updated dependencies and improved skip logic -## License +# License [![GNU GPLv3](https://www.gnu.org/graphics/gplv3-127x51.png)](https://www.gnu.org/licenses/gpl-3.0.en.html) diff --git a/create_config.py b/create_config.py new file mode 100644 index 0000000..26738df --- /dev/null +++ b/create_config.py @@ -0,0 +1,105 @@ +import pyatv +import json +import asyncio +from pyatv.const import DeviceModel +from pyatv.scripts import TransformProtocol +import sys + +def load_config(config_file="config.json"): + try: + with open(config_file) as f: + config = json.load(f) + except: + config = {} + return config + +def save_config(config, config_file="config.json"): + with open(config_file, "w") as f: + json.dump(config, f) + +#Taken from postlund/pyatv atvremote.py +async def _read_input(loop: asyncio.AbstractEventLoop, prompt: str): + sys.stdout.write(prompt) + sys.stdout.flush() + user_input = await loop.run_in_executor(None, sys.stdin.readline) + return user_input.strip() + +async def find_atvs(loop): + devices = await pyatv.scan(loop) + if not devices: + print("No devices found") + return + atvs = [] + for i in devices: + #Only get Apple TV's + if i.device_info.model in [DeviceModel.Gen4, DeviceModel.Gen4K, DeviceModel.AppleTV4KGen2]: + #if i.device_info.model in [DeviceModel.AppleTV4KGen2]: #FOR TESTING + if input("Found {}. Do you want to add it? (y/n) ".format(i.name)) == "y": + + identifier = i.identifier + + pairing = await pyatv.pair(i, loop=loop, protocol=pyatv.Protocol.AirPlay) + await pairing.begin() + if pairing.device_provides_pin: + pin = await _read_input(loop, "Enter PIN on screen: ") + pairing.pin(pin) + await pairing.finish() + creds = pairing.service.credentials + atvs.append({"identifier": identifier, "airplay_credentials": creds}) + print("Pairing successful") + await pairing.close() + return atvs + + + + +def main(): + config = load_config() + try: num_atvs = len(config["atvs"]) + except: num_atvs = 0 + if input("Found {} Apple TV(s) in config.json. Add more? (y/n) ".format(num_atvs)) == "y": + loop = asyncio.get_event_loop_policy().get_event_loop() + asyncio.set_event_loop(loop) + task = loop.create_task(find_atvs(loop)) + loop.run_until_complete(task) + atvs = task.result() + try: + for i in atvs: + config["atvs"].append(i) + print("done adding") + except: + print("rewriting atvs (don't worry if none were saved before)") + config["atvs"] = atvs + + try : apikey = config["apikey"] + except: + apikey = "" + if apikey != "" : + if input("Apikey already specified. Change it? (y/n) ") == "y": + apikey = input("Enter your API key: ") + config["apikey"] = apikey + else: + print("get youtube apikey here: https://developers.google.com/youtube/registering_an_application") + apikey = input("Enter your API key: ") + config["apikey"] = apikey + + try: skip_categories = config["skip_categories"] + except: + skip_categories = [] + + if skip_categories != []: + if input("Skip categories already specified. Change them? (y/n) ") == "y": + categories = input("Enter skip categories (space sepparated) Options: [sponsor, selfpromo, exclusive_access, interaction, poi_highlight, intro, outro, preview, filler, music_offtopic:\n") + skip_categories = categories.split(" ") + else: + categories = input("Enter skip categories (space sepparated) Options: [sponsor, selfpromo, exclusive_access, interaction, poi_highlight, intro, outro, preview, filler, music_offtopic:\n") + skip_categories = categories.split(" ") + config["skip_categories"] = skip_categories + print("config finished") + save_config(config) + + + +if __name__ == "__main__": + print("starting") + main()