Skip to content

Commit

Permalink
All around fixes
Browse files Browse the repository at this point in the history
* Switched Trending and user API, the new one is more stable.
* Introduced logging. It'll be very useful to understand what the code is doing, and why something broke.
* Reworked detect_dead_link() which broke recently.
  • Loading branch information
nanometer5088 committed Feb 4, 2023
1 parent 978d6f9 commit c4b5aa1
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 43 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,5 @@ dmypy.json
#Project files
Likes.txt
features-missing.txt
/video
/video
/logs
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3
0.4
2 changes: 2 additions & 0 deletions log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from src.logs import Logging
logtofile = Logging().log
27 changes: 25 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Introduction and pre-test
from log import logtofile as log

import sys

from src.init import init

a = init()

if a == -1:
print("Dependencies installed successfully.\nOpen the program again\n")
log("Dependencies were installed, user was prompted to run the software again.")
sys.exit()

log("Pre-test complete\n")


# Import libraries and required functions after sucessful pre-test
import os
Expand All @@ -19,6 +26,7 @@
from src.trending import streamtrending

# Needlessly big code to simply prompt the user which action they want to do
log("Main menu started")
try:
question = int(
input(
Expand Down Expand Up @@ -46,26 +54,29 @@

## Download liked videos
if downloadquestion == 1:
log("The user chose to download liked videos\n")
urls = listas()[0]
downloadtiktoks(urls)
sys.exit()

## Download creator
if downloadquestion == 2:
log("The user chose to download videos from a creator")
print(
"Due to specific limitations of the current data method, downloading by creator will only get the latest 30 videos."
)
print(
"This limitation is being actively researched, any contributions will be welcome."
)
username = str(input("Enter the tiktok username here: "))
log(f"The creator chosen was: @{username}\n")
links = getLinks(username)
downloadtiktoks(links)
sys.exit()

## Stream
if question == 2:

watchquestion = int(
input(
"""Do you want to watch your liked videos, a creator or trending videos?
Expand Down Expand Up @@ -93,30 +104,37 @@

## Stream liked videos randomized
if randomquestion == 1:
log("The user chose to stream liked videos in shuffled mode\n")
urls = listas()[0]
datas = listas()[1]
playbackrandom(urls, datas)
sys.exit()

## Stream liked videos in descending order
if randomquestion == 2:
log("The user chose to stream liked videos in regular mode\n")
urls = listas()[0]
datas = listas()[1]
playback(urls, datas)
sys.exit()

## Stream creator
if watchquestion == 2:
log("The user chose to stream videos from a creator")
print(
"Due to specific limitations of the current data method, watching by creator will only get the latest 30 videos."
)
print(
"This limitation is being actively researched, any contributions will be welcome."
)
username = str(input("Enter the tiktok username here: "))
log(f"The creator chosen was: @{username}\n")
streamuser(username)
sys.exit()

## Stream trending videos
if watchquestion == 3:
log("The user chose to stream trending videos\n")
print(
"Due to specific limitations of the current data method, watching by creator will only get the latest 30 videos."
)
Expand All @@ -127,25 +145,30 @@
sys.exit()

# Error handling for invalid number (3, 4, 6, 133)
log("The user entered an invalid numeric choice, and the software exited")
print("The option you chose isn't valid.")

# Error handling for invalid input (ENTER, 't', '5ga')
except ValueError:
log("The user entered an invalid non-numeric choice, and the software exited")
print("The option you chose isn't valid.")

# Error handling for missing Likes.txt file
except FileNotFoundError:
log("The user does not have a Likes.txt file, but chose an option that depends on it, so the software exited")
print(
"The 'Likes.txt' file was not found. Make sure it is in the program folder and try again."
)

# Error handling for MPV media player or MPV not found in PATH
except subprocess.CalledProcessError:
log("Tried to run MPV media player, but it was not found in the PATH, so the software exited")
os.system("cls || clear")
print(
"Mpv media player was not found on your system path. Make sure it's installed and try again."
"MPV media player was not found on your system path. Make sure it's installed and try again."
)

# Error handling for exiting the code with CTRL + C
except KeyboardInterrupt:
log("The user used CTRL + C to force-stop the software.")
print("\n\tKeyboardInterrupt was detected - Goodbye!")
24 changes: 15 additions & 9 deletions src/byuser.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import sys
from log import logtofile as log

import atoma
import requests
from src.streaming import getVideoInfo


def info(username):

response = requests.get(f"https://proxitok.pussthecat.org/@{username}/rss")
response = requests.get(f"https://tik.hostux.net/@{username}/rss")
if response.status_code == 404:
print(
"Something went wrong while getting the information. Make sure the username was correctly inserted and try again."
)
log(f"https://tik.hostux.net/@{username}/rss returned a 404 error. The username is likely incorrect")
sys.exit()
if str(response.content) == "b''":
log("https://tik.hostux.net/@{username}/rss returned no information. The account likely does not exist")
print("The specified account does not exist.")
sys.exit()
return atoma.parse_rss_bytes(response.content)

# if feed.description == None:
# print("This account does not have a bio.")
# if response.description == None:
# log("This account does not have a bio.\n")
# else:
# print(feed.description) ## TIKTOK BIO
# log(f"Bio: {str(response.description)}\n") ## TIKTOK BIO

return atoma.parse_rss_bytes(response.content)


def getLinks(username):
Expand All @@ -36,9 +41,10 @@ def streamuser(username):
links = getLinks(username)

if len(links) == 0:
log("The link list is empty. The specified account is likely private or has no published videos")
print("This account is private or has no published videos.")

from src.streaming import mpv, getVideoInfo
for i in range(len(links)):
from src.streaming import mpv

mpv(links[i])
url = getVideoInfo(links[i])
mpv(url)
log(f"Video {links[i]} was played.")
25 changes: 16 additions & 9 deletions src/downloader.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import os

from src.functions import detect_dead_link, url_redirection
from log import logtofile as log
from src.functions import url_redirection
from yt_dlp import YoutubeDL

from yt_dlp.utils import DownloadError

def downloader(url):
ydl_opts = {
"ignoreerrors": True,
"format": "bestvideo*+bestaudio/best",
"outtmpl": os.getcwd()
+ "/video/by-creator/%(creator)s/%(id)s.%(ext)s",
Expand All @@ -22,27 +21,35 @@ def downloadtiktoks(urls):
**WARNING**
This action will download up to {len(urls)} tiktoks in CLI-TIkTok/video/
Ensure you have enough free space before proceeding!
\n\t\tPress ENTER to proceed...
\n\tPress ENTER to proceed...
"""
)

if a != "":
log(f"User denied to download {len(urls)} tiktoks - Software exited")
print("Operation canceled.")
return
log(f"User accepted to download {len(urls)} tiktoks")
while True:
try:
randomvideo = index = index + 1
url = url_redirection(urls[randomvideo])

if detect_dead_link(url) == True:
try:
downloader(url)
log(f"Video {url} was downloaded")
print("")
else:
except DownloadError:
print("This video is unavailable ")
log(f"Video {url} will not be downloaded - The video is unavailable (banned or taken down)")
errorcount.append(urls)

except IndexError:
print("The tiktoks were downloaded")
return
log("The tiktoks were downloaded")
if len(errorcount) != 0:
print(
f"\n{len(errorcount)} video(s) failed to download.\nThe video(s) were likely banned or removed from the platform."
)
break
log(f"{len(errorcount)} video(s) failed to download.")
return
9 changes: 5 additions & 4 deletions src/functions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import random

from log import logtofile as log
import requests


Expand Down Expand Up @@ -28,7 +28,7 @@ def listas():

for i in range(2, len(vet), 3):
listadatas.append(vet[i - 2][1] + " " + vet[i - 2][2])

log("Likes.txt file was processed sucessfully")
return listalinks, listadatas


Expand All @@ -38,7 +38,8 @@ def removevideo():
if os.path.exists(os.getcwd() + "/video/video"):
os.remove(os.getcwd() + "/video/video")


# Broken as of 2023-02-03
# A workaround has been put in place
def detect_dead_link(url):
# Detects if the video is available to be streamed or downloaded.
dead_url_start_with = "https://www.tiktok.com/@/video"
Expand All @@ -52,7 +53,7 @@ def detect_dead_link(url):
def url_redirection(url):
# Tiktok links from the Likes.txt are shortened. They need to be redirected to the final link, which is done here.
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/109.0"
}
response = requests.get(url, headers=headers)
return response.url
Expand Down
20 changes: 16 additions & 4 deletions src/init.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
from os import system

from log import logtofile as log

def init():
# Intro for the user
Expand All @@ -10,14 +10,17 @@ def init():
)

# Detect and install libraries - If they aren't installed,
# the user is prompted to make the auto-installation.
# the user is prompted to make the automatic installation.
log("Started dependency test")
try:
import atoma
import requests
import yt_dlp

system("cls || clear")
log("Dependency test sucessful!")
except ModuleNotFoundError:
log("Dependency test failed - Missing library")
system("cls || clear")
input(
"""
Expand All @@ -27,6 +30,7 @@ def init():
(You will need to open the program again afterwards)
"""
)
log("User accepted automatic installation, running it.")
system("pip install -r requirements.txt --user")
system("cls || clear")
return -1
Expand All @@ -35,13 +39,16 @@ def init():
# If the user does not have internet access, warns him the software won't work properly and quit.
try:
import requests

log("Started update / networking test")
data = requests.get(
"https://raw.githubusercontent.com/nanometer5088/CLI-TikTok/main/VERSION"
)
version = open("VERSION", "r", encoding="utf=8")
if version.readline().rstrip() < (data.text):
userversion = version.readline().rstrip()
if userversion < (data.text):
log(f"New version detected! User version is {userversion}, but {data.text} was found on Github.")
system("cls || clear")
log("User was prompted to update")
input(
"""
There's a new version available!
Expand All @@ -53,13 +60,18 @@ def init():
Press ENTER to proceed
"""
)
system("cls || clear")
else:
log("The user has internet acess and the software is up-to-date.")
version.close()
except requests.exceptions.ConnectionError:
log("A connection error was detected when trying to connect to https://raw.githubusercontent.com/ to check for updates.")
print(
"CLI-TikTok detected your device isn't connected to the internet"
)
print(
"This software requires a reliable and uncensored internet connection to properly work"
)
print("Please try again with an internet connection")
log("The software exited, and the user was notified of the connection problem.")
sys.exit()
28 changes: 28 additions & 0 deletions src/logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import glob
import os
import time

class Logging:
def __init__(self):
self.logFileOpened = False

def log(self, stringToLog: str):
# creating logs folder
try:
os.mkdir(os.getcwd() + "/logs")
except FileExistsError:
pass
filenames = []
for filename in glob.glob(r"logs/log-*.txt"):
filenames.append(int(filename[9:-4]))
if len(filenames) == 0:
filenames.append(0)
if self.logFileOpened:
with open(f"logs/log-{max(filenames)}.txt", "a") as logFile:
logFile.write(f"[{time.strftime('%Y.%m.%d-%H.%M.%S', time.localtime(time.time()))}]"
f" {stringToLog.encode('ascii', 'replace').decode()}\n")
else:
with open(f"logs/log-{max(filenames) + 1}.txt", "w") as logFile:
self.logFileOpened = True
logFile.write(f"[{time.strftime('%Y.%m.%d-%H.%M.%S', time.localtime(time.time()))}]"
f" {stringToLog.encode('ascii', 'replace').decode()}\n")
Loading

0 comments on commit c4b5aa1

Please sign in to comment.