mirror of
https://github.com/dmunozv04/iSponsorBlockTV.git
synced 2025-12-06 11:56:45 +03:00
Finish refactoring
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,7 +30,6 @@ MANIFEST
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
0
iSponsorBlockTV/__init__.py
Normal file
0
iSponsorBlockTV/__init__.py
Normal file
100
iSponsorBlockTV/config_setup.py
Normal file
100
iSponsorBlockTV/config_setup.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import pyatv
|
||||
import json
|
||||
import asyncio
|
||||
from pyatv.const import DeviceModel
|
||||
import sys
|
||||
|
||||
|
||||
def save_config(config, config_file):
|
||||
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()
|
||||
if pairing.has_paired:
|
||||
creds = pairing.service.credentials
|
||||
atvs.append({"identifier": identifier, "airplay_credentials": creds})
|
||||
print("Pairing successful")
|
||||
await pairing.close()
|
||||
return atvs
|
||||
|
||||
|
||||
|
||||
|
||||
def main(config, config_file, debug):
|
||||
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()
|
||||
if debug:
|
||||
loop.set_debug(True)
|
||||
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, config_file)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("starting")
|
||||
main()
|
||||
46
iSponsorBlockTV/helpers.py
Normal file
46
iSponsorBlockTV/helpers.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import argparse
|
||||
from . import config_setup
|
||||
from . import main
|
||||
from . import macos_install
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
|
||||
def load_config(config_file):
|
||||
try:
|
||||
with open(config_file) as f:
|
||||
config = json.load(f)
|
||||
except:
|
||||
if os.getenv('iSPBTV_docker'):
|
||||
print("You are running in docker, you have to mount the config file.\nPlease check the README.md for more information.")
|
||||
else:
|
||||
config = {} #Create blank config to setup
|
||||
return config
|
||||
|
||||
|
||||
def app_start():
|
||||
parser = argparse.ArgumentParser(description='iSponsorblockTV')
|
||||
parser.add_argument('--file', '-f', default='config.json', help='config file')
|
||||
parser.add_argument('--setup', '-s', action='store_true', help='setup the program')
|
||||
parser.add_argument('--debug', '-d', action='store_true', help='debug mode')
|
||||
parser.add_argument('--macos_install', action='store_true', help='install in macOS')
|
||||
args = parser.parse_args()
|
||||
|
||||
config = load_config(args.file)
|
||||
if args.debug:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
if args.setup: #Setup the config file
|
||||
config_setup.main(config, args.file, args.debug)
|
||||
if args.macos_install:
|
||||
macos_install.main()
|
||||
|
||||
else:
|
||||
try: #Check if config file has the correct structure
|
||||
config["atvs"], config["apikey"], config["skip_categories"]
|
||||
except: #If not, ask to setup the program
|
||||
print("invalid config file, please run with --setup")
|
||||
os.exit()
|
||||
main.main(config["atvs"], config["apikey"], config["skip_categories"], args.debug)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app_start()
|
||||
46
iSponsorBlockTV/macos_install.py
Normal file
46
iSponsorBlockTV/macos_install.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import plistlib
|
||||
import os
|
||||
from . import helpers, config_setup
|
||||
|
||||
default_plist = {"Label": "com.dmunozv04iSponsorBlockTV",
|
||||
"RunAtLoad": True,
|
||||
"StartInterval": 20,
|
||||
"EnvironmentVariables": {"PYTHONUNBUFFERED": "YES"},
|
||||
"StandardErrorPath": "", #Fill later
|
||||
"StandardOutPath": "",
|
||||
"ProgramArguments" : "",
|
||||
"WorkingDirectory": ""
|
||||
}
|
||||
def create_plist(path):
|
||||
plist = default_plist
|
||||
plist["ProgramArguments"] = [path + "/iSponsorBlockTV"]
|
||||
plist["StandardErrorPath"] = path + "/iSponsorBlockTV.error.log"
|
||||
plist["StandardOutPath"] = path + "/iSponsorBlockTV.out.log"
|
||||
plist["WorkingDirectory"] = path
|
||||
launchd_path = os.path.expanduser("~/Library/LaunchAgents/")
|
||||
path_to_save = launchd_path + "com.dmunozv04.iSponsorBlockTV.plist"
|
||||
|
||||
with open(path_to_save, 'wb') as fp:
|
||||
plistlib.dump(plist, fp)
|
||||
|
||||
def run_setup(file):
|
||||
config = {}
|
||||
config_setup.main(config, file, debug=False)
|
||||
|
||||
def main():
|
||||
correct_path = os.path.expanduser("~/iSponsorBlockTV")
|
||||
if os.path.isfile(correct_path + "/iSponsorBlockTV"):
|
||||
print("Program is on the right path")
|
||||
print("The launch daemon will now be installed")
|
||||
create_plist(correct_path)
|
||||
run_setup(correct_path + "/config.json")
|
||||
print("Launch daemon installed. Please restart the computer to enable it or use:\n launchctl load ~/Library/LaunchAgents/com.dmunozv04.iSponsorBlockTV.plist")
|
||||
else:
|
||||
if not os.path.exists(correct_path):
|
||||
os.makedirs(correct_path)
|
||||
print("Please move the program to the correct path: " + correct_path + "opeing now on finder...")
|
||||
os.system("open -R " + correct_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
172
iSponsorBlockTV/main.py
Normal file
172
iSponsorBlockTV/main.py
Normal file
@@ -0,0 +1,172 @@
|
||||
import asyncio
|
||||
import pyatv
|
||||
import aiohttp
|
||||
from cache import AsyncTTL
|
||||
import time
|
||||
import logging
|
||||
|
||||
def listToTuple(function):
|
||||
def wrapper(*args):
|
||||
args = [tuple(x) if type(x) == list else x for x in args]
|
||||
result = function(*args)
|
||||
result = tuple(result) if type(result) == list else result
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
class MyPushListener(pyatv.interface.PushListener):
|
||||
task = None
|
||||
apikey = None
|
||||
rc = None
|
||||
|
||||
web_session = None
|
||||
categories = ["sponsor"]
|
||||
|
||||
def __init__(self, apikey, atv, categories, web_session):
|
||||
self.apikey = apikey
|
||||
self.rc = atv.remote_control
|
||||
self.web_session = web_session
|
||||
self.categories = categories
|
||||
self.atv = atv
|
||||
|
||||
|
||||
def playstatus_update(self, updater, playstatus):
|
||||
logging.debug("Playstatus update" + str(playstatus))
|
||||
try:
|
||||
self.task.cancel()
|
||||
except:
|
||||
pass
|
||||
time_start = time.time()
|
||||
self.task = asyncio.create_task(process_playstatus(playstatus, self.apikey, self.rc, self.web_session, self.categories, self.atv, time_start))
|
||||
def playstatus_error(self, updater, exception):
|
||||
logging.error(exception)
|
||||
print("stopped")
|
||||
|
||||
|
||||
|
||||
async def process_playstatus(playstatus, apikey, rc, web_session, categories, atv, time_start):
|
||||
logging.debug("App playing is:" + str(atv.metadata.app.identifier))
|
||||
if playstatus.device_state == playstatus.device_state.Playing and atv.metadata.app.identifier == "com.google.ios.youtube":
|
||||
vid_id = await get_vid_id(playstatus.title, playstatus.artist, apikey, web_session)
|
||||
print(vid_id)
|
||||
segments, duration = await get_segments(vid_id, web_session, categories)
|
||||
print(segments)
|
||||
await time_to_segment(segments, playstatus.position, rc, time_start)
|
||||
|
||||
|
||||
@AsyncTTL(time_to_live=300, maxsize=5)
|
||||
async def get_vid_id(title, artist, api_key, web_session):
|
||||
url = f"https://youtube.googleapis.com/youtube/v3/search?q={title} - {artist}&key={api_key}&maxResults=1"
|
||||
async with web_session.get(url) as response:
|
||||
response = await response.json()
|
||||
vid_id = response["items"][0]["id"]["videoId"]
|
||||
return vid_id
|
||||
|
||||
@listToTuple
|
||||
@AsyncTTL(time_to_live=300, maxsize=5)
|
||||
async def get_segments(vid_id, web_session, categories = ["sponsor"]):
|
||||
params = {"videoID": vid_id,
|
||||
"category": categories,
|
||||
"actionType": "skip",
|
||||
"service": "youtube"}
|
||||
headers = {'Accept': 'application/json'}
|
||||
url = "https://sponsor.ajay.app/api/skipSegments"
|
||||
async with web_session.get(url, headers = headers, params = params) as response:
|
||||
response = await response.json()
|
||||
segments = []
|
||||
try:
|
||||
duration = response[0]["videoDuration"]
|
||||
for i in response:
|
||||
segment = i["segment"]
|
||||
try:
|
||||
#Get segment before to check if they are too close to each other
|
||||
segment_before_end = segments[-1][1]
|
||||
segment_before_start = segments[-1][0]
|
||||
|
||||
except:
|
||||
segment_before_end = -10
|
||||
if segment[0] - segment_before_end < 1: #Less than 1 second appart, combine them and skip them together
|
||||
segment = [segment_before_start, segment[1]]
|
||||
segments.pop()
|
||||
segments.append(segment)
|
||||
except:
|
||||
duration = 0
|
||||
return segments, duration
|
||||
|
||||
|
||||
async def time_to_segment(segments, position, rc, time_start):
|
||||
position = position + (time.time() - time_start)
|
||||
for segment in segments:
|
||||
if position < 2 and (position >= segment[0] and position < segment[1]):
|
||||
next_segment = [position, segment[1]]
|
||||
break
|
||||
if segment[0] > position:
|
||||
next_segment = segment
|
||||
break
|
||||
time_to_next = next_segment[0] - position
|
||||
await skip(time_to_next, next_segment[1], rc)
|
||||
|
||||
async def skip(time_to, position, rc):
|
||||
await asyncio.sleep(time_to)
|
||||
await rc.set_position(position)
|
||||
|
||||
|
||||
async def connect_atv(loop, identifier, airplay_credentials):
|
||||
"""Find a device and print what is playing."""
|
||||
print("Discovering devices on network...")
|
||||
atvs = await pyatv.scan(loop, identifier = identifier)
|
||||
|
||||
if not atvs:
|
||||
print("No device found, will retry")
|
||||
return
|
||||
|
||||
config = atvs[0]
|
||||
config.set_credentials(pyatv.Protocol.AirPlay, airplay_credentials)
|
||||
|
||||
print(f"Connecting to {config.address}")
|
||||
return await pyatv.connect(config, loop)
|
||||
|
||||
|
||||
async def loop_atv(event_loop, atv_config, apikey, categories, web_session):
|
||||
identifier = atv_config["identifier"]
|
||||
airplay_credentials = atv_config["airplay_credentials"]
|
||||
atv = await connect_atv(event_loop, identifier, airplay_credentials)
|
||||
if atv:
|
||||
listener = MyPushListener(apikey, atv, categories, web_session)
|
||||
|
||||
atv.push_updater.listener = listener
|
||||
atv.push_updater.start()
|
||||
print("Push updater started")
|
||||
while True:
|
||||
await asyncio.sleep(20)
|
||||
try:
|
||||
atv.metadata.app
|
||||
except:
|
||||
print("Reconnecting to Apple TV")
|
||||
#reconnect to apple tv
|
||||
atv = await connect_atv(event_loop, identifier, airplay_credentials)
|
||||
if atv:
|
||||
listener = MyPushListener(apikey, atv, categories, web_session)
|
||||
|
||||
atv.push_updater.listener = listener
|
||||
atv.push_updater.start()
|
||||
print("Push updater started")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main(atv_configs, apikey, categories, debug):
|
||||
loop = asyncio.get_event_loop_policy().get_event_loop()
|
||||
if debug:
|
||||
loop.set_debug(True)
|
||||
asyncio.set_event_loop(loop)
|
||||
web_session = aiohttp.ClientSession()
|
||||
for i in atv_configs:
|
||||
loop.create_task(loop_atv(loop, i, apikey, categories, web_session))
|
||||
loop.run_forever()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("starting")
|
||||
main()
|
||||
7
main-macos.py
Normal file
7
main-macos.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from iSponsorBlockTV import helpers
|
||||
import sys
|
||||
import os
|
||||
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.environ['SSL_CERT_FILE'] = os.path.join(sys._MEIPASS, 'lib', 'cert.pem')
|
||||
helpers.app_start()
|
||||
47
main-macos.spec
Normal file
47
main-macos.spec
Normal file
@@ -0,0 +1,47 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
from PyInstaller.utils.hooks import exec_statement
|
||||
cert_datas = exec_statement("""
|
||||
import ssl
|
||||
print(ssl.get_default_verify_paths().cafile)""").strip().split()
|
||||
cert_datas = [(f, 'lib') for f in cert_datas]
|
||||
|
||||
block_cipher = None
|
||||
|
||||
options = [ ('u', None, 'OPTION') ]
|
||||
|
||||
a = Analysis(['main-macos.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=cert_datas,
|
||||
hiddenimports=['certifi'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
options,
|
||||
name='iSponsorBlockTV',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None)
|
||||
174
main.py
174
main.py
@@ -1,173 +1,3 @@
|
||||
import sys
|
||||
import asyncio
|
||||
import pyatv
|
||||
import aiohttp
|
||||
from cache import AsyncTTL
|
||||
import json
|
||||
import time
|
||||
from iSponsorBlockTV import helpers
|
||||
|
||||
def listToTuple(function):
|
||||
def wrapper(*args):
|
||||
args = [tuple(x) if type(x) == list else x for x in args]
|
||||
result = function(*args)
|
||||
result = tuple(result) if type(result) == list else result
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
class MyPushListener(pyatv.interface.PushListener):
|
||||
task = None
|
||||
apikey = None
|
||||
rc = None
|
||||
|
||||
web_session = None
|
||||
categories = ["sponsor"]
|
||||
|
||||
def __init__(self, apikey, atv, categories, web_session):
|
||||
self.apikey = apikey
|
||||
self.rc = atv.remote_control
|
||||
self.web_session = web_session
|
||||
self.categories = categories
|
||||
self.atv = atv
|
||||
|
||||
|
||||
def playstatus_update(self, updater, playstatus):
|
||||
try:
|
||||
self.task.cancel()
|
||||
except:
|
||||
pass
|
||||
time_start = time.time()
|
||||
self.task = asyncio.create_task(process_playstatus(playstatus, self.apikey, self.rc, self.web_session, self.categories, self.atv, time_start))
|
||||
def playstatus_error(self, updater, exception):
|
||||
print(exception)
|
||||
print("stopped")
|
||||
|
||||
|
||||
|
||||
async def process_playstatus(playstatus, apikey, rc, web_session, categories, atv, time_start):
|
||||
if playstatus.device_state == playstatus.device_state.Playing and atv.metadata.app.identifier == "com.google.ios.youtube":
|
||||
vid_id = await get_vid_id(playstatus.title, playstatus.artist, apikey, web_session)
|
||||
print(vid_id)
|
||||
segments, duration = await get_segments(vid_id, web_session, categories)
|
||||
print(segments)
|
||||
await time_to_segment(segments, playstatus.position, rc, time_start)
|
||||
|
||||
|
||||
@AsyncTTL(time_to_live=300, maxsize=5)
|
||||
async def get_vid_id(title, artist, api_key, web_session):
|
||||
url = f"https://youtube.googleapis.com/youtube/v3/search?q={title} - {artist}&key={api_key}&maxResults=1"
|
||||
async with web_session.get(url) as response:
|
||||
response = await response.json()
|
||||
vid_id = response["items"][0]["id"]["videoId"]
|
||||
return vid_id
|
||||
|
||||
@listToTuple
|
||||
@AsyncTTL(time_to_live=300, maxsize=5)
|
||||
async def get_segments(vid_id, web_session, categories = ["sponsor"]):
|
||||
params = {"videoID": vid_id,
|
||||
"category": categories,
|
||||
"actionType": "skip",
|
||||
"service": "youtube"}
|
||||
headers = {'Accept': 'application/json'}
|
||||
url = "https://sponsor.ajay.app/api/skipSegments"
|
||||
async with web_session.get(url, headers = headers, params = params) as response:
|
||||
response = await response.json()
|
||||
segments = []
|
||||
try:
|
||||
duration = response[0]["videoDuration"]
|
||||
for i in response:
|
||||
segment = i["segment"]
|
||||
try:
|
||||
#Get segment before to check if they are too close to each other
|
||||
segment_before_end = segments[-1][1]
|
||||
segment_before_start = segments[-1][0]
|
||||
|
||||
except:
|
||||
segment_before_end = -10
|
||||
if segment[0] - segment_before_end < 1: #Less than 1 second appart, combine them and skip them together
|
||||
segment = [segment_before_start, segment[1]]
|
||||
segments.pop()
|
||||
segments.append(segment)
|
||||
except:
|
||||
duration = 0
|
||||
return segments, duration
|
||||
|
||||
|
||||
async def time_to_segment(segments, position, rc, time_start):
|
||||
position = position + (time.time() - time_start)
|
||||
for segment in segments:
|
||||
if position < 2 and (position >= segment[0] and position < segment[1]):
|
||||
next_segment = [position, segment[1]]
|
||||
break
|
||||
if segment[0] > position:
|
||||
next_segment = segment
|
||||
break
|
||||
time_to_next = next_segment[0] - position
|
||||
await skip(time_to_next, next_segment[1], rc)
|
||||
|
||||
async def skip(time_to, position, rc):
|
||||
await asyncio.sleep(time_to)
|
||||
await rc.set_position(position)
|
||||
|
||||
|
||||
async def connect_atv(loop, identifier, airplay_credentials):
|
||||
"""Find a device and print what is playing."""
|
||||
print("Discovering devices on network...")
|
||||
atvs = await pyatv.scan(loop, identifier = identifier)
|
||||
|
||||
if not atvs:
|
||||
print("No device found, will retry")
|
||||
return
|
||||
|
||||
config = atvs[0]
|
||||
config.set_credentials(pyatv.Protocol.AirPlay, airplay_credentials)
|
||||
|
||||
print(f"Connecting to {config.address}")
|
||||
return await pyatv.connect(config, loop)
|
||||
|
||||
|
||||
async def loop_atv(event_loop, atv_config, apikey, categories, web_session):
|
||||
identifier = atv_config["identifier"]
|
||||
airplay_credentials = atv_config["airplay_credentials"]
|
||||
atv = await connect_atv(event_loop, identifier, airplay_credentials)
|
||||
if atv:
|
||||
listener = MyPushListener(apikey, atv, categories, web_session)
|
||||
|
||||
atv.push_updater.listener = listener
|
||||
atv.push_updater.start()
|
||||
print("Push updater started")
|
||||
while True:
|
||||
await asyncio.sleep(20)
|
||||
try:
|
||||
atv.metadata.app
|
||||
except:
|
||||
print("Reconnecting to Apple TV")
|
||||
#reconnect to apple tv
|
||||
atv = await connect_atv(event_loop, identifier, airplay_credentials)
|
||||
if atv:
|
||||
listener = MyPushListener(apikey, atv, categories, web_session)
|
||||
|
||||
atv.push_updater.listener = listener
|
||||
atv.push_updater.start()
|
||||
print("Push updater started")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def load_config(config_file="config.json"):
|
||||
with open(config_file) as f:
|
||||
config = json.load(f)
|
||||
return config["atvs"], config["apikey"], config["skip_categories"]
|
||||
|
||||
def start_async():
|
||||
loop = asyncio.get_event_loop_policy().get_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
atv_configs, apikey, categories = load_config()
|
||||
web_session = aiohttp.ClientSession()
|
||||
for i in atv_configs:
|
||||
loop.create_task(loop_atv(loop, i, apikey, categories, web_session))
|
||||
loop.run_forever()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("starting")
|
||||
start_async()
|
||||
helpers.app_start()
|
||||
@@ -2,3 +2,4 @@ pyatv
|
||||
aiohttp
|
||||
aiodns
|
||||
async-cache
|
||||
argparse
|
||||
|
||||
Reference in New Issue
Block a user