Closed Tinonee111 closed 1 month ago
channel 9 keep killing the user used. i suggest using the kodi 9now add-on if you want reliable streams
also, if your using tivimate, you should be using the Kodi playlist. as the streams are currently working but need specific user agent which the kodi style playlist adds
Sorry I should have stated it’s the kodi add on that’s not working atm
On Wed, 31 Jul 2024 at 1:31 PM, Matt Huisman @.***> wrote:
channel 9 keep killing the user used. i suggest using the kodi 9now add-on if you want reliable streams
also, if your using tivimate, you should be using the Kodi playlist. as the streams are currently working but need specific user agent which the kodi style playlist adds
— Reply to this email directly, view it on GitHub https://github.com/matthuisman/slyguy.addons/issues/825#issuecomment-2259570545, or unsubscribe https://github.com/notifications/unsubscribe-auth/BKHBQW5SVQWCAC6TFM56XQLZPBLBFAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENJZGU3TANJUGU . You are receiving this because you authored the thread.Message ID: @.***>
make sure your using the latest version. It will make you login now using a 9now login (which are free)
if you are on latest, then please provide a full kodi debug log showing the error
Thanks, I was tricked by the new setup requiring a login All good now, thank you for the app and your assistance
On Wed, Jul 31, 2024 at 1:36 PM Matt Huisman @.***> wrote:
if you are on latest, then please provide a full kodi debug log showing the error
— Reply to this email directly, view it on GitHub https://github.com/matthuisman/slyguy.addons/issues/825#issuecomment-2259575121, or unsubscribe https://github.com/notifications/unsubscribe-auth/BKHBQWZ2JBBQOWTDXYWPEHTZPBLVLAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENJZGU3TKMJSGE . You are receiving this because you authored the thread.Message ID: @.***>
I'm using the raw-tv m3u8 with Threadfin(Steve) with ffmpeg 7 as a buffer and the streams are working fine. Would it be better for me to switch to the Kodi m3u8?
If its working, just keep as is. I'm not sure if that program supports the Kodi style
On Wed, 31 Jul 2024, 21:07 tresby, @.***> wrote:
I'm using the raw-tv m3u8 with Threadfin(Steve) with ffmpeg 7 as a buffer and the streams are working fine. Would it be better for me to switch to the Kodi m3u8?
— Reply to this email directly, view it on GitHub https://github.com/matthuisman/slyguy.addons/issues/825#issuecomment-2260026019, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE . You are receiving this because you modified the open/close state.Message ID: @.***>
If its working, just keep as is. I'm not sure if that program supports the Kodi style … On Wed, 31 Jul 2024, 21:07 tresby, @.> wrote: I'm using the raw-tv m3u8 with Threadfin(Steve) with ffmpeg 7 as a buffer and the streams are working fine. Would it be better for me to switch to the Kodi m3u8? — Reply to this email directly, view it on GitHub <#825 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE . You are receiving this because you modified the open/close state.Message ID: @.>
Just went to try it again and its gone bad again.
Was messing around with Kodi.proxy last night and I can get up to getting an m3u8 with the plugin:// links, but I can only individually play the channels from replay using the tvs.sh.
Would there be an easy way/script to have on a cron job to using the plugin:// links and tvs.sh to get the http link in a new m3u8? If that makes sense.
Don't run tvh so can't use the pipe:// method unfortunately.
Another user on twitter made a flask app to redirect to the new url.
On Wed, 31 Jul 2024, 21:29 tresby, @.***> wrote:
If its working, just keep as is. I'm not sure if that program supports the Kodi style … <#m-8210583645172429004> On Wed, 31 Jul 2024, 21:07 tresby, @.> wrote: I'm using the raw-tv m3u8 with Threadfin(Steve) with ffmpeg 7 as a buffer and the streams are working fine. Would it be better for me to switch to the Kodi m3u8? — Reply to this email directly, view it on GitHub <#825 (comment) https://github.com/matthuisman/slyguy.addons/issues/825#issuecomment-2260026019>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE . You are receiving this because you modified the open/close state.Message ID: @.>
Just went to try it again and its gone bad again.
Was messing around with Kodi.proxy last night and I can get up to getting an m3u8 with the plugin:// links, but I can only individually play the channels from replay using the tvs.sh.
Would there be an easy way/script to have on a cron job to using the plugin:// links and tvs.sh to get the http link in a new m3u8? If that makes sense.
Don't run tvh so can't use the pipe:// method unfortunately.
— Reply to this email directly, view it on GitHub https://github.com/matthuisman/slyguy.addons/issues/825#issuecomment-2260076322, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKJ5EPNYUH773WEAUDLZPCU6PAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGA3TMMZSGI . You are receiving this because you modified the open/close state.Message ID: @.***>
Another user on twitter made a flask app to redirect to the new url. … On Wed, 31 Jul 2024, 21:29 tresby, @.> wrote: If its working, just keep as is. I'm not sure if that program supports the Kodi style … <#m-8210583645172429004> On Wed, 31 Jul 2024, 21:07 tresby, @.> wrote: I'm using the raw-tv m3u8 with Threadfin(Steve) with ffmpeg 7 as a buffer and the streams are working fine. Would it be better for me to switch to the Kodi m3u8? — Reply to this email directly, view it on GitHub <#825 (comment) <#825 (comment)>>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE https://github.com/notifications/unsubscribe-auth/ABPQAKOCMDCRBF2MRRSRQHTZPCSOXAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAZDMMBRHE . You are receiving this because you modified the open/close state.Message ID: @.> Just went to try it again and its gone bad again. Was messing around with Kodi.proxy last night and I can get up to getting an m3u8 with the plugin:// links, but I can only individually play the channels from replay using the tvs.sh. Would there be an easy way/script to have on a cron job to using the plugin:// links and tvs.sh to get the http link in a new m3u8? If that makes sense. Don't run tvh so can't use the pipe:// method unfortunately. — Reply to this email directly, view it on GitHub <#825 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPQAKJ5EPNYUH773WEAUDLZPCU6PAVCNFSM6AAAAABLXSNJR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGA3TMMZSGI . You are receiving this because you modified the open/close state.Message ID: @.>
Oh awesome, did you happen to have the link handy? Trying to have a look for it on twitter now but can't seem to find it atm.
He posted it in a DM. Its basically doing what the 9now addon does
import os
import json
import time
import requests
import logging
from flask import Flask, Response, redirect
from urllib.parse import urlencode, parse_qsl, urlparse, parse_qs
import threading
# Import constants from the 9Now addon
from constants import *
app = Flask(__name__)
# Set up file logging
log_file_path = '/var/www/9now/9now_api.log'
file_handler = logging.FileHandler(log_file_path)
file_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
REFRESH_TOKEN_PATH = '/var/www/kodi.proxy/userdata/addon_data/slyguy.9now/refresh_token.json'
class Settings:
REGION = 'nsw'
CHANNEL_REFERENCE = 'live-ch9-syd-ssai' # Reference for Channel 9 Sydney
settings = Settings()
def get_refresh_token():
with open(REFRESH_TOKEN_PATH, 'r') as f:
data = json.load(f)
return data.get('refresh_token')
class API:
def __init__(self):
self.session = requests.Session()
self.session.headers.update(HEADERS)
self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
self.session.headers.update({'User-Agent': self.user_agent})
self._access_token = None
self._token_expires = 0
self.cached_url = None
self.url_expiry = 0
self.url_cache_lock = threading.Lock()
def _refresh_token(self):
if self._token_expires > time.time():
return
refresh_token = get_refresh_token()
params = {
'refresh_token': refresh_token,
'client_id': '9nowdevice',
'response_types': 'id_token',
}
try:
headers = self.session.headers.copy()
headers.update({'User-Agent': self.user_agent})
response = self.session.post(AUTH_URL.format('/refresh-token'), params=params, timeout=30, verify=True)
response.raise_for_status()
data = response.json()
if 'error' in data:
raise Exception(data['error'])
self._access_token = data.get('accessToken') or data.get('access_token')
expires_in = data.get('expiresIn') or data.get('expires_in')
self._token_expires = int(time.time()) + int(expires_in) - 30
self.session.headers.update({'Authorization': f'Bearer {self._access_token}'})
except requests.exceptions.RequestException as e:
raise
def channels(self, region='nsw'):
self._refresh_token()
params = {
'device': 'web',
'streamParams': 'web,chrome,windows',
'region': region,
'offset': 0,
}
try:
headers = self.session.headers.copy()
headers.update({'User-Agent': self.user_agent})
response = self.session.get(LIVESTREAM_URL, params=params, timeout=30,verify=True)
response.raise_for_status()
data = response.json()
return data['data']['getLivestream']
except requests.RequestException as e:
raise
def _channels(self):
region = settings.REGION
data = self.channels(region)
data['channels'].extend([row for row in data['events'] if row['type'] == 'live-event' and row['nextEvent']['name']])
data['events'] = [row for row in data['events'] if row not in data['channels']]
return data
def get_expiry_from_url(self, url):
parsed_url = urlparse(url)
query_params = parse_qs(parsed_url.query)
exp_param = query_params.get('exp', [None])[0]
return int(exp_param) if exp_param else None
def get_channel9_url(self):
with self.url_cache_lock:
current_time = time.time()
if self.cached_url and current_time < self.url_expiry - 60: # Refresh 60 seconds before expiry
return self.cached_url
try:
data = self._channels()
url = None
for row in data['channels']:
if row['referenceId'] == settings.CHANNEL_REFERENCE:
url = row['stream']['url']
break
if not url:
return None
# fix encoded query
if '?' in url:
url = url.split('?')[0] + '?' + urlencode(parse_qsl(url.split('?')[1]))
self.cached_url = url
self.url_expiry = self.get_expiry_from_url(url) or (current_time + 3600) # Default to 1 hour if no expiry found
app.logger.info(f"Updated cached URL (expires at {time.ctime(self.url_expiry)}): {url}")
return url
except Exception as e:
app.logger.error(f"Error fetching Channel 9 URL: {str(e)}")
return None
api = API()
def update_url_periodically():
while True:
api.get_channel9_url() # This will update the cache if necessary
time.sleep(60) # Check every minute
@app
.route('/9')
def get_channel9_live():
url = api.get_channel9_url()
if url:
app.logger.info(f"Serving URL (expires at {time.ctime(api.url_expiry)}): {url}")
return redirect(url)
else:
return Response("Unable to fetch Channel 9 URL", status=500, mimetype='text/plain')
if __name__ == '__main__':
# Start the background thread to update the URL periodically
threading.Thread(target=update_url_periodically, daemon=True).start()
app.run(host='0.0.0.0', port=9001)
He posted it in a DM. Its basically doing what the 9now addon does
import os import json import time import requests import logging from flask import Flask, Response, redirect from urllib.parse import urlencode, parse_qsl, urlparse, parse_qs import threading # Import constants from the 9Now addon from constants import * app = Flask(__name__) # Set up file logging log_file_path = '/var/www/9now/9now_api.log' file_handler = logging.FileHandler(log_file_path) file_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) REFRESH_TOKEN_PATH = '/var/www/kodi.proxy/userdata/addon_data/slyguy.9now/refresh_token.json' class Settings: REGION = 'nsw' CHANNEL_REFERENCE = 'live-ch9-syd-ssai' # Reference for Channel 9 Sydney settings = Settings() def get_refresh_token(): with open(REFRESH_TOKEN_PATH, 'r') as f: data = json.load(f) return data.get('refresh_token') class API: def __init__(self): self.session = requests.Session() self.session.headers.update(HEADERS) self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' self.session.headers.update({'User-Agent': self.user_agent}) self._access_token = None self._token_expires = 0 self.cached_url = None self.url_expiry = 0 self.url_cache_lock = threading.Lock() def _refresh_token(self): if self._token_expires > time.time(): return refresh_token = get_refresh_token() params = { 'refresh_token': refresh_token, 'client_id': '9nowdevice', 'response_types': 'id_token', } try: headers = self.session.headers.copy() headers.update({'User-Agent': self.user_agent}) response = self.session.post(AUTH_URL.format('/refresh-token'), params=params, timeout=30, verify=True) response.raise_for_status() data = response.json() if 'error' in data: raise Exception(data['error']) self._access_token = data.get('accessToken') or data.get('access_token') expires_in = data.get('expiresIn') or data.get('expires_in') self._token_expires = int(time.time()) + int(expires_in) - 30 self.session.headers.update({'Authorization': f'Bearer {self._access_token}'}) except requests.exceptions.RequestException as e: raise def channels(self, region='nsw'): self._refresh_token() params = { 'device': 'web', 'streamParams': 'web,chrome,windows', 'region': region, 'offset': 0, } try: headers = self.session.headers.copy() headers.update({'User-Agent': self.user_agent}) response = self.session.get(LIVESTREAM_URL, params=params, timeout=30,verify=True) response.raise_for_status() data = response.json() return data['data']['getLivestream'] except requests.RequestException as e: raise def _channels(self): region = settings.REGION data = self.channels(region) data['channels'].extend([row for row in data['events'] if row['type'] == 'live-event' and row['nextEvent']['name']]) data['events'] = [row for row in data['events'] if row not in data['channels']] return data def get_expiry_from_url(self, url): parsed_url = urlparse(url) query_params = parse_qs(parsed_url.query) exp_param = query_params.get('exp', [None])[0] return int(exp_param) if exp_param else None def get_channel9_url(self): with self.url_cache_lock: current_time = time.time() if self.cached_url and current_time < self.url_expiry - 60: # Refresh 60 seconds before expiry return self.cached_url try: data = self._channels() url = None for row in data['channels']: if row['referenceId'] == settings.CHANNEL_REFERENCE: url = row['stream']['url'] break if not url: return None # fix encoded query if '?' in url: url = url.split('?')[0] + '?' + urlencode(parse_qsl(url.split('?')[1])) self.cached_url = url self.url_expiry = self.get_expiry_from_url(url) or (current_time + 3600) # Default to 1 hour if no expiry found app.logger.info(f"Updated cached URL (expires at {time.ctime(self.url_expiry)}): {url}") return url except Exception as e: app.logger.error(f"Error fetching Channel 9 URL: {str(e)}") return None api = API() def update_url_periodically(): while True: api.get_channel9_url() # This will update the cache if necessary time.sleep(60) # Check every minute @app .route('/9') def get_channel9_live(): url = api.get_channel9_url() if url: app.logger.info(f"Serving URL (expires at {time.ctime(api.url_expiry)}): {url}") return redirect(url) else: return Response("Unable to fetch Channel 9 URL", status=500, mimetype='text/plain') if __name__ == '__main__': # Start the background thread to update the URL periodically threading.Thread(target=update_url_periodically, daemon=True).start() app.run(host='0.0.0.0', port=9001)
was brainstorming on ChatGPT with this code, and here are some potential ways.. Obviously the token would need to be done on the hosts machine.
Instead of relying on a dynamically changing URL, you can use a proxy server or create an intermediate static endpoint that always points to the most current URL.
Steps:
Create a Static Proxy Server
You can set up a small proxy server (e.g., using Nginx or Apache) to serve a static URL that always redirects to the latest Channel 9 URL.
Set up NextPVR to use the static URL endpoint. For example:
URL for Channel 9: http://yourserver:9001/current_url?channel=channel9
URL for 9Gem: http://yourserver:9001/current_url?channel=9gem
URL for 9Go: http://yourserver:9001/current_url?channel=9go
URL for 9Life: http://yourserver:9001/current_url?channel=9life
Videohelp.com is also another excellent site to assist with issues like these.
Thanks all for this code. I have tried running it and get as far as a m3u8 file, which works for about 2 seconds if I open it in VLC then freezes. It seems like the http://localhost:9001/9 url needs to somehow be loaded continually rather than just once? Am I missing something?
Hi mate Could you have a look at channel 9 please Been down for a few days now Kind. Regards