123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- #####################################################################
- # #
- # 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. #
- # #
- #####################################################################
- # This file will fetch an LBRY URL directly and print out various
- # options that the user may do with the publication.
- from subprocess import *
- import json
- import os
- from flbry.variables import *
- from flbry import markdown
- from flbry import channel
- from flbry import search
- from flbry import comments
- import urllib.request
- from flbry import following
- from flbry import settings
- from flbry import wallet
- def get(url=""):
-
- # The user might type the word url and nothing else.
-
- if not url:
- url = input(" LBRY url :: ")
- ##### Converting an HTTPS domain ( of any website ) into lbry url ###
- # Any variation of this:
- # https://odysee.com/@blenderdumbass:f/hacking-fastlbry-live-with-you:6
- # customlbry.com/@blenderdumbass:f/hacking-fastlbry-live-with-you:6
- # Should become this:
- # lbry://@blenderdumbass:f/hacking-fastlbry-live-with-you:6
- if "/" in url and not url.startswith("@") and not url.startswith("lbry://"):
- if "@" in url:
- url = url[url.find("@"):]
- else:
- url = url[text.rfind("/")-1:]
- url = "lbry://"+url
-
- # Then let's fetch the url from our beloved SDK.
- out = check_output(["flbry/lbrynet",
- "resolve", url])
- # Now we want to parse the json
- try:
- out = json.loads(out)
- except:
- print(" Connect to LBRY first.")
- return
- out = out[url]
- #### FORCE SEARCH ###
- # Sometimes user might type something that is not a url
- # in this case ["value_type"] will not be loaded. And in
- # this case we can load search instead.
- if "value_type" not in out:
- search.simple(url)
- return
- # Now that we know that don't search for it. We can make
- # one thing less broken. Sometimes a user might type a
- # urls that's going to be resolved but that doesn't have
- # the lbry:// in the beginning of it. Like typing
- # @blenderdumbass instead of lbry://blenderdumbass
- # I want to add the lbry:// to it anyway. So non of the
- # stuff later will break.
- if not url.startswith("lbry://") and not url.startswith("@"):
- url = "lbry://" + url
-
- # Now let's print some useful information
- ##### NAME URL INFORMATION #####
-
- center("Publication Information")
- d = {"categories":["lbry url", "title"],
- "size":[1,1],
- "data":[[url]]}
- try:
- # This prints out the title
- d["data"][0].append(out["value"]["title"])
- except:
- d["data"][0] = [url]
- d["data"][0].append("[no title]")
- table(d, False)
- #### LICENSE ####
- try:
-
- d = {"categories":["License"],
- "size":[1],
- "data":[[out["value"]["license"]]]}
- except:
- d = {"categories":["License"],
- "size":[1],
- "data":[["[failed to load license]"]]}
- table(d, False)
-
- #### TAGS #####
- d = {"categories":[],
- "size":[],
- "data":[[]]}
- try:
- for tag in out["value"]["tags"]:
- d["categories"].append(" ")
- d["size"].append(1)
- d["data"][0].append(tag)
- except:
- d = {"categories":[" "],
- "size":[1],
- "data":[["[no tags found]"]]}
-
- table(d, False)
- #### FILE INFO #####
- d = {"categories":["Value Type", "File Type", "File Size", "Duration"],
- "size":[1,1,1, 1],
- "data":[[]]}
- try:
- d["data"][0].append(what[out["value_type"]])
- except:
- d["data"][0].append("[no value type]")
- try:
- d["data"][0].append(out["value"]["source"]["media_type"])
- except:
- d["data"][0].append("[no file type]")
- try:
- d["data"][0].append(csize(out["value"]["source"]["size"]))
- except:
- d["data"][0].append("[no file size]")
- try:
- d["data"][0].append(timestring(float(out["value"]["video"]["duration"])))
- except:
- d["data"][0].append("[no duration]")
-
- table(d, False)
- ##### CHANNEL INFORMATION ####
- center("Channel Information")
- d = {"categories":["lbry url", "title"],
- "size":[1,1],
- "data":[[]]}
- try:
- # This prints out the title
- d["data"][0].append(out["signing_channel"]["name"])
- title = "[no title]"
- try:
- title = out["signing_channel"]["value"]["title"]
- except:
- pass
- d["data"][0].append(title)
- except:
- d["data"][0] = []
- d["data"][0].append("[no url]")
- d["data"][0].append("[anonymous publisher]")
- table(d, False)
- #### LBC INFORMATION ####
- center("LBRY Coin ( LBC ) Information")
- d = {"categories":["combined", "at upload", "support"],
- "size":[1,1,1],
- "data":[[]]}
- try:
- fullamount = float(out["amount"]) + float(out["meta"]["support_amount"])
- # This prints out the title
- d["data"][0].append(fullamount)
- d["data"][0].append(out["amount"])
- d["data"][0].append(out["meta"]["support_amount"])
-
- except:
- d["data"][0] = []
- d["data"][0].append("[no data]")
- d["data"][0].append("[no data]")
- d["data"][0].append("[no data]")
- table(d, False)
- #### PRICE ####
-
- try:
- # Print the prince of this publication in LBC
- center("PRICE: "+out["value"]["fee"]["amount"]+" "+out["value"]["fee"]["currency"], "bdrd", blink=True)
- except:
- pass
-
- ### REPOST ####
- # Sometimes a user wants to select a repost. This will not
- # load anything of a value. A repost is an empty blob that
- # links to another blob. So I want to automatically load
- # the actuall publication it self here.
- if out["value_type"] == "repost":
- get(out["reposted_claim"]["canonical_url"])
- return
-
-
- # Some things are too big to output like this in the terminal
- # so for them I want the user to type a command.
- center("--- for publication commands list type 'help' --- ")
- # So we are going to start a new while loop here. IK crazy.
- # this one will handle all the commands associated with the
- # currently selected publication.
- # Completer thingy
- url_commands = [
- "help",
- "link",
- "id",
- "web",
- "description",
- "read",
- "channel",
- "comments",
- "reply",
- "open",
- "play",
- "save",
- "rss",
- "thumbnail",
- "follow",
- "unfollow",
- "support",
- "tip"
- ]
- complete(url_commands)
- settings_cache = settings.get_all_settings()
-
- while True:
- c = input(typing_dots())
- if not c:
- break
- elif c == "help":
- markdown.draw("help/url.md", "Publication Help")
-
- elif c == "web":
- d = {"categories":["Name", "URL", "Maintainer", "Interface"],
- "size":[1,2,1,1],
- "data":web_instances}
- table(d)
- center("")
- # Choose an instance
- which = input(typing_dots())
- try:
- print(" "+url.replace("lbry://", web_instances[int(which)][1]))
- except:
- print(" "+url.replace("lbry://", web_instances[0][1]))
- elif c == "link":
- print(" "+url)
- elif c == "id":
- print(" "+out["claim_id"])
-
- elif c.startswith("open"):
- if settings_cache["default_opener"]:
- p = settings_cache["default_opener"]
- else:
- # Selecting the software command in a smart way
- if len(c) < 6:
- p = input(" Open in : ")
- else:
- p = c[5:]
- Popen([p,
- url.replace("lbry://", "https://spee.ch/").replace("#", ":").replace("(", "%28").replace(")", "%29")],
- stdout=DEVNULL,
- stderr=STDOUT)
-
- elif c == "description":
-
- #print(out["value"]["description"])
- # Here I want to print out the description of the publication.
- # but since, they are most likely in the markdown format I
- # need to implement a simple markdown parser. Oh wait.... I
- # have one. For the article read function. How about using it
- # here?
- # First we need to save the description into a file. Let's use
- # /tmp/ since there files are automatically cleaned up by the
- # system.
- try:
- savedes = open("/tmp/fastlbrylastdescription.md", "w")
- savedes.write(out["value"]["description"])
- savedes.close()
- except:
- savedes = open("/tmp/fastlbrylastdescription.md", "w")
- savedes.write("This file has no description.")
- savedes.close()
- # Now let's just simply load the markdown on this file.
- markdown.draw("/tmp/fastlbrylastdescription.md", "Description")
-
- elif c == "play":
- # Then we want to tell the SDK to start downloading.
- playout = check_output(["flbry/lbrynet",
- "get", url])
- # Parsing the Json
- playout = json.loads(playout)
-
- # Then we want to launch the player
- Popen([settings_cache["player"],
- playout['download_path']],
- stdout=DEVNULL,
- stderr=STDOUT)
- elif c == "music":
- # Then we want to tell the SDK to start downloading.
- playout = check_output(["flbry/lbrynet",
- "get", url])
- # Parsing the Json
- playout = json.loads(playout)
-
- # Then we want to launch the player
- Popen([settings.get("music_player"),
- playout['download_path']],
- stdout=DEVNULL,
- stderr=STDOUT)
- elif c == "save":
- # Then we want to tell the SDK to start downloading.
- playout = check_output(["flbry/lbrynet",
- "get", url])
- # Parsing the Json
- playout = json.loads(playout)
-
- print(" Saved to :", playout['download_path'])
- elif c == "read":
- # Then we want to tell the SDK to start downloading.
- playout = check_output(["flbry/lbrynet",
- "get", url])
- # Parsing the Json
- playout = json.loads(playout)
- # Present the article to the user.
- markdown.draw(playout['download_path'], out["value"]["title"])
- elif c == "channel":
- # This a weird one. If the publication is a channel we
- # want it to list the publications by that channel.
- # If a publication is a publication. We want it to list
- # publications by the channel that made the publication.
- if out["value_type"] == "channel":
- channel.simple(url)
- else:
- try:
- channel.simple(out["signing_channel"]["canonical_url"].replace("lbry://",""))
- except:
- center("Publication is anonymous", "bdrd")
- elif c == "comments":
- comments.list(out["claim_id"], url)
- elif c.startswith("reply"):
- c = c + ' '
- comments.post(out["claim_id"], c[c.find(" "):])
- elif c == "rss":
- if out["value_type"] == "channel":
- url = out["short_url"].replace("#", ":")
- if url.startswith("lbry://"):
- url = url.split("lbry://", 1)[1]
- print(" https://odysee.com/$/rss/"+url)
- else:
- try:
- url = out["signing_channel"]["short_url"].replace("#", ":")
- url = url.split("lbry://", 1)[1]
- print(" https://odysee.com/$/rss/"+url)
- except:
- center("Publication is anonymous!", "bdrd")
- elif c == "thumbnail":
- try:
- thumb_url = out["value"]["thumbnail"]["url"]
- urllib.request.urlretrieve(thumb_url, "/tmp/fastlbrythumbnail")
- Popen(["xdg-open",
- "/tmp/fastlbrythumbnail"],
- stdout=DEVNULL,
- stderr=STDOUT)
- except:
- center("Publication does not have a thumbnail", "bdrd")
- elif c == "follow":
- if out["value_type"] == "channel":
- try:
- name = out["value"]["title"]
- except:
- name = out["normalized_name"]
- url = out["permanent_url"]
- following.follow_channel(url, name)
- else:
- try:
- try:
- name = out["signing_channel"]["value"]["title"]
- except:
- name = out["signing_channel"]["normalized_name"]
- url = out["signing_channel"]["permanent_url"]
- following.follow_channel(url, name)
- except:
- center("Publication is anonymous.", "bdrd")
- elif c == "unfollow":
- if out["value_type"] == "channel":
- try:
- name = out["value"]["title"]
- except:
- name = out["normalized_name"]
- url = out["permanent_url"]
- following.unfollow_channel(url, name)
- else:
- try:
- try:
- name = out["signing_channel"]["value"]["title"]
- except:
- name = out["signing_channel"]["normalized_name"]
- url = out["signing_channel"]["permanent_url"]
- following.unfollow_channel(url, name)
- except:
- center("Publication is anonymous.", "bdrd")
- elif c == "support":
- wallet.support(out["claim_id"])
- elif c == "tip":
- wallet.support(out["claim_id"], True)
- complete(url_commands)
|