2021-04-05 16:38:47 +02:00
|
|
|
#coding: utf8
|
|
|
|
import downloader
|
|
|
|
from io import BytesIO
|
2022-07-21 07:14:09 +02:00
|
|
|
from utils import Downloader, LazyUrl, get_print, try_n, lock, clean_title, get_max_range
|
2021-04-05 16:38:47 +02:00
|
|
|
import ffmpeg
|
|
|
|
import ytdl
|
|
|
|
from m3u8_tools import M3u8_stream
|
2022-07-21 07:14:09 +02:00
|
|
|
from ratelimit import limits, sleep_and_retry
|
2021-04-05 16:38:47 +02:00
|
|
|
CLIENT_ID = None
|
|
|
|
|
|
|
|
|
|
|
|
@lock
|
|
|
|
def get_cid(force=False):
|
|
|
|
global CLIENT_ID
|
|
|
|
if CLIENT_ID is None or force:
|
|
|
|
print('update cid...')
|
|
|
|
d = ytdl.YoutubeDL()
|
|
|
|
e = ytdl.extractor.soundcloud.SoundcloudIE(d)
|
|
|
|
e._update_client_id()
|
|
|
|
CLIENT_ID = e._CLIENT_ID
|
|
|
|
return CLIENT_ID
|
|
|
|
|
|
|
|
|
2022-09-18 08:40:54 +02:00
|
|
|
class Audio:
|
2021-04-05 16:38:47 +02:00
|
|
|
_url = None
|
2022-07-21 07:14:09 +02:00
|
|
|
|
|
|
|
def __init__(self, url, album_art, cw=None):
|
2021-04-05 16:38:47 +02:00
|
|
|
self.album_art = album_art
|
|
|
|
self.cw = cw
|
2022-07-21 07:14:09 +02:00
|
|
|
self.url = LazyUrl(url, self.get, self, pp=self.pp)
|
2021-04-05 16:38:47 +02:00
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
@try_n(2)
|
|
|
|
@sleep_and_retry
|
|
|
|
@limits(1, 1)
|
2021-04-05 16:38:47 +02:00
|
|
|
def get(self, url):
|
|
|
|
print_ = get_print(self.cw)
|
|
|
|
if self._url:
|
|
|
|
return self._url
|
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
ydl = ytdl.YoutubeDL()
|
|
|
|
self.info = info = ydl.extract_info(url)
|
2021-04-05 16:38:47 +02:00
|
|
|
|
|
|
|
formats = info['formats']
|
|
|
|
print(formats)
|
|
|
|
formats = sorted(formats, key=lambda x: int(x.get('abr', 0)), reverse=True)
|
|
|
|
url_audio = None
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
for format in formats:
|
|
|
|
protocol = format['protocol']
|
2022-07-21 07:14:09 +02:00
|
|
|
print_('【{}】 format【{}】 abr【{}】'.format(protocol, format['format'], format.get('abr', 0)))
|
2021-04-05 16:38:47 +02:00
|
|
|
if not url_audio and protocol in ['http', 'https']:
|
|
|
|
url_audio = format['url']
|
|
|
|
|
|
|
|
if not url_audio:
|
|
|
|
url_audio = M3u8_stream(formats[0]['url'])
|
|
|
|
self.album_art = False#
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
self.username = info['uploader']
|
2022-07-21 07:14:09 +02:00
|
|
|
self.title = '{} - {}'.format(self.username, info['title'])
|
|
|
|
self.filename = '{}{}'.format(clean_title(self.title, allow_dot=True, n=-4), '.mp3')
|
2021-04-05 16:38:47 +02:00
|
|
|
|
|
|
|
thumb = None
|
|
|
|
for t in info['thumbnails'][::-1]:
|
|
|
|
width = t.get('width', 1080)
|
|
|
|
if not 100 <= width <= 500:
|
|
|
|
continue
|
|
|
|
url_thumb = t['url']
|
|
|
|
thumb = BytesIO()
|
|
|
|
try:
|
|
|
|
downloader.download(url_thumb, buffer=thumb)
|
|
|
|
break
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
thumb = None
|
|
|
|
self.thumb = thumb
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
self._url = url_audio
|
|
|
|
return self._url
|
|
|
|
|
|
|
|
def pp(self, filename):
|
|
|
|
if self.thumb and self.album_art:
|
|
|
|
self.thumb.seek(0)#
|
|
|
|
ffmpeg.add_cover(filename, self.thumb, {'artist':self.username, 'title':self.info['title']}, cw=self.cw)
|
|
|
|
|
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
class Downloader_soundcloud(Downloader):
|
|
|
|
type = 'soundcloud'
|
|
|
|
single = True
|
|
|
|
URLS = ['soundcloud.com']
|
|
|
|
#lock = True
|
|
|
|
audio = None
|
|
|
|
display_name = 'SoundCloud'
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
def init(self):
|
|
|
|
if 'soundcloud.com' in self.url.lower():
|
|
|
|
self.url = self.url.replace('http://', 'https://')
|
|
|
|
else:
|
|
|
|
self.url = 'https://soundcloud.com/{}'.format(self.url)
|
2022-09-18 08:40:54 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def fix_url(cls, url):
|
|
|
|
return url.split('?')[0]
|
2021-04-05 16:38:47 +02:00
|
|
|
|
|
|
|
def read(self):
|
|
|
|
album_art = self.ui_setting.albumArt.isChecked()
|
|
|
|
info = get_audios(self.url, self.cw, album_art)
|
|
|
|
audios = info['audios']
|
2022-07-21 07:14:09 +02:00
|
|
|
|
2021-04-05 16:38:47 +02:00
|
|
|
if not audios:
|
|
|
|
raise Exception('no audios')
|
|
|
|
|
|
|
|
# first audio must be valid
|
|
|
|
while audios:
|
|
|
|
audio = audios[0]
|
|
|
|
try:
|
|
|
|
audio.url()
|
|
|
|
break
|
|
|
|
except Exception as e:
|
|
|
|
e_ = e
|
|
|
|
print(e)
|
|
|
|
audios.remove(audio)
|
|
|
|
else:
|
|
|
|
raise e_
|
|
|
|
|
|
|
|
if len(audios) > 1:
|
|
|
|
audio = self.process_playlist(info['title'], audios)
|
|
|
|
else:
|
|
|
|
self.urls.append(audio.url)
|
|
|
|
self.title = audio.title
|
|
|
|
|
|
|
|
self.artist = audio.username
|
|
|
|
self.setIcon(audio.thumb)
|
|
|
|
|
|
|
|
|
|
|
|
@try_n(2)
|
|
|
|
def get_audios(url, cw, album_art):
|
|
|
|
print_ = get_print(cw)
|
|
|
|
url = url.rstrip('/')
|
|
|
|
if url.count('/') == 3:
|
|
|
|
url += '/tracks'
|
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
options = {
|
|
|
|
'extract_flat': True,
|
|
|
|
'playlistend': get_max_range(cw),
|
2021-04-05 16:38:47 +02:00
|
|
|
}
|
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
ydl = ytdl.YoutubeDL(options, cw=cw)
|
2021-04-05 16:38:47 +02:00
|
|
|
info = ydl.extract_info(url)
|
|
|
|
if 'entries' in info:
|
|
|
|
entries = info['entries']
|
|
|
|
title = info['title']
|
|
|
|
for _type in ['All', 'Tracks', 'Albums', 'Sets', 'Reposts', 'Likes', 'Spotlight']:
|
|
|
|
x = '({})'.format(_type)
|
|
|
|
if x in title:
|
|
|
|
title = title.replace(x, '')
|
|
|
|
kind = _type
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
kind = 'Playlist'
|
2022-07-21 07:14:09 +02:00
|
|
|
print_('kind: {}'.format(kind))
|
|
|
|
info['title'] = '[{}] {}'.format(kind.capitalize(), title)
|
2021-04-05 16:38:47 +02:00
|
|
|
else:
|
|
|
|
entries = [info]
|
|
|
|
|
|
|
|
audios = []
|
|
|
|
for e in entries:
|
2022-07-21 07:14:09 +02:00
|
|
|
url = e.get('webpage_url') or e['url']
|
|
|
|
if '/sets/' in url:
|
2021-04-05 16:38:47 +02:00
|
|
|
continue
|
2022-07-21 07:14:09 +02:00
|
|
|
audio = Audio(url, album_art, cw=cw)
|
2021-04-05 16:38:47 +02:00
|
|
|
audios.append(audio)
|
|
|
|
|
|
|
|
info['audios'] = audios
|
|
|
|
|
2022-07-21 07:14:09 +02:00
|
|
|
return info
|