[IMP] major improvements to the UI, refactor on processor

refactor_total
Brett Spaulding 3 years ago
parent 303881038b
commit e02285924a

@ -1 +1 @@
from . import const

@ -1,3 +1,4 @@
from database import Model
from flask import Flask, render_template from flask import Flask, render_template
from redis import Redis from redis import Redis
from utils.processor import process_download from utils.processor import process_download
@ -5,6 +6,7 @@ from utils.processor import process_download
app = Flask(__name__) app = Flask(__name__)
redis = Redis(host='redis', port=6379) redis = Redis(host='redis', port=6379)
Album = Model('album')
@app.route('/') @app.route('/')
@ -15,7 +17,7 @@ def index():
return render_template('base.html') return render_template('base.html')
@app.route('/api/v1/get/<path:path>') @app.route('/api/v1/get/artist/<path:path>')
def get_artist(path): def get_artist(path):
""" """
Process for the requested Artist Process for the requested Artist
@ -23,10 +25,20 @@ def get_artist(path):
:return: a status :return: a status
""" """
if path: if path:
proc = process_download(path) res = process_download(path)
return {'status': 200, 'data': proc, 'artist': path}
else: else:
return {'status': 501} res = {'status': 501, 'message': 'Could not process download..'}
return res
@app.route('/api/v1/get/queue')
def get_queue():
album_ids = Album.search([('downloaded', '=', False)])
data = {'album_ids': album_ids}
print('======================')
print(data)
return render_template('download_queue.html', **data)
if __name__ == "__main__": if __name__ == "__main__":

@ -0,0 +1,84 @@
import operator as oprtr
from pysondb import PysonDB
def evaluate_condition(record_field, operator, condition):
return operator(record_field, condition)
def evaluate_operator(op):
if op == '>':
op = oprtr.gt
elif op == '<':
op = oprtr.lt
elif op == '=':
op = oprtr.eq
elif op == '!=':
op = oprtr.ne
else:
raise UserWarning('Invalid Operator: %s' % op)
return op
class Model:
# TODO: Modify some of this to be wrapped into an ENV wrapper that gets loaded in when the server starts and creates
# class objects that can be manipulated easier by things like update_by_id
def __init__(self, name):
self.env = PysonDB('/home/stonesoft/Apps/getDiscography/database/%s.json' % name)
def _search(self, records, params):
"""
Iterate through list of condition tuples and append results to a checklist that will evaluate at the end
ex params: [('name', '=', 'John'), ('zip', '!=', '12345')]
:param params: List of tuples
:return: Record to search recordset if True
"""
filtered_record_ids =[]
for record in records:
record_id = self.env.get_by_id(record)
print('===')
print(record_id)
checklist = []
for param in params:
field = param[0]
operator = evaluate_operator(param[1])
condition = param[2]
checklist.append(evaluate_condition(record_id[field], operator, condition))
passed = all(x for x in checklist)
if passed:
filtered_record_ids.append(record_id)
return filtered_record_ids
def search(self, params):
"""
:param params: List of tuples that will be evaluated and return a total list of records
:return: None, List or Single record
"""
records = self.env.get_all()
record_ids = self._search(records, params)
if not record_ids:
record_ids = None
return record_ids
def read(self, record_id):
data = self.env.get_by_id(record_id)
return data
def create(self, vals):
record = self.env.add(vals)
return record
def create_many(self, record_list):
record_ids = self.env.add_many(record_list)
return record_ids
def write(self, record_id, vals):
self.env.update_by_id(record_id, vals)
def unlink(self, record_id):
self.env.delete_by_id(record_id)
return True

@ -0,0 +1,93 @@
{
"version": 2,
"keys": [
"album",
"artist",
"cover",
"downloaded",
"downloading",
"link"
],
"data": {
"199074445401889600": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_nr-vlAyokNEb25RLBNe1XHsFo9gkvu2Pg&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_nr-vlAyokNEb25RLBNe1XHsFo9gkvu2Pg/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCN-N_qMG&rs=AOn4CLBo8tjoBHrUytlN1kfqTHYVMaVA4Q&v=1686079199",
"album": "Quick Revive"
},
"187732915376923467": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_lS0tCQXZ-1ppWJOMhaMel8GKGtnUzsvnU&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_lS0tCQXZ-1ppWJOMhaMel8GKGtnUzsvnU/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCPDOhaQG&rs=AOn4CLBa8Mmhg8B0A7ljEpCsig_bzTju0A&v=1686202224",
"album": "Winds of Paradise"
},
"206562046422345861": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_movr4fRkYisvKvX92G_D6fWfV1umrn3hs&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_movr4fRkYisvKvX92G_D6fWfV1umrn3hs/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCIKr_6MG&rs=AOn4CLDiszLRoh4cueTcK9h20CQ3KNpeXQ&v=1686099330",
"album": "Selection:3"
},
"321688139888393359": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_kW87DzVan7NyJ7j06XBmOHlg1WaFm38LA&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_kW87DzVan7NyJ7j06XBmOHlg1WaFm38LA/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCIDi_aMG&rs=AOn4CLA4dE1oa2TYSqb0pvfNTdK7ZSgERw&v=1686073600",
"album": "Bruh Moment (2020 Scraps)"
},
"633598784099856320": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_n1DHIq4LZlVVBvyilCzrjxAyCmsBSRfY0&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_n1DHIq4LZlVVBvyilCzrjxAyCmsBSRfY0/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCJGzn6QG&rs=AOn4CLD_qLcb-Z1EabBDe3449f3d0mh3Cg&v=1686624657",
"album": "Yent Szn 3"
},
"131921253377227610": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_nm2zfpc5MDyzOp2ftFqdlHBQ-L3tE2BQM&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_nm2zfpc5MDyzOp2ftFqdlHBQ-L3tE2BQM/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCIPhgaQG&rs=AOn4CLBM_1qrbE_tAOEp51oGRYQMeTkRsw&v=1686139011",
"album": "Voyager"
},
"271867710382714948": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_kEzRY57fWs2iqQv7mg9jA8XEwdctH3vdk&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_kEzRY57fWs2iqQv7mg9jA8XEwdctH3vdk/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCLKkkaQG&rs=AOn4CLCsG_4SxEMgAp96U-dAiavg1BZggQ&v=1686393394",
"album": "Chapter III"
},
"322585091946466973": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_nWWfDckTPSOY4nN_5bXMz1y83Qrc160sM&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_nWWfDckTPSOY4nN_5bXMz1y83Qrc160sM/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCILUmaQG&rs=AOn4CLBW1i3Fi_0G31s8k81YFjUNM6ui_w&v=1686530562",
"album": "Chapter II"
},
"219693029017574393": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_kwpt9qeeS577nxNUo8kh2S4R_3gFFf5Ys&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_kwpt9qeeS577nxNUo8kh2S4R_3gFFf5Ys/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCJeClqQG&rs=AOn4CLD82PHRl_xq8BKF2EtuLOC2d-WStg&v=1686470935",
"album": "Chapter 1"
},
"106299219586508927": {
"artist": "Inteus",
"downloaded": false,
"downloading": false,
"link": "/playlist?list=OLAK5uy_kA-xQTNx8Az1t4HAFQ9vB1oTWG4A5cAIQ&playnext=1&index=1",
"cover": "https://i9.ytimg.com/s_p/OLAK5uy_kA-xQTNx8Az1t4HAFQ9vB1oTWG4A5cAIQ/mqdefault.jpg?sqp=CJT0pKQGir7X7AMGCNaakaQG&rs=AOn4CLDN92pGYYBFP0Vwi5c28qE7L43K_w&v=1686392150",
"album": "Selection: 2"
}
}
}

@ -14,6 +14,7 @@ Jinja2==3.1.2
MarkupSafe==2.1.3 MarkupSafe==2.1.3
mutagen==1.46.0 mutagen==1.46.0
pycryptodomex==3.18.0 pycryptodomex==3.18.0
pysondb-v2==2.0.0
redis==4.5.5 redis==4.5.5
requests==2.31.0 requests==2.31.0
requests-file==1.5.1 requests-file==1.5.1

@ -60,8 +60,16 @@ a {
width: 100%; width: 100%;
} }
.page-wrapper { #action_list {
padding-top: 144px; float: right;
padding: 20px;
color: white;
position: fixed;
right: 0;
}
#action_list a {
color: white;
} }
#logo { #logo {
@ -104,11 +112,22 @@ a {
width: 100%; width: 100%;
} }
.dl_queue_img {
position: relative;
}
.icn-spinner { .icn-spinner {
animation: spin-animation 0.9s infinite; animation: spin-animation 0.9s infinite;
display: inline-block; display: inline-block;
} }
.icn-downloading {
top: 50%;
left: 50%;
position: absolute;
transform: translate(-50%, -50%);
}
@keyframes spin-animation { @keyframes spin-animation {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);

@ -1,20 +1,48 @@
const appModal = $('#modalDownloadQueue');
const appModalContent = $('#modal_content');
function proc_notification(icon, title, text) {
Swal.fire({
title: title,
icon: icon,
text: text
})
}
$('.queue_btn').on('click', () => {
console.log('Get Queue!');
$.ajax({
url: '/api/v1/get/queue'
}).done( (res) => {
console.log(res);
appModalContent.html(res);
appModal.modal('toggle');
})
})
$('#download_btn').on('click', () => { $('#download_btn').on('click', () => {
let artist = $('#search_bar').val(); let artist = $('#search_bar').val();
// Prevent // Prevent
$('#search_bar').val(''); $('#search_bar').val('');
let icon = 'error';
let title = 'What the flip?!';
let text = 'You need to add an artist bro..';
if (artist) { if (artist) {
$("#loader-wrapper").fadeIn(300); $("#loader-wrapper").fadeIn(300);
$.ajax({ $.ajax({
url: `/api/v1/get/${artist}`, url: `/api/v1/get/artist/${artist}`,
}).done(function (res) { }).done(function (res) {
console.log('---'); text = res.message;
console.log(res); if (res.status === 200) {
console.log('---'); icon = 'success';
title = 'Shazam!';
}
$("#loader-wrapper").fadeOut(700); $("#loader-wrapper").fadeOut(700);
proc_notification(icon, title, text);
}); });
} else { } else {
console.log('No artist'); proc_notification(icon, title, text);
} }
}) })

@ -15,6 +15,7 @@
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="apple-touch-icon.png"> <link rel="apple-touch-icon" type="image/png" sizes="180x180" href="apple-touch-icon.png">
<link rel="icon" type="image/svg+xml" href="/static/favicon.png"> <link rel="icon" type="image/svg+xml" href="/static/favicon.png">
<meta name="theme-color" content="#1db8d7"> <meta name="theme-color" content="#1db8d7">
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</head> </head>
<body> <body>
<div id="loader-wrapper" class="bg-white position-fixed z-3 w-100 h-100 text-center"> <div id="loader-wrapper" class="bg-white position-fixed z-3 w-100 h-100 text-center">
@ -27,6 +28,18 @@
<div class="wrapper"> <div class="wrapper">
<div class="page-wrapper"> <div class="page-wrapper">
<div class="page-content"> <div class="page-content">
<div id="action_list">
<span>
<a href="#download-queue">
<i class="las la-3x la-server queue_btn"></i>
</a>
<a href="#download-queue">
<i class="las la-3x la-server queue_btn"></i>
</a>
</span>
</div>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div id="disk" class="card centered"> <div id="disk" class="card centered">
@ -65,6 +78,26 @@
</div> </div>
</div> </div>
<!-- Modal -->
<div class="modal fade"
id="modalDownloadQueue" tabindex="-1" aria-labelledby="modalDownloadQueue" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg modal-dialog-scrollable modal-fullscreen-md-down modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Download Queue</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="modal_content"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!--[if IE]> <!--[if IE]>
<div class="position-fixed bottom-0 w-100 p-2 text-bg-dark d-flex justify-content-between"><p> <div class="position-fixed bottom-0 w-100 p-2 text-bg-dark d-flex justify-content-between"><p>
Outdated Outdated
@ -101,5 +134,6 @@
</div> </div>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

@ -0,0 +1,41 @@
<div class="row">
{% for album_id in album_ids %}
<div class="col-12">
<div class="queue_card">
<div class="card mb-3 p-0">
<div class="row g-0">
<div class="col-md-3">
<div class="dl_queue_img">
{% if not album_id.downloading %}
<div class="icn-downloading">
<i class="la la-6x la-compact-disc icn-spinner text-white"></i>
</div>
{% endif %}
<img src="{{ album_id.cover }}" class="img-fluid rounded-start"
alt="{{ album_id.album }}" style="width: 100%; height: 100%; min-height: 180px;">
</div>
</div>
<div class="col-md-9">
<div class="card-body">
<h5 class="card-title">{{ album_id.album }}</h5>
<p class="card-text">{{ album_id.artist }}</p>
{% if album_id.downloading %}
<p>Downloading...</p>
{% else %}
<p>Waiting to Download</p>
{% endif %}
<p class="card-text"><small class="text-muted"><a
href="https://youtube.com{{ album_id.link }}">Album Page</a></small></p>
</div>
</div>
</div>
</div>
</div>
</div>
{% else %}
<p>Nothing waiting to download</p>
{% endfor %}
</div>

@ -1,2 +1,5 @@
from . import browser from . import browser
from . import download
from . import processor from . import processor
from . import scraper
from . import yt_dlp_logger

@ -0,0 +1,59 @@
import os
from const import *
from .yt_dlp_logger import *
import wget
import yt_dlp
def download_process_list(artist, processed_albums_data_list):
"""
Take a list of dictionaries that have the values needed to create a file-structure and save the downloaded files
:param artist:
:param processed_albums_data_list:
:return:
"""
artist_path = MEDIA_FOLDER + '/%s' % artist
if not os.path.exists(artist_path):
os.mkdir(artist_path)
for item in processed_albums_data_list:
print('---')
# Create album folder
album = item.get('album')
album_path = artist_path + '/%s' % album
if not os.path.exists(album_path):
os.mkdir(album_path)
# Save album cover
if item.get('cover'):
try:
download_file(item.get('cover'), album_path)
except Exception as e:
print("Warning: %s" % e)
# Download album
print(item)
ydl_opts = {
'logger': YtDlpLogger(),
'progress_hooks': [yt_dlp_log_hook],
'format': 'mp3/bestaudio/best',
'outtmpl': album_path + '/%(title)s.%(ext)s',
# See help(yt_dlp.postprocessor) for a list of available Postprocessors and their arguments
'postprocessors': [{ # Extract audio using ffmpeg
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
}]
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
try:
error_code = ydl.download('https://youtube.com' + item.get('link'))
except Exception as e:
print('!!!!!!!!!')
print(e)
def download_file(url, output):
filename = wget.download(url, out=output)
os.rename(filename, output + '/album.jpg')
return filename

@ -1,86 +1,18 @@
import os from database import Model
from .scraper import scrape, process_scraped_data
from pysondb import PysonDB
import bs4
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from .browser import new_browser
from .yt_dlp_logger import *
from const import *
import time
import wget
import yt_dlp
# db = PysonDB('/home/stonesoft/Apps/getDiscography/database/db.json')
Album = Model('album')
def download_file(url, output):
filename = wget.download(url, out=output)
os.rename(filename, output + '/album.jpg')
return filename
def process_download(artist):
artist = artist.title()
# Initialize a new browser object to go collect the data we need
browser = new_browser(headless=True)
url = QUERY_URL + artist
browser.maximize_window()
browser.implicitly_wait(1)
response = browser.get(url)
last_height = browser.execute_script("return document.body.scrollHeight")
browser.execute_script("window.scrollTo(0, 500);")
time.sleep(1)
res_value = ''
try:
# get the financial value when it's populated to the page
value_element = WebDriverWait(browser, 5).until(
EC.presence_of_element_located(locator=(By.XPATH, '//div[@id="shelf-container"]'))
)
element = browser.find_element(By.XPATH, ALBUM_CONTAINER_ITEMS_XPATH)
if element:
time.sleep(1)
res_value += element.get_attribute('outerHTML')
btn_right = browser.find_element(By.XPATH, BTN_RIGHT_FULL_XPATH)
btn_right_displayed = True
safety_index = 0
while btn_right_displayed:
# actions = ActionChains(browser)
# actions.move_to_element(btn_right).perform()
safety_index += 1
time.sleep(1)
browser.execute_script(click_script)
time.sleep(1)
element = browser.find_element(By.XPATH, ALBUM_CONTAINER_ITEMS_XPATH)
res_value += element.get_attribute('outerHTML')
time.sleep(1)
btn_right_displayed = btn_right.is_displayed()
if safety_index > 5:
btn_right_displayed = False
time.sleep(1)
finally:
# after 5 seconds, give up
browser.quit()
# Process the gathered HTML data for list of data
html = bs4.BeautifulSoup(res_value, features="html.parser")
albums = html.find_all('a')
albums_data_list = []
for album in albums:
album_data = {'artist': artist.title()}
if album.has_key('href'):
album_data.update({'link': album['href']})
album_image = album.find('img')
if album_image and album_image.has_key('src'):
album_data.update({'cover': album_image['src']})
album_title = album.find('div', {'id': 'card-title'})
if album_title and hasattr(album_title, 'text'):
album_data.update({'album': album_title.text.replace('\n', '').replace('/', '-')})
albums_data_list.append(album_data)
def filter_data_list(albums_data_list):
"""
Ensure there are no duplicate entries or cover-less entries (Intermittent issue when scrape runs)
:param albums_data_list: A list of dicts that was processed after scrape()
:return: A clean list of dicts
"""
processed_albums_data_list = [] processed_albums_data_list = []
processed_album_names = [] processed_album_names = []
# Eliminate duplicate entries: # Eliminate duplicate entries:
@ -89,47 +21,34 @@ def process_download(artist):
processed_albums_data_list.append(item) processed_albums_data_list.append(item)
processed_album_names.append(item.get('album')) processed_album_names.append(item.get('album'))
#===:= Download the albums ===# return processed_albums_data_list
# Create Artist folder/path
artist_path = MEDIA_FOLDER + '/%s' % artist
if not os.path.exists(artist_path):
os.mkdir(artist_path)
for item in processed_albums_data_list:
print('---')
# Create album folder
album = item.get('album')
album_path = artist_path + '/%s' % album
if not os.path.exists(album_path):
os.mkdir(album_path)
# Save album cover
if item.get('cover'):
try:
download_file(item.get('cover'), album_path)
except Exception as e:
print("Warning: %s" % e)
# Download album
print(item)
ydl_opts = {
'logger': MyLogger(),
'progress_hooks': [my_hook],
'format': 'mp3/bestaudio/best',
'outtmpl': album_path + '/%(title)s.%(ext)s',
# See help(yt_dlp.postprocessor) for a list of available Postprocessors and their arguments
'postprocessors': [{ # Extract audio using ffmpeg
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
}]
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl: def process_download(artist):
"""
Main entrypoint for job processing
:param artist:
:return:
"""
artist = artist.title()
res = {'status': 801, 'message': 'Could not find artist %s' % artist}
# Initialize a new browser object to go collect the data we need
try: try:
error_code = ydl.download('https://youtube.com' + item.get('link')) scrape_data = scrape(artist)
if scrape_data:
albums_data_list = process_scraped_data(artist, scrape_data)
processed_albums_data_list = filter_data_list(albums_data_list)
if len(processed_albums_data_list) == 1:
Album.create(processed_albums_data_list)
else:
Album.create_many(processed_albums_data_list)
res.update({
'status': 200,
'data': processed_albums_data_list,
'message': 'Artist %s added to the download queue!' % artist
})
except Exception as e: except Exception as e:
print('!!!!!!!!!')
print(e) print(e)
return processed_albums_data_list return res

@ -0,0 +1,80 @@
import bs4
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from .browser import new_browser
from const import *
def process_scraped_data(artist, res_value):
# Process the gathered HTML data for list of data
html = bs4.BeautifulSoup(res_value, features="html.parser")
albums = html.find_all('a')
albums_data_list = []
for album in albums:
album_data = {
'artist': artist.title(),
'downloaded': False,
'downloading': False,
}
if album.has_key('href'):
album_data.update({'link': album['href']})
album_image = album.find('img')
if album_image and album_image.has_key('src'):
album_data.update({'cover': album_image['src']})
album_title = album.find('div', {'id': 'card-title'})
if album_title and hasattr(album_title, 'text'):
album_data.update({'album': album_title.text.replace('\n', '').replace('/', '-')})
albums_data_list.append(album_data)
return albums_data_list
def scrape(artist):
browser = new_browser(headless=True)
url = QUERY_URL + artist
browser.maximize_window()
browser.implicitly_wait(1)
response = browser.get(url)
last_height = browser.execute_script("return document.body.scrollHeight")
browser.execute_script("window.scrollTo(0, 500);")
time.sleep(1)
scrape_data = ''
try:
# get the financial value when it's populated to the page
value_element = WebDriverWait(browser, 5).until(
EC.presence_of_element_located(locator=(By.XPATH, '//div[@id="shelf-container"]'))
)
element = browser.find_element(By.XPATH, ALBUM_CONTAINER_ITEMS_XPATH)
if element:
time.sleep(1)
scrape_data += element.get_attribute('outerHTML')
btn_right = browser.find_element(By.XPATH, BTN_RIGHT_FULL_XPATH)
btn_right_displayed = True
safety_index = 0
while btn_right_displayed:
# actions = ActionChains(browser)
# actions.move_to_element(btn_right).perform()
safety_index += 1
time.sleep(1)
browser.execute_script(click_script)
time.sleep(1)
element = browser.find_element(By.XPATH, ALBUM_CONTAINER_ITEMS_XPATH)
scrape_data += element.get_attribute('outerHTML')
time.sleep(1)
btn_right_displayed = btn_right.is_displayed()
if safety_index > 5:
btn_right_displayed = False
time.sleep(1)
finally:
# after 5 seconds, give up
browser.quit()
return scrape_data

@ -1,4 +1,4 @@
class MyLogger: class YtDlpLogger:
def debug(self, msg): def debug(self, msg):
# For compatibility with youtube-dl, both debug and info are passed into debug # For compatibility with youtube-dl, both debug and info are passed into debug
# You can distinguish them by the prefix '[debug] ' # You can distinguish them by the prefix '[debug] '
@ -18,6 +18,6 @@ class MyLogger:
# See "progress_hooks" in help(yt_dlp.YoutubeDL) # See "progress_hooks" in help(yt_dlp.YoutubeDL)
def my_hook(d): def yt_dlp_log_hook(d):
if d['status'] == 'finished': if d['status'] == 'finished':
print('Done downloading, now post-processing ...') print('Done downloading, now post-processing ...')

Loading…
Cancel
Save