optimize code

This commit is contained in:
Yaronzz
2022-01-17 16:53:50 +08:00
parent 1b3afaabd0
commit 133def9722
80 changed files with 746 additions and 888 deletions

View File

@@ -26,44 +26,11 @@ from tidal_dl.lang.language import setLang, initLang, getLangChoicePrint
from tidal_dl.printf import Printf, VERSION
from tidal_dl.settings import Settings, TokenSettings, getLogPath
from tidal_dl.tidal import TidalAPI
from tidal_dl.util import API
from tidal_dl.util import API, CONF, TOKEN, LANG, displayTime, loginByConfig, loginByWeb
import tidal_dl.apiKey as apiKey
ssl._create_default_https_context = ssl._create_unverified_context
TOKEN = TokenSettings.read()
CONF = Settings.read()
LANG = initLang(CONF.language)
API.apiKey = apiKey.getItem(CONF.apiKeyIndex)
logging.basicConfig(filename=getLogPath(),
level=logging.INFO,
format='%(asctime)s - %(levelname)s: %(message)s')
def displayTime(seconds, granularity=2):
if seconds <= 0:
return "unknown"
result = []
intervals = (
('weeks', 604800),
('days', 86400),
('hours', 3600),
('minutes', 60),
('seconds', 1),
)
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ', '.join(result[:granularity])
def login():
print(LANG.AUTH_START_LOGIN)
msg, check = API.getDeviceCode()
@@ -74,29 +41,7 @@ def login():
# print(LANG.AUTH_LOGIN_CODE.format(green(API.key.userCode)))
print(LANG.AUTH_NEXT_STEP.format(green("http://" + API.key.verificationUrl + "/" + API.key.userCode), yellow(displayTime(API.key.authCheckTimeout))))
print(LANG.AUTH_WAITING)
start = time.time()
elapsed = 0
while elapsed < API.key.authCheckTimeout:
elapsed = time.time() - start
# print("Check auth status...")
msg, check = API.checkAuthStatus()
if not check:
if msg == "pending":
time.sleep(API.key.authCheckInterval + 1)
continue
Printf.err(msg)
break
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.refreshToken = API.key.refreshToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
break
if elapsed >= API.key.authCheckTimeout:
Printf.err(LANG.AUTH_TIMEOUT)
loginByWeb()
return
@@ -139,33 +84,13 @@ def setAPIKey():
def checkLogin():
if not isNull(TOKEN.accessToken):
# print('Checking Access Token...') #add to translations
msg, check = API.verifyAccessToken(TOKEN.accessToken)
if check:
Printf.info(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(TOKEN.expiresAfter - time.time()))))
return
else:
Printf.info(LANG.MSG_INVAILD_ACCESSTOKEN)
msg, check = API.refreshAccessToken(TOKEN.refreshToken)
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
return
else:
Printf.err(msg)
tmp = TokenSettings() # clears saved tokens
TokenSettings.save(tmp)
if loginByConfig():
return
login()
return
def checkLogout():
global LANG
login()
return

View File

@@ -22,396 +22,13 @@ from tidal_dl.model import Track, Video, Lyrics, Mix
from tidal_dl.printf import Printf
from tidal_dl.settings import Settings
from tidal_dl.tidal import TidalAPI
from tidal_dl.util import getVideoPath, getTrackPath, getAlbumPath, getArtistsName, convertToM4a, setMetaData, \
isNeedDownload, API, getLyricsFromGemius
from tidal_dl.util import convert, downloadTrack, downloadVideo, encrypted, getVideoPath, getTrackPath, getAlbumPath, API
def __loadAPI__(user):
API.key.accessToken = user.accessToken
API.key.userId = user.userid
API.key.countryCode = user.countryCode
# API.key.sessionId = user.sessionid1
def __loadVideoAPI__(user):
API.key.accessToken = user.accessToken
API.key.userId = user.userid
API.key.countryCode = user.countryCode
# API.key.sessionId = user.sessionid2 if not aigpy.string.isNull(user.sessionid2) else user.sessionid1
# def __getIndexStr__(index):
# pre = "0"
# if index < 10:
# return pre + str(index)
# if index < 99:
# return str(index)
# return str(index)
# def __getExtension__(url):
# if '.flac' in url:
# return '.flac'
# if '.mp4' in url:
# return '.mp4'
# return '.m4a'
# def __getArtists__(array):
# ret = []
# for item in array:
# ret.append(item.name)
# return ret
# def __getArtistsString__(artists):
# return ", ".join(map(lambda artist: artist.name, artists))
# def __parseContributors__(roleType, Contributors):
# if Contributors is None:
# return None
# try:
# ret = []
# for item in Contributors['items']:
# if item['role'] == roleType:
# ret.append(item['name'])
# return ret
# except:
# return None
# GEMIUS = lyricsgenius.Genius('vNKbAWAE3rVY_48nRaiOrDcWNLvsxS-Z8qyG5XfEzTOtZvkTfg6P3pxOVlA2BjaW')
#
#
# def __getLyrics__(trackName, artistName, proxy):
# try:
# if not aigpy.string.isNull(proxy):
# GEMIUS._session.proxies = {
# 'http': f'http://{proxy}',
# 'https': f'http://{proxy}',
# }
#
# song = GEMIUS.search_song(trackName, artistName)
# return song.lyrics
# except:
# return ""
#
# def __setMetaData__(track, album, filepath, contributors, lyrics):
# obj = aigpy.tag.TagTool(filepath)
# obj.album = track.album.title
# obj.title = track.title
# if not aigpy.string.isNull(track.version):
# obj.title += ' (' + track.version + ')'
#
# obj.artist = map(lambda artist: artist.name, track.artists) # __getArtists__(track.artists)
# obj.copyright = track.copyRight
# obj.tracknumber = track.trackNumber
# obj.discnumber = track.volumeNumber
# obj.composer = __parseContributors__('Composer', contributors)
# obj.isrc = track.isrc
#
# obj.albumartist = map(lambda artist: artist.name, album.artists) #__getArtists__(album.artists)
# obj.date = album.releaseDate
# obj.totaldisc = album.numberOfVolumes
# obj.lyrics = lyrics
# if obj.totaldisc <= 1:
# obj.totaltrack = album.numberOfTracks
# coverpath = API.getCoverUrl(album.cover, "1280", "1280")
# obj.save(coverpath)
# return
# def __convertToM4a__(filepath, codec):
# if 'ac4' in codec or 'mha1' in codec:
# return filepath
# if '.mp4' not in filepath:
# return filepath
# newpath = filepath.replace('.mp4', '.m4a')
# aigpy.path.remove(newpath)
# os.rename(filepath, newpath)
# return newpath
# def __stripPathParts__(stripped_path, separator):
# result = ""
# stripped_path = stripped_path.split(separator)
# for stripped_path_part in stripped_path:
# result += stripped_path_part.strip()
# if not stripped_path.index(stripped_path_part) == len(stripped_path) - 1:
# result += separator
# return result.strip()
#
#
# def __stripPath__(path):
# result = __stripPathParts__(path, "/")
# result = __stripPathParts__(result, "\\")
# return result.strip()
# "{ArtistName}/{Flag} [{AlbumID}] [{AlbumYear}] {AlbumTitle}"
# def getAlbumPath(conf: Settings, album):
# base = conf.downloadPath + '/Album/'
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(album.artists), '-')
# # album folder pre: [ME][ID]
# flag = API.getFlag(album, Type.Album, True, "")
# if conf.audioQuality != AudioQuality.Master:
# flag = flag.replace("M", "")
# if not conf.addExplicitTag:
# flag = flag.replace("E", "")
# if not aigpy.string.isNull(flag):
# flag = "[" + flag + "] "
#
# sid = str(album.id)
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-')
# year = ""
# if album.releaseDate is not None:
# year = aigpy.string.getSubOnlyEnd(album.releaseDate, '-')
# # retpath
# retpath = conf.albumFolderFormat
# if retpath is None or len(retpath) <= 0:
# retpath = Settings.getDefaultAlbumFolderFormat()
# retpath = retpath.replace(R"{ArtistName}", artist.strip())
# retpath = retpath.replace(R"{Flag}", flag)
# retpath = retpath.replace(R"{AlbumID}", sid)
# retpath = retpath.replace(R"{AlbumYear}", year)
# retpath = retpath.replace(R"{AlbumTitle}", albumname.strip())
# retpath = __stripPath__(retpath.strip())
# return base + retpath
#
#
# def __getAlbumPath2__(conf, album):
# # outputdir/Album/artist/
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(album.artists), '-').strip()
# base = conf.downloadPath + '/Album/' + artist + '/'
#
# # album folder pre: [ME][ID]
# flag = API.getFlag(album, Type.Album, True, "")
# if conf.audioQuality != AudioQuality.Master:
# flag = flag.replace("M", "")
# if not conf.addExplicitTag:
# flag = flag.replace("E", "")
# if not aigpy.string.isNull(flag):
# flag = "[" + flag + "] "
#
# sid = "[" + str(album.id) + "] " if conf.addAlbumIDBeforeFolder else ""
#
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-').strip()
# year = ""
# if conf.addYear and album.releaseDate is not None:
# year = "[" + aigpy.string.getSubOnlyEnd(album.releaseDate, '-') + "] "
# return base + flag + sid + year + albumname + '/'
#
#
# def getPlaylistPath(conf, playlist):
# # outputdir/Playlist/
# base = conf.downloadPath + '/Playlist/'
# # name
# name = aigpy.path.replaceLimitChar(playlist.title, '-')
# return base + name + '/'
#
#
# # "{TrackNumber} - {ArtistName} - {TrackTitle}{ExplicitFlag}"
#
#
# def getTrackPath(conf: Settings, track, stream, album=None, playlist=None):
# if album is not None:
# base = getAlbumPath(conf, album) + '/'
# if album.numberOfVolumes > 1:
# base += 'CD' + str(track.volumeNumber) + '/'
# if playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
# # number
# number = __getIndexStr__(track.trackNumber)
# if playlist is not None and conf.usePlaylistFolder:
# number = __getIndexStr__(track.trackNumberOnPlaylist)
# # artist
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(track.artists), '-')
# # title
# title = track.title
# if not aigpy.string.isNull(track.version):
# title += ' (' + track.version + ')'
# title = aigpy.path.replaceLimitChar(title, '-')
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and track.explicit else ''
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-')
# year = ""
# if album.releaseDate is not None:
# year = aigpy.string.getSubOnlyEnd(album.releaseDate, '-')
# # extension
# extension = __getExtension__(stream.url)
# retpath = conf.trackFileFormat
# if retpath is None or len(retpath) <= 0:
# retpath = Settings.getDefaultTrackFileFormat()
# retpath = retpath.replace(R"{TrackNumber}", number)
# retpath = retpath.replace(R"{ArtistName}", artist.strip())
# retpath = retpath.replace(R"{TrackTitle}", title)
# retpath = retpath.replace(R"{ExplicitFlag}", explicit)
# retpath = retpath.replace(R"{AlbumYear}", year)
# retpath = retpath.replace(R"{AlbumTitle}", albumname.strip())
# retpath = retpath.strip()
# return base + retpath + extension
#
#
# def __getTrackPath2__(conf, track, stream, album=None, playlist=None):
# if album is not None:
# base = getAlbumPath(conf, album)
# if album.numberOfVolumes > 1:
# base += 'CD' + str(track.volumeNumber) + '/'
# if playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
#
# # hyphen
# hyphen = ' - ' if conf.addHyphen else ' '
# # get number
# number = ''
# if conf.useTrackNumber:
# number = __getIndexStr__(track.trackNumber) + hyphen
# if playlist is not None:
# number = __getIndexStr__(track.trackNumberOnPlaylist) + hyphen
# # get artist
# artist = ''
# if conf.artistBeforeTitle:
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(track.artists), '-') + hyphen
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and track.explicit else ''
# # title
# title = track.title
# if not aigpy.string.isNull(track.version):
# title += ' - ' + track.version
# title = aigpy.path.replaceLimitChar(title, '-')
# # extension
# extension = __getExtension__(stream.url)
# return base + number + artist.strip() + title + explicit + extension
#
#
# def getVideoPath(conf, video, album=None, playlist=None):
# if album is not None and album.title is not None:
# base = getAlbumPath(conf, album)
# elif playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
# else:
# base = conf.downloadPath + '/Video/'
#
# # hyphen
# hyphen = ' - ' if conf.addHyphen else ' '
# # get number
# number = ''
# if conf.useTrackNumber:
# number = __getIndexStr__(video.trackNumber) + hyphen
# # get artist
# artist = ''
# if conf.artistBeforeTitle:
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(video.artists), '-') + hyphen
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and video.explicit else ''
# # title
# title = aigpy.path.replaceLimitChar(video.title, '-')
# # extension
# extension = ".mp4"
# return base + number + artist.strip() + title + explicit + extension
# def __isNeedDownload__(path, url):
# curSize = aigpy.file.getSize(path)
# if curSize <= 0:
# return True
# netSize = aigpy.net.getSize(url)
# if curSize >= netSize:
# return False
# return True
def __downloadVideo__(conf, video: Video, album=None, playlist=None):
if video.allowStreaming is False:
Printf.err("Download failed! " + video.title + ' not allow streaming.')
return
msg, stream = API.getVideoStreamUrl(video.id, conf.videoQuality)
Printf.video(video, stream)
if not aigpy.string.isNull(msg):
Printf.err(video.title + "." + msg)
return
path = getVideoPath(conf, video, album, playlist)
logging.info("[DL Video] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.m3u8Url)
m3u8content = requests.get(stream.m3u8Url).content
if m3u8content is None:
Printf.err(video.title + ' get m3u8 content failed.')
return
urls = aigpy.m3u8.parseTsUrls(m3u8content)
if len(urls) <= 0:
Printf.err(video.title + ' parse ts urls failed.')
logging.info("[DL Video] title=" + video.title + "\m3u8Content=" + str(m3u8content))
return
check, msg = aigpy.m3u8.downloadByTsUrls(urls, path)
# check, msg = aigpy.m3u8.download(stream.m3u8Url, path)
if check is True:
Printf.success(aigpy.path.getFileName(path))
else:
Printf.err("\nDownload failed!" + msg + '(' + aigpy.path.getFileName(path) + ')')
def __downloadTrack__(conf: Settings, track: Track, album=None, playlist=None):
try:
# if track.allowStreaming is False:
# Printf.err("Download failed! " + track.title + ' not allow streaming.')
# return
msg, stream = API.getStreamUrl(track.id, conf.audioQuality)
if conf.showTrackInfo:
Printf.track(track, stream)
if not aigpy.string.isNull(msg) or stream is None:
Printf.err(track.title + "." + msg)
return
path = getTrackPath(conf, track, stream, album, playlist)
# check exist
if conf.checkExist and isNeedDownload(path, stream.url) == False:
Printf.success(aigpy.path.getFileName(path) + " (skip:already exists!)")
return
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
tool = aigpy.download.DownloadTool(path + '.part', [stream.url])
check, err = tool.start(conf.showProgress)
if not check:
Printf.err("Download failed! " + aigpy.path.getFileName(path) + ' (' + str(err) + ')')
return
# encrypted -> decrypt and remove encrypted file
if aigpy.string.isNull(stream.encryptionKey):
os.replace(path + '.part', path)
else:
key, nonce = decrypt_security_token(stream.encryptionKey)
decrypt_file(path + '.part', path, key, nonce)
os.remove(path + '.part')
path = convertToM4a(path, stream.codec)
# contributors
msg, contributors = API.getTrackContributors(track.id)
msg, tidalLyrics = API.getLyrics(track.id)
lyrics = '' if tidalLyrics is None else tidalLyrics.subtitles
if conf.addLyrics and lyrics == '':
lyrics = getLyricsFromGemius(track.title, getArtistsName(track.artists), conf.lyricsServerProxy)
if conf.lyricFile:
if tidalLyrics is None:
Printf.info(f'Failed to get lyrics from tidal!"{track.title}"')
else:
lrcPath = path.rsplit(".", 1)[0] + '.lrc'
aigpy.fileHelper.write(lrcPath, tidalLyrics.subtitles, 'w')
setMetaData(track, album, path, contributors, lyrics)
Printf.success(aigpy.path.getFileName(path))
except Exception as e:
Printf.err("Download failed! " + track.title + ' (' + str(e) + ')')
def __downloadCover__(conf, album):
@@ -462,21 +79,21 @@ def __album__(conf, obj):
if conf.saveCovers:
__downloadCover__(conf, obj)
for item in tracks:
__downloadTrack__(conf, item, obj)
downloadTrack(item, obj)
for item in videos:
__downloadVideo__(conf, item, obj)
downloadVideo(item, obj)
def __track__(conf, obj):
msg, album = API.getAlbum(obj.album.id)
if conf.saveCovers:
__downloadCover__(conf, album)
__downloadTrack__(conf, obj, album)
downloadTrack(obj, album)
def __video__(conf, obj):
# Printf.video(obj)
__downloadVideo__(conf, obj, obj.album)
downloadVideo(obj, obj.album)
def __artist__(conf, obj):
@@ -499,11 +116,11 @@ def __playlist__(conf, obj):
for index, item in enumerate(tracks):
mag, album = API.getAlbum(item.album.id)
item.trackNumberOnPlaylist = index + 1
__downloadTrack__(conf, item, album, obj)
downloadTrack(item, album, obj)
if conf.saveCovers and not conf.usePlaylistFolder:
__downloadCover__(conf, album)
for item in videos:
__downloadVideo__(conf, item, None)
downloadVideo(item, None)
def __mix__(conf, obj: Mix):
@@ -511,11 +128,11 @@ def __mix__(conf, obj: Mix):
for index, item in enumerate(obj.tracks):
mag, album = API.getAlbum(item.album.id)
item.trackNumberOnPlaylist = index + 1
__downloadTrack__(conf, item, album)
downloadTrack(item, album)
if conf.saveCovers and not conf.usePlaylistFolder:
__downloadCover__(conf, album)
for item in obj.videos:
__downloadVideo__(conf, item, None)
downloadVideo(item, None)
def file(user, conf, string):
@@ -558,7 +175,6 @@ def start(user, conf, string):
if etype == Type.Track:
__track__(conf, obj)
if etype == Type.Video:
__loadVideoAPI__(user)
__video__(conf, obj)
if etype == Type.Artist:
__artist__(conf, obj)

View File

@@ -51,6 +51,17 @@ class Album(ModelBase):
artists = Artist()
class Playlist(ModelBase):
uuid = None
title = None
numberOfTracks = 0
numberOfVideos = 0
description = None
duration = 0
image = None
squareImage = None
class Track(ModelBase):
id = None
title = None
@@ -67,6 +78,7 @@ class Track(ModelBase):
artists = Artist()
album = Album()
allowStreaming = False
playlist = None
class Video(ModelBase):
@@ -83,17 +95,7 @@ class Video(ModelBase):
artists = Artist()
album = Album()
allowStreaming = False
class Playlist(ModelBase):
uuid = None
title = None
numberOfTracks = 0
numberOfVideos = 0
description = None
duration = 0
image = None
squareImage = None
playlist = None
class Mix(ModelBase):

View File

@@ -397,6 +397,14 @@ class TidalAPI(object):
if sid is None or sid == "":
return None
return "https://resources.tidal.com/images/" + sid.replace("-", "/") + "/" + width + "x" + height + ".jpg"
def getCoverData(self, sid, width="320", height="320"):
url = self.getCoverUrl(sid, width, height)
try:
respond = requests.get(url)
return respond.content
except:
return ''
def getArtistsName(self, artists=[]):
array = []

View File

@@ -11,19 +11,32 @@
import logging
import os
import time
from urllib import request
import aigpy
import lyricsgenius
import datetime
from tidal_dl import apiKey
import tidal_dl
from tidal_dl.decryption import decrypt_file
from tidal_dl.decryption import decrypt_security_token
from tidal_dl.enums import Type, AudioQuality
from tidal_dl.lang.language import initLang
from tidal_dl.model import Track, Video, Lyrics, Mix, Album
from tidal_dl.printf import Printf
from tidal_dl.settings import Settings
from tidal_dl.settings import Settings, TokenSettings, getLogPath
from tidal_dl.tidal import TidalAPI
TOKEN = TokenSettings.read()
CONF = Settings.read()
LANG = initLang(CONF.language)
API = TidalAPI()
API.apiKey = apiKey.getItem(CONF.apiKeyIndex)
logging.basicConfig(filename=getLogPath(),
level=logging.INFO,
format='%(asctime)s - %(levelname)s: %(message)s')
def __getIndexStr__(index):
@@ -49,6 +62,7 @@ def __secondsToTimeStr__(seconds):
time_string = time_string[2:]
return time_string
def __parseContributors__(roleType, Contributors):
if Contributors is None:
return None
@@ -273,3 +287,216 @@ def isNeedDownload(path, url):
if curSize >= netSize:
return False
return True
def encrypted(stream, srcPath, descPath):
if aigpy.string.isNull(stream.encryptionKey):
os.replace(srcPath, descPath)
else:
key, nonce = decrypt_security_token(stream.encryptionKey)
decrypt_file(srcPath, descPath, key, nonce)
os.remove(srcPath)
def getAudioQualityList():
return map(lambda quality: quality.name, tidal_dl.enums.AudioQuality)
def getVideoQualityList():
return map(lambda quality: quality.name, tidal_dl.enums.VideoQuality)
def skip(path, url):
if CONF.checkExist and isNeedDownload(path, url) is False:
return True
return False
def convert(srcPath, stream):
if CONF.onlyM4a:
return convertToM4a(srcPath, stream.codec)
return srcPath
def downloadTrack(track: Track, album=None, playlist=None, userProgress=None):
try:
msg, stream = API.getStreamUrl(track.id, CONF.audioQuality)
if not aigpy.string.isNull(msg) or stream is None:
Printf.err(track.title + "." + msg)
return False, msg
if CONF.showTrackInfo:
Printf.track(track, stream)
path = getTrackPath(CONF, track, stream, album, playlist)
# check exist
if skip(path, stream.url):
Printf.success(aigpy.path.getFileName(path) + " (skip:already exists!)")
return True, ""
# download
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
tool = aigpy.download.DownloadTool(path + '.part', [stream.url])
tool.setUserProgress(userProgress)
check, err = tool.start(CONF.showProgress)
if not check:
Printf.err("Download failed! " + aigpy.path.getFileName(path) + ' (' + str(err) + ')')
return False, str(err)
# encrypted -> decrypt and remove encrypted file
encrypted(stream, path + '.part', path)
# convert
path = convert(path, stream)
# contributors
msg, contributors = API.getTrackContributors(track.id)
msg, tidalLyrics = API.getLyrics(track.id)
lyrics = '' if tidalLyrics is None else tidalLyrics.subtitles
if CONF.lyricFile:
if tidalLyrics is None:
Printf.info(f'Failed to get lyrics from tidal!"{track.title}"')
else:
lrcPath = path.rsplit(".", 1)[0] + '.lrc'
aigpy.fileHelper.write(lrcPath, tidalLyrics.subtitles, 'w')
setMetaData(track, album, path, contributors, lyrics)
Printf.success(aigpy.path.getFileName(path))
return True, ""
except Exception as e:
Printf.err("Download failed! " + track.title + ' (' + str(e) + ')')
return False, str(e)
def downloadVideo(video: Video, album=None, playlist=None):
msg, stream = API.getVideoStreamUrl(video.id, CONF.videoQuality)
Printf.video(video, stream)
if not aigpy.string.isNull(msg):
Printf.err(video.title + "." + msg)
return False, msg
path = getVideoPath(CONF, video, album, playlist)
logging.info("[DL Video] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.m3u8Url)
m3u8content = request.get(stream.m3u8Url).content
if m3u8content is None:
Printf.err(video.title + ' get m3u8 content failed.')
return False, "Get m3u8 content failed"
urls = aigpy.m3u8.parseTsUrls(m3u8content)
if len(urls) <= 0:
Printf.err(video.title + ' parse ts urls failed.')
logging.info("[DL Video] title=" + video.title + "\m3u8Content=" + str(m3u8content))
return False, 'Parse ts urls failed.'
check, msg = aigpy.m3u8.downloadByTsUrls(urls, path)
# check, msg = aigpy.m3u8.download(stream.m3u8Url, path)
if check is True:
Printf.success(aigpy.path.getFileName(path))
return True, ''
else:
Printf.err("\nDownload failed!" + msg + '(' + aigpy.path.getFileName(path) + ')')
return False, msg
def displayTime(seconds, granularity=2):
if seconds <= 0:
return "unknown"
result = []
intervals = (
('weeks', 604800),
('days', 86400),
('hours', 3600),
('minutes', 60),
('seconds', 1),
)
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ', '.join(result[:granularity])
def loginByConfig():
if aigpy.stringHelper.isNull(TOKEN.accessToken):
return False
msg, check = API.verifyAccessToken(TOKEN.accessToken)
if check:
Printf.info(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(TOKEN.expiresAfter - time.time()))))
API.key.countryCode = TOKEN.countryCode
API.key.userId = TOKEN.userid
API.key.accessToken = TOKEN.accessToken
return True
Printf.info(LANG.MSG_INVAILD_ACCESSTOKEN)
msg, check = API.refreshAccessToken(TOKEN.refreshToken)
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
return True
else:
tmp = TokenSettings() # clears saved tokens
TokenSettings.save(tmp)
return False
def loginByWeb():
start = time.time()
elapsed = 0
while elapsed < API.key.authCheckTimeout:
elapsed = time.time() - start
msg, check = API.checkAuthStatus()
if not check:
if msg == "pending":
time.sleep(API.key.authCheckInterval + 1)
continue
return False
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.refreshToken = API.key.refreshToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
return True
Printf.err(LANG.AUTH_TIMEOUT)
return False
def getArtistsNames(artists): # : list[tidal_dl.model.Artist]
ret = []
for item in artists:
ret.append(item.name)
return ','.join(ret)
def getDurationString(seconds: int):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
return "%02d:%02d:%02d" % (h, m, s)
def getBasePath(model):
if isinstance(model, tidal_dl.model.Album):
return getAlbumPath(CONF, model)
if isinstance(model, tidal_dl.model.Playlist):
return getPlaylistPath(CONF, model)
if isinstance(model, tidal_dl.model.Track):
return getAlbumPath(CONF, model)
if isinstance(model, tidal_dl.model.Video):
filePath = getVideoPath(CONF, model, model.album, model.playlist)
return aigpy.pathHelper.getDirName(filePath)
return './'
def getFilePath(model, stream=None):
if isinstance(model, tidal_dl.model.Track):
return getTrackPath(CONF, model, stream, model.album, model.playlist)
if isinstance(model, tidal_dl.model.Video):
return getVideoPath(CONF, model, model.album, model.playlist)
return './'

View File

@@ -23,11 +23,12 @@ def main():
mainView = MainModel()
mainView.show()
app.exec_()
mainView.uninit()
sys.exit()
if __name__ == '__main__':
main()

View File

@@ -8,12 +8,12 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QComboBox, QListView
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QComboBox, QListView
class ComboBox(QComboBox):
def __init__(self, items: list, width: int=200):
def __init__(self, items: list, width: int = 200):
super(ComboBox, self).__init__()
self.setItems(items)
self.setFixedWidth(width)

View File

@@ -8,13 +8,7 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import ctypes.wintypes
from ctypes.wintypes import POINT
import typing
import PyQt5
import win32api
import win32con
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QWidget, QGridLayout, QHBoxLayout

View File

@@ -8,7 +8,6 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QListWidget, QListWidgetItem, QWidget

View File

@@ -29,4 +29,3 @@ class PushButton(QPushButton):
if iconUrl != '':
self.setIcon(QIcon(iconUrl))

View File

@@ -9,21 +9,19 @@
@Desc :
"""
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QListWidget, QListWidgetItem, QWidget, QScrollArea, QVBoxLayout, QPushButton, QBoxLayout
from PyQt5.QtWidgets import QWidget, QScrollArea, QVBoxLayout
class ScrollWidget(QScrollArea):
def __init__(self):
super(ScrollWidget, self).__init__()
self._layout = QVBoxLayout()
self._layout.addStretch(1)
self._mainW = QWidget()
self._mainW.setLayout(self._layout)
self.setWidget(self._mainW)
self.setWidgetResizable(True)

View File

@@ -10,7 +10,7 @@
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QTableView, QTableWidgetItem, QAbstractItemView
from PyQt5.QtWidgets import QTableView, QAbstractItemView
class TableView(QTableView):
@@ -25,7 +25,7 @@ class TableView(QTableView):
self._model.setHeaderData(index, Qt.Horizontal, name)
self.setModel(self._model)
# self.setHorizontalHeaderItem(index, QTableWidgetItem(name))
# self.setHorizontalHeaderItem(index, QTableWidgetItem(name))
# for index in range(0, rowCount):
# self.setRowHeight(index, 50)

View File

@@ -8,13 +8,13 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import aigpy
import requests
import threading
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QAbstractItemView, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QAbstractItemView
from tidal_gui.control.label import Label, LabelStyle

View File

@@ -8,16 +8,18 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.Qt import QThread
from queue import Queue
from tidal_gui.viewModel.taskModel import TaskModel
import time
from PyQt5.Qt import QThread
from tidal_gui.viewModel.taskModel import TaskModel
class DownloaderImp(QThread):
def __init__(self):
super(DownloaderImp, self).__init__()
self._taskModel = None
def run(self):
print('DownloadImp start...')
while not self.isInterruptionRequested():
@@ -27,12 +29,13 @@ class DownloaderImp(QThread):
item.download()
time.sleep(1)
print('DownloadImp stop...')
def setTaskModel(self, model: TaskModel):
self._taskModel = model
def stop(self):
self.requestInterruption()
self.wait()
downloadImp = DownloaderImp()

View File

@@ -1 +1,12 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629184159878" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23123" xmlns:xlink="http://www.w3.org/1999/xlink" width="136.5" height="128"><defs><style type="text/css"></style></defs><path d="M538.624 1017.344L0.580267 405.162667 212.445867 0h652.356266L1076.565333 405.162667z" fill="#46F256" p-id="23124"></path><path d="M538.624 748.6464l-317.44-351.607467 67.618133-61.098666 249.787734 276.718933 249.821866-276.6848 67.618134 61.064533z" fill="#000000" p-id="23125"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629184159878" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="23123" width="136.5" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M538.624 1017.344L0.580267 405.162667 212.445867 0h652.356266L1076.565333 405.162667z" fill="#46F256"
p-id="23124"></path>
<path d="M538.624 748.6464l-317.44-351.607467 67.618133-61.098666 249.787734 276.718933 249.821866-276.6848 67.618134 61.064533z"
fill="#000000" p-id="23125"></path>
</svg>

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 694 B

View File

@@ -1 +1,5 @@
<svg t="1629268466285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18338" width="128" height="128"><path d="M294.314667 0L242.432 119.424H165.418667v107.648h29.653333L225.152 418.133333H178.005333l62.293334 351.146667 40.021333-0.426667 40.192 255.146667h380.501333l2.645334-17.066667 37.546666-238.08 37.888 0.426667 62.293334-351.189333h-45.056l30.08-191.018667h32.256V119.466667h-81.834667L724.906667 0H294.314667z m22.528 34.346667h385.834666l32.896 75.946666H283.818667l33.024-75.946666z m-117.333334 119.338666H824.32v39.253334H199.509333v-39.253334z m19.328 298.581334h581.76l-50.176 282.453333-241.024-2.56-240.469333 2.56-50.090667-282.453333z" p-id="18339" fill="#ffffff"></path></svg>
<svg t="1629268466285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="18338" width="128" height="128">
<path d="M294.314667 0L242.432 119.424H165.418667v107.648h29.653333L225.152 418.133333H178.005333l62.293334 351.146667 40.021333-0.426667 40.192 255.146667h380.501333l2.645334-17.066667 37.546666-238.08 37.888 0.426667 62.293334-351.189333h-45.056l30.08-191.018667h32.256V119.466667h-81.834667L724.906667 0H294.314667z m22.528 34.346667h385.834666l32.896 75.946666H283.818667l33.024-75.946666z m-117.333334 119.338666H824.32v39.253334H199.509333v-39.253334z m19.328 298.581334h581.76l-50.176 282.453333-241.024-2.56-240.469333 2.56-50.090667-282.453333z"
p-id="18339" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 743 B

After

Width:  |  Height:  |  Size: 764 B

View File

@@ -3,4 +3,8 @@
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#cbcbcb"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#cbcbcb"></path></svg>
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609"
width="128" height="128">
<path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1610" fill="#cbcbcb"></path>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -3,4 +3,8 @@
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#326cf3"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#326cf3"></path></svg>
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609"
width="128" height="128">
<path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1610" fill="#326cf3"></path>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -1 +1,5 @@
<svg t="1629268481541" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19187" width="128" height="128"><path d="M512.032 831.904c-19.168 0-38.304-9.92-58.144-29.76-7.808-7.808-7.808-20.48 0-28.288s20.48-7.808 28.288 0C494.368 786.08 504.16 792 512.032 792s17.664-5.92 29.856-18.144c7.808-7.808 20.48-7.808 28.288 0s7.808 20.48 0 28.288c-19.84 19.84-38.976 29.76-58.144 29.76z m-512-306.4c0 49.888 4.256 95.136 12.8 135.68s20.544 75.744 36 105.536 35.008 55.904 58.656 78.336 49.344 40.928 77.056 55.456c27.744 14.528 59.456 26.304 95.2 35.264S351.84 951.04 388.8 954.624 466.496 960 510.944 960c44.448 0 85.248-1.792 122.4-5.376s73.6-9.856 109.344-18.848c35.744-8.96 67.552-20.736 95.456-35.264s53.792-33.024 77.6-55.456c23.808-22.432 43.456-48.544 58.944-78.336s27.552-64.96 36.256-105.536c8.704-40.576 13.056-85.792 13.056-135.68 0-89.376-27.744-166.368-83.2-230.976 3.2-8.608 5.952-18.496 8.256-29.6s4.544-26.816 6.656-47.104c2.144-20.288 1.344-43.712-2.4-70.272S942.56 93.888 932.256 66.24l-8-1.632c-5.344-1.088-14.048-0.704-26.144 1.088s-26.208 5.024-42.4 9.696-37.056 13.92-62.656 27.744-52.608 31.328-81.056 52.512c-48.352-14.72-115.008-30.112-200-30.112s-151.808 15.392-200.544 30.112c-28.448-21.184-55.552-38.592-81.344-52.224s-46.4-22.976-61.856-28c-15.456-5.024-29.792-8.256-42.944-9.696s-21.6-1.888-25.344-1.344c-3.744 0.544-6.496 1.152-8.256 1.888-10.304 27.648-17.408 54.752-21.344 81.312s-4.8 49.888-2.656 69.984c2.144 20.096 4.448 35.904 6.944 47.392S80 286.304 83.2 294.56C27.744 358.816 0 435.808 0 525.536z m136.544 113.888c0-58.016 21.344-110.624 64-157.856 12.8-14.4 27.648-25.312 44.544-32.704s36.096-11.616 57.6-12.608 42.048-0.8 61.6 0.608 43.744 3.296 72.544 5.696 53.696 3.616 74.656 3.616c20.96 0 45.856-1.184 74.656-3.616s52.992-4.288 72.544-5.696c19.552-1.408 40.096-1.6 61.6-0.608s40.8 5.216 57.856 12.608c17.056 7.392 32 18.304 44.8 32.704 42.656 47.232 64 99.84 64 157.856 0 34.016-3.552 64.32-10.656 90.944s-16.096 48.928-26.944 66.912c-10.848 18.016-26.048 33.216-45.6 45.632s-38.496 22.016-56.8 28.8c-18.304 6.784-41.952 12.096-70.944 15.904s-54.944 6.112-77.856 6.912c-22.944 0.8-51.808 1.216-86.656 1.216s-63.648-0.416-86.4-1.216c-22.752-0.8-48.608-3.104-77.6-6.912s-52.608-9.12-70.944-15.904c-18.304-6.816-37.248-16.416-56.8-28.8s-34.752-27.616-45.6-45.632c-10.848-18.016-19.84-40.32-26.944-66.912s-10.656-56.928-10.656-90.944zM256.032 608c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z m384 0c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z" p-id="19188"></path></svg>
<svg t="1629268481541" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="19187" width="128" height="128">
<path d="M512.032 831.904c-19.168 0-38.304-9.92-58.144-29.76-7.808-7.808-7.808-20.48 0-28.288s20.48-7.808 28.288 0C494.368 786.08 504.16 792 512.032 792s17.664-5.92 29.856-18.144c7.808-7.808 20.48-7.808 28.288 0s7.808 20.48 0 28.288c-19.84 19.84-38.976 29.76-58.144 29.76z m-512-306.4c0 49.888 4.256 95.136 12.8 135.68s20.544 75.744 36 105.536 35.008 55.904 58.656 78.336 49.344 40.928 77.056 55.456c27.744 14.528 59.456 26.304 95.2 35.264S351.84 951.04 388.8 954.624 466.496 960 510.944 960c44.448 0 85.248-1.792 122.4-5.376s73.6-9.856 109.344-18.848c35.744-8.96 67.552-20.736 95.456-35.264s53.792-33.024 77.6-55.456c23.808-22.432 43.456-48.544 58.944-78.336s27.552-64.96 36.256-105.536c8.704-40.576 13.056-85.792 13.056-135.68 0-89.376-27.744-166.368-83.2-230.976 3.2-8.608 5.952-18.496 8.256-29.6s4.544-26.816 6.656-47.104c2.144-20.288 1.344-43.712-2.4-70.272S942.56 93.888 932.256 66.24l-8-1.632c-5.344-1.088-14.048-0.704-26.144 1.088s-26.208 5.024-42.4 9.696-37.056 13.92-62.656 27.744-52.608 31.328-81.056 52.512c-48.352-14.72-115.008-30.112-200-30.112s-151.808 15.392-200.544 30.112c-28.448-21.184-55.552-38.592-81.344-52.224s-46.4-22.976-61.856-28c-15.456-5.024-29.792-8.256-42.944-9.696s-21.6-1.888-25.344-1.344c-3.744 0.544-6.496 1.152-8.256 1.888-10.304 27.648-17.408 54.752-21.344 81.312s-4.8 49.888-2.656 69.984c2.144 20.096 4.448 35.904 6.944 47.392S80 286.304 83.2 294.56C27.744 358.816 0 435.808 0 525.536z m136.544 113.888c0-58.016 21.344-110.624 64-157.856 12.8-14.4 27.648-25.312 44.544-32.704s36.096-11.616 57.6-12.608 42.048-0.8 61.6 0.608 43.744 3.296 72.544 5.696 53.696 3.616 74.656 3.616c20.96 0 45.856-1.184 74.656-3.616s52.992-4.288 72.544-5.696c19.552-1.408 40.096-1.6 61.6-0.608s40.8 5.216 57.856 12.608c17.056 7.392 32 18.304 44.8 32.704 42.656 47.232 64 99.84 64 157.856 0 34.016-3.552 64.32-10.656 90.944s-16.096 48.928-26.944 66.912c-10.848 18.016-26.048 33.216-45.6 45.632s-38.496 22.016-56.8 28.8c-18.304 6.784-41.952 12.096-70.944 15.904s-54.944 6.112-77.856 6.912c-22.944 0.8-51.808 1.216-86.656 1.216s-63.648-0.416-86.4-1.216c-22.752-0.8-48.608-3.104-77.6-6.912s-52.608-9.12-70.944-15.904c-18.304-6.816-37.248-16.416-56.8-28.8s-34.752-27.616-45.6-45.632c-10.848-18.016-19.84-40.32-26.944-66.912s-10.656-56.928-10.656-90.944zM256.032 608c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z m384 0c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z"
p-id="19188"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1 +1,5 @@
<svg t="1629270772080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1817" width="128" height="128"><path d="M658.059636 187.826424a31.030303 31.030303 0 0 1 0 43.876849l-288.364606 288.364606 288.364606 288.364606a31.030303 31.030303 0 0 1-43.876848 43.876848l-310.30303-310.30303a31.030303 31.030303 0 0 1 0-43.876848l310.30303-310.303031a31.030303 31.030303 0 0 1 43.876848 0z" p-id="1818"></path></svg>
<svg t="1629270772080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1817"
width="128" height="128">
<path d="M658.059636 187.826424a31.030303 31.030303 0 0 1 0 43.876849l-288.364606 288.364606 288.364606 288.364606a31.030303 31.030303 0 0 1-43.876848 43.876848l-310.30303-310.30303a31.030303 31.030303 0 0 1 0-43.876848l310.30303-310.303031a31.030303 31.030303 0 0 1 43.876848 0z"
p-id="1818"></path>
</svg>

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 473 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182866847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22424" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22425" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182866847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22424" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z"
p-id="22425" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 798 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629183863957" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22616" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22617" fill="#e6e6e6"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629183863957" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22616" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z"
p-id="22617" fill="#e6e6e6"></path>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 798 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182847499" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22040" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m42.837333-298.752h42.624v85.333333h-170.666666v-85.333333h42.666666v-85.333333h-42.666666v-85.333334h128v170.666667z m-42.837333-213.333333a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z" p-id="22041" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182847499" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22040" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m42.837333-298.752h42.624v85.333333h-170.666666v-85.333333h42.666666v-85.333333h-42.666666v-85.333334h128v170.666667z m-42.837333-213.333333a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z"
p-id="22041" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 874 B

After

Width:  |  Height:  |  Size: 880 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629181942259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21410" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M696.32 635.989333l229.845333 229.845334-60.330666 60.330666-229.845334-229.845333a341.333333 341.333333 0 1 1 60.330667-60.330667zM426.666667 682.666667a256 256 0 1 0 0-512 256 256 0 0 0 0 512z" p-id="21411" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629181942259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="21410" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M696.32 635.989333l229.845333 229.845334-60.330666 60.330666-229.845334-229.845333a341.333333 341.333333 0 1 1 60.330667-60.330667zM426.666667 682.666667a256 256 0 1 0 0-512 256 256 0 0 0 0 512z"
p-id="21411" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 621 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182857650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22232" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M890.581333 797.013333l-94.592 94.592-121.088-33.706666-34.602666 14.250666L578.133333 981.333333h-133.76l-61.824-109.525333-34.56-14.506667-121.088 33.322667-94.549333-94.549333 33.706667-121.088-14.250667-34.602667L42.666667 578.133333v-133.76l109.568-61.824 14.506666-34.56-33.322666-121.088 94.506666-94.506666 121.088 33.749333 34.56-14.250667L445.696 42.666667h133.802667l61.824 109.568 34.56 14.506666 121.045333-33.322666 94.72 94.506666-33.792 121.130667 14.293333 34.56L981.333333 445.738667v133.802666l-109.525333 61.781334-14.506667 34.688 33.28 121.045333z m-123.392-126.805333l37.205334-88.832L896 529.664v-34.304l-91.605333-52.053333-36.650667-88.874667 28.245333-101.333333-24.277333-24.234667-101.674667 27.946667-88.746666-37.205334L529.621333 128h-34.304l-52.053333 91.605333-88.874667 36.650667-101.376-28.288-24.149333 24.149333 27.946667 101.674667-37.205334 88.746667L128 494.208v34.346667l91.52 52.138666 36.650667 88.874667-28.245334 101.376 24.192 24.192 101.674667-27.946667 88.746667 37.205334 51.626666 91.562666h34.346667l52.138667-91.52 88.874666-36.650666 101.376 28.245333 24.234667-24.234667-27.946667-101.589333zM512 682.666667a170.666667 170.666667 0 1 1 0-341.333334 170.666667 170.666667 0 0 1 0 341.333334z m0-85.333334a85.333333 85.333333 0 1 0 0-170.666666 85.333333 85.333333 0 0 0 0 170.666666z" p-id="22233" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182857650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22232" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M890.581333 797.013333l-94.592 94.592-121.088-33.706666-34.602666 14.250666L578.133333 981.333333h-133.76l-61.824-109.525333-34.56-14.506667-121.088 33.322667-94.549333-94.549333 33.706667-121.088-14.250667-34.602667L42.666667 578.133333v-133.76l109.568-61.824 14.506666-34.56-33.322666-121.088 94.506666-94.506666 121.088 33.749333 34.56-14.250667L445.696 42.666667h133.802667l61.824 109.568 34.56 14.506666 121.045333-33.322666 94.72 94.506666-33.792 121.130667 14.293333 34.56L981.333333 445.738667v133.802666l-109.525333 61.781334-14.506667 34.688 33.28 121.045333z m-123.392-126.805333l37.205334-88.832L896 529.664v-34.304l-91.605333-52.053333-36.650667-88.874667 28.245333-101.333333-24.277333-24.234667-101.674667 27.946667-88.746666-37.205334L529.621333 128h-34.304l-52.053333 91.605333-88.874667 36.650667-101.376-28.288-24.149333 24.149333 27.946667 101.674667-37.205334 88.746667L128 494.208v34.346667l91.52 52.138666 36.650667 88.874667-28.245334 101.376 24.192 24.192 101.674667-27.946667 88.746667 37.205334 51.626666 91.562666h34.346667l52.138667-91.52 88.874666-36.650666 101.376 28.245333 24.234667-24.234667-27.946667-101.589333zM512 682.666667a170.666667 170.666667 0 1 1 0-341.333334 170.666667 170.666667 0 0 1 0 341.333334z m0-85.333334a85.333333 85.333333 0 1 0 0-170.666666 85.333333 85.333333 0 0 0 0 170.666666z"
p-id="22233" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1 +1,5 @@
<svg t="1629268420515" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16731" width="128" height="128"><path d="M350.8 591.8c-7 38.4-34.8 217.4-43 268-0.6 3.6-2 5-6 5H152.6c-15.2 0-26.2-13.2-24.2-27.8L245.6 93.2c3-19.2 20.2-33.8 40-33.8 304.6 0 330.2-7.4 408 22.8 120.2 46.6 131.2 159 88 280.6-43 125.2-145 179-280.2 180.6-86.8 1.4-139-14-150.6 48.4zM842.2 304c-3.6-2.6-5-3.6-6 2.6-4 22.8-10.2 45-17.6 67.2-79.8 227.6-301 207.8-409 207.8-12.2 0-20.2 6.6-21.8 18.8-45.2 280.8-54.2 339.4-54.2 339.4-2 14.2 7 25.8 21.2 25.8h127c17.2 0 31.4-12.6 34.8-29.8 1.4-10.8-2.2 12.2 28.8-182.6 9.2-44 28.6-39.4 58.6-39.4 142 0 252.8-57.6 285.8-224.6 13-69.6 9.2-142.8-47.6-185.2z" p-id="16732" fill="#ffffff"></path></svg>
<svg t="1629268420515" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="16731" width="128" height="128">
<path d="M350.8 591.8c-7 38.4-34.8 217.4-43 268-0.6 3.6-2 5-6 5H152.6c-15.2 0-26.2-13.2-24.2-27.8L245.6 93.2c3-19.2 20.2-33.8 40-33.8 304.6 0 330.2-7.4 408 22.8 120.2 46.6 131.2 159 88 280.6-43 125.2-145 179-280.2 180.6-86.8 1.4-139-14-150.6 48.4zM842.2 304c-3.6-2.6-5-3.6-6 2.6-4 22.8-10.2 45-17.6 67.2-79.8 227.6-301 207.8-409 207.8-12.2 0-20.2 6.6-21.8 18.8-45.2 280.8-54.2 339.4-54.2 339.4-2 14.2 7 25.8 21.2 25.8h127c17.2 0 31.4-12.6 34.8-29.8 1.4-10.8-2.2 12.2 28.8-182.6 9.2-44 28.6-39.4 58.6-39.4 142 0 252.8-57.6 285.8-224.6 13-69.6 9.2-142.8-47.6-185.2z"
p-id="16732" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 753 B

After

Width:  |  Height:  |  Size: 774 B

View File

@@ -1 +1,5 @@
<svg t="1629270798317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1968" width="128" height="128"><path d="M365.940364 187.826424a31.030303 31.030303 0 0 1 43.876848 0l310.30303 310.303031a31.030303 31.030303 0 0 1 0 43.876848l-310.30303 310.30303a31.030303 31.030303 0 0 1-43.876848-43.876848l288.364606-288.364606-288.364606-288.364606a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1969"></path></svg>
<svg t="1629270798317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1968"
width="128" height="128">
<path d="M365.940364 187.826424a31.030303 31.030303 0 0 1 43.876848 0l310.30303 310.303031a31.030303 31.030303 0 0 1 0 43.876848l-310.30303 310.30303a31.030303 31.030303 0 0 1-43.876848-43.876848l288.364606-288.364606-288.364606-288.364606a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1969"></path>
</svg>

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 472 B

View File

@@ -1 +1,5 @@
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15526" width="128" height="128"><path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z" p-id="15527" fill="#ffffff"></path></svg>
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="15526" width="128" height="128">
<path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z"
p-id="15527" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1,5 @@
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15526" width="128" height="128"><path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z" p-id="15527" fill="#0f0f0f"></path></svg>
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="15526" width="128" height="128">
<path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z"
p-id="15527" fill="#0f0f0f"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m14 14 20 20M14 34l20-20" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m14 14 20 20M14 34l20-20"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -1 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M8 15h32l-3 29H11L8 15z" clip-rule="evenodd" data-follow-stroke="#333"/><path stroke-linecap="round" stroke-width="4" stroke="#333" d="M20.002 25.002v10M28.002 25v9.997" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M12 15 28.324 3 36 15" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M8 15h32l-3 29H11L8 15z" clip-rule="evenodd"
data-follow-stroke="#333"/>
<path stroke-linecap="round" stroke-width="4" stroke="#333" d="M20.002 25.002v10M28.002 25v9.997"
data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M12 15 28.324 3 36 15"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 607 B

View File

@@ -1 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M22 42H6V26M26 6h16v16" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M22 42H6V26M26 6h16v16"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -1 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M5 8a2 2 0 0 1 2-2h12l5 6h17a2 2 0 0 1 2 2v26a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8z" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m30 28-6.007 6L18 28.013M24 20v14" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path stroke-linejoin="round" stroke-width="4" stroke="#333"
d="M5 8a2 2 0 0 1 2-2h12l5 6h17a2 2 0 0 1 2 2v26a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8z" data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333"
d="m30 28-6.007 6L18 28.013M24 20v14" data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 429 B

View File

@@ -1 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M36.728 36.728A17.943 17.943 0 0 1 24 42c-9.941 0-18-8.059-18-18S14.059 6 24 6c4.97 0 9.47 2.015 12.728 5.272C38.386 12.93 42 17 42 17" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M42 8v9h-9" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333"
d="M36.728 36.728A17.943 17.943 0 0 1 24 42c-9.941 0-18-8.059-18-18S14.059 6 24 6c4.97 0 9.47 2.015 12.728 5.272C38.386 12.93 42 17 42 17"
data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M42 8v9h-9"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 534 B

After

Width:  |  Height:  |  Size: 580 B

View File

@@ -1 +1,5 @@
<svg t="1629255942168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8597" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM432.64 748.256 197.056 512.64l90.496-90.496 145.056 145.12 307.744-307.744 90.496 90.496L432.64 748.256z" p-id="8598" fill="#2DB84D"></path></svg>
<svg t="1629255942168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8597"
width="128" height="128">
<path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM432.64 748.256 197.056 512.64l90.496-90.496 145.056 145.12 307.744-307.744 90.496 90.496L432.64 748.256z"
p-id="8598" fill="#2DB84D"></path>
</svg>

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 412 B

View File

@@ -1 +1,5 @@
<svg t="1629255998157" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM320 768 320 256l512.256 256L320 768z" p-id="8793" fill="#00BCD4"></path></svg>
<svg t="1629255998157" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792"
width="128" height="128">
<path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM320 768 320 256l512.256 256L320 768z"
p-id="8793" fill="#00BCD4"></path>
</svg>

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -1 +1,5 @@
<svg t="1629256110134" class="icon" viewBox="0 0 1185 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3025" width="128" height="128"><path d="M700.365715 60.074208l468.319709 783.01037a118.307323 118.307323 0 0 1-45.345458 164.539234 127.444603 127.444603 0 0 1-62.324434 16.297089H124.376114A122.739586 122.739586 0 0 1 0 903.567918a117.557248 117.557248 0 0 1 16.706221-60.346963L485.02593 60.210586A126.694528 126.694528 0 0 1 655.020257 16.365278a122.739586 122.739586 0 0 1 45.345458 43.845308zM592.764011 916.046443a80.803561 80.803561 0 1 0-80.80356-80.803561 80.803561 80.803561 0 0 0 80.735372 80.803561z m0-673.567572a95.464122 95.464122 0 0 0-94.373104 106.988006l34.09433 270.640786a61.369793 61.369793 0 0 0 121.103058 0l34.094329-270.640786a95.464122 95.464122 0 0 0-94.373103-106.919818z" p-id="3026" fill="#DB3340"></path></svg>
<svg t="1629256110134" class="icon" viewBox="0 0 1185 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3025"
width="128" height="128">
<path d="M700.365715 60.074208l468.319709 783.01037a118.307323 118.307323 0 0 1-45.345458 164.539234 127.444603 127.444603 0 0 1-62.324434 16.297089H124.376114A122.739586 122.739586 0 0 1 0 903.567918a117.557248 117.557248 0 0 1 16.706221-60.346963L485.02593 60.210586A126.694528 126.694528 0 0 1 655.020257 16.365278a122.739586 122.739586 0 0 1 45.345458 43.845308zM592.764011 916.046443a80.803561 80.803561 0 1 0-80.80356-80.803561 80.803561 80.803561 0 0 0 80.735372 80.803561z m0-673.567572a95.464122 95.464122 0 0 0-94.373104 106.988006l34.09433 270.640786a61.369793 61.369793 0 0 0 121.103058 0l34.094329-270.640786a95.464122 95.464122 0 0 0-94.373103-106.919818z"
p-id="3026" fill="#DB3340"></path>
</svg>

Before

Width:  |  Height:  |  Size: 857 B

After

Width:  |  Height:  |  Size: 878 B

View File

@@ -1 +1,5 @@
<svg t="1629251564375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1864" width="128" height="128"><path d="M490.061576 311.947636a31.030303 31.030303 0 0 1 43.876848 0l310.303031 310.303031a31.030303 31.030303 0 0 1-43.876849 43.876848L512 377.762909l-288.364606 288.364606a31.030303 31.030303 0 0 1-43.876849-43.876848l310.303031-310.303031z" p-id="1865" fill="#326cf3"></path></svg>
<svg t="1629251564375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1864"
width="128" height="128">
<path d="M490.061576 311.947636a31.030303 31.030303 0 0 1 43.876848 0l310.303031 310.303031a31.030303 31.030303 0 0 1-43.876849 43.876848L512 377.762909l-288.364606 288.364606a31.030303 31.030303 0 0 1-43.876849-43.876848l310.303031-310.303031z"
p-id="1865" fill="#326cf3"></path>
</svg>

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 453 B

View File

@@ -1 +1,12 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629184159878" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23123" xmlns:xlink="http://www.w3.org/1999/xlink" width="136.5" height="128"><defs><style type="text/css"></style></defs><path d="M538.624 1017.344L0.580267 405.162667 212.445867 0h652.356266L1076.565333 405.162667z" fill="#46F256" p-id="23124"></path><path d="M538.624 748.6464l-317.44-351.607467 67.618133-61.098666 249.787734 276.718933 249.821866-276.6848 67.618134 61.064533z" fill="#000000" p-id="23125"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629184159878" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="23123" width="136.5" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M538.624 1017.344L0.580267 405.162667 212.445867 0h652.356266L1076.565333 405.162667z" fill="#46F256"
p-id="23124"></path>
<path d="M538.624 748.6464l-317.44-351.607467 67.618133-61.098666 249.787734 276.718933 249.821866-276.6848 67.618134 61.064533z"
fill="#000000" p-id="23125"></path>
</svg>

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 694 B

View File

@@ -1 +1,5 @@
<svg t="1629268466285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18338" width="128" height="128"><path d="M294.314667 0L242.432 119.424H165.418667v107.648h29.653333L225.152 418.133333H178.005333l62.293334 351.146667 40.021333-0.426667 40.192 255.146667h380.501333l2.645334-17.066667 37.546666-238.08 37.888 0.426667 62.293334-351.189333h-45.056l30.08-191.018667h32.256V119.466667h-81.834667L724.906667 0H294.314667z m22.528 34.346667h385.834666l32.896 75.946666H283.818667l33.024-75.946666z m-117.333334 119.338666H824.32v39.253334H199.509333v-39.253334z m19.328 298.581334h581.76l-50.176 282.453333-241.024-2.56-240.469333 2.56-50.090667-282.453333z" p-id="18339" fill="#ffffff"></path></svg>
<svg t="1629268466285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="18338" width="128" height="128">
<path d="M294.314667 0L242.432 119.424H165.418667v107.648h29.653333L225.152 418.133333H178.005333l62.293334 351.146667 40.021333-0.426667 40.192 255.146667h380.501333l2.645334-17.066667 37.546666-238.08 37.888 0.426667 62.293334-351.189333h-45.056l30.08-191.018667h32.256V119.466667h-81.834667L724.906667 0H294.314667z m22.528 34.346667h385.834666l32.896 75.946666H283.818667l33.024-75.946666z m-117.333334 119.338666H824.32v39.253334H199.509333v-39.253334z m19.328 298.581334h581.76l-50.176 282.453333-241.024-2.56-240.469333 2.56-50.090667-282.453333z"
p-id="18339" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 743 B

After

Width:  |  Height:  |  Size: 764 B

View File

@@ -3,4 +3,8 @@
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#cbcbcb"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#cbcbcb"></path></svg>
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609"
width="128" height="128">
<path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1610" fill="#cbcbcb"></path>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -3,4 +3,8 @@
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#326cf3"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#326cf3"></path></svg>
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609"
width="128" height="128">
<path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1610" fill="#326cf3"></path>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -1 +1,5 @@
<svg t="1629268481541" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19187" width="128" height="128"><path d="M512.032 831.904c-19.168 0-38.304-9.92-58.144-29.76-7.808-7.808-7.808-20.48 0-28.288s20.48-7.808 28.288 0C494.368 786.08 504.16 792 512.032 792s17.664-5.92 29.856-18.144c7.808-7.808 20.48-7.808 28.288 0s7.808 20.48 0 28.288c-19.84 19.84-38.976 29.76-58.144 29.76z m-512-306.4c0 49.888 4.256 95.136 12.8 135.68s20.544 75.744 36 105.536 35.008 55.904 58.656 78.336 49.344 40.928 77.056 55.456c27.744 14.528 59.456 26.304 95.2 35.264S351.84 951.04 388.8 954.624 466.496 960 510.944 960c44.448 0 85.248-1.792 122.4-5.376s73.6-9.856 109.344-18.848c35.744-8.96 67.552-20.736 95.456-35.264s53.792-33.024 77.6-55.456c23.808-22.432 43.456-48.544 58.944-78.336s27.552-64.96 36.256-105.536c8.704-40.576 13.056-85.792 13.056-135.68 0-89.376-27.744-166.368-83.2-230.976 3.2-8.608 5.952-18.496 8.256-29.6s4.544-26.816 6.656-47.104c2.144-20.288 1.344-43.712-2.4-70.272S942.56 93.888 932.256 66.24l-8-1.632c-5.344-1.088-14.048-0.704-26.144 1.088s-26.208 5.024-42.4 9.696-37.056 13.92-62.656 27.744-52.608 31.328-81.056 52.512c-48.352-14.72-115.008-30.112-200-30.112s-151.808 15.392-200.544 30.112c-28.448-21.184-55.552-38.592-81.344-52.224s-46.4-22.976-61.856-28c-15.456-5.024-29.792-8.256-42.944-9.696s-21.6-1.888-25.344-1.344c-3.744 0.544-6.496 1.152-8.256 1.888-10.304 27.648-17.408 54.752-21.344 81.312s-4.8 49.888-2.656 69.984c2.144 20.096 4.448 35.904 6.944 47.392S80 286.304 83.2 294.56C27.744 358.816 0 435.808 0 525.536z m136.544 113.888c0-58.016 21.344-110.624 64-157.856 12.8-14.4 27.648-25.312 44.544-32.704s36.096-11.616 57.6-12.608 42.048-0.8 61.6 0.608 43.744 3.296 72.544 5.696 53.696 3.616 74.656 3.616c20.96 0 45.856-1.184 74.656-3.616s52.992-4.288 72.544-5.696c19.552-1.408 40.096-1.6 61.6-0.608s40.8 5.216 57.856 12.608c17.056 7.392 32 18.304 44.8 32.704 42.656 47.232 64 99.84 64 157.856 0 34.016-3.552 64.32-10.656 90.944s-16.096 48.928-26.944 66.912c-10.848 18.016-26.048 33.216-45.6 45.632s-38.496 22.016-56.8 28.8c-18.304 6.784-41.952 12.096-70.944 15.904s-54.944 6.112-77.856 6.912c-22.944 0.8-51.808 1.216-86.656 1.216s-63.648-0.416-86.4-1.216c-22.752-0.8-48.608-3.104-77.6-6.912s-52.608-9.12-70.944-15.904c-18.304-6.816-37.248-16.416-56.8-28.8s-34.752-27.616-45.6-45.632c-10.848-18.016-19.84-40.32-26.944-66.912s-10.656-56.928-10.656-90.944zM256.032 608c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z m384 0c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z" p-id="19188"></path></svg>
<svg t="1629268481541" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="19187" width="128" height="128">
<path d="M512.032 831.904c-19.168 0-38.304-9.92-58.144-29.76-7.808-7.808-7.808-20.48 0-28.288s20.48-7.808 28.288 0C494.368 786.08 504.16 792 512.032 792s17.664-5.92 29.856-18.144c7.808-7.808 20.48-7.808 28.288 0s7.808 20.48 0 28.288c-19.84 19.84-38.976 29.76-58.144 29.76z m-512-306.4c0 49.888 4.256 95.136 12.8 135.68s20.544 75.744 36 105.536 35.008 55.904 58.656 78.336 49.344 40.928 77.056 55.456c27.744 14.528 59.456 26.304 95.2 35.264S351.84 951.04 388.8 954.624 466.496 960 510.944 960c44.448 0 85.248-1.792 122.4-5.376s73.6-9.856 109.344-18.848c35.744-8.96 67.552-20.736 95.456-35.264s53.792-33.024 77.6-55.456c23.808-22.432 43.456-48.544 58.944-78.336s27.552-64.96 36.256-105.536c8.704-40.576 13.056-85.792 13.056-135.68 0-89.376-27.744-166.368-83.2-230.976 3.2-8.608 5.952-18.496 8.256-29.6s4.544-26.816 6.656-47.104c2.144-20.288 1.344-43.712-2.4-70.272S942.56 93.888 932.256 66.24l-8-1.632c-5.344-1.088-14.048-0.704-26.144 1.088s-26.208 5.024-42.4 9.696-37.056 13.92-62.656 27.744-52.608 31.328-81.056 52.512c-48.352-14.72-115.008-30.112-200-30.112s-151.808 15.392-200.544 30.112c-28.448-21.184-55.552-38.592-81.344-52.224s-46.4-22.976-61.856-28c-15.456-5.024-29.792-8.256-42.944-9.696s-21.6-1.888-25.344-1.344c-3.744 0.544-6.496 1.152-8.256 1.888-10.304 27.648-17.408 54.752-21.344 81.312s-4.8 49.888-2.656 69.984c2.144 20.096 4.448 35.904 6.944 47.392S80 286.304 83.2 294.56C27.744 358.816 0 435.808 0 525.536z m136.544 113.888c0-58.016 21.344-110.624 64-157.856 12.8-14.4 27.648-25.312 44.544-32.704s36.096-11.616 57.6-12.608 42.048-0.8 61.6 0.608 43.744 3.296 72.544 5.696 53.696 3.616 74.656 3.616c20.96 0 45.856-1.184 74.656-3.616s52.992-4.288 72.544-5.696c19.552-1.408 40.096-1.6 61.6-0.608s40.8 5.216 57.856 12.608c17.056 7.392 32 18.304 44.8 32.704 42.656 47.232 64 99.84 64 157.856 0 34.016-3.552 64.32-10.656 90.944s-16.096 48.928-26.944 66.912c-10.848 18.016-26.048 33.216-45.6 45.632s-38.496 22.016-56.8 28.8c-18.304 6.784-41.952 12.096-70.944 15.904s-54.944 6.112-77.856 6.912c-22.944 0.8-51.808 1.216-86.656 1.216s-63.648-0.416-86.4-1.216c-22.752-0.8-48.608-3.104-77.6-6.912s-52.608-9.12-70.944-15.904c-18.304-6.816-37.248-16.416-56.8-28.8s-34.752-27.616-45.6-45.632c-10.848-18.016-19.84-40.32-26.944-66.912s-10.656-56.928-10.656-90.944zM256.032 608c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z m384 0c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z"
p-id="19188"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1 +1,5 @@
<svg t="1629270772080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1817" width="128" height="128"><path d="M658.059636 187.826424a31.030303 31.030303 0 0 1 0 43.876849l-288.364606 288.364606 288.364606 288.364606a31.030303 31.030303 0 0 1-43.876848 43.876848l-310.30303-310.30303a31.030303 31.030303 0 0 1 0-43.876848l310.30303-310.303031a31.030303 31.030303 0 0 1 43.876848 0z" p-id="1818"></path></svg>
<svg t="1629270772080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1817"
width="128" height="128">
<path d="M658.059636 187.826424a31.030303 31.030303 0 0 1 0 43.876849l-288.364606 288.364606 288.364606 288.364606a31.030303 31.030303 0 0 1-43.876848 43.876848l-310.30303-310.30303a31.030303 31.030303 0 0 1 0-43.876848l310.30303-310.303031a31.030303 31.030303 0 0 1 43.876848 0z"
p-id="1818"></path>
</svg>

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 473 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182866847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22424" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22425" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182866847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22424" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z"
p-id="22425" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 798 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629183863957" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22616" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22617" fill="#e6e6e6"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629183863957" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22616" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z"
p-id="22617" fill="#e6e6e6"></path>
</svg>

Before

Width:  |  Height:  |  Size: 792 B

After

Width:  |  Height:  |  Size: 798 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182847499" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22040" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m42.837333-298.752h42.624v85.333333h-170.666666v-85.333333h42.666666v-85.333333h-42.666666v-85.333334h128v170.666667z m-42.837333-213.333333a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z" p-id="22041" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182847499" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22040" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m42.837333-298.752h42.624v85.333333h-170.666666v-85.333333h42.666666v-85.333333h-42.666666v-85.333334h128v170.666667z m-42.837333-213.333333a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z"
p-id="22041" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 874 B

After

Width:  |  Height:  |  Size: 880 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629181942259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21410" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M696.32 635.989333l229.845333 229.845334-60.330666 60.330666-229.845334-229.845333a341.333333 341.333333 0 1 1 60.330667-60.330667zM426.666667 682.666667a256 256 0 1 0 0-512 256 256 0 0 0 0 512z" p-id="21411" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629181942259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="21410" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M696.32 635.989333l229.845333 229.845334-60.330666 60.330666-229.845334-229.845333a341.333333 341.333333 0 1 1 60.330667-60.330667zM426.666667 682.666667a256 256 0 1 0 0-512 256 256 0 0 0 0 512z"
p-id="21411" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 621 B

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182857650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22232" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M890.581333 797.013333l-94.592 94.592-121.088-33.706666-34.602666 14.250666L578.133333 981.333333h-133.76l-61.824-109.525333-34.56-14.506667-121.088 33.322667-94.549333-94.549333 33.706667-121.088-14.250667-34.602667L42.666667 578.133333v-133.76l109.568-61.824 14.506666-34.56-33.322666-121.088 94.506666-94.506666 121.088 33.749333 34.56-14.250667L445.696 42.666667h133.802667l61.824 109.568 34.56 14.506666 121.045333-33.322666 94.72 94.506666-33.792 121.130667 14.293333 34.56L981.333333 445.738667v133.802666l-109.525333 61.781334-14.506667 34.688 33.28 121.045333z m-123.392-126.805333l37.205334-88.832L896 529.664v-34.304l-91.605333-52.053333-36.650667-88.874667 28.245333-101.333333-24.277333-24.234667-101.674667 27.946667-88.746666-37.205334L529.621333 128h-34.304l-52.053333 91.605333-88.874667 36.650667-101.376-28.288-24.149333 24.149333 27.946667 101.674667-37.205334 88.746667L128 494.208v34.346667l91.52 52.138666 36.650667 88.874667-28.245334 101.376 24.192 24.192 101.674667-27.946667 88.746667 37.205334 51.626666 91.562666h34.346667l52.138667-91.52 88.874666-36.650666 101.376 28.245333 24.234667-24.234667-27.946667-101.589333zM512 682.666667a170.666667 170.666667 0 1 1 0-341.333334 170.666667 170.666667 0 0 1 0 341.333334z m0-85.333334a85.333333 85.333333 0 1 0 0-170.666666 85.333333 85.333333 0 0 0 0 170.666666z" p-id="22233" fill="#ffffff"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1629182857650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="22232" width="128" height="128">
<defs>
<style type="text/css"></style>
</defs>
<path d="M890.581333 797.013333l-94.592 94.592-121.088-33.706666-34.602666 14.250666L578.133333 981.333333h-133.76l-61.824-109.525333-34.56-14.506667-121.088 33.322667-94.549333-94.549333 33.706667-121.088-14.250667-34.602667L42.666667 578.133333v-133.76l109.568-61.824 14.506666-34.56-33.322666-121.088 94.506666-94.506666 121.088 33.749333 34.56-14.250667L445.696 42.666667h133.802667l61.824 109.568 34.56 14.506666 121.045333-33.322666 94.72 94.506666-33.792 121.130667 14.293333 34.56L981.333333 445.738667v133.802666l-109.525333 61.781334-14.506667 34.688 33.28 121.045333z m-123.392-126.805333l37.205334-88.832L896 529.664v-34.304l-91.605333-52.053333-36.650667-88.874667 28.245333-101.333333-24.277333-24.234667-101.674667 27.946667-88.746666-37.205334L529.621333 128h-34.304l-52.053333 91.605333-88.874667 36.650667-101.376-28.288-24.149333 24.149333 27.946667 101.674667-37.205334 88.746667L128 494.208v34.346667l91.52 52.138666 36.650667 88.874667-28.245334 101.376 24.192 24.192 101.674667-27.946667 88.746667 37.205334 51.626666 91.562666h34.346667l52.138667-91.52 88.874666-36.650666 101.376 28.245333 24.234667-24.234667-27.946667-101.589333zM512 682.666667a170.666667 170.666667 0 1 1 0-341.333334 170.666667 170.666667 0 0 1 0 341.333334z m0-85.333334a85.333333 85.333333 0 1 0 0-170.666666 85.333333 85.333333 0 0 0 0 170.666666z"
p-id="22233" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1 +1,5 @@
<svg t="1629268420515" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16731" width="128" height="128"><path d="M350.8 591.8c-7 38.4-34.8 217.4-43 268-0.6 3.6-2 5-6 5H152.6c-15.2 0-26.2-13.2-24.2-27.8L245.6 93.2c3-19.2 20.2-33.8 40-33.8 304.6 0 330.2-7.4 408 22.8 120.2 46.6 131.2 159 88 280.6-43 125.2-145 179-280.2 180.6-86.8 1.4-139-14-150.6 48.4zM842.2 304c-3.6-2.6-5-3.6-6 2.6-4 22.8-10.2 45-17.6 67.2-79.8 227.6-301 207.8-409 207.8-12.2 0-20.2 6.6-21.8 18.8-45.2 280.8-54.2 339.4-54.2 339.4-2 14.2 7 25.8 21.2 25.8h127c17.2 0 31.4-12.6 34.8-29.8 1.4-10.8-2.2 12.2 28.8-182.6 9.2-44 28.6-39.4 58.6-39.4 142 0 252.8-57.6 285.8-224.6 13-69.6 9.2-142.8-47.6-185.2z" p-id="16732" fill="#ffffff"></path></svg>
<svg t="1629268420515" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="16731" width="128" height="128">
<path d="M350.8 591.8c-7 38.4-34.8 217.4-43 268-0.6 3.6-2 5-6 5H152.6c-15.2 0-26.2-13.2-24.2-27.8L245.6 93.2c3-19.2 20.2-33.8 40-33.8 304.6 0 330.2-7.4 408 22.8 120.2 46.6 131.2 159 88 280.6-43 125.2-145 179-280.2 180.6-86.8 1.4-139-14-150.6 48.4zM842.2 304c-3.6-2.6-5-3.6-6 2.6-4 22.8-10.2 45-17.6 67.2-79.8 227.6-301 207.8-409 207.8-12.2 0-20.2 6.6-21.8 18.8-45.2 280.8-54.2 339.4-54.2 339.4-2 14.2 7 25.8 21.2 25.8h127c17.2 0 31.4-12.6 34.8-29.8 1.4-10.8-2.2 12.2 28.8-182.6 9.2-44 28.6-39.4 58.6-39.4 142 0 252.8-57.6 285.8-224.6 13-69.6 9.2-142.8-47.6-185.2z"
p-id="16732" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 753 B

After

Width:  |  Height:  |  Size: 774 B

View File

@@ -1 +1,5 @@
<svg t="1629270798317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1968" width="128" height="128"><path d="M365.940364 187.826424a31.030303 31.030303 0 0 1 43.876848 0l310.30303 310.303031a31.030303 31.030303 0 0 1 0 43.876848l-310.30303 310.30303a31.030303 31.030303 0 0 1-43.876848-43.876848l288.364606-288.364606-288.364606-288.364606a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1969"></path></svg>
<svg t="1629270798317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1968"
width="128" height="128">
<path d="M365.940364 187.826424a31.030303 31.030303 0 0 1 43.876848 0l310.30303 310.303031a31.030303 31.030303 0 0 1 0 43.876848l-310.30303 310.30303a31.030303 31.030303 0 0 1-43.876848-43.876848l288.364606-288.364606-288.364606-288.364606a31.030303 31.030303 0 0 1 0-43.876849z"
p-id="1969"></path>
</svg>

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 472 B

View File

@@ -1 +1,5 @@
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15526" width="128" height="128"><path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z" p-id="15527" fill="#ffffff"></path></svg>
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="15526" width="128" height="128">
<path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z"
p-id="15527" fill="#ffffff"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1,5 @@
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15526" width="128" height="128"><path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z" p-id="15527" fill="#0f0f0f"></path></svg>
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="15526" width="128" height="128">
<path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z"
p-id="15527" fill="#0f0f0f"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m14 14 20 20M14 34l20-20" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m14 14 20 20M14 34l20-20"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -1 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M8 15h32l-3 29H11L8 15z" clip-rule="evenodd" data-follow-stroke="#333"/><path stroke-linecap="round" stroke-width="4" stroke="#333" d="M20.002 25.002v10M28.002 25v9.997" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M12 15 28.324 3 36 15" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M8 15h32l-3 29H11L8 15z" clip-rule="evenodd"
data-follow-stroke="#333"/>
<path stroke-linecap="round" stroke-width="4" stroke="#333" d="M20.002 25.002v10M28.002 25v9.997"
data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M12 15 28.324 3 36 15"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 607 B

View File

@@ -1 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M22 42H6V26M26 6h16v16" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M22 42H6V26M26 6h16v16"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -1 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path stroke-linejoin="round" stroke-width="4" stroke="#333" d="M5 8a2 2 0 0 1 2-2h12l5 6h17a2 2 0 0 1 2 2v26a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8z" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="m30 28-6.007 6L18 28.013M24 20v14" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path stroke-linejoin="round" stroke-width="4" stroke="#333"
d="M5 8a2 2 0 0 1 2-2h12l5 6h17a2 2 0 0 1 2 2v26a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8z" data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333"
d="m30 28-6.007 6L18 28.013M24 20v14" data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 429 B

View File

@@ -1 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M36.728 36.728A17.943 17.943 0 0 1 24 42c-9.941 0-18-8.059-18-18S14.059 6 24 6c4.97 0 9.47 2.015 12.728 5.272C38.386 12.93 42 17 42 17" data-follow-stroke="#333"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M42 8v9h-9" data-follow-stroke="#333"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<path fill-opacity=".01" fill="#fff" d="M0 0h48v48H0z" data-follow-fill="#fff"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333"
d="M36.728 36.728A17.943 17.943 0 0 1 24 42c-9.941 0-18-8.059-18-18S14.059 6 24 6c4.97 0 9.47 2.015 12.728 5.272C38.386 12.93 42 17 42 17"
data-follow-stroke="#333"/>
<path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#333" d="M42 8v9h-9"
data-follow-stroke="#333"/>
</svg>

Before

Width:  |  Height:  |  Size: 534 B

After

Width:  |  Height:  |  Size: 580 B

View File

@@ -1 +1,5 @@
<svg t="1629255942168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8597" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM432.64 748.256 197.056 512.64l90.496-90.496 145.056 145.12 307.744-307.744 90.496 90.496L432.64 748.256z" p-id="8598" fill="#2DB84D"></path></svg>
<svg t="1629255942168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8597"
width="128" height="128">
<path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM432.64 748.256 197.056 512.64l90.496-90.496 145.056 145.12 307.744-307.744 90.496 90.496L432.64 748.256z"
p-id="8598" fill="#2DB84D"></path>
</svg>

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 412 B

View File

@@ -1 +1,5 @@
<svg t="1629255998157" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM320 768 320 256l512.256 256L320 768z" p-id="8793" fill="#00BCD4"></path></svg>
<svg t="1629255998157" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792"
width="128" height="128">
<path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM320 768 320 256l512.256 256L320 768z"
p-id="8793" fill="#00BCD4"></path>
</svg>

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -1 +1,5 @@
<svg t="1629256110134" class="icon" viewBox="0 0 1185 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3025" width="128" height="128"><path d="M700.365715 60.074208l468.319709 783.01037a118.307323 118.307323 0 0 1-45.345458 164.539234 127.444603 127.444603 0 0 1-62.324434 16.297089H124.376114A122.739586 122.739586 0 0 1 0 903.567918a117.557248 117.557248 0 0 1 16.706221-60.346963L485.02593 60.210586A126.694528 126.694528 0 0 1 655.020257 16.365278a122.739586 122.739586 0 0 1 45.345458 43.845308zM592.764011 916.046443a80.803561 80.803561 0 1 0-80.80356-80.803561 80.803561 80.803561 0 0 0 80.735372 80.803561z m0-673.567572a95.464122 95.464122 0 0 0-94.373104 106.988006l34.09433 270.640786a61.369793 61.369793 0 0 0 121.103058 0l34.094329-270.640786a95.464122 95.464122 0 0 0-94.373103-106.919818z" p-id="3026" fill="#DB3340"></path></svg>
<svg t="1629256110134" class="icon" viewBox="0 0 1185 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3025"
width="128" height="128">
<path d="M700.365715 60.074208l468.319709 783.01037a118.307323 118.307323 0 0 1-45.345458 164.539234 127.444603 127.444603 0 0 1-62.324434 16.297089H124.376114A122.739586 122.739586 0 0 1 0 903.567918a117.557248 117.557248 0 0 1 16.706221-60.346963L485.02593 60.210586A126.694528 126.694528 0 0 1 655.020257 16.365278a122.739586 122.739586 0 0 1 45.345458 43.845308zM592.764011 916.046443a80.803561 80.803561 0 1 0-80.80356-80.803561 80.803561 80.803561 0 0 0 80.735372 80.803561z m0-673.567572a95.464122 95.464122 0 0 0-94.373104 106.988006l34.09433 270.640786a61.369793 61.369793 0 0 0 121.103058 0l34.094329-270.640786a95.464122 95.464122 0 0 0-94.373103-106.919818z"
p-id="3026" fill="#DB3340"></path>
</svg>

Before

Width:  |  Height:  |  Size: 857 B

After

Width:  |  Height:  |  Size: 878 B

View File

@@ -1 +1,5 @@
<svg t="1629251564375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1864" width="128" height="128"><path d="M490.061576 311.947636a31.030303 31.030303 0 0 1 43.876848 0l310.303031 310.303031a31.030303 31.030303 0 0 1-43.876849 43.876848L512 377.762909l-288.364606 288.364606a31.030303 31.030303 0 0 1-43.876849-43.876848l310.303031-310.303031z" p-id="1865" fill="#326cf3"></path></svg>
<svg t="1629251564375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1864"
width="128" height="128">
<path d="M490.061576 311.947636a31.030303 31.030303 0 0 1 43.876848 0l310.303031 310.303031a31.030303 31.030303 0 0 1-43.876849 43.876848L512 377.762909l-288.364606 288.364606a31.030303 31.030303 0 0 1-43.876849-43.876848l310.303031-310.303031z"
p-id="1865" fill="#326cf3"></path>
</svg>

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 453 B

View File

@@ -94,7 +94,18 @@ QWidget#AboutWidget {
}
QScrollBar::vertical{
background:transparent;
width: 4px;
border-radius:6px;
}
QScrollBar::handle{
background: lightgray;
border-radius:6px;
}
QScrollBar::handle:hover{background:gray;}
QScrollBar::sub-line{background:transparent;}
QScrollBar::add-line{background:transparent;}
/* PushButton Style */

View File

@@ -33,13 +33,13 @@ class ButtonStyle(Enum):
PrePage = 14
NextPage = 15
TaskRetry = 16,
TaskCancel = 17,
TaskDelete = 18,
TaskOpen = 19,
TaskExpand = 20,
class LabelStyle(Enum):
Default = 0,

View File

@@ -10,7 +10,9 @@
"""
import os
import aigpy
from tidal_gui.style import ThemeStyle
_RESOURCE_PATH = './resource'
@@ -20,7 +22,6 @@ else:
_RESOURCE_PATH = aigpy.path.getDirName(__file__).replace('\\', '/') + "resource"
def __getParam__(line: str):
key = aigpy.string.getSub(line, "--", ":")
value = aigpy.string.getSub(line, ":", ";")
@@ -55,9 +56,11 @@ def __getQss__(filePath: str) -> str:
qss = __parseQss__(content, params)
return qss
def getResourcePath():
return _RESOURCE_PATH
def getThemeQssContent(style: ThemeStyle = ThemeStyle.Default):
name = "theme" + style.name + ".qss"
return __getQss__(_RESOURCE_PATH + '/' + name)

View File

@@ -1,165 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : tidalImp.py
@Date : 2021/9/2
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import time
import requests
import tidal_dl.model
import tidal_dl.enums
from aigpy.stringHelper import isNull
from tidal_dl import TokenSettings, TOKEN, TidalAPI, CONF
from tidal_dl.util import getAlbumPath, getPlaylistPath, getTrackPath
class TidalImp(TidalAPI):
def __init__(self):
super(TidalImp, self).__init__()
def loginByConfig(self):
if isNull(TOKEN.accessToken):
return False
msg, check = self.verifyAccessToken(TOKEN.accessToken)
if check:
self.key.countryCode = TOKEN.countryCode
self.key.userId = TOKEN.userid
self.key.accessToken = TOKEN.accessToken
return True
msg, check = self.refreshAccessToken(TOKEN.refreshToken)
if check:
TOKEN.userid = self.key.userId
TOKEN.countryCode = self.key.countryCode
TOKEN.accessToken = self.key.accessToken
TOKEN.expiresAfter = time.time() + int(self.key.expiresIn)
TokenSettings.save(TOKEN)
return True
else:
tmp = TokenSettings() # clears saved tokens
TokenSettings.save(tmp)
return False
def loginByWeb(self):
start = time.time()
elapsed = 0
while elapsed < self.key.authCheckTimeout:
elapsed = time.time() - start
msg, check = self.checkAuthStatus()
if not check:
if msg == "pending":
time.sleep(self.key.authCheckInterval + 1)
continue
return False
if check:
TOKEN.userid = self.key.userId
TOKEN.countryCode = self.key.countryCode
TOKEN.accessToken = self.key.accessToken
TOKEN.refreshToken = self.key.refreshToken
TOKEN.expiresAfter = time.time() + int(self.key.expiresIn)
TokenSettings.save(TOKEN)
return True
return False
@staticmethod
def getArtistsNames(artists): # : list[tidal_dl.model.Artist]
ret = []
for item in artists:
ret.append(item.name)
return ','.join(ret)
@staticmethod
def getDurationString(seconds: int):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
return "%02d:%02d:%02d" % (h, m, s)
def getCoverData(self, sid, width="320", height="320"):
url = self.getCoverUrl(sid, width, height)
try:
respond = requests.get(url)
return respond.content
except:
return ''
@staticmethod
def getAudioQualityList():
return map(lambda quality: quality.name, tidal_dl.enums.AudioQuality)
@staticmethod
def getVideoQualityList():
return map(lambda quality: quality.name, tidal_dl.enums.VideoQuality)
def getBasePath(self, model):
if isinstance(model, tidal_dl.model.Album):
return getAlbumPath(CONF, model)
if isinstance(model, tidal_dl.model.Playlist):
return getPlaylistPath(CONF, model)
if isinstance(model, tidal_dl.model.Track):
return getAlbumPath(CONF, model.album)
if isinstance(model, tidal_dl.model.Video):
return CONF.downloadPath + '/Video/'
return './'
def getConfig(self):
return CONF
# def getTackPath(self, basePath, track, stream, album=None, playlist=None):
# # number
# number = __getIndexStr__(track.trackNumber)
# if playlist is not None and CONF.usePlaylistFolder:
# number = __getIndexStr__(track.trackNumberOnPlaylist)
# # artist
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(track.artists), '-')
# # title
# title = track.title
# if not aigpy.string.isNull(track.version):
# title += ' (' + track.version + ')'
# title = aigpy.path.replaceLimitChar(title, '-')
# # get explicit
# explicit = "(Explicit)" if CONF.addExplicitTag and track.explicit else ''
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-')
# year = ""
# if album.releaseDate is not None:
# year = aigpy.string.getSubOnlyEnd(album.releaseDate, '-')
# # extension
# extension = __getExtension__(stream.url)
# retpath = CONF.trackFileFormat
# if retpath is None or len(retpath) <= 0:
# retpath = Settings.getDefaultTrackFileFormat()
# retpath = retpath.replace(R"{TrackNumber}", number)
# retpath = retpath.replace(R"{ArtistName}", artist.strip())
# retpath = retpath.replace(R"{TrackTitle}", title)
# retpath = retpath.replace(R"{ExplicitFlag}", explicit)
# retpath = retpath.replace(R"{AlbumYear}", year)
# retpath = retpath.replace(R"{AlbumTitle}", albumname.strip())
# retpath = retpath.strip()
# return basePath + retpath + extension
# def getVideoPath(self, basePath, video):
# # hyphen
# hyphen = ' - ' if CONF.addHyphen else ' '
# # get number
# number = ''
# if CONF.useTrackNumber:
# number = __getIndexStr__(video.trackNumber) + hyphen
# # get artist
# artist = ''
# if CONF.artistBeforeTitle:
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(video.artists), '-') + hyphen
# # get explicit
# explicit = "(Explicit)" if CONF.addExplicitTag and video.explicit else ''
# # title
# title = aigpy.path.replaceLimitChar(video.title, '-')
# # extension
# extension = ".mp4"
# return basePath + number + artist.strip() + title + explicit + extension
tidalImp = TidalImp()

View File

@@ -8,14 +8,11 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, QVBoxLayout, QGridLayout, QProgressBar
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QGridLayout, QProgressBar
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout, createVBoxLayout
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import LabelStyle, ButtonStyle
from tidal_gui.style import LabelStyle
class DownloadItemView(QWidget):
@@ -38,6 +35,7 @@ class DownloadItemView(QWidget):
self._progress.setTextVisible(False)
self._progress.setFixedHeight(3)
self._progress.setFixedWidth(300)
self._progress.setRange(0, 100)
grid = QGridLayout(self)
grid.addWidget(self._indexLabel, 0, 0, Qt.AlignLeft | Qt.AlignVCenter)
@@ -46,14 +44,14 @@ class DownloadItemView(QWidget):
grid.addWidget(self._progress, 0, 3, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._actionLabel, 0, 4, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._errLabel, 1, 1, Qt.AlignLeft | Qt.AlignVCenter)
grid.setColumnStretch(1, 1)
layout = QHBoxLayout()
layout.setSpacing(30)
layout.addWidget(self._sizeLabel)
layout.addWidget(self._speedLabel)
grid.addLayout(layout, 1, 3, Qt.AlignLeft | Qt.AlignVCenter)
def setLabel(self, index, title, own):
@@ -70,9 +68,9 @@ class DownloadItemView(QWidget):
def setProgress(self, value):
self._progress.setValue(value)
pass
def setSize(self, curSize: str, totalSize: str):
self._sizeLabel.setText(f'{curSize}/{totalSize}')
def setSpeed(self, speed: str):
self._speedLabel.setText(speed)

View File

@@ -87,7 +87,7 @@ class MainView(FramelessWidget):
self._moveWidget.setFixedHeight(30)
self._moveWidget.setObjectName("BaseWidget")
return self._moveWidget
def __initContent__(self) -> QGridLayout:
self._searchView = None
self._settingsView = None

View File

@@ -9,21 +9,20 @@
@Desc :
"""
import threading
import tidal_dl.model
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QTabWidget
from tidal_dl import Type
import tidal_dl.model
from tidal_dl import Type
from tidal_dl.util import API, getDurationString
from tidal_gui.control.comboBox import ComboBox
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout, createVBoxLayout
from tidal_gui.control.lineEdit import LineEdit
from tidal_gui.control.pushButton import PushButton
from tidal_gui.control.tableView import TableView
from tidal_gui.control.tableWidget import TableWidget
from tidal_gui.style import ButtonStyle, LabelStyle
from tidal_gui.theme import getResourcePath
from tidal_gui.tidalImp import tidalImp
class SearchView(QWidget):
@@ -57,7 +56,7 @@ class SearchView(QWidget):
self._prePageBtn = PushButton('', ButtonStyle.PrePage)
self._nextPageBtn = PushButton('', ButtonStyle.NextPage)
self._pageIndexEdit = LineEdit('')
self._pageIndexEdit.setAlignment(Qt.AlignCenter)
self._pageIndexEdit.setEnabled(False)
@@ -123,12 +122,12 @@ class SearchView(QWidget):
datas = []
for index, item in enumerate(items):
rowData = [str(index + 1 + indexOffset),
QUrl(tidalImp.getCoverUrl(item.cover)),
tidalImp.getFlag(item, Type.Album, True),
QUrl(API.getCoverUrl(item.cover)),
API.getFlag(item, Type.Album, True),
item.title,
item.artists[0].name,
str(item.releaseDate),
tidalImp.getDurationString(item.duration)]
API.getDurationString(item.duration)]
datas.append(rowData)
elif stype == Type.Track:
@@ -136,11 +135,11 @@ class SearchView(QWidget):
datas = []
for index, item in enumerate(items):
rowData = [str(index + 1 + indexOffset),
tidalImp.getFlag(item, Type.Track, True),
API.getFlag(item, Type.Track, True),
item.title,
item.album.title,
item.artists[0].name,
tidalImp.getDurationString(item.duration)]
getDurationString(item.duration)]
datas.append(rowData)
elif stype == Type.Video:
@@ -148,11 +147,11 @@ class SearchView(QWidget):
datas = []
for index, item in enumerate(items):
rowData = [str(index + 1 + indexOffset),
QUrl(tidalImp.getCoverUrl(item.imageID)),
tidalImp.getFlag(item, Type.Video, True),
QUrl(API.getCoverUrl(item.imageID)),
API.getFlag(item, Type.Video, True),
item.title,
item.artists[0].name,
tidalImp.getDurationString(item.duration)]
getDurationString(item.duration)]
datas.append(rowData)
elif stype == Type.Playlist:
@@ -160,10 +159,10 @@ class SearchView(QWidget):
datas = []
for index, item in enumerate(items):
rowData = [str(index + 1 + indexOffset),
QUrl(tidalImp.getCoverUrl(item.squareImage)),
QUrl(API.getCoverUrl(item.squareImage)),
item.title,
'',
tidalImp.getDurationString(item.duration)]
getDurationString(item.duration)]
datas.append(rowData)
for index, rowData in enumerate(datas):

View File

@@ -8,14 +8,14 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, QVBoxLayout, QListView, QGridLayout
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout, createVBoxLayout
from tidal_gui.control.pushButton import PushButton
from tidal_gui.control.listWidget import ListWidget
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import LabelStyle, ButtonStyle, ListWidgetStyle
@@ -25,12 +25,12 @@ class TaskItemView(QWidget):
self.__initView__()
self.setObjectName('TaskItemView')
self.setAttribute(Qt.WA_StyledBackground)
def __initView__(self):
layout = QVBoxLayout()
layout.addLayout(self.__initHead__(), Qt.AlignTop)
layout.addWidget(self.__initList__(), Qt.AlignTop)
self.setLayout(layout)
def __initHead__(self):
@@ -95,4 +95,3 @@ class TaskItemView(QWidget):
self._btnDelete.clicked.connect(func)
elif name == 'open':
self._btnOpen.clicked.connect(func)

View File

@@ -9,8 +9,9 @@
@Desc :
"""
from enum import Enum
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QWidget, QGridLayout, QListWidgetItem, QListView
from PyQt5.QtWidgets import QWidget, QGridLayout, QListWidgetItem
from tidal_gui.control.label import Label
from tidal_gui.control.line import Line
@@ -18,7 +19,6 @@ from tidal_gui.control.listWidget import ListWidget
from tidal_gui.control.scrollWidget import ScrollWidget
from tidal_gui.style import LabelStyle, ListWidgetStyle
from tidal_gui.theme import getResourcePath
from tidal_gui.view.taskItemView import TaskItemView
class TaskListType(Enum):

View File

@@ -8,4 +8,3 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""

View File

@@ -9,27 +9,42 @@
@Desc :
"""
import _thread
import os
import time
from abc import ABC, ABCMeta
from enum import Enum
from pickle import FALSE
from aigpy.downloadHelper import UserProgress
import aigpy.stringHelper
from tidal_dl import Type
from tidal_dl.model import Album, Track, Video, Playlist
from tidal_gui.tidalImp import tidalImp
from tidal_dl.model import Track
from tidal_dl.util import downloadTrack, downloadVideo, getArtistsNames, setMetaData
from tidal_gui.view.downloadItemView import DownloadItemView
from tidal_gui.viewModel.viewModel import ViewModel
class DownloadStatus(Enum):
Wait = 0,
Running = 1,
Finish = 2,
Error = 3,
Cancel = 4,
_endStatus_ = [DownloadStatus.Finish, DownloadStatus.Error, DownloadStatus.Cancel]
class Progress(UserProgress):
def __init__(self, model):
super().__init__()
self.model = model
def updateCurNum(self):
self.model.update(self.curNum, self.maxNum)
def updateMaxNum(self):
pass
class DownloadItemModel(ViewModel):
def __init__(self, index, data, basePath):
super(DownloadItemModel, self).__init__()
@@ -37,8 +52,9 @@ class DownloadItemModel(ViewModel):
self.data = data
self.basePath = basePath
self.isTrack = isinstance(data, Track)
self.progress = Progress(self)
self.__setStatus__(DownloadStatus.Wait)
if self.isTrack:
self.__initTrack__(index)
else:
@@ -50,7 +66,12 @@ class DownloadItemModel(ViewModel):
self.view.setAction(status.name)
else:
self.view.setAction(status.name + '-' + desc)
def __setErrStatus__(self, errmsg: str):
self.status = DownloadStatus.Error
self.view.setAction(self.status.name)
self.view.setErrmsg(errmsg)
def __initTrack__(self, index):
title = self.data.title
own = self.data.album.title
@@ -58,84 +79,36 @@ class DownloadItemModel(ViewModel):
def __initVideo__(self, index):
title = self.data.title
own = tidalImp.getArtistsNames(self.data.artists)
own = getArtistsNames(self.data.artists)
self.view.setLabel(index, title, own)
def update(self, curNum, maxNum):
per = curNum * 100 / maxNum
self.view.setProgress(per)
def isInWait(self):
return self.status == DownloadStatus.Wait
def stopDownload(self):
if self.status not in _endStatus_:
self.__setStatus__(DownloadStatus.Cancel)
def retry(self):
self.__setStatus__(DownloadStatus.Wait)
def download(self):
self.__setStatus__(DownloadStatus.Running)
if self.isTrack:
if not self.__dlTrack__():
return
check, msg = downloadTrack(self.data, self.data.album, self.data.playlist, self.progress)
else:
if not self.__dlVideo__():
return
check, msg = downloadVideo(self.data)
if check is False:
self.__setErrStatus__(msg)
else:
self.__setStatus__(DownloadStatus.Finish)
self.view.setProgress(100)
self.__setStatus__(DownloadStatus.Finish)
def __dlTrack__(self):
try:
track = self.data
conf = tidalImp.getConfig()
msg, stream = tidalImp.getStreamUrl(track.id, conf.audioQuality)
if not aigpy.string.isNull(msg) or stream is None:
self.__setStatus__(DownloadStatus.Error)
return False
tidalImp.getBasePath(track)
path = tidalImp.getTackPath(self.basePath, track, stream)
# # check exist
# if conf.checkExist and tidalImp.__isNeedDownload__(path, stream.url) == False:
# return True
tool = aigpy.download.DownloadTool(path + '.part', [stream.url])
check, err = tool.start(conf.showProgress)
if not check:
Printf.err("Download failed! " + aigpy.path.getFileName(path) + ' (' + str(err) + ')')
return
# encrypted -> decrypt and remove encrypted file
if aigpy.string.isNull(stream.encryptionKey):
os.replace(path + '.part', path)
else:
key, nonce = decrypt_security_token(stream.encryptionKey)
decrypt_file(path + '.part', path, key, nonce)
os.remove(path + '.part')
path = __convertToM4a__(path, stream.codec)
# contributors
msg, contributors = API.getTrackContributors(track.id)
msg, tidalLyrics = API.getLyrics(track.id)
lyrics = '' if tidalLyrics is None else tidalLyrics.subtitles
if conf.addLyrics and lyrics == '':
lyrics = __getLyrics__(track.title, __getArtistsString__(track.artists), conf.lyricsServerProxy)
if conf.lyricFile:
if tidalLyrics is None:
Printf.info(f'Failed to get lyrics from tidal!"{track.title}"')
else:
lrcPath = path.rsplit(".", 1)[0] + '.lrc'
aigpy.fileHelper.write(lrcPath, tidalLyrics.subtitles, 'w')
__setMetaData__(track, album, path, contributors, lyrics)
Printf.success(aigpy.path.getFileName(path))
except Exception as e:
Printf.err("Download failed! " + track.title + ' (' + str(e) + ')')
def __dlVideo__(self):
pass

View File

@@ -9,15 +9,15 @@
@Desc :
"""
import _thread
import time
import webbrowser
from PyQt5.QtCore import QTimer, pyqtSignal, QObject
from PyQt5.QtCore import pyqtSignal
from tidal_dl.util import API, loginByConfig, loginByWeb
from tidal_gui.tidalImp import tidalImp
from tidal_gui.view.loginView import LoginView
from tidal_gui.viewModel.viewModel import ViewModel
class LoginModel(ViewModel):
SIGNAL_LOGIN_SUCCESS = pyqtSignal()
@@ -26,7 +26,7 @@ class LoginModel(ViewModel):
self.view = LoginView()
self.view.connectConfirmButton(self.__openWeb__)
self.SIGNAL_REFRESH_VIEW.connect(self.__refresh__)
def __refresh__(self, stype: str, text: str):
if stype == "userCode":
self.view.setDeviceCode(text)
@@ -37,11 +37,11 @@ class LoginModel(ViewModel):
self.view.hideEnterView()
self.view.setMsg(text)
def login(self, useConfig = True):
def login(self, useConfig=True):
self.SIGNAL_REFRESH_VIEW.emit('showMsg', "LOGIN...")
def __thread_login__(model: LoginModel, useConfig: bool):
if useConfig and tidalImp.loginByConfig():
if useConfig and loginByConfig():
model.SIGNAL_LOGIN_SUCCESS.emit()
return
model.getDeviceCode()
@@ -52,9 +52,9 @@ class LoginModel(ViewModel):
self.SIGNAL_REFRESH_VIEW.emit('showMsg', "GET DEVICE-CODE...")
def __thread_getCode__(model: LoginModel):
msg, check = tidalImp.getDeviceCode()
msg, check = API.getDeviceCode()
if check:
model.SIGNAL_REFRESH_VIEW.emit('userCode', tidalImp.key.userCode)
model.SIGNAL_REFRESH_VIEW.emit('userCode', API.key.userCode)
else:
model.SIGNAL_REFRESH_VIEW.emit('showMsg', msg)
@@ -62,10 +62,10 @@ class LoginModel(ViewModel):
def __openWeb__(self):
self.view.enableConfirmButton(False)
webbrowser.open('http://link.tidal.com/' + tidalImp.key.userCode, new=0, autoraise=True)
webbrowser.open('http://link.tidal.com/' + API.key.userCode, new=0, autoraise=True)
def __thread_waitLogin__(model: LoginModel):
if tidalImp.loginByWeb():
if loginByWeb():
model.SIGNAL_LOGIN_SUCCESS.emit()
else:
model.getDeviceCode()

View File

@@ -37,17 +37,17 @@ class MainModel(ViewModel):
self.view.setAboutView(self.aboutModel.view)
self.view.showPage()
downloadImp.setTaskModel(self.taskModel)
downloadImp.start()
def uninit(self):
self.taskModel.stopDownloadItem()
downloadImp.stop()
def show(self, relogin:bool = False):
def show(self, relogin: bool = False):
self.view.hide()
self.loginModel.login(bool(1-relogin))
self.loginModel.login(bool(1 - relogin))
self.loginModel.show()
def __loginSuccess__(self):

View File

@@ -12,13 +12,12 @@ import _thread
import threading
import aigpy.stringHelper
import tidal_dl
from PyQt5.QtCore import pyqtSignal
from aigpy.modelHelper import ModelBase
from tidal_dl import Type
from tidal_dl.model import Album, SearchResult
from tidal_gui.tidalImp import tidalImp
import tidal_dl
from tidal_dl import Type
from tidal_dl.util import API, getAudioQualityList, getVideoQualityList
from tidal_gui.view.searchView import SearchView
from tidal_gui.viewModel.viewModel import ViewModel
@@ -33,8 +32,8 @@ class SearchModel(ViewModel):
self.view = SearchView()
self.view.setPageIndex(1, 1)
self.view.setTrackQualityItems(tidalImp.getAudioQualityList())
self.view.setVideoQualityItems(tidalImp.getVideoQualityList())
self.view.setTrackQualityItems(getAudioQualityList())
self.view.setVideoQualityItems(getVideoQualityList())
self.view.connectButton('search', self.__search__)
self.view.connectButton('prePage', self.__searchPre__)
self.view.connectButton('nextPage', self.__searchNext__)
@@ -76,7 +75,7 @@ class SearchModel(ViewModel):
limit = 20
offset = (index - 1) * limit
stype = tidal_dl.Type(typeIndex)
msg, model._resultData = tidalImp.search(searchText, stype, offset, limit)
msg, model._resultData = API.search(searchText, stype, offset, limit)
if not aigpy.stringHelper.isNull(msg):
model.SIGNAL_REFRESH_VIEW.emit('setSearchErrmsg', msg)

View File

@@ -20,10 +20,10 @@ class SettingsModel(ViewModel):
self.view.connectButton('Logout', self.__logout__)
self.view.connectButton('Cancel', self.__cancel__)
self.view.connectButton('OK', self.__ok__)
def __logout__(self):
self._parent.show(True)
def __cancel__(self):
pass

View File

@@ -10,17 +10,16 @@
"""
import _thread
import os
import time
import aigpy.stringHelper
from tidal_dl import Type
from tidal_dl.model import Album, Track, Video, Playlist
from tidal_gui.tidalImp import tidalImp
from tidal_dl.util import API, getArtistsNames, getBasePath, getDurationString
from tidal_gui.view.taskItemView import TaskItemView
from tidal_gui.viewModel.viewModel import ViewModel
from tidal_gui.viewModel.downloadItemModel import DownloadItemModel
from PyQt5.QtWidgets import QListWidget, QListWidgetItem, QWidget, QScrollArea, QVBoxLayout, QPushButton
import time
from tidal_gui.viewModel.viewModel import ViewModel
class TaskItemModel(ViewModel):
@@ -47,11 +46,11 @@ class TaskItemModel(ViewModel):
self.SIGNAL_REFRESH_VIEW.connect(self.__refresh__)
def __refresh__(self, stype: str, text: str):
def __refresh__(self, stype: str, obj):
if stype == "setPic":
self.view.setPic(text)
self.view.setPic(obj)
elif stype == "addListItem":
for index, item in enumerate(text):
for index, item in enumerate(obj):
downItem = DownloadItemModel(index + 1, item, self.path)
self.view.addListItem(downItem.view)
self.downloadModelList.append(downItem)
@@ -75,24 +74,29 @@ class TaskItemModel(ViewModel):
os.startfile(self.path)
def __initAlbum__(self, data: Album):
self.path = tidalImp.getBasePath(data)
self.path = getBasePath(data)
title = data.title
desc = f"by {tidalImp.getArtistsNames(data.artists)} " \
f"{tidalImp.getDurationString(data.duration)} " \
desc = f"by {getArtistsNames(data.artists)} " \
f"{getDurationString(data.duration)} " \
f"Track-{data.numberOfTracks} " \
f"Video-{data.numberOfVideos}"
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, album: Album):
cover = tidalImp.getCoverData(album.cover, '1280', '1280')
cover = API.getCoverData(album.cover, '1280', '1280')
model.SIGNAL_REFRESH_VIEW.emit('setPic', cover)
msg, tracks, videos = tidalImp.getItems(album.id, Type.Album)
msg, tracks, videos = API.getItems(album.id, Type.Album)
if not aigpy.stringHelper.isNull(msg):
model.view.setErrmsg(msg)
return
for item in tracks:
item.album = album
for item in videos:
item.album = album
model.SIGNAL_REFRESH_VIEW.emit('addListItem', tracks + videos)
print('__initAlbum__')
time.sleep(1)

View File

@@ -8,40 +8,36 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QPushButton, QCheckBox, QWidget
from tidal_dl import Type
from tidal_dl.model import Album, Artist
from tidal_gui.control.layout import createHBoxLayout
from tidal_gui.view.taskView import TaskView, TaskListType
from tidal_gui.viewModel.downloadItemModel import DownloadItemModel
from tidal_gui.viewModel.taskItemModel import TaskItemModel
from tidal_gui.viewModel.viewModel import ViewModel
from tidal_gui.viewModel.downloadItemModel import DownloadItemModel
class TaskModel(ViewModel):
def __init__(self):
super(TaskModel, self).__init__()
self.view = TaskView()
self._listMap = {}
for item in map(lambda typeItem: typeItem.name, TaskListType):
self._listMap[item] = []
self.test()
def addTaskItem(self, data):
item = TaskItemModel(data)
self._listMap[TaskListType.Download.name].append(item)
self.view.addItemView(TaskListType.Download, item.view)
def getWaitDownloadItem(self) -> DownloadItemModel:
for item in self._listMap[TaskListType.Download.name]:
for downItem in item.downloadModelList:
if downItem.isInWait():
return downItem
return None
def stopDownloadItem(self):
for item in self._listMap[TaskListType.Download.name]:
for downItem in item.downloadModelList:

View File

@@ -9,12 +9,12 @@
@Desc :
"""
from PyQt5.QtCore import QObject
from PyQt5.QtCore import QTimer, pyqtSignal
from PyQt5.QtCore import pyqtSignal
class ViewModel(QObject):
SIGNAL_REFRESH_VIEW = pyqtSignal(str, object)
def __init__(self):
super(ViewModel, self).__init__()
self.view = None