Add files from 6a34355fda commit of FastLBRY-GTK notabug.org repo by jyamihud without the flbry/lbrynet binary
989 lines
32 KiB
Python
989 lines
32 KiB
Python
#####################################################################
|
|
# #
|
|
# 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. #
|
|
# #
|
|
#####################################################################
|
|
|
|
# Preparing the executable of lbrynet to be running. If we don't that
|
|
# there will be a nasty error of permission being denied.
|
|
|
|
import os
|
|
os.system("chmod u+x flbry/lbrynet")
|
|
|
|
# I'm not trying to make it pretty. I'm trying to make it snappy.
|
|
# It's FastLBRY not SlowLBRY.
|
|
|
|
import gi
|
|
import threading
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk
|
|
from gi.repository import Gdk
|
|
from gi.repository import GLib
|
|
|
|
# It's gonna take a couple of things to make the button run
|
|
from flbry import connect
|
|
from flbry import parse
|
|
from flbry import settings
|
|
from flbry import url
|
|
from flbry import ui
|
|
from flbry import claim_search
|
|
from flbry import fetch
|
|
from flbry import publish
|
|
from flbry import downloads
|
|
from flbry import analytics
|
|
from flbry import livestreams
|
|
from flbry import suggest
|
|
from flbry import odysee
|
|
|
|
settings.make_sure_file_exists()
|
|
|
|
##########################################################################
|
|
# #
|
|
# THE MAIN WINDOW OF FASTLBRY GTK #
|
|
# #
|
|
##########################################################################
|
|
|
|
win = Gtk.Window() # Make a GTK window object
|
|
win.connect("destroy", Gtk.main_quit) # If you close the window, program quits
|
|
win.set_title("FastLBRY GTK") # Title
|
|
win.set_default_icon_from_file("icon.png") # Icon
|
|
win.set_size_request(800, 700) # Minimum size
|
|
|
|
##########################################################################
|
|
# #
|
|
# GLOBAL VARIABLES HACK ( adding things to 'win' ) #
|
|
# #
|
|
##########################################################################
|
|
|
|
# This hack is very simple. Our main Gtk.Window() is a class to which we
|
|
# can add variables later on. Like the example you see below.
|
|
# This way, giving some function only 'win' and nothing else, will give
|
|
# that other function the entire list of global variable ( added this way ).
|
|
|
|
win.settings = settings.load() # Settings
|
|
win.SDK_running = connect.check() # Is the SDK running ( from 0 to 1 to draw progress bar)
|
|
win.resolved = {} # Last resolved data
|
|
win.commenting = {} # Data for while chatting in comments
|
|
win.subs = [] # What you are subscribed to
|
|
win.tabs = [] # List of Gtk.Notebook tabs
|
|
win.resolve_tab = 0 # What tab to resolve the page
|
|
win.notebook = Gtk.Notebook() # Tabs object
|
|
win.download_buttons = {} # Keep alive handlers for Download buttons
|
|
win.downloads = {} # Data for the Downloads window
|
|
|
|
##########################################################################
|
|
# #
|
|
# TOP PANNEL #
|
|
# #
|
|
##########################################################################
|
|
|
|
# Gtk.HeaderBar() is like a box but it draws itself in the headerbar insead
|
|
# of in the window itself.
|
|
|
|
pannel = Gtk.HeaderBar()
|
|
pannel.set_show_close_button(True)
|
|
win.set_titlebar(pannel) # Dumbasses wrote GTK
|
|
|
|
# Untill the user connected to the SDK, search and other functions should
|
|
# not work. So we split the pannel into two parts. The other one is a
|
|
# normal box.
|
|
|
|
restofpannel = Gtk.HBox() # H for Horrizontal
|
|
pannel.pack_end(restofpannel)
|
|
|
|
|
|
############## CONNECT BUTTON ################
|
|
|
|
# Connect button will also be a disconnect button
|
|
|
|
|
|
# Icons for both
|
|
icon_connect = ui.icon(win, "network-wired")
|
|
icon_disconnect = ui.icon(win, "network-wired-disconnected")
|
|
|
|
# Boxes for both
|
|
connect_box = Gtk.HBox()
|
|
disconnect_box = Gtk.HBox()
|
|
|
|
# Connect box
|
|
connect_box.pack_start(icon_connect, False, False, False)
|
|
connect_box.set_tooltip_text("Connect to LBRY Network")
|
|
connect_box.pack_start(Gtk.Label("Connect "), False, False, False)
|
|
|
|
# Disconnect box
|
|
disconnect_box.pack_start(icon_disconnect, False, False, False)
|
|
disconnect_box.set_tooltip_text("Disconnect from LBRY Network")
|
|
disconnect_box.pack_start(Gtk.Label("Disconnect "), False, False, False)
|
|
|
|
# By whether SDK was running while the software was launched
|
|
# we present the correct button to the user and set the rest-of-pannel
|
|
# accordingly.
|
|
|
|
if win.SDK_running:
|
|
title = disconnect_box
|
|
restofpannel.set_sensitive(True)
|
|
else:
|
|
title = connect_box
|
|
restofpannel.set_sensitive(False)
|
|
|
|
|
|
connect_disconncet_button = Gtk.Button()
|
|
connect_disconncet_button.add(title)
|
|
connect_disconncet_button.set_relief(Gtk.ReliefStyle.NONE)
|
|
pannel.pack_start(connect_disconncet_button)#, False, False, False)
|
|
|
|
############### CONNECT / DISCONNECT BUTTONS FUNCTION ################
|
|
|
|
# The button should do something.
|
|
|
|
def connect_disconnect_function(w):
|
|
|
|
w.set_sensitive(False)
|
|
|
|
dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
progress_connect = Gtk.ProgressBar(show_text=True)
|
|
dynamic_box.pack_start(progress_connect, True, True, 30)
|
|
win.show_all()
|
|
|
|
def do_sdk(w, pb):
|
|
wasrunning = win.SDK_running
|
|
if win.SDK_running == 1:
|
|
connect.stop(win)
|
|
|
|
else:
|
|
connect.start(win)
|
|
|
|
def update_pb(pb):
|
|
pb.set_fraction(win.SDK_running)
|
|
pb.set_text("Connecting: "+str(int(round(win.SDK_running*100)))+"%")
|
|
|
|
def update_buttons(w):
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
w.get_child().destroy()
|
|
if win.SDK_running == 1:
|
|
w.add(disconnect_box)
|
|
restofpannel.set_sensitive(True)
|
|
else:
|
|
w.add(connect_box)
|
|
restofpannel.set_sensitive(False)
|
|
w.show_all()
|
|
w.set_sensitive(True)
|
|
if win.SDK_running == 1:
|
|
load_following()
|
|
load_channel(win)
|
|
check_lock_button()
|
|
ui.notify(win, "Connected to LBRY")
|
|
|
|
if wasrunning == 0:
|
|
while True:
|
|
win.SDK_running = connect.check()
|
|
if win.SDK_running == 1:
|
|
break
|
|
GLib.idle_add(update_pb, pb)
|
|
|
|
GLib.idle_add(update_buttons, w)
|
|
|
|
|
|
load_thread = threading.Thread(target=do_sdk, args=(w, progress_connect))
|
|
load_thread.setDaemon(True)
|
|
load_thread.start()
|
|
|
|
|
|
connect_disconncet_button.connect("clicked", connect_disconnect_function)
|
|
|
|
|
|
##########################################################################
|
|
# #
|
|
# LOCK BUTTON #
|
|
# #
|
|
##########################################################################
|
|
|
|
|
|
|
|
|
|
win.lock_button = Gtk.ToggleButton()
|
|
|
|
def check_lock_button():
|
|
try:
|
|
wallet_status = fetch.lbrynet("wallet_status")
|
|
except:
|
|
wallet_status = {}
|
|
if wallet_status.get("is_locked"):
|
|
win.lock_button.set_active(True)
|
|
|
|
if not win.settings["lock_password"]:
|
|
win.lock_button.set_sensitive(False)
|
|
else:
|
|
win.lock_button.set_sensitive(True)
|
|
|
|
check_lock_button()
|
|
win.lock_button.set_tooltip_text("Lock / Unlock LBRY wallet. \n\n While the wallet is locked, no transaction could be signed. So nobody could use the running SDK to harm you.\n\nTo set the password look into settings.")
|
|
win.lock_button.set_relief(Gtk.ReliefStyle.NONE)
|
|
win.lock_button.add(ui.icon(win, "system-lock-screen-symbolic"))
|
|
restofpannel.pack_start(win.lock_button, False, False, False)
|
|
|
|
def lock_unlock(w):
|
|
|
|
passw = win.settings["lock_password"]
|
|
|
|
wallets = fetch.lbrynet("wallet_list")
|
|
ID = wallets["items"][0]["id"]
|
|
|
|
if w.get_active():
|
|
# If we are locking
|
|
print(fetch.lbrynet("wallet_encrypt", {"new_password":passw}))
|
|
print(fetch.lbrynet("wallet_lock", {"wallet_id":ID}))
|
|
|
|
else:
|
|
# If decrypt
|
|
print(fetch.lbrynet("wallet_unlock", {"password":passw, "wallet_id":ID}))
|
|
print(fetch.lbrynet("wallet_decrypt", {"wallet_id":ID}))
|
|
|
|
|
|
print("I AM FUCKING PRESSED")
|
|
|
|
|
|
win.lock_button.connect("clicked", lock_unlock)
|
|
|
|
|
|
|
|
|
|
##########################################################################
|
|
# #
|
|
# PUBLISH BUTTON #
|
|
# #
|
|
##########################################################################
|
|
|
|
restofpannel.pack_start(Gtk.VSeparator(), True, True, 20)
|
|
|
|
publ = Gtk.Button()
|
|
publ.set_tooltip_text("Publish to LBRY")
|
|
publ.set_relief(Gtk.ReliefStyle.NONE)
|
|
publ.add(ui.icon(win, "list-add"))
|
|
restofpannel.pack_start(publ, False, False, False)
|
|
def do_publish(w):
|
|
publish.window(win)
|
|
publ.connect("clicked", do_publish)
|
|
|
|
restofpannel.pack_start(Gtk.VSeparator(), True, True, 20)
|
|
|
|
##########################################################################
|
|
# #
|
|
# SEARCH / URL BAR #
|
|
# #
|
|
##########################################################################
|
|
|
|
|
|
# Note that I add this directly into the 'win' to make it a global variable.
|
|
# This let's me to start any url from anywhere in the software.
|
|
|
|
win.url = Gtk.Entry() # Gtk.SearchEntry() also looks good, but nah
|
|
win.url.set_size_request(400,40)
|
|
restofpannel.pack_start(win.url, True, True, False)
|
|
|
|
####### SEARCH FUNCTION #######
|
|
|
|
def search(w):
|
|
|
|
if win.resolve_tab == "current":
|
|
win.resolve_tab = win.notebook.get_current_page()
|
|
|
|
try:
|
|
dynamic_box = win.tabs[win.resolve_tab]["box"]
|
|
except:
|
|
|
|
new_tab()
|
|
dynamic_box = win.tabs[win.resolve_tab]["box"]
|
|
|
|
|
|
|
|
|
|
# DRAG AND DROP FOR PUBLISH
|
|
if win.url.get_text().startswith("file://") or os.path.exists(win.url.get_text()):
|
|
|
|
# TODO: Some filenames include weird characters like %20 for spacebar and
|
|
# stuff like that. We need to filter that out.
|
|
|
|
filepath = win.url.get_text().replace("file://", "")
|
|
publish.window(win, {"file_path":filepath})
|
|
win.url.set_text("")
|
|
return
|
|
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
## IF WE ARE NOT FORCING IT TO SEACH, IT WILL TRY TO RESOLVE THE LBRY URL FIRST ##
|
|
|
|
if not force_search.get_active() or win.url.get_text().startswith("lbry://"):
|
|
win.url.set_text(parse.bar(win.url.get_text()))
|
|
|
|
ltext = win.url.get_text()
|
|
ltext = ltext[ltext.rfind("/")+1:]
|
|
win.tabs[win.resolve_tab]["label"].set_text(ltext[:10]+"...")
|
|
win.tabs[win.resolve_tab]["label"].set_tooltip_text(win.url.get_text())
|
|
|
|
resolve = ui.load(win, url.resolve, url.render_resolve, w, win, win.url.get_text())
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
win.show_all()
|
|
else:
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, win.url.get_text(), [], 1, {"order_by":""})
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
win.show_all()
|
|
|
|
ltext = win.url.get_text()
|
|
win.tabs[win.resolve_tab]["label"].set_text(ltext[:10]+"...")
|
|
win.tabs[win.resolve_tab]["label"].set_tooltip_text(win.url.get_text())
|
|
|
|
dynamic_box.show_all()
|
|
win.notebook.set_current_page(win.resolve_tab)
|
|
win.resolve_tab = "current"
|
|
hamburger.hide()
|
|
|
|
# Button to activate seach for those who don't know that you can press Enter
|
|
search_button = Gtk.Button()
|
|
search_icon = ui.icon(win, "system-search")
|
|
search_button.add(search_icon)
|
|
search_button.set_relief(Gtk.ReliefStyle.NONE)
|
|
search_button.connect("clicked", search)
|
|
win.url.connect("activate", search)
|
|
restofpannel.pack_start(search_button, False, False, False)
|
|
|
|
##########################################################################
|
|
# #
|
|
# HAMBURGER MENU #
|
|
# #
|
|
##########################################################################
|
|
|
|
# Popover is the new GTK menu thingy that looks like a comic book dialog
|
|
# box. Which is what we want here. Because we want it to look nice I suppose.
|
|
|
|
def on_hamburger(w):
|
|
|
|
|
|
################# NOTIFICATIONS #####################
|
|
|
|
notifications = odysee.get_odysee_notifications(win)
|
|
|
|
for i in win.notifications_box.get_children():
|
|
i.destroy()
|
|
|
|
if notifications:
|
|
scrl = Gtk.ScrolledWindow()
|
|
scrl.set_size_request(200,200)
|
|
win.notifications_box.pack_start(scrl, 1,1,0)
|
|
|
|
notbox = Gtk.VBox()
|
|
scrl.add(notbox)
|
|
|
|
for i in notifications:
|
|
i = i.get("notification_parameters", {})
|
|
author = i.get("dynamic", {}).get("reply_author")
|
|
publication = i.get("device", {}).get("target")
|
|
comment = i.get("device", {}).get("text")
|
|
|
|
# Channel button
|
|
def resolve_channel(win, url):
|
|
out = fetch.lbrynet("resolve", {"urls":url})
|
|
out = out[url]
|
|
return [win, out]
|
|
def render_channel(out):
|
|
win, out = out
|
|
return ui.go_to_channel(win, out)
|
|
|
|
notbox.pack_start(Gtk.HSeparator(), 1,1,5)
|
|
|
|
channel_button = ui.load(win, resolve_channel, render_channel, win, author)
|
|
notbox.pack_start(channel_button, 1,1,5)
|
|
|
|
comment_label = Gtk.Label(comment)
|
|
comment_label.set_selectable(True)
|
|
comment_label.set_line_wrap_mode( Gtk.WrapMode.WORD )
|
|
comment_label.set_line_wrap(True)
|
|
comment_label.set_max_width_chars(20)
|
|
|
|
def resolve_publication(w, publication):
|
|
|
|
win.resolve_tab = "new_tab"
|
|
win.url.set_text(publication)
|
|
win.url.activate()
|
|
|
|
comment_button = Gtk.Button()
|
|
comment_button.add(comment_label)
|
|
comment_button.connect("clicked", resolve_publication, publication)
|
|
comment_button.set_relief(Gtk.ReliefStyle.NONE)
|
|
notbox.pack_start(comment_button, 1,1,5)
|
|
|
|
|
|
win.notifications_box.show_all()
|
|
|
|
|
|
hamburger = Gtk.Popover()
|
|
hambutton = Gtk.MenuButton(popover=hamburger)
|
|
hambutton.connect("clicked", on_hamburger)
|
|
hambutton_icon = ui.icon(win, "system-users")
|
|
hambutton.add(hambutton_icon)
|
|
hambutton.set_relief(Gtk.ReliefStyle.NONE)
|
|
pannel.pack_start(hambutton)
|
|
|
|
# Let's now pack the hamburger menu with items
|
|
|
|
hambox = Gtk.HBox()
|
|
|
|
|
|
# For the elements inside the box we need a scrolled window, to fit a lot of
|
|
# them there.
|
|
|
|
hamscrl = Gtk.ScrolledWindow()
|
|
hamscrl.set_size_request(200,200)
|
|
hamburger.add(hambox)
|
|
|
|
hambox.pack_start(hamscrl, False, False, False)
|
|
|
|
# "hamchannelbox" will be empty untill the user connects and it loads his channel
|
|
# list
|
|
|
|
hamchannelbox = Gtk.VBox()
|
|
hamscrl.add_with_viewport(hamchannelbox)
|
|
#hambox.pack_start(hamchannelbox, False, False, False)
|
|
|
|
###### CHANNELS SELECTOR ########
|
|
|
|
win.channel = False
|
|
def load_channel(win):
|
|
|
|
def change_channel(w, win, channel ):
|
|
win.channel = channel
|
|
win.settings["channel"] = win.channel["claim_id"]
|
|
settings.save(win.settings)
|
|
|
|
try:
|
|
hambutton.get_child().destroy()
|
|
try:
|
|
newicon = ui.load(win, ui.net_image_calculation, ui.net_image_render, channel["value"]["thumbnail"]["url"], 40, 40, "", False )
|
|
except:
|
|
newicon = ui.icon(win, "system-users")
|
|
hambutton.add(newicon)
|
|
pannel.show_all()
|
|
except Exception as e:
|
|
print("What?", e)
|
|
|
|
out = fetch.lbrynet("channel_list")
|
|
win.my_channels = out
|
|
|
|
# We are chooseing first only if there is no channel set in the settings
|
|
|
|
|
|
try:
|
|
first = out["items"][0]
|
|
win.channel = first
|
|
except:
|
|
pass
|
|
|
|
if "channel" in win.settings:
|
|
|
|
try:
|
|
for i in out["items"]:
|
|
if i["claim_id"] == win.settings["channel"]:
|
|
first = i
|
|
break
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
change_channel(False, win, first)
|
|
except:
|
|
pass
|
|
try:
|
|
|
|
|
|
|
|
go.set_sensitive(True)
|
|
|
|
for i in out["items"]:
|
|
channel_button = ui.go_to_channel(win, i, resolve=False)
|
|
channel_button.connect("clicked", change_channel, win, i)
|
|
hamchannelbox.pack_start(channel_button, False, False, False)
|
|
hamchannelbox.show_all()
|
|
second_raw.show_all()
|
|
except Exception as e:
|
|
print("CHANNEL ERROR:", e)
|
|
|
|
second_raw = Gtk.VBox()
|
|
hambox.pack_start(Gtk.VSeparator(), False, False, 5)
|
|
hambox.pack_start(second_raw, False, False, False)
|
|
|
|
####### Go to channel button #####
|
|
|
|
def go_to_channel(w):
|
|
|
|
channel_url = win.channel["name"]
|
|
try:
|
|
channel_url = channel_url + "#" + win.channel["claim_id"]
|
|
except:
|
|
pass
|
|
|
|
win.url.set_text(channel_url)
|
|
win.url.activate()
|
|
|
|
go = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "folder-remote"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Go To Channel "), True, True, False)
|
|
go.add(b)
|
|
go.set_sensitive(False)
|
|
go.set_relief(Gtk.ReliefStyle.NONE)
|
|
go.connect("clicked", go_to_channel)
|
|
second_raw.pack_start(go, False, False, False)
|
|
|
|
########## UPLOADS BUTTON #########
|
|
|
|
def load_uploads(w=False):
|
|
hamburger.hide()
|
|
dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
send = {"method":"claim_list"}
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
dynamic_box.show_all()
|
|
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_text("Uploads")
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text("Uploads")
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "go-up-symbolic"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Uploads "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_uploads)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
|
|
|
|
############## ANALYTICS ################
|
|
|
|
def load_analytics(w):
|
|
hamburger.hide()
|
|
analytics.window(win)
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "text-csv"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Wallet "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_analytics)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
second_raw.pack_start(Gtk.HSeparator(), False, False,5)
|
|
|
|
######## FOLLOWING BUTTON ###########
|
|
|
|
def load_following( w=False, mode="following"):
|
|
|
|
hamburger.hide()
|
|
dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
try:
|
|
if not win.subs:
|
|
out = fetch.lbrynet("preference_get")
|
|
win.subs = out["shared"]["value"]["subscriptions"]
|
|
|
|
subs_raw = fetch.lbrynet("resolve", {"urls":win.subs})
|
|
subs = []
|
|
for i in subs_raw:
|
|
try:
|
|
subs.append(subs_raw[i]["claim_id"])
|
|
except:
|
|
pass
|
|
except Exception as e:
|
|
print("\n\nERROR:", e, "\n\n")
|
|
subs = []
|
|
|
|
suggest_tags = suggest.suggest()
|
|
|
|
if mode == "suggest":
|
|
send = {"any_tags":suggest_tags,
|
|
"order_by":"trending_mixed"}
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
|
|
else:
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, "", subs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Currently live!
|
|
all_lives = livestreams.get_all()
|
|
liveids = []
|
|
|
|
if mode != "suggest":
|
|
upcoming = livestreams.get_upcoming(channels=subs)
|
|
|
|
for s in upcoming.get("items", []):
|
|
if "claim_id" in s:
|
|
liveids.append(s["claim_id"])
|
|
|
|
for livestream in all_lives.get("data", []):
|
|
live_id = livestream.get("ActiveClaim", {}).get("ClaimID", "")
|
|
if livestream.get("ChannelClaimID", "") in subs:
|
|
liveids.append(live_id)
|
|
else:
|
|
upcoming = livestreams.get_upcoming(tags=suggest_tags)
|
|
|
|
for s in upcoming.get("items", []):
|
|
if "claim_id" in s:
|
|
liveids.append(s["claim_id"])
|
|
|
|
for livestream in all_lives.get("data", []):
|
|
live_id = livestream.get("ActiveClaim", {}).get("ClaimID", "")
|
|
liveids.append(live_id)
|
|
|
|
if liveids:
|
|
send = {"claim_ids":liveids}
|
|
if mode == "suggest":
|
|
send["any_tags"] = suggest.suggest()
|
|
|
|
resolve_lives = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
|
|
lives_frame = Gtk.Expander(label=" Livestreams: ")
|
|
if mode != "suggest":
|
|
lives_frame.set_expanded(True)
|
|
resolve_lives.set_size_request(350,350)
|
|
lives_frame.add(resolve_lives)
|
|
dynamic_box.pack_start(lives_frame, 0,0,0)
|
|
|
|
dynamic_box.pack_start(Gtk.HSeparator(), 0,0,5)
|
|
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
dynamic_box.show_all()
|
|
|
|
if mode == "suggest":
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_text("Suggested")
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text("Suggested")
|
|
else:
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_text("Following")
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text("Following")
|
|
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "semi-starred"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Suggested "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_following, "suggest")
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "emblem-favorite"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Following "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_following)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
|
|
######## TRENDING BUTTONS ###########
|
|
|
|
def load_trending(w=False, articles=False):
|
|
hamburger.hide()
|
|
dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
send = {"order_by":"trending_mixed"}
|
|
if articles:
|
|
send["media_types"] = ["text/markdown"]
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
dynamic_box.show_all()
|
|
|
|
if articles:
|
|
lname = "Articles"
|
|
else:
|
|
lname = "Trending"
|
|
|
|
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_text(lname)
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text(lname)
|
|
|
|
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
# The other one was showing web-browsers at some themes
|
|
b.pack_start(ui.icon(win, "emblem-shared"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Trending "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_trending)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "text-x-generic"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Articles "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_trending, True)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
#### LIVESTREAMS ####
|
|
|
|
def load_livestreams(w):
|
|
hamburger.hide()
|
|
|
|
|
|
# First let's fetch the data about all livestreams
|
|
|
|
all_lives = livestreams.get_all()
|
|
liveids = []
|
|
|
|
# Upcoming
|
|
upcoming = livestreams.get_upcoming()
|
|
for s in upcoming.get("items", []):
|
|
if "claim_id" in s:
|
|
liveids.append(s["claim_id"])
|
|
|
|
for livestream in all_lives.get("data", []):
|
|
live_id = livestream.get("ActiveClaim", {}).get("ClaimID", "")
|
|
liveids.append(live_id)
|
|
|
|
# Then we gonna search all the liveids
|
|
|
|
dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
|
|
|
|
for i in dynamic_box.get_children():
|
|
i.destroy()
|
|
|
|
send = {"claim_ids":liveids}
|
|
|
|
resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
|
|
dynamic_box.pack_start(resolve, True, True, True)
|
|
dynamic_box.show_all()
|
|
|
|
lname = "Live Streams"
|
|
|
|
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_text(lname)
|
|
win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text(lname)
|
|
|
|
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "emblem-new"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Live Streams "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_livestreams)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
|
|
second_raw.pack_start(Gtk.HSeparator(), False, False,5)
|
|
|
|
######## DOWNLOADS #########
|
|
|
|
def load_downloads(w):
|
|
hamburger.hide()
|
|
downloads.window(win)
|
|
|
|
following = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "go-down-symbolic"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Downloads "), True, True, False)
|
|
following.add(b)
|
|
following.set_relief(Gtk.ReliefStyle.NONE)
|
|
following.connect("clicked", load_downloads)
|
|
second_raw.pack_start(following, False, False,False)
|
|
|
|
|
|
|
|
second_raw.pack_start(Gtk.HSeparator(), False, False,5)
|
|
|
|
######## SETTINGS BUTTON ############
|
|
|
|
second_raw.pack_start(Gtk.HSeparator(), False, False,5)
|
|
|
|
settings_button = Gtk.Button()
|
|
b = Gtk.HBox()
|
|
b.pack_start(ui.icon(win, "preferences-system"), False, False, False)
|
|
b.pack_start(Gtk.Label(" Settings "), True, True, False)
|
|
settings_button.add(b)
|
|
settings_button.set_relief(Gtk.ReliefStyle.NONE)
|
|
settings_button.connect("clicked", settings.dialogue, win)
|
|
second_raw.pack_start(settings_button, False, False, False)
|
|
|
|
second_raw.pack_start(Gtk.HSeparator(), False, False,5)
|
|
|
|
########## FORCE SEARCH BUTTON #######
|
|
|
|
force_search_box = Gtk.HBox()
|
|
force_search = Gtk.Switch()
|
|
force_search_box.pack_end(force_search, False, False, 0)
|
|
force_search_box.pack_start(ui.icon(win, "system-search"), False, False, 0)
|
|
force_search_box.pack_start(Gtk.Label(" Force Search "), True, True, 0)
|
|
force_search.set_tooltip_text("If not activated it will try to resolve the claim first.")
|
|
second_raw.pack_start(force_search_box, False, False, False)
|
|
|
|
|
|
###### THE BOX FOR THE NOTIFICATIONS #####
|
|
|
|
win.notifications_box = Gtk.VBox()
|
|
hambox.pack_start(Gtk.VSeparator(), False, False, 5)
|
|
hambox.pack_start(win.notifications_box, False, False, False)
|
|
hambox.show_all()
|
|
|
|
##########################################################################
|
|
# #
|
|
# DYNAMIC BOX ( REST ) #
|
|
# #
|
|
##########################################################################
|
|
|
|
# Dynamic box is a box contents of which will change depending on the "page"
|
|
# that the user is loading.
|
|
|
|
box = Gtk.VBox() # I'm making a top level box just in case
|
|
win.add(box)
|
|
|
|
|
|
win.notebook.set_scrollable(True)
|
|
|
|
def new_tab():
|
|
dynamic_box = Gtk.VBox() # And here our dynamic box
|
|
|
|
label = Gtk.Label("Tab "+str(len(win.tabs)+1))
|
|
|
|
|
|
|
|
kill = Gtk.Button()
|
|
|
|
kill.add(ui.icon(win, "delete"))
|
|
kill.set_relief(Gtk.ReliefStyle.NONE)
|
|
|
|
box = Gtk.HBox()
|
|
box.pack_start(label, False, False, 5)
|
|
box.pack_start(kill, False, False, 0)
|
|
box.show_all()
|
|
|
|
tab = {"box":dynamic_box, "label":label, "index":len(win.tabs)}
|
|
|
|
def on_kill(w, tab):
|
|
|
|
if len(win.tabs) == 1:
|
|
load_following(mode=win.settings["default_tab"])
|
|
return
|
|
|
|
i = tab["index"]
|
|
win.notebook.remove_page(i)
|
|
del win.tabs[i]
|
|
|
|
for r, t in enumerate(win.tabs):
|
|
t["index"] = r
|
|
|
|
|
|
|
|
kill.connect("clicked", on_kill, tab)
|
|
|
|
win.tabs.append(tab)
|
|
win.resolve_tab = len(win.tabs) - 1
|
|
|
|
win.notebook.append_page(win.tabs[-1]["box"], box)
|
|
|
|
|
|
|
|
new_tab()
|
|
|
|
box.pack_start(win.notebook, True, True, False)
|
|
|
|
|
|
|
|
# Just something to run if we are connected
|
|
|
|
if win.SDK_running == 1:
|
|
load_following(mode=win.settings["default_tab"])
|
|
load_channel(win)
|
|
else:
|
|
win.tabs[0]["box"].pack_start(Gtk.Label("LBRY is not connected. Please connect."), True, True, 20)
|
|
|
|
##########################################################################
|
|
# #
|
|
# DRAG AND DROP #
|
|
# #
|
|
##########################################################################
|
|
|
|
def on_drop(widget, drag_context, x, y, data, info, time):
|
|
|
|
win.url.set_text(data.get_text())
|
|
win.url.activate()
|
|
|
|
|
|
enforce_target = Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags(4), 129)
|
|
box.drag_dest_set(Gtk.DestDefaults.ALL, [enforce_target], Gdk.DragAction.COPY)
|
|
box.connect("drag-data-received", on_drop)
|
|
|
|
if win.settings["autoconnect"] and win.SDK_running != 1:
|
|
connect_disconnect_function(connect_disconncet_button)
|
|
|
|
# Application CSS
|
|
|
|
style_provider=Gtk.CssProvider()
|
|
css=b"""
|
|
.thumbnail_overlay {
|
|
background-color: rgba(.5, .5, .5, .7);
|
|
border-radius: 5px;
|
|
padding: 5px;
|
|
}
|
|
"""
|
|
style_provider.load_from_data(css)
|
|
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
|
|
|
# Starting Everything
|
|
|
|
win.show_all()
|
|
Gtk.main()
|
|
|
|
#### Clearing the cache of images ###
|
|
|
|
ui.clean_image_cache()
|
|
|
|
if win.settings["autoconnect"]:
|
|
connect.stop(win)
|