import httpx
import json
import uvicorn
import re
import time
from fastapi import FastAPI, HTTPException, Response
from threading import Thread
from datetime import datetime

access_key = '10676a016f8cd24de953192fdc49714a'
masked_access_keys = {
    'topdasgalaxias': access_key
}
app = FastAPI()

class Globo:
    def __init__(self):
        self.locations = [
            ('intertvminasmontesclaros', -15.152057904961916, -42.866718211924635, 'Inter TV Montes Claros'),
            ('globoacredeamaznicacruzeirodosulhd', -7.637880083959007, -72.67046772808176, 'Globo Acre - Cruzeiro do Sul'),
            ('globoacredeamaznicariobrancohd', -9.939437223978711, -67.83129016243451, 'Globo Acre - Rio Branco'),
            ('globoaltvgazetadealagoasmaceihd', -9.653589329959448, -35.733717418148174, 'Globo Alagoas - Maceió'),
            ('globoamredeamaznicacoarihd', -4.092427275170119, -63.139726795049874, 'Globo AM - Coari'),
            ('globoamredeamaznicahumaithd', -7.501306304163114, -63.0291592336363, 'Globo AM - Humaitá'),
            ('globoamredeamaznicaitacoatiarahd', -3.1350281307094923, -58.44527481278878, 'Globo AM - Itacoatiara'),
            ('globoamredeamaznicamanacapuruhd', -3.2517715924898263, -60.67797229460627, 'Globo AM - Manacapuru'),
            ('globoamredeamaznicamanaushd', -3.0977549784443643, -59.99259287971541, 'Globo AM - Manaus'),
            ('globoamredeamaznicaparintinshd', -2.6327976296269737, -56.73907606067403, 'Globo AM - Parintins'),
            ('globoapredeamaznicamacaphd', 0.0404681671285465, -51.06822759407549, 'Globo AP - Macapá'),
            ('globobatvbahiahd', -12.974173932398365, -38.512374017392105, 'Globo Bahia'),
            ('globobatvoestehd', -12.147847490616137, -44.99567772418691, 'Globo Oeste da Bahia'),
            ('globobatvsantacruzhd', -14.791931045962029, -39.28241862445153, 'Globo Santa Cruz'),
            ('globobatvsubahd', -12.25825340131257, -38.965387883594616, 'Globo Sul da Bahia'),
            ('globobatvsudoestehd', -14.858831949778944, -40.83954482042116, 'Globo Sudoeste da Bahia'),
            ('globobatvsofranciscohd', -9.431493562044965, -40.50811429566912, 'Globo São Francisco'),
            ('globocetvverdesmarescaririhd', -7.145877138972411, -39.71327262341779, 'Globo Verde Mar - Cariri'),
            ('globocetvverdesmareshd', -3.771462571532495, -38.211871683463634, 'Globo Verde Mar'),
            ('globoestvgazetanoroestehd', -18.718417239418766, -39.85977569292309, 'Globo Noroeste'),
            ('globoestvgazetanortehd', -18.718417239418766, -39.85977569292309, 'Globo Norte'),
            ('globoestvgazetasulhd', -20.856032810727417, -41.12181259944064, 'Globo Sul'),
            ('globoestvgazetavitriahd', -20.31379178092789, -40.357384303203624, 'Globo Vitria'),
            ('globogotvanhangueraanpolishd', -16.294670520638658, -48.95029758743446, 'Globo Hanguera - Anápolis'),
            ('globogotvanhangueracatalohd', -18.154585740679142, -47.94862979717676, 'Globo Hanguera - Catalão'),
            ('globogotvanhangueragoiniahd', -16.722066007880336, -49.264373385572945, 'Globo Hanguera - Goiânia'),
            ('globogotvanhangueraitumbiarahd', -18.390700184227327, -49.219508918066246, 'Globo Hanguera - Itumbiara'),
            ('globogotvanhanguerajatahd', -18.390700184227327, -49.219508918066246, 'Globo Hanguera - Jataí'),
            ('globogotvanhangueraluziniahd', -16.252149145817015, -47.92510410354397, 'Globo Hanguera - Luziania'),
            ('globogotvanhangueraporangatuhd', -13.43383016355595, -49.13426926606903, 'Globo Hanguera - Porangatu'),
            ('globogotvanhanguerarioverdehd', -17.789933445984364, -50.88914631199367, 'Globo Hanguera - Rio Verde'),
            ('globomatvmirantebalsashd', -7.52046334428768, -46.03423973548709, 'Globo Mirante - Balsas'),
            ('globomatvmiranteimperatrizhd', -5.458548335803677, -47.46013381556811, 'Globo Mirante - Imperatriz'),
            ('globomatvmirantesolushd', -2.350004294252703, -44.702381535521184, 'Globo Mirante - Solus'),
            ('globomgeptvsuldeminashd', -22.228559023459066, -45.93107632885557, 'Globo MG - Sul de Minas'),
            ('globomgintertvdosvalesgovernadorvaladareshd', -18.853554865058896, -41.94199662360602, 'Globo MG - Governador Valadares'),
            ('globomgintertvgrandeminashd', -18.853554865058896, -41.94199662360602, 'Globo MG - Grande Minas'),
            ('globomgtvintegraoaraxdivinpolishd', -20.10941634813606, -44.76033568697683, 'Globo MG - Araxá'),
            ('globomgtvintegraoituiutabahd', -18.83801130175618, -48.67872287528572, 'Globo MG - Ituiutaba'),
            ('globomgtvintegraojuizdeforahd', -21.74733326258907, -43.353819048653655, 'Globo MG - Juiz de Fora'),
            ('globomgtvintegraouberabahd', -19.658627901675498, -48.09181513423691, 'Globo MG - Uberaba'),
            ('globomgtvintegraouberlndiahd', -18.884800974387563, -48.26137586408258, 'Globo MG - Uberlândia'),
            ('globomstvmorenacorumbhd', -19.001362474570517, -57.636282858526464, 'Globo MS - Corumbá'),
            ('globomstvmorenahd', -19.001362474570517, -57.636282858526464, 'Globo MS - Morena'),
            ('globomstvmorenapontaporhd', -22.527769525719258, -55.71487276952474, 'Globo MS - Ponta Porã'),
            ('globomttvcentroamricacuiabhd', -15.584732409982779, -56.09446472554252, 'Globo MT - Centro América'),
            ('globomttvcentroamricanortehd', -15.584732409982779, -56.09446472554252, 'Globo MT - Centro América Norte'),
            ('globomttvcentroamricasulhd', -15.584732409982779, -56.09446472554252, 'Globo MT - Centro América Sul'),
            ('globomttvcentroamricatangardaserrahd', -14.62799768348942, -57.50140643720664, 'Globo MT - Tangará da Serra'),
            ('globopatvliberalaltamirahd', -3.2116573810426807, -52.226941423893685, 'Globo Liberal - Altamira'),
            ('globopatvliberalbelmhd', -3.2051840677772194, -52.20749790723549, 'Globo Liberal - Belém'),
            ('globopatvliberalcastanhalhd', -1.2962312638145972, -47.94155577972818, 'Globo Liberal - Castanhal'),
            ('globopatvliberalmarabhd', -1.2962312638145972, -47.94155577972818, 'Globo Liberal - Marabá'),
            ('globopatvliberalparagominashd', -2.9971891473440895, -47.35876254027354, 'Globo Liberal - Paragominas'),
            ('globopatvliberalparauapebashd', -2.9971891473440895, -47.35876254027354, 'Globo Liberal - Parauapebas'),
            ('globopatvliberalredenohd', -8.036020292815422, -50.02038547040424, 'Globo Liberal - Redenção'),
            ('globopatvtapajshd', -2.4297339794345136, -54.70850781834709, 'Globo Tapajós'),
            ('globopbtvcabobrancohd', -7.116088907621701, -34.875253389462436, 'Globo PB - Cabedelo'),
            ('globopbtvparabahd', -7.1059153652042735, -34.83778593594084, 'Globo PB - Paraíba'),
            ('globopetvasabrancahd', -8.294797609566706, -35.9862361508193, 'Globo PE - Sabará'),
            ('globopetvgloborecifehd', -8.054683324101322, -34.876672948971745, 'Globo PE - Recife'),
            ('globopetvgranderiohd', -8.054683324101322, -34.876672948971745, 'Globo PE - Grande Rio'),
            ('globopitvalvoradahd', -8.392451748295509, -35.25874523368156, 'Globo Pitvalv'),
            ('globopitvclubehd', -5.110304084919481, -42.79562979503958, 'Globo Clube'),
            ('globoprrpccascavelhd', -24.96744621586949, -53.451347152783654, 'Globo PR - Cascavel'),
            ('globoprrpccuritibahd', -25.41715074451694, -49.28638020435038, 'Globo PR - Curitiba'),
            ('globoprrpcfozdoiguauhd', -25.521149466819267, -54.57137614247357, 'Globo PR - Foz do Iguaçu'),
            ('globoprrpcguarapuavahd', -25.365916555064544, -51.433877098799385, 'Globo PR - Guarapuava'),
            ('globoprrpclondrinahd', -23.317159387237734, -51.165766944319685, 'Globo PR - Londrina'),
            ('globoprrpcmaringhd', -23.416655784244607, -51.92865797158255, 'Globo PR - Maringá'),
            ('globoprrpcparanavahd', -23.07455910693249, -52.445258758220696, 'Globo PR - Paranavaí'),
            ('globoprrpcpontagrossahd', -25.088634929310903, -50.15857576573565, 'Globo PR - Ponta Grossa'),
            ('globoriodejaneirofhd', -22.964732379941587, -43.22158986395762, 'Globo RJ - Rio de Janeiro'),
            ('globoriodejaneirosd', -22.964732379941587, -43.22158986395762, 'Globo RJ - Rio de Janeiro SD'),
            ('globorjintertvaltolitoralhd', -22.837079850426882, -42.06891455879652, 'Globo RJ - Inter TV Litoral'),
            ('globorjintertvplanciehd', -21.759533659402333, -41.32335198706706, 'Globo RJ - Inter TV Planície'),
            ('globorjintertvserramarhd', -22.297028647136028, -42.539882204456724, 'Globo RJ - Inter TV Serramar'),
            ('globorjtvriosulhd', -22.408062001805362, -43.6569515370396, 'Globo RJ - TV Rio Sul'),
            ('globornintertvcabugihd', -5.833211554455341, -35.21296203365772, 'Globo RN - Cabugi'),
            ('globornintertvcostabrancahd', -5.190934517200593, -37.340923933345955, 'Globo RN - Costa Branca'),
            ('globororedeamaznicaariquemeshd', -9.922376281400211, -63.03691168756876, 'Globo RO - Ariquemes'),
            ('globororedeamaznicacacoalhd', -11.428381421531393, -61.456864075900114, 'Globo RO - Cacoal'),
            ('globororedeamaznicajiparanhd', -11.428381421531393, -61.456864075900114, 'Globo RO - Jiparan'),
            ('globororedeamaznicaportovelhohd', -8.68727475480573, -64.0194917661983, 'Globo RO - Porto Velho'),
            ('globororedeamaznicavilhenahd', -8.766076463205623, -63.882555177796895, 'Globo RO - Vilhena'),
            ('globorrredeamaznicaboavistahd', 2.8198053507034877, -60.66905226809979, 'Globo RR - Boa Vista'),
            ('globorrredeamaznicarorainpolishd', 0.9439581265962609, -60.42989711818263, 'Globo RR - Roraima'),
            ('globorsrbstvbaghd', -31.35217591390039, -54.120201240357105, 'Globo RS - Bagé'),
            ('globorsrbstvcaxiasdosulhd', -29.16561129534937, -51.17673814838717, 'Globo RS - Caxias do Sul'),
            ('globorsrbstvcruzaltahd', -28.632426522474844, -53.59698462751241, 'Globo RS - Cruz Alta'),
            ('globorsrbstvdosvaleshd', -29.71837400968329, -52.43381649254404, 'Globo RS - Dos Vales'),
            ('globorsrbstverechimhd', -27.627516393146927, -52.281538687074026, 'Globo RS - Erechim'),
            ('globorsrbstvpassofundohd', -28.258840537668483, -52.42651772618933, 'Globo RS - Passo Fundo'),
            ('globorsrbstvpelotashd', -31.752090627951812, -52.31344186177223, 'Globo RS - Pelotas'),
            ('globorsrbstvportoalegrehd', -30.070604993732285, -51.22979714649939, 'Globo RS - Porto Alegre'),
            ('globorsrbstvriograndehd', -30.013265828273884, -51.30607990453289, 'Globo RS - Rio Grande'),
            ('globorsrbstvsantamariahd', -29.6938123536418, -53.78798323309491, 'Globo RS - Santa Maria'),
            ('globorsrbstvsantarosahd', -27.842600474175793, -54.47687735637913, 'Globo RS - Santa Rosa'),
            ('globorsrbstvuruguaianahd', -29.754614774246427, -57.08414279492959, 'Globo RS - Uruguaiana'),
            ('globoscnsctvblumenauhd', -26.917494112637772, -49.067890885249994, 'Globo SC - Blumenau'),
            ('globoscnsctvcentrooestehd', -30.165526063079575, -53.56741968415987, 'Globo SC - Centro-Oeste'),
            ('globoscnsctvchapechd', -27.096251774935993, -52.61385953488663, 'Globo SC - Chapecó'),
            ('globoscnsctvcricimahd', -28.6580407723375, -49.36378807169045, 'Globo SC - Criciúma'),
            ('globoscnsctvflorianpolishd', -27.588973463040503, -48.53827124766528, 'Globo SC - Florianópolis'),
            ('globoscnsctvjoinvillehd', -26.2957640537845, -48.83510621225816, 'Globo SC - Joinville'),
            ('globosetvsergipehd', -10.891213219946001, -37.06903014098549, 'Globo SE - Sergipe'),
            ('globospeptvcampinashd', -22.90905241228107, -47.06469607657691, 'Globo SP - Campinas'),
            ('globospeptvcentralhd', -22.032416681307982, -47.8807245370029, 'Globo SP - Central'),
            ('globospeptvribeirohd', -21.136228680532298, -47.81889450210669, 'Globo SP - Ribeirão Preto'),
            ('globosptvdiriohd', -23.50628896966426, -46.14785867928293, 'Globo SP - Diário'),
            ('globosptvfronteirapaulistahd', -22.12279463239931, -51.44385273294569, 'Globo SP - Fronteira Paulista'),
            ('globosptvtembauruhd', -22.32080825709641, -49.0809516466665, 'Globo SP - Tembau'),
            ('globosptvtemitapetiningahd', -23.577273981570883, -48.03751624489197, 'Globo SP - Itapetininga'),
            ('globospttemsorocabahd', -23.480353855244587, -47.42011162955176, 'Globo SP - Sorocaba'),
            ('globosptvtemsojosdoriopretohd', -20.801125903697923, -49.347434814294466, 'Globo SP - São José do Rio Preto'),
            ('globosptvtribunahd', -23.959910523894475, -46.32904299074828, 'Globo SP - Tribuna'),
            ('globosptvvanguardasojosdoscamposhd', -23.19898728845108, -45.88253407559139, 'Globo SP - Vanguarda'),
            ('globosptvvanguardataubathd', -23.02922531974585, -45.578556056015856, 'Globo SP - Taubaté'),
            ('globototvanhangueraaraguanahd', -7.180679152208242, -48.21403750560309, 'Globo TO - Araguaína'),
            ('globototvanhangueragurupihd', -11.726599998369366, -49.07946909347975, 'Globo TO - Gurupi'),
            ('globototvanhanguerapalmashd', -15.78516379406356, -47.88784592977562, 'Globo TO - Palmas'),
            ('globotvglobobrasliahd', -15.78516379406356, -47.88784592977562, 'Globo Brasília'),
            ('globotvglobominasbhhd', -19.898796728022486, -43.95266486514384, 'Globo Minas - Belo Horizonte'),
            ('globorjcapitalhd', -22.964732379941587, -43.22158986395762, 'Globo RJ - Capital'),
            ('globotvglobosopaulohd', -23.614932240821442, -46.69734043880185, 'Globo SP - São Paulo'),
        ]
        self.bearer = '1958ddad64091b0e2ee40368a3ff506374348545f7655697a5665425a54764650774b555f51695a48384a6875733959795243674c394e5169555173726667737279457859715969366a424d52484a5066354c3941513165394d6e5338327261474e7a66364e413d3d3a303a75336173726b3561713473706b64753133746d79'
        self.channels = {}
        self.new_channels = {}

    def get_resolution_name(self, largura, altura):
        if largura == 1280 and altura == 720:
            return "HD"
        elif largura == 1920 and altura == 1080:
            return "Full HD"
        elif largura == 3840 and altura == 2160:
            return "4K"
        elif largura < 1280 and altura < 720:
            return "SD"
        else:
            return "SD"

    def get_channel_info(self, channel_id, latitude=-15.811666896782167, longitude=-47.89914181947207):
        try:
            r = httpx.post(
                url='https://playback.video.globo.com/v4/video-session',
                headers={
                    'Authorization': f'Bearer {self.bearer}',
                    'User-Agent': 'Globoplay/3.405.0 Dalvik/2.1.0 (Linux; U; Android 5.1.1; G011A Build/LMY48Z)',
                    'Content-Type': 'application/json; charset=utf-8'
                },
                data=json.dumps({
                    "video_id": channel_id,
                    "player_type": "android_native",
                    "quality": "max",
                    "content_protection": "widevine",
                    "lat": str(latitude),
                    "long": str(longitude)
                })
            )

            if r.status_code != 200:
                print(f"Erro ao acessar a URL: {r.status_code}, {r.text}")
                return []

            js = r.json()
        except httpx.HTTPStatusError as e:
            print(f"Erro de status HTTP: {e}")
            return []
        except json.JSONDecodeError:
            print("Erro ao decodificar JSON")
            print(f"Conteúdo recebido: {r.text}")
            return []
        except Exception as e:
            print(f"Erro inesperado: {e}")
            return []

        code = js.get('code')
        if code is not None:
            return []

        src = []
        for index, source in enumerate(js.get('sources', []), start=1):
            url = source.get('url')
            url_base = re.match(r"(.*/)", url).group(1)
            try:
                r = httpx.get(url, timeout=15)
                if r.headers.get('Content-Type') == 'application/dash+xml':
                    continue
                _all = []
                for width, height, link in re.findall('RESOLUTION=([0-9]+)x([0-9]+).*\n(.*)\n?', r.text):
                    width = int(width)
                    height = int(height)
                    res = self.get_resolution_name(width, height)
                    _all.append([res, (width, height), url_base + link])

                melhores_resolucoes = {}
                for item in _all:
                    categoria, resolucao, arquivo = item
                    if categoria not in melhores_resolucoes or resolucao > melhores_resolucoes[categoria][1]:
                        melhores_resolucoes[categoria] = item
                lista = list(melhores_resolucoes.values())
                for item in lista:
                    src.append((item[0], item[2]))
            except Exception as e:
                print(f"Erro ao obter informações do canal: {e}")
                continue
        return src

    def format_channel_info(self, data):
        if isinstance(data, dict):
            data = [data]
        for channel in data:
            for index, content in enumerate(channel.get('links', []), start=1):
                resolution, link = content
                _id = f"{channel.get('id')}-{resolution.lower()}-{index}"
                name = f"{channel.get('name')} {resolution} #{index}"
                group = channel.get('group')
                self.new_channels.update({_id: {'name': name, 'group': group, 'link': link}})

    def get_globo_channels(self) -> list:
        channels = []
        for uf, lat, long, name in self.locations:
            info = self.get_channel_info('6120663', lat, long)
            if info:
                channels.append({
                    'id': f'globo-{uf.lower()}',
                    'name': name,
                    'group': "Canais | Globo",
                    'links': info
                })
        print(f"Canais encontrados para Globo: {len(channels)}")
        return channels

    def update_all_channels(self):
        print("Iniciando atualização de canais...")
        self.format_channel_info(self.get_globo_channels())
        self.channels = self.new_channels
        self.new_channels = {}
        print('Canais atualizados em', datetime.now().strftime('%d/%m/%Y às %H:%M:%S'))

    def format_channels(self, masked_key):
        channels = []
        for _id, data in self.channels.items():
            fmt = f'#EXTINF:-1 tvg-id="" tvg-name="{data.get("name")}" tvg-logo="" group-title="{data.get("group")}",{data.get("name")}\nhttp://45.89.30.203:8000/{masked_key}/play/{_id}.m3u8'
            channels.append(fmt)
        data = "\n".join(channels)
        content = f'#EXTM3U\n{data}'
        return content

    def format_single_channels(self, masked_key):
        channels = []
        already = []
        for _id in self.channels:
            data = self.channels[_id]
            name = re.sub(' #[0-9]+', '', data.get("name"))
            if name not in already:
                fmt = f'#EXTINF:-1 tvg-id="" tvg-name="{name}" tvg-logo="" group-title="{data.get("group")}",{name}\nhttp://45.89.30.203:8000/{masked_key}/play/{_id}.m3u8'
                channels.append(fmt)
                already.append(name)

        data = "\n".join(channels)
        content = f'#EXTM3U\n{data}'
        return content

    def __start(self):
        tm = 3600 * 3  # 3 horas
        while True:
            self.update_all_channels()
            time.sleep(tm)

    def start(self):
        Thread(target=self.__start).start()


globo = Globo()
globo.start()


@app.get('/{masked_key}/index.m3u')
async def index(masked_key: str):
    if masked_key not in masked_access_keys:
        raise HTTPException(status_code=403, detail='Acesso negado.')
    return Response(content=globo.format_channels(masked_key), media_type='application/x-mpegURL')


@app.get('/{masked_key}/single.m3u')
async def single(masked_key: str):
    if masked_key not in masked_access_keys:
        raise HTTPException(status_code=403, detail='Acesso negado.')
    return Response(content=globo.format_single_channels(masked_key), media_type='application/x-mpegURL')


@app.get('/{masked_key}/play/{id}.m3u8')
async def play(masked_key: str, id: str):
    if masked_key not in masked_access_keys:
        raise HTTPException(status_code=403, detail='Acesso negado.')

    if id not in globo.channels:
        raise HTTPException(status_code=404, detail='Canal não encontrado.')

    link = globo.channels[id]['link']
    url_base = re.match(r"(.*\/)", link).group(1)

    async with httpx.AsyncClient() as client:
        response = await client.get(link)
        if response.status_code == 200:
            content = response.text
            modified_content = re.sub(r'(\n)([^\n]+\.ts)', r'\1' + url_base + r'\2', content)
            return Response(content=modified_content, media_type=response.headers.get('Content-Type'))
        else:
            raise HTTPException(status_code=404, detail="Segmento de mídia não encontrado")


if __name__ == '__main__':
    uvicorn.run(
        app=app,
        host='0.0.0.0',
        port=8000,
        log_level="warning"  # Adicione esta linha
    )