Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #Библиотеки, нужные для запуска скрипта:
- #vk_audio, vk_api, mutagen, flask_compress, flask
- #ОБРАТИТЕ ВНИМАНИЕ: использовуйте данный скрипт на свой стах и риск:
- #не исключины возможности xss уязвимостей и утечек данных
- #этот код является примером сайта для скачивания музыки из вк.
- from urllib.request import urlopen
- import sys,html,urllib.parse
- from io import BytesIO, BufferedIOBase
- from flask import Flask, Response, stream_with_context,request,redirect
- from flask_compress import Compress
- import vk_audio,vk_api
- from mutagen.id3 import ID3,APIC,TPE1,Encoding,TIT2
- vks = vk_audio.VkAudio(login="login",password="password")
- HEAD = """<html>
- <head>
- <style>
- body{
- margin:0;
- }
- img{
- height: 80px;
- border-radius: 9px;
- margin: 10px;
- display:inherit;
- }
- .photo_artist_item{
- float:left;
- }
- .artist_item:hover .title_artist_item{
- text-decoration: underline;
- }
- .artist_item,.title_artist_item{
- display:inline-block;
- }
- .title_artist_item{
- font-size: 16px;
- font-family: cursive;
- margin: 8px 14px 0 3px;
- width: 150px;
- text-overflow: ellipsis;
- overflow: hidden;
- }
- .title{
- font-size: 15px;
- font-weight: 400;
- color: #2c2d2e;
- height: 21px;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- margin: 0 0 0 0;
- }
- .artist{
- font-size: 13px;
- height: 16px;
- color: #909499;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- }
- .image{
- background-size: 100%;
- width: 40px;
- height: 40px;
- border-radius: 4px;
- float: left;
- position: relative;
- margin:2px 14px 2px 10px;
- }
- .listen{
- float: right;
- width: 100px;
- height: 25px;
- background: #ae8af1;
- text-align: center;
- font-family: cursive;
- cursor: pointer;
- display: table-cell;
- position: relative;
- border-radius: 8px;
- margin: 10px;
- }
- .audio{
- border-radius: inherit;
- height: 44px;
- }
- .audio:hover{
- background: #e8c5e5;
- }
- .playlist{
- width: 150px;
- display: inline-block;
- }
- .playlists, .artists{
- padding: 14px 16px 12px 16px;
- border-bottom: 1px solid #ebebeb;
- overflow-y: hidden;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- white-space: nowrap;
- }
- .playlist_cover{
- width: 135;
- height: 135px;
- background-size: 100%;
- border-radius: 5px;
- }
- .duration{
- float: right;
- margin: 9px;
- font: bold 1.2em "Fira Sans", monospace;
- }
- .playing{
- background: aliceblue;
- }
- .audios_count,.playlists_count{
- font: 2em cursive;
- text-align: center;
- color: #1b00a4;
- }
- .search_input{
- margin: 11px;
- height: 28px;
- width: 90%;
- font-size: 1em;
- background: antiquewhite;
- border-radius: 7px;
- border: none;
- outline: none;
- }
- .search_el{
- width: 100%;
- height: 40px;
- text-align: center;
- }
- </style>
- <script>
- let audio = new Audio();
- audio.addEventListener("ended",function(){
- let g = document.querySelector(".playing");
- if(g){
- g.nextElementSibling.nextElementSibling.querySelector('.listen').click();
- }
- });
- document.addEventListener("click",function(e){
- if(e.target.className ==="listen"){
- let el = e.target.parentElement,g=document.querySelector(".playing");
- if(g)g.classList.remove("playing");
- if(!el.classList.contains("playing"))el.classList.add("playing");
- let src = el.querySelector(".download").attributes.href.value.split("?download")[0];
- if(audio.src.indexOf(src)===-1)audio.src=src;
- if(audio.paused)audio.play();
- else audio.pause();
- }
- })
- </script>
- </head>"""
- SEARCH_EL = """
- <div class="search_el">
- <form action="/search" method="get" target="_blank">
- <input name="q" class="search_input" placeholder="Поиск...">
- </form>
- </div>
- """
- MAIN_PAGE = """
- <title>Скачивания музыки из вк.</title>
- <form action="" method="get">
- <input name="id" class="search_input" placeholder="Введите id пользователя ( для групп id отрицательный )">
- </form>
- """
- def get_audios_html(audios:list):
- def get_duration_str(duration:int):
- minutes =duration//60
- seconds = duration%60
- return "{}.{}".format(minutes,(seconds if seconds>=10 else "0{}".format(seconds)))
- yield "<div class='audios'>"
- for i in audios:
- if(i.artists_info):
- artist = "<b>,</b> ".join("<a href='/artist/%s' target='_blank'>"%i.zip_artist(j) + html.escape(item['name']) +"</a>" for j,item in enumerate(i.artists_info))
- else:
- artist = i.artist
- text = '''
- <div class="audio">
- <div class="listen">Прослушать</div>
- <div class="duration">{duration}</div>
- <a class="download" href="/download/{hash}?download" target="_blank">
- <div class="image" style="background-image:url('{image}');"></div>
- <b class="title">{title}</b>
- <br>
- <b class="artist">{artist}</b>
- </a>
- </div>
- <br>'''.format(
- title=html.escape(i.title),
- artist=artist,
- hash = i.zip(),
- image = i.image or "/no_image.png",
- duration =get_duration_str( i.duration)
- )
- yield text
- yield "</div>"
- def get_playlists_html(p:list):
- yield "<div class='playlists'>"
- for i in p:
- yield """
- <div class="playlist" >
- <a href="{href}" target="_blank">
- <div class="playlist_cover" style="background-image:url('{image}');"></div>
- <div class="title">{title}</div>
- <div class="artist">{artist}</div>
- <div class="audios_count">{count}</div>
- </a>
- </div>
- """.format(
- image = (i.images and i.images[0]) or "/no_image.png",
- title = html.escape(i.title),
- artist = "<b>,<b> ".join("<a class='one_artist' href='/artist/%s' target='_blank'>"%i.zip_artist(j)+html.escape(item['name'])+"</a>" for j,item in enumerate(i.author_info)),
- count=i.audios_count,
- href = "/playlist/"+i.zip_audios()+"?"+urllib.parse.urlencode({"title":"Плейлист "+i.title})
- )
- yield "</div>"
- def get_artists_html(auds):
- yield "<div class='artists'>"
- for i,item in enumerate(auds.artists_info):
- yield """
- <div class="artist_item">
- <a href="{href}">
- <div class="image photo_artist_item" style="background-image:url('{photo}')"></div>
- <div class="title_artist_item">{title}</div>
- </a>
- </div>
- """.format(href="/artist/"+urllib.parse.quote(auds.zip_artist(i)),
- photo = item['photo'] if "photo" in item else '/no_image.png',
- title = item['name']
- )
- yield '</div>'
- def get_music_html(auds:vk_audio.Audio,title=""):
- yield HEAD
- yield '<body>'
- if(title):yield "<title>%s</title>"%html.escape(title)
- yield SEARCH_EL
- if(isinstance(auds,vk_audio.AudioSearch)):
- for i in get_artists_html(auds):yield i
- if(auds.Playlists):
- yield '<div class="playlists_count">%i Плейлист</div>'%len(auds.Playlists)
- for i in get_playlists_html(auds.Playlists):yield i
- yield '<div class="audios_count">%i Аудио</div>'%len(auds.Audios)
- for i in get_audios_html(auds.Audios):yield i
- yield "</body></html>"
- def get_music_from_playlist_hash(hash,args):
- yield HEAD
- yield "<body>"
- if(args.get("title")):
- yield "<title>%s</title>"%html.escape(args.get("title"))
- auds = vk_audio.Playlist.unzip_audios(hash,vks)
- for i in get_audios_html(auds):yield i
- yield "</doby></html>"
- app = Flask(__name__)
- Compress(app)
- @app.route("/no_image.png")
- def no_image():
- return Response(open(r'C:\Users\imart\OneDrive\Pictures\galochka.png','rb'),mimetype="image/png")
- @app.route("/<int:post_id>")
- def get_music(post_id:int):
- music = vks.load(post_id)
- return Response(get_music_html(music), mimetype='text/html')
- @app.route("/download/<hash>")
- def download(hash:str):
- def download_audio(audio):
- class Ge(BufferedIOBase):
- def __init__(self,stream,b):
- self.b = BytesIO(b)
- self.stream= stream
- def read(self,c=-1):
- if(c==-1):return self.b.read()+self.stream.read()
- b = self.b.read(c)
- c-=len(b)
- if(c>0):b+=self.stream.read(c)
- return b
- def close(self):
- if(not self.b.closed):self.b.close()
- if(not self.stream.closed):self.stream.close()
- def __del__(self):
- self.close()
- def edit_data(bytes,s):
- with BytesIO(bytes) as b:
- data = ID3(b)
- if(audio.image):
- apic = APIC(mime='image/jpeg',type=3,desc=u'Cover',data=urlopen(audio.image).read())
- data.add(apic)
- if('TPE1' in data.keys()):
- splited = audio.artist.split(",")
- data['TPE1'].text[0]=splited.pop(0)
- if(splited):
- while splited:
- data['TPE1'].text.append(splited.pop(0));
- else:
- data['TPE1'] = TPE1(encoding=Encoding.UTF8,text=audio.artist.split(","))#TPE1(encoding=Encoding.UTF8,text=[audio.artist])
- if('TIT2' in data.keys()):
- data['TIT2'].text[0]=audio.title
- else:
- data['TIT2']= TIT2(encoding=Encoding.UTF8,text=[audio.title])
- with BytesIO() as b:
- data.save(b)
- readed = b.getvalue()
- length = len(readed)+s.length-len(bytes)
- ans = Ge(s,readed)
- data.clear()
- return length,ans
- s = urlopen(audio.url)
- bytes = s.read(10)
- if(bytes.startswith(b'ID3')):
- size = bytes[9]+ (bytes[8] << 7)+ (bytes[7] << 14)+(bytes[6] << 21);
- data =bytes+s.read(size)
- return edit_data(data,s)
- return s.length,s
- def get_content_d_header(audio):
- name = ''.join(i for i in '{} - {}'.format(audio.artist,audio.title) if i not in '|\/<>:*?;"')
- return "attachment;charset=utf-8; filename={}.mp3".format(urllib.parse.quote(name)).encode()
- DOWN = request.args.get('download') != None
- audio = vk_audio.AudioObj.unzip(hash,vks)
- if(not audio):return "К сожалению, аудиозапись не найдена!"
- if(DOWN):
- l,audio_downloaded = download_audio(audio[0])
- else:
- audio_downloaded= urlopen(audio[0].url)
- l= audio_downloaded.length
- headers = {"Content-length":l,
- "Content-type": "audio/mpeg",
- "accept-ranges": "bytes"
- }
- print(get_content_d_header(audio[0]))
- if('download' in request.args):headers[ "Content-Disposition"] = get_content_d_header(audio[0])
- return Response(audio_downloaded,mimetype="audio/mpeg",headers=headers)
- @app.route("/playlist/<hash>")
- def playl(hash):
- return Response(get_music_from_playlist_hash(hash,request.args),mimetype='text/html')
- @app.route("/artist/<artist_name>")
- def get_artist_music(artist_name):
- audios = vks.load_artist(artist_hash=artist_name)
- if(isinstance(audios,vk_audio.ArtistAudio)):
- return Response(get_music_html(audios),mimetype='text/html')
- else:#Такого артиста нет - выкидывает поиск
- return Response(get_music_html(audios),mimetype='text/html')
- @app.route("/search")
- def search_req():
- q = request.args.get("q")
- if(not q):return HEAD+SEARCH_EL+"<br>Прости, но пустой посковой запрос недопускается."
- resp = vks.search(q)
- return Response(get_music_html(resp,"Поиск "+q),mimetype='text/html')
- @app.route("/")
- def main_page():
- id= request.args.get("id")
- if(id and id.lstrip("id").lstrip("-").isdigit()):
- return redirect("/%i"%int(id),code=302)
- return HEAD+MAIN_PAGE;
- app.run(debug=True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement