#####################################################################
#                                                                   #
#  THIS IS A SOURCE CODE FILE FROM A PROGRAM TO INTERACT WITH THE   #
# LBRY PROTOCOL ( lbry.com ). IT WILL USE THE LBRY SDK ( lbrynet )  #
# FROM THEIR REPOSITORY ( https://github.com/lbryio/lbry-sdk )      #
# WHICH I GONNA PRESENT TO YOU AS A BINARY. SINCE I DID NOT DEVELOP #
# IT AND I'M LAZY TO INTEGRATE IN A MORE SMART WAY. THE SOURCE CODE #
# OF THE SDK IS AVAILABLE IN THE REPOSITORY MENTIONED ABOVE.        #
#                                                                   #
#      ALL THE CODE IN THIS REPOSITORY INCLUDING THIS FILE IS       #
# (C) J.Y.Amihud and Other Contributors 2021. EXCEPT THE LBRY SDK.  #
# YOU CAN USE THIS FILE AND ANY OTHER FILE IN THIS REPOSITORY UNDER #
# THE TERMS OF GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER    #
# VERSION. TO FIND THE FULL TEXT OF THE LICENSE GO TO THE GNU.ORG   #
# WEBSITE AT ( https://www.gnu.org/licenses/gpl-3.0.html ).         #
#                                                                   #
# THE LBRY SDK IS UNFORTUNATELY UNDER THE MIT LICENSE. IF YOU ARE   #
# NOT INTENDING TO USE MY CODE AND JUST THE SDK. YOU CAN FIND IT ON #
# THEIR OFFICIAL REPOSITORY ABOVE. THEIR LICENSE CHOICE DOES NOT    #
# SPREAD ONTO THIS PROJECT. DON'T GET A FALSE ASSUMPTION THAT SINCE #
# THEY USE A PUSH-OVER LICENSE, I GONNA DO THE SAME. I'M NOT.       #
#                                                                   #
# THE LICENSE CHOSEN FOR THIS PROJECT WILL PROTECT THE 4 ESSENTIAL  #
# FREEDOMS OF THE USER FURTHER, BY NOT ALLOWING ANY WHO TO CHANGE   #
# THE LICENSE AT WILL. SO NO PROPRIETARY SOFTWARE DEVELOPER COULD   #
# TAKE THIS CODE AND MAKE THEIR USER-SUBJUGATING SOFTWARE FROM IT.  #
#                                                                   #
#####################################################################

import os
import time
import urllib.request
import threading
import json

from subprocess import *
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib
from gi.repository import Pango
from gi.repository import GdkPixbuf
from PIL import Image, ImageSequence

from flbry import markdown
from flbry import data_view
from flbry import ui
from flbry import fetch
from flbry import claim_search
from flbry import comments
from flbry import follow
from flbry import publish
from flbry import analytics
from flbry import livestreams
from flbry import suggest
from flbry import odysee
from flbry import oscalls

def resolve(w, win, url):
    
    # This function will draw a widget of resolved url


    #####################################################
    #              RESOLVING PART ( NO GTK )            #
    #####################################################


    out = fetch.lbrynet("resolve",
                        {"urls":[url]}
    )
    out = out[url]


    # Saving the resolved thing into the win for later use
    win.resolved = out
    
    # out = check_output(["flbry/lbrynet",
    #                      "resolve", url])
    # raw_data = out.decode("utf-8")
    
    # # Now we want to parse the json

    # try:
    #     out = json.loads(out)
    #     out = out[url]
    # except:
    #     print("Resolve Failed")
    #     return False
    try:
        is_channel = "value_type" in out and out["value_type"] == "channel"
        percentage = downloaded(out["claim_id"])
    except:
        # If this fails we activate search
        return ["search", False, False, w, win, url, False]
    
    # make sure the url path starts with lbry://
    if not url.startswith("lbry://"):
        url = "lbry://"+url
        win.url.set_text(url)

    if is_channel:
        stream_data = livestreams.get_data(out["claim_id"])
    else:
        try:
            stream_data = livestreams.get_data(out["signing_channel"]["claim_id"])
        except:
            stream_data = {}

    # Aditional data
    out["address_is_mine"] = fetch.lbrynet("address_is_mine", {"address":out["address"]})
    out["supports_preview"] = fetch.lbrynet("support_abandon", {"claim_id":out["claim_id"],
                                                                "preview":True})
    
        
    return [out, is_channel, percentage, w, win, url, stream_data]

def render_resolve(data):

    out, is_channel, percentage, w, win,  url, stream_data = data


    # It could be failed
    if out == "search":
        return ui.load(win, claim_search.find, claim_search.render, win, win.url.get_text(), [], 1, {"order_by":""})

    
    
    #####################################################
    #              DRAWING PART ( GTK )                 #
    #####################################################
    try:
        price = out["value"]["fee"]["amount"]
    except:
        price = 0
    try:
        currency = out["value"]["fee"]["currency"]
    except:
        currency = "LBC"
    
        
    
    box = Gtk.HBox()
    outbox = Gtk.VBox()

    #### THUMBNAIL ###

    thumb = ""
    try:
        thumb = out["value"]["thumbnail"]["url"]
        thumb_url = ui.image_save_name(thumb)
        def thumb_open(w):
            oscalls.Open(thumb_url)

        thumb_button = Gtk.Button()
        thumb_button.set_tooltip_text(thumb)
        if is_channel:
            thumb_image = ui.load(win, ui.net_image_calculation, ui.net_image_render, thumb, 150, "", True)
        else:
            thumb_image = ui.load(win, ui.net_image_calculation, ui.net_image_render, thumb, 400,  "", True)
        thumb_button.add(thumb_image)
        thumb_button.set_relief(Gtk.ReliefStyle.NONE)
        thumb_button.connect("clicked", thumb_open)

        box.pack_start(thumb_button, False, False, False)
    except:
        pass
        
    outbox.pack_start(box, False, False, False)

    from_right_to_thumbnail = Gtk.VBox()
    box.pack_end(from_right_to_thumbnail, True, True, False)

    # If channel load banner
    if is_channel:
        if "cover" in out["value"]:

            # This is a hack to set the scroller at the center
            # of the cover image

            def render_cover(calc):

                # So this fucntion pretends to be the net_image_render
                
                r = ui.net_image_render(calc) # It does call it though

                # But we need the size of the image and we need to do
                # something after the image is loaded.

                def wait():

                    # This will execute after a delay
                    
                    v = channel_scroll.get_vadjustment()
                    h = channel_scroll.get_hadjustment()

                    # TODO: Check that the math is correct. It seems
                    # to move the scrolls a bit too far.
                    v.set_value( r.get_pixbuf().get_height() / 2 - 75)
                    h.set_value( r.get_pixbuf().get_width() / 2  - 100)
                    
                def start_waiting():

                    # This is the delay thread
                    
                    time.sleep(0.1)
                    GLib.idle_add(wait) # Making sure to use GLib so not
                                        # to get Segmentation Fault
                                        
                load_thread = threading.Thread(target=start_waiting)
                load_thread.start()

                # And we need to give the renderer the image itself, so it
                # could be added into the UI. 
                return r # This happens before we scroll to the center

                # So think about it:
                # 1. ui.load loads the ui.net_image_calclation which downloads the cover
                # 2. This function runs. Activating ui.net_image_render getting the Gtk.Image
                # 3. We setup the thread that waits for 0.1 seconds
                # 4. Meanwhile ui.load recieves the ui.image and window updates with it
                # 5. 0.1 seconds later: we calculate the width and height of the image
                #    and set the scroll adjustments accordilgly.

                # Simple isn't it?
                
            channel_banner = ui.load(win, ui.net_image_calculation, render_cover, out["value"]["cover"]["url"], False, "", True)
            channel_scroll = Gtk.ScrolledWindow()
            channel_scroll.set_size_request(400,150)
            channel_scroll.add_with_viewport(channel_banner)
            from_right_to_thumbnail.pack_start(channel_scroll, False, False, False)
        else:
            try:
                channel_scroll.destroy()
            except:
                pass
            
    
    #### NAME / CHANNEL ####

    the_packing_box = from_right_to_thumbnail
    if is_channel:
        the_packing_box = outbox
    
    name_channel_box = Gtk.VBox()
    the_packing_box.pack_start(name_channel_box, False, False, False)

    # Channel

    if "signing_channel" in out:
        chbox = Gtk.HBox()
        name_channel_box.pack_start(chbox, False, False, 0)
        chbox.pack_start(ui.go_to_channel(win, out["signing_channel"]),True,True,False)
        
        fbutton = follow.button(win, out["signing_channel"]["permanent_url"])
        chbox.pack_start(fbutton, False, False, 0 )

    elif is_channel:
        fbutton = follow.button(win, out["permanent_url"])
        name_channel_box.pack_start(fbutton, False, False, False)
        
    # name it self
    title = out["name"]
    try:
        title = out["value"]["title"]
    except:
        pass
    title_label = Gtk.Label()
    title_label.set_line_wrap_mode( Gtk.WrapMode.WORD )
    title_label.set_line_wrap(True)
    title_label.set_markup('<span size="x-large">  '+title+'</span> ')
    title_label.set_selectable(True)
    title_label.set_css_name("")
    name_channel_box.pack_start(title_label, False, False, False)

    ################# TOOL BAR ##################

    print("streamdata          ++++++++++++++++++++++++++++++++++++       ", stream_data)

    toolbox = Gtk.HBox()
    the_packing_box.pack_start(toolbox, False, False,False)

    # The channel might be live from a different publication. I want to give a button to resolve it.
    active_id = stream_data.get("data",{}).get("ActiveClaim", {}).get("ClaimID", "")
    if stream_data.get("data",{}).get("Live", False) and active_id != out["claim_id"]:
        
        live_elsewhere_box = Gtk.HBox()
        the_packing_box.pack_start(Gtk.HSeparator(), False, False, 5)
        the_packing_box.pack_start(live_elsewhere_box, False, False,False)

        live_elsewhere_box.pack_start(Gtk.VSeparator(), 0,0,10)
        live_elsewhere_box.pack_start(ui.icon(win, "dialog-warning"), 0,0,0)
        
        live_elsewhere_box.pack_start(Gtk.Label(" Currently Streaming! "), 0,0,0)

        def go_to_livestream(widget):
            resolve_url = fetch.lbrynet("claim_search", {"claim_id":active_id}).get("items", [{}])[0].get("canonical_url","")
            win.resolve_tab = "new_tab"
            win.url.set_text(resolve_url)
            win.url.activate()
            
        go_button = Gtk.Button()
        go_button.set_relief(Gtk.ReliefStyle.NONE)
        go_box = Gtk.HBox()
        go_button.add(go_box)
        go_box.pack_start(ui.icon(win, "go-jump"), 0,0,0)
        go_box.pack_start(Gtk.Label(" Go To Livestream "),0,0,0)
        go_button.connect("clicked", go_to_livestream)
        live_elsewhere_box.pack_start(go_button, 0,0,0)
        

    if not is_channel:

        # LIVESTREAM LAUNCH
        if stream_data.get("data",{}).get("Live", False) and active_id == out["claim_id"]:
            def live_launch_action(w):
                suggest.record_tags_to_suggestions(out.get("value", {}).get("tags", []))
                Popen([win.settings["live_stream_player"], win.settings["librarian_instance"]+"/live/content/"+out["signing_channel"]["claim_id"]+"/master.m3u8"])

            live_launch_button = Gtk.Button()
            live_launch_button.connect("clicked", live_launch_action)
            live_launch_button.set_relief(Gtk.ReliefStyle.NONE)
            live_launch_box = Gtk.HBox()
            live_launch_button.add(live_launch_box)
            live_launch_icon = ui.icon(win, "media-playback-start")
            live_launch_box.pack_start(live_launch_icon, False, False, False)
            live_launch_box.pack_start(Gtk.Label("  Watch Livestream  "), False, False, False)
            toolbox.pack_start(live_launch_button, False,False,False)
        else:


            def download_action(w):
                suggest.record_tags_to_suggestions(out.get("value", {}).get("tags", []))
                start_downloading(url)

            download_button = Gtk.Button()
            download_button.connect("clicked", download_action)
            download_button.set_relief(Gtk.ReliefStyle.NONE)
            download_box = Gtk.HBox()
            download_button.add(download_box)
            download_icon = ui.icon(win, "go-down")
            download_box.pack_start(download_icon, False, False, False)
            #filesize
            labeltext = "  Download"
            if price:
                labeltext = "  Buy for "+str(price)+" "+currency
            try:
                filesize = out["value"]["source"]["size"]
                labeltext = labeltext + " ("+csize(filesize)+")"
            except:
                filesize = 0

            download_box.pack_start(Gtk.Label(labeltext), False, False, False)
            toolbox.pack_start(download_button, False,False,False)

            download_bar = Gtk.ProgressBar()
            the_packing_box.pack_start(download_bar, False, False,False)

            def delete_action(w):
                filename = get_downloaded_file(out["claim_id"])
                delete_file(out["claim_id"])

                try:
                    os.remove(filename)
                except:
                    pass

            delete_button = Gtk.Button()
            delete_button.connect("clicked", delete_action)
            delete_button.set_relief(Gtk.ReliefStyle.NONE)
            delete_box = Gtk.HBox()
            delete_button.add(delete_box)
            delete_icon = ui.icon(win,"edit-delete")
            delete_box.pack_start(delete_icon, False, False, False)
            delete_box.pack_start(Gtk.Label("  Delete  "), False, False, False)
            toolbox.pack_start(delete_button, False,False,False)

            def launch_action(w):
                oscalls.Open(get_downloaded_file(out["claim_id"]))

            launch_button = Gtk.Button()
            launch_button.connect("clicked", launch_action)
            launch_button.set_relief(Gtk.ReliefStyle.NONE)
            launch_box = Gtk.HBox()
            launch_button.add(launch_box)
            launch_icon = ui.icon(win, "media-playback-start")
            launch_box.pack_start(launch_icon, False, False, False)
            launch_box.pack_start(Gtk.Label("  Launch  "), False, False, False)
            toolbox.pack_start(launch_button, False,False,False)




            win.download_buttons[out["claim_id"]] = True

            t = threading.Thread(target=downloading_check_thread, args=(win, out["claim_id"],download_button, delete_button, launch_button, download_bar))
            t.setDaemon(True)
            t.start()
            def kill_daemon(w):
                win.download_buttons[out["claim_id"]] = False
            download_button.connect("destroy", kill_daemon)

    #################### REPOST BUTTON #######################

    try:
    
        toolbox.pack_start(Gtk.HSeparator(), False,False,5)

        def repost_action(w):
            # If name is empty, show message and let user input a new
            # value without hiding the popup
            if repost_name_entry.get_text() == "":
                ui.simple_message_box("Name is empty",
                    "Name cannot be empty. Please enter something and try again.")
                return
            print("name", repost_name_entry.get_text())
            print("bid", repost_bid_entry.get_value())
            print("channel", win.channel["name"])
            print("channel_id", win.channel["claim_id"])

            repost_out = fetch.lbrynet("stream_repost",
                                       {"name":repost_name_entry.get_text(),
                                        "bid":str(float(repost_bid_entry.get_value())),
                                        "claim_id":out["claim_id"],
                                        "channel_id":win.channel["claim_id"]})
            print(repost_out)
            if "error" in repost_out:
                ui.notify(win, "Error while reposting", str(repost_out["error"]))
            else:
                ui.notify(win, "Reposted succesfully.", "lbry://"+win.channel["name"]+"/"+repost_name_entry.get_text())

            repost_menu.hide()
                
        repost_menu = Gtk.Popover()
        # Make the re-post popup show at the bottom of the button
        repost_menu.set_position(Gtk.PositionType.BOTTOM)
        repost_menu_box = Gtk.VBox()
        repost_menu.add(repost_menu_box)

        # Repost requires 3 entries of data:

        # Name:
        def on_url(w):
            w.set_text(publish.lbryname(w.get_text(), force=False))
        repost_name_box = Gtk.HBox()
        repost_menu_box.pack_start(repost_name_box, 0,0,0)
        channel_name = win.channel.get("name", "")
        repost_name_box_label = Gtk.Label("  lbry://")
        repost_name_box.pack_start(repost_name_box_label, 0,0,0)
        repost_name_entry = Gtk.Entry()
        repost_name_entry.connect("changed", on_url)
        repost_name_box.pack_start(repost_name_entry, 1,1,0)

        # Bid:
        repost_bid_box = Gtk.HBox()
        repost_menu_box.pack_start(repost_bid_box, 0,0,0)

        bid_adjust = Gtk.Adjustment(0.01,
                                lower=0.0001,
                                upper=1000000000,
                                step_increment=0.1) 
        repost_bid_entry  = Gtk.SpinButton(adjustment=bid_adjust,
                                    digits=4)

        repost_bid_box.pack_start(Gtk.Label("  Bid:  "), False, False, 0)
        repost_bid_box.pack_end(repost_bid_entry, False, False, 0)

        # Repost button
        do_repost_button = Gtk.Button()
        do_repost_button.connect("clicked", repost_action)
        do_repost_button.set_relief(Gtk.ReliefStyle.NONE)
        do_repost_box = Gtk.HBox()
        do_repost_box.pack_start(ui.icon(win, "media-playlist-repeat"), 0,0,0)
        do_repost_box.pack_start(Gtk.Label("  Do Re-Post  "), False, False, False)
        do_repost_button.add(do_repost_box)
        repost_menu_box.pack_start(do_repost_button, 0,0,0)


        repost_menu_box.show_all()

        repost_button = Gtk.Button()
        repost_menu.set_relative_to(repost_button)

        repost_button.set_relief(Gtk.ReliefStyle.NONE)
        repost_box = Gtk.HBox()
        repost_button.add(repost_box)
        repost_icon = ui.icon(win, "media-playlist-repeat")
        repost_box.pack_start(repost_icon, False, False, False)
        try:
            reposted_times = out["meta"]["reposted"]
            if not reposted_times:
                1/0 # kill switch to go straig to except LOL. I'm hacking. What
                    # do you want from me.
            repost_label = "  Re-Post ( "+str(reposted_times)+" )  "
        except:
            repost_label = "  Re-Post  "
        repost_box.pack_start(Gtk.Label(repost_label), False, False, False)
        def repost_button_action(button, event):
            # If:
            # - mouse clicked or
            # - key pressed
            #   - either space (32)
            #   - or enter (65293)
            if isinstance(event, Gdk.EventButton) or ( isinstance(event, Gdk.EventKey) and (event.keyval == 32 or event.keyval == 65293) ):
                channel_name = win.channel.get("name", "")
                # Show current channel name on label (not editable by user)
                repost_name_box_label.set_text("  lbry://"+channel_name+"/")
                # Show name of Re-Post (editable by user)
                repost_name_entry.set_text(out["normalized_name"])
                # Show Re-Post popup
                repost_menu.popup()
        # Capture mouse events on Re-Post button
        repost_button.connect("button-release-event", repost_button_action)
        # Capture key presses on Re-Post button (enter, space)
        repost_button.connect("key-release-event", repost_button_action)
        toolbox.pack_start(repost_button, False,False,False)

    except Exception as e:
        print("Re-Post error: ", e)

    ############# SUPPORT BUTTON ############

    support_menu = Gtk.Popover()
    support_menu_box = Gtk.VBox()
    support_menu.add(support_menu_box)
    

     # Bid:
    support_bid_box = Gtk.HBox()
    support_menu_box.pack_start(support_bid_box, 0,0,0)

    support_bid_adjust = Gtk.Adjustment(0.01,
                            lower=0.0001,
                            upper=1000000000,
                            step_increment=0.1) 
    support_bid_entry  = Gtk.SpinButton(adjustment=support_bid_adjust,
                                digits=4)

    support_bid_box.pack_start(Gtk.Label("  Amount:  "), False, False, 0)
    support_bid_box.pack_end(support_bid_entry, False, False, 0)

    # Do button
    def support_action(w):
        print("support amount", support_bid_entry.get_value())
        print("channel", win.channel["name"])
        print("channel_id", win.channel["claim_id"])

        support_out = fetch.lbrynet("support_create",
                                   {"amount":str(float(support_bid_entry.get_value())),
                                    "claim_id":out["claim_id"],
                                    "channel_id":win.channel["claim_id"],
                                    "tip":True})
        print(support_out)
        if "error" in support_out:
            ui.notify(win, "Error while reposting", str(support_out["error"]))
        else:
            ui.notify(win, "Supported succesfully.")

        support_menu.hide()

    
    do_support_button = Gtk.Button()
    do_support_button.connect("clicked", support_action)
    do_support_button.set_relief(Gtk.ReliefStyle.NONE)
    do_support_box = Gtk.HBox()
    do_support_box.pack_start(ui.icon(win, "emblem-favorite"), 0,0,0)
    do_support_box.pack_start(Gtk.Label("  Do Support  "), False, False, False)
    do_support_button.add(do_support_box)
    support_menu_box.pack_start(do_support_button, 0,0,0)
    
    support_menu_box.show_all()

    support_button = Gtk.MenuButton(popover=support_menu)

    support_button.set_relief(Gtk.ReliefStyle.NONE)
    support_box = Gtk.HBox()
    support_button.add(support_box)
    support_icon = ui.icon(win, "emblem-favorite")
    support_box.pack_start(support_icon, False, False, False)
    try:
        rounded = round(float(out["meta"]["effective_amount"]), 2)
        if not rounded:
            rounded = out["meta"]["effective_amount"]
        support_label = "  Support ( "+str(rounded)+" )  "
    except Exception as e:
        print(e)
        support_label = "  Support  "
    support_box.pack_start(Gtk.Label(support_label), False, False, False)
    toolbox.pack_start(support_button, False,False,False)


    ############# ADITIONAL MENU #############


    aditional_menu = Gtk.Popover()
    aditional_menu_box = Gtk.VBox()
    aditional_menu.add(aditional_menu_box)

    aditional_menu_button = Gtk.MenuButton(popover=aditional_menu)
    aditional_menu_button.add(ui.icon(win, "view-more"))
    aditional_menu_button.set_relief(Gtk.ReliefStyle.NONE)
    toolbox.pack_end(aditional_menu_button, False,False,False)

    # If the publication is mine.
    

    ## Unlock Tips ##
    unlock_menu = Gtk.Popover()
    unlock_menu_box = Gtk.VBox()
    unlock_menu.add(unlock_menu_box)

    unlock_button = Gtk.MenuButton(popover=unlock_menu)
    unlock_button.set_relief(Gtk.ReliefStyle.NONE)
    unlock_bbox = Gtk.HBox()
    unlock_button.add(unlock_bbox)
    unlock_bbox.pack_start(ui.icon(win, "insert-object-symbolic"), 0,0,0)
    unlock_bbox.pack_start(Gtk.Label("Unlock Tips"), 0,0,5)
    aditional_menu_box.pack_start(unlock_button, 0,0,5)

    unlockable = float(out["supports_preview"].get("total_output", 0))
    unlock_menu_box.pack_start(Gtk.Label("  You can unlock up to: "+str(unlockable)+" LBC  "), 0,0,5)

    unlock_counter_box = Gtk.HBox()
    unlock_menu_box.pack_start(unlock_counter_box, 0,0,5)

    unlock_amount_adjust = Gtk.Adjustment(0.01,
                                        lower=0,
                                        upper=unlockable,
                                        step_increment=0.1) 
    unlock_amount_entry  = Gtk.SpinButton(adjustment=unlock_amount_adjust,
                                        digits=4)
    unlock_counter_box.pack_start(Gtk.Label("  Unlock:"), 0,0,5)
    unlock_counter_box.pack_end(unlock_amount_entry, 0,0,5)

    def do_unlock_action(w):
        result = fetch.lbrynet("support_abandon", {"claim_id":out["claim_id"],
                                                   "keep": str(unlockable - unlock_amount_entry.get_value())})
        print("\n\nUNLOCKING RESULT:\n\n", result, "\n\n")
        unlock_menu.hide()
        aditional_menu.hide()
        
    do_unlock_button = Gtk.Button()
    do_unlock_button.set_relief(Gtk.ReliefStyle.NONE)
    do_unlock_button.connect("clicked", do_unlock_action)
    do_unlock_box = Gtk.HBox()
    do_unlock_button.add(do_unlock_box)
    do_unlock_box.pack_start(ui.icon(win, "insert-object-symbolic"), 0,0,0)
    do_unlock_box.pack_start(Gtk.Label("  Do Unlock  "), 0,0,0)
    unlock_menu_box.pack_start(do_unlock_button, 0,0,5)

    
    unlock_menu_box.show_all()



    ## Share ##
    share_menu = Gtk.Popover()
    share_menu_box = Gtk.VBox()
    share_menu_box.set_size_request(600, -1)
    share_menu.add(share_menu_box)

    share_button = Gtk.MenuButton(popover=share_menu)
    share_button.set_relief(Gtk.ReliefStyle.NONE)
    share_bbox = Gtk.HBox()
    share_button.add(share_bbox)
    share_bbox.pack_start(ui.icon(win, "emblem-shared-symbolic"), 0,0,0)
    share_bbox.pack_start(Gtk.Label("Share"), 0,0,5)
    aditional_menu_box.pack_start(share_button, 0,0,5)

    # LBRY share #

    def do_share_lbry_copy(w):
        share_lbry_entry.grab_focus()
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        clipboard.set_text(share_lbry_entry.get_text(), -1)
        clipboard.store()

    share_lbry_box = Gtk.HBox()
    share_menu_box.pack_start(share_lbry_box, 0,0,5)
    share_lbry_entry = Gtk.Entry(text=url)
    share_lbry_entry.set_editable(False)
    share_lbry_box.pack_start(Gtk.Label("  LBRY:"), 0,0,5)
    share_lbry_box.pack_start(share_lbry_entry, 1,1,5)
    share_lbry_copy_button = Gtk.Button()
    share_lbry_copy_button.connect("clicked", do_share_lbry_copy)
    share_lbry_copy_button.add(ui.icon(win, "edit-copy"))
    share_lbry_copy_button.set_relief(Gtk.ReliefStyle.NONE)
    share_lbry_box.pack_end(share_lbry_copy_button, 0,0,5)

    # Librarian share #

    def do_share_librarian_copy(w):
        share_librarian_entry.grab_focus()
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        clipboard.set_text(share_librarian_entry.get_text(), -1)
        clipboard.store()

    share_librarian_box = Gtk.HBox()
    share_menu_box.pack_start(share_librarian_box, 0,0,5)
    share_librarian_entry = Gtk.Entry(text=publish.librarian_url(url, win.settings["librarian_instance"]))
    share_librarian_entry.set_editable(False)
    share_librarian_box.pack_start(Gtk.Label("  Librarian:"), 0,0,5)
    share_librarian_box.pack_start(share_librarian_entry, 1,1,5)
    share_librarian_copy_button = Gtk.Button()
    share_librarian_copy_button.connect("clicked", do_share_librarian_copy)
    share_librarian_copy_button.add(ui.icon(win, "edit-copy"))
    share_librarian_copy_button.set_relief(Gtk.ReliefStyle.NONE)
    share_librarian_box.pack_end(share_librarian_copy_button, 0,0,5)



    share_menu_box.show_all()



    

    aditional_menu_box.show_all()

    
    ########### BOTTOM NOTEBOOK ##############

    notebook = Gtk.Notebook()
    notebook.set_scrollable(True)
    outbox.pack_start(notebook, True, True,False)


    
        
    
    # If article read article
    try:
        if out["value"]["source"]["media_type"] == "text/markdown" and price == 0:

            suggest.record_tags_to_suggestions(out.get("value", {}).get("tags", []))
            
            # We download it first
            
            playout = fetch.lbrynet("get", {"uri":url, "save_file":True})

            # playout = check_output(["flbry/lbrynet",
            #                             "get", url])
            # # Parsing the Json
            # playout = json.loads(playout)

            md_text = open(playout['download_path'])
            
            md_text = md_text.read()

            
            

            # Markdown covenreted
            md_scrl = Gtk.ScrolledWindow()
            md_view = Gtk.TextView()
            md_view.set_wrap_mode(Gtk.WrapMode.WORD )
            md_buffer = md_view.get_buffer()
            md_view.set_editable(False)
            md_scrl.add(md_view)
            md_buffer.set_text(md_text)
            markdown.convert(win, md_view)
            detailsbox = Gtk.HBox()
            detailsbox.pack_start(ui.icon(win, "text-x-generic"), False, False, False)
            detailsbox.pack_start(Gtk.Label("  Read Article  "), True, True, True)
            detailsbox.show_all()
            notebook.append_page(md_scrl, detailsbox)

            # Markdown source
            md_scrl = Gtk.ScrolledWindow()
            md_view = Gtk.TextView()
            #md_view.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.2,0.2,0.2, 1))
            #md_view.override_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.9,0.9,0.9, 1))
            md_view.override_font(Pango.FontDescription("Monospace"))
            md_view.set_wrap_mode(Gtk.WrapMode.WORD )
            md_buffer = md_view.get_buffer()
            md_view.set_editable(False)
            md_scrl.add(md_view)
            md_buffer.set_text(md_text)
            detailsbox = Gtk.HBox()
            detailsbox.pack_start(ui.icon(win, "text-x-preview"), False, False, False)
            detailsbox.pack_start(Gtk.Label("  Source of Article  "), True, True, True)
            detailsbox.show_all()
            notebook.append_page(md_scrl, detailsbox)

            
    except Exception as e:
        print("FUCKING ERROR")
        print(e)
        print()

    # Channel Uploads / Publications
    
    if is_channel:

        uploads_box = ui.load(win, claim_search.find, claim_search.render, win, "", [out["claim_id"]], )
        detailsbox = Gtk.HBox()
        detailsbox.pack_start(ui.icon(win, "folder-remote"), False, False, False)
        detailsbox.pack_start(Gtk.Label("  Publications  "), True, True, True)
        detailsbox.show_all()
        notebook.append_page(uploads_box, detailsbox)
        
    
    ##### DESCRIPTION ####
    
    try:
        description_scrl = Gtk.ScrolledWindow()
        description_scrl.set_size_request(500,200)
        description_field = Gtk.TextView()
        description_field.set_wrap_mode(Gtk.WrapMode.WORD )
        description_field.set_editable(False)
        description_buffer = description_field.get_buffer()
        description_buffer.set_text(out["value"]["description"])
        markdown.convert(win, description_field)

        description_box = Gtk.VBox()
        detailsbox = Gtk.HBox()
        detailsbox.pack_start(ui.icon(win, "text-x-generic"), False, False, False)
        detailsbox.pack_start(Gtk.Label("  Description  "), True, True, True)
        detailsbox.show_all()
        notebook.append_page(description_scrl, detailsbox)
        
        description_box.pack_start(description_scrl, False, False, False)
        description_scrl.add(description_field)
    except:
        pass

    ######## COMMENTS ########

    
    com_box = Gtk.VPaned()
    com_box.set_position(250)
    com_scrl = Gtk.ScrolledWindow()
    com_scrl.set_vexpand(0)
    #com_scrl.set_hexpand(0)
    comments_widget = ui.load(win, comments.list_comments, comments.render_comments, win, out )
    com_scrl.add(comments_widget)
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(ui.icon(win, "document-send"), False, False, False)
    detailsbox.pack_start(Gtk.Label("  Comments  "), True, True, True)
    detailsbox.show_all()
    com_box.add1(comments.comment_input(win, out["claim_id"]))
    com_box.add2(com_scrl)
    notebook.append_page(com_box, detailsbox)

    
    ##### Details  #######

    # Almost like Raw Data but shows only the important stuff

    
    details = {"LBRY URL: ":url,
               "Price: ":str(price)+" "+str(currency)}
    try:
        details["Claim ID: "] = out["claim_id"]
    except:
        pass

    try:
        details["Upload Bid: "] = out["amount"]+" LBC"
    except:
        pass

    try:
        details["Support: "] = out["meta"]["support_amount"]+" LBC"
    except:
        pass

    try:
        if is_channel:
            details["Odysee Subscribers: "] = odysee.get_odysee_subs(win, out["claim_id"])[0]
        else:
            details["Odysee Views: "] = odysee.get_odysee_views(win, out["claim_id"])[0]
    except:
        pass
    
    try:
        details["Filename: "] = out["value"]["source"]["name"]
    except:
        pass
    try:
        details["File Size:"] = csize(filesize)
    except:
        pass
    try:
        details["License: "] = out["value"]["license"]
    except:
        pass

    try:
        details["Released at: "] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(out["value"]["release_time"])))
    except:
        pass

    try:
        #print(out["value"]["tags"])
        details["Tags: "] = out["value"]["tags"] 
    except:
        pass
    
    det_scrl = Gtk.ScrolledWindow()
    det_view = data_view.data_widget(details)
    det_scrl.add(det_view)
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(ui.icon(win, "dialog-information"), False, False, False)
    detailsbox.pack_start(Gtk.Label("  Details  "), True, True, True)
    detailsbox.show_all()
    notebook.append_page(det_scrl, detailsbox)

    ######### ANALYTICS GRAPH #######
    
    plot_chart =  fetch.lbrynet("txo_plot", { "days_back":1000, # Fetch 100 days of txo
                                              "exclude_internal_transfers":True, # Without crap
                                              "is_not_my_input":True, # Not from me ( as in support only )
                                              "claim_id":out["claim_id"]
         })
    if plot_chart:

        chart_box = Gtk.VBox()
        detailsbox = Gtk.HBox()
        detailsbox.pack_start(ui.icon(win, "text-csv"), False, False, False)
        detailsbox.pack_start(Gtk.Label("  Analytics  "), True, True, True)
        detailsbox.show_all()
        notebook.append_page(chart_box, detailsbox)

        graph_data = {"items":[],
                      "zoom":[0,0],
                      "allow_negative":False
        }
        
        for i in plot_chart:

             a = {}
             a["amount"] = i["total"]
             a["timestamp"] = int(time.mktime(time.strptime(i["day"],"%Y-%m-%d")))

             graph_data["items"].append(a)
            
        
        the_graph = analytics.graph(win, graph_data, "Analytics")
        chart_box.pack_start(the_graph,1,1,1)

    try:

        t = title
        if is_channel:
            t = ""
            
        uploads_box = ui.load(win, claim_search.find, claim_search.render, win, t, [], 1, {"any_tags":out["value"]["tags"] , "claim_type":out["value_type"]} )
        detailsbox = Gtk.HBox()
        detailsbox.pack_start(ui.icon(win, "folder-remote"), False, False, False)
        detailsbox.pack_start(Gtk.Label("  Similar  "), True, True, True)
        detailsbox.show_all()
        notebook.append_page(uploads_box, detailsbox)
    except:
        pass
        
    ##### Raw Data #######

    raw_scrl = Gtk.ScrolledWindow()
    raw_view = data_view.data_widget(out)
    raw_scrl.add(raw_view)
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(ui.icon(win, "dialog-warning"), False, False, False)
    detailsbox.pack_start(Gtk.Label("  Extra Details  "), True, True, True)
    detailsbox.show_all()
    notebook.append_page(raw_scrl, detailsbox)


    
    
    #outbox.show_all()
    return outbox



def downloaded(claim_id):

    # Returns a fraction ( from 0 to 1 ) of the download
    # percentage. If it's a 0, we can use it to display
    # the download button.

    #out = check_output(["flbry/lbrynet",
    #                     "file", "list", "--claim_id="+claim_id])
    out = fetch.lbrynet("file_list", {"claim_id":claim_id})
    #print(out, '\n\n')
    
    try:
        #out = json.loads(out)
        out = out["items"][0]
        
        if out["status"] == "finished":
            return 1
        else:
            return out["written_bytes"] / out["total_bytes"]
        
    except:
        return 0

def get_downloaded_file(claim_id):

    #out = check_output(["flbry/lbrynet",
    #                     "file", "list", "--claim_id="+claim_id])
    out = fetch.lbrynet("file_list", {"claim_id":claim_id})

    try:
        #out = json.loads(out)
        out = out["items"][0]

        return out["download_path"]
    except:
        return ""

def delete_file(claim_id):
    #check_output(["flbry/lbrynet",
    #                     "file", "delete", "--claim_id="+claim_id])
    fetch.lbrynet("file_delete", {"claim_id":claim_id})
def start_downloading(url):
    out = fetch.lbrynet("get", {"uri":url, "save_file":True})
    
def downloading_check_thread(win, claim_id,
                             download_button,
                             delete_button,
                             launch_button,
                             progress_bar):

    # This is a thread that will toggle buttons on/off
    # based on a curretly downloading file.

    def update(fraction):
        if not fraction: # if it's 0
            download_button.set_visible(True)
            delete_button.set_visible(False)
            launch_button.set_visible(False)
            progress_bar.set_visible(False)
        else:
            download_button.set_visible(False)
            delete_button.set_visible(True)
            launch_button.set_visible(True)
            progress_bar.set_visible(True)
            progress_bar.set_fraction(fraction)
        if fraction == 1:
            progress_bar.set_visible(False)
    
    while True:
        
        fraction = downloaded(claim_id)
        GLib.idle_add(update, fraction)
        time.sleep(2) # The new algorithm is too fast LOL

        if not win.download_buttons[claim_id]:
            return
def csize(x):

    x = float(x)

    l = ["B","KB", "MB", "GB", "TB"]

    for i in range(5):
        if x > 1024:
            x = x / 1024
        else:
            return str(round(x, 2))+" "+l[i]
    return str(round(x, 2))+" "+l[i]
