FastLBRY-GTK-master/flbry/url.py
auser e2cdd0e5fc Add commit 6a34355fda files minus lbrynet binary
Add files from 6a34355fda commit of FastLBRY-GTK notabug.org repo
by jyamihud without the flbry/lbrynet binary
2026-09-29 20:07:22 +00:00

1062 lines
38 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. #
# #
#####################################################################
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, 150, "", True)
else:
thumb_image = ui.load(win, ui.net_image_calculation, ui.net_image_render, thumb, 400, 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, 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]