Advertisement
Guest User

Сайт для скачивания аудио на flask python

a guest
Sep 16th, 2020
3,230
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.38 KB | None | 1 0
  1. #Библиотеки, нужные для запуска скрипта:
  2. #vk_audio, vk_api, mutagen, flask_compress, flask
  3. #ОБРАТИТЕ ВНИМАНИЕ: использовуйте данный скрипт на свой стах и риск:
  4. #не исключины возможности xss уязвимостей и утечек данных
  5. #этот код является примером сайта для скачивания музыки из вк.
  6. from urllib.request import urlopen
  7. import sys,html,urllib.parse
  8. from io import BytesIO, BufferedIOBase
  9. from flask import Flask, Response, stream_with_context,request,redirect
  10. from flask_compress import Compress
  11.  
  12. import vk_audio,vk_api
  13. from mutagen.id3 import ID3,APIC,TPE1,Encoding,TIT2
  14.  
  15. vks = vk_audio.VkAudio(login="login",password="password")
  16.  
  17. HEAD = """<html>
  18.    <head>
  19.        <style>
  20.            body{
  21.                margin:0;
  22.            }
  23.            img{
  24.                height: 80px;
  25.                border-radius: 9px;
  26.                margin: 10px;
  27.                display:inherit;
  28.            }
  29.            .photo_artist_item{
  30.                float:left;
  31.            }
  32.            .artist_item:hover .title_artist_item{
  33.                text-decoration: underline;
  34.            }
  35.            .artist_item,.title_artist_item{
  36.                display:inline-block;
  37.            }
  38.            .title_artist_item{
  39.                font-size: 16px;
  40.                font-family: cursive;
  41.                margin: 8px 14px 0 3px;
  42.                width: 150px;
  43.                text-overflow: ellipsis;
  44.                overflow: hidden;
  45.            }
  46.            .title{
  47.                font-size: 15px;
  48.                font-weight: 400;
  49.                color: #2c2d2e;
  50.                height: 21px;
  51.                white-space: nowrap;
  52.                text-overflow: ellipsis;
  53.                overflow: hidden;
  54.                margin: 0 0 0 0;
  55.            }
  56.            .artist{
  57.                font-size: 13px;
  58.                height: 16px;
  59.                color: #909499;
  60.                white-space: nowrap;
  61.                text-overflow: ellipsis;
  62.                overflow: hidden;
  63.            }
  64.            .image{
  65.                background-size: 100%;
  66.                width: 40px;
  67.                height: 40px;
  68.                border-radius: 4px;
  69.                float: left;
  70.                position: relative;
  71.                margin:2px 14px 2px 10px;
  72.            }
  73.            .listen{
  74.               float: right;
  75.                width: 100px;
  76.                height: 25px;
  77.                background: #ae8af1;
  78.                text-align: center;
  79.                font-family: cursive;
  80.                cursor: pointer;
  81.                display: table-cell;
  82.                position: relative;
  83.                border-radius: 8px;
  84.                margin: 10px;
  85.            }
  86.            
  87.            .audio{
  88.                border-radius: inherit;
  89.                height: 44px;
  90.            }
  91.            .audio:hover{
  92.                background: #e8c5e5;
  93.            }
  94.            .playlist{
  95.                width: 150px;
  96.                display: inline-block;
  97.            }
  98.            .playlists, .artists{
  99.                padding: 14px 16px 12px 16px;
  100.                border-bottom: 1px solid #ebebeb;
  101.                overflow-y: hidden;
  102.                overflow-x: auto;
  103.                -webkit-overflow-scrolling: touch;
  104.                white-space: nowrap;
  105.            }
  106.            .playlist_cover{
  107.                width: 135;
  108.                height: 135px;
  109.                background-size: 100%;
  110.                border-radius: 5px;
  111.            }
  112.            .duration{
  113.                float: right;
  114.                margin: 9px;
  115.                font: bold 1.2em "Fira Sans", monospace;
  116.            }
  117.            .playing{
  118.                background: aliceblue;
  119.            }
  120.            .audios_count,.playlists_count{
  121.                font: 2em cursive;
  122.                text-align: center;
  123.                color: #1b00a4;
  124.            }
  125.            .search_input{
  126.                    margin: 11px;
  127.                    height: 28px;
  128.                    width: 90%;
  129.                    font-size: 1em;
  130.                    background: antiquewhite;
  131.                    border-radius: 7px;
  132.                    border: none;
  133.                    outline: none;
  134.            }
  135.            .search_el{
  136.                width: 100%;
  137.                height: 40px;
  138.                text-align: center;
  139.            }
  140.        </style>
  141.        <script>
  142.            let audio = new Audio();
  143.            audio.addEventListener("ended",function(){
  144.                let g = document.querySelector(".playing");
  145.                if(g){
  146.                    g.nextElementSibling.nextElementSibling.querySelector('.listen').click();
  147.                }
  148.            });
  149.            document.addEventListener("click",function(e){
  150.                if(e.target.className ==="listen"){
  151.                  let el = e.target.parentElement,g=document.querySelector(".playing");
  152.                  if(g)g.classList.remove("playing");
  153.                  if(!el.classList.contains("playing"))el.classList.add("playing");
  154.                  
  155.                  let src = el.querySelector(".download").attributes.href.value.split("?download")[0];
  156.                  
  157.                  if(audio.src.indexOf(src)===-1)audio.src=src;
  158.                  if(audio.paused)audio.play();
  159.                  else audio.pause();
  160.                }
  161.            })
  162.        </script>
  163.    </head>"""
  164. SEARCH_EL = """
  165. <div class="search_el">
  166.    <form action="/search" method="get" target="_blank">
  167.        <input name="q" class="search_input" placeholder="Поиск...">
  168.    </form>
  169. </div>
  170. """
  171. MAIN_PAGE = """
  172. <title>Скачивания музыки из вк.</title>
  173. <form action="" method="get">
  174.    <input name="id" class="search_input" placeholder="Введите id пользователя ( для групп id отрицательный )">
  175. </form>
  176. """
  177. def get_audios_html(audios:list):
  178.     def get_duration_str(duration:int):
  179.         minutes =duration//60
  180.         seconds = duration%60
  181.         return "{}.{}".format(minutes,(seconds  if seconds>=10 else "0{}".format(seconds)))
  182.        
  183.     yield "<div class='audios'>"
  184.     for i in audios:
  185.         if(i.artists_info):
  186.             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))
  187.         else:
  188.             artist = i.artist
  189.         text =  '''
  190.            <div class="audio">
  191.                <div class="listen">Прослушать</div>
  192.                <div class="duration">{duration}</div>
  193.                <a class="download" href="/download/{hash}?download" target="_blank">
  194.                     <div class="image" style="background-image:url('{image}');"></div>
  195.                     <b class="title">{title}</b>
  196.                     <br>
  197.                     <b class="artist">{artist}</b>
  198.                </a>
  199.            </div>
  200.            <br>'''.format(
  201.                 title=html.escape(i.title),
  202.                 artist=artist,
  203.                 hash = i.zip(),
  204.                 image = i.image or "/no_image.png",
  205.                 duration =get_duration_str( i.duration)
  206.             )
  207.         yield text
  208.     yield "</div>"
  209. def get_playlists_html(p:list):
  210.     yield "<div class='playlists'>"
  211.     for i in p:
  212.         yield  """
  213.            <div class="playlist" >
  214.                <a href="{href}" target="_blank">
  215.                    <div class="playlist_cover" style="background-image:url('{image}');"></div>
  216.                    <div class="title">{title}</div>
  217.                    <div class="artist">{artist}</div>
  218.                    <div class="audios_count">{count}</div>
  219.                </a>
  220.            </div>
  221.            """.format(
  222.                 image = (i.images and i.images[0]) or "/no_image.png",
  223.                 title = html.escape(i.title),
  224.                 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)),
  225.                 count=i.audios_count,
  226.                 href = "/playlist/"+i.zip_audios()+"?"+urllib.parse.urlencode({"title":"Плейлист "+i.title})
  227.  
  228.             )
  229.     yield "</div>"
  230. def get_artists_html(auds):
  231.     yield "<div class='artists'>"
  232.     for i,item in enumerate(auds.artists_info):
  233.         yield """
  234.        <div class="artist_item">
  235.            <a href="{href}">
  236.                <div class="image photo_artist_item" style="background-image:url('{photo}')"></div>
  237.                <div class="title_artist_item">{title}</div>
  238.            </a>
  239.        </div>
  240.        """.format(href="/artist/"+urllib.parse.quote(auds.zip_artist(i)),
  241.                    photo = item['photo'] if "photo" in item else '/no_image.png',
  242.                    title = item['name']
  243.                    )
  244.     yield '</div>'
  245. def get_music_html(auds:vk_audio.Audio,title=""):
  246.     yield HEAD
  247.     yield '<body>'
  248.     if(title):yield "<title>%s</title>"%html.escape(title)
  249.     yield SEARCH_EL
  250.     if(isinstance(auds,vk_audio.AudioSearch)):
  251.         for i in get_artists_html(auds):yield i
  252.     if(auds.Playlists):
  253.         yield '<div class="playlists_count">%i Плейлист</div>'%len(auds.Playlists)
  254.         for i in get_playlists_html(auds.Playlists):yield i
  255.     yield '<div class="audios_count">%i Аудио</div>'%len(auds.Audios)
  256.     for i in get_audios_html(auds.Audios):yield i
  257.     yield "</body></html>"
  258. def get_music_from_playlist_hash(hash,args):
  259.     yield HEAD
  260.     yield "<body>"
  261.     if(args.get("title")):
  262.         yield "<title>%s</title>"%html.escape(args.get("title"))
  263.     auds = vk_audio.Playlist.unzip_audios(hash,vks)
  264.     for i in get_audios_html(auds):yield i    
  265.     yield "</doby></html>"
  266.  
  267. app = Flask(__name__)
  268. Compress(app)
  269.  
  270. @app.route("/no_image.png")
  271. def no_image():
  272.     return Response(open(r'C:\Users\imart\OneDrive\Pictures\galochka.png','rb'),mimetype="image/png")
  273. @app.route("/<int:post_id>")
  274. def get_music(post_id:int):
  275.     music = vks.load(post_id)
  276.     return Response(get_music_html(music), mimetype='text/html')
  277.    
  278. @app.route("/download/<hash>")
  279. def download(hash:str):
  280.     def download_audio(audio):
  281.         class Ge(BufferedIOBase):
  282.             def __init__(self,stream,b):
  283.                 self.b = BytesIO(b)
  284.                 self.stream= stream
  285.             def read(self,c=-1):
  286.                 if(c==-1):return self.b.read()+self.stream.read()
  287.                 b = self.b.read(c)
  288.                 c-=len(b)
  289.                 if(c>0):b+=self.stream.read(c)
  290.                 return b
  291.             def close(self):
  292.                 if(not self.b.closed):self.b.close()
  293.                 if(not self.stream.closed):self.stream.close()
  294.             def __del__(self):
  295.                 self.close()
  296.         def edit_data(bytes,s):
  297.             with BytesIO(bytes) as b:
  298.                 data = ID3(b)
  299.                 if(audio.image):
  300.                     apic = APIC(mime='image/jpeg',type=3,desc=u'Cover',data=urlopen(audio.image).read())
  301.                     data.add(apic)
  302.                 if('TPE1' in data.keys()):
  303.                     splited = audio.artist.split(",")
  304.                     data['TPE1'].text[0]=splited.pop(0)
  305.                     if(splited):
  306.                         while splited:
  307.                             data['TPE1'].text.append(splited.pop(0));
  308.                 else:
  309.                      data['TPE1'] = TPE1(encoding=Encoding.UTF8,text=audio.artist.split(","))#TPE1(encoding=Encoding.UTF8,text=[audio.artist])
  310.                 if('TIT2' in data.keys()):
  311.                     data['TIT2'].text[0]=audio.title
  312.                 else:
  313.                     data['TIT2']= TIT2(encoding=Encoding.UTF8,text=[audio.title])
  314.  
  315.                 with BytesIO() as b:
  316.                     data.save(b)
  317.                     readed = b.getvalue()
  318.                     length =  len(readed)+s.length-len(bytes)
  319.                     ans = Ge(s,readed)
  320.                     data.clear()
  321.                     return length,ans
  322.  
  323.         s = urlopen(audio.url)
  324.         bytes = s.read(10)
  325.         if(bytes.startswith(b'ID3')):
  326.             size = bytes[9]+ (bytes[8] << 7)+ (bytes[7] << 14)+(bytes[6] << 21);
  327.             data =bytes+s.read(size)
  328.             return edit_data(data,s)
  329.         return s.length,s
  330.     def get_content_d_header(audio):
  331.         name = ''.join(i for i in '{} - {}'.format(audio.artist,audio.title)  if i not in '|\/<>:*?;"')
  332.         return "attachment;charset=utf-8; filename={}.mp3".format(urllib.parse.quote(name)).encode()
  333.     DOWN = request.args.get('download') != None
  334.     audio = vk_audio.AudioObj.unzip(hash,vks)
  335.     if(not audio):return "К сожалению, аудиозапись не найдена!"
  336.     if(DOWN):
  337.         l,audio_downloaded = download_audio(audio[0])
  338.     else:
  339.         audio_downloaded= urlopen(audio[0].url)
  340.         l= audio_downloaded.length
  341.     headers = {"Content-length":l,
  342.                "Content-type": "audio/mpeg",
  343.                "accept-ranges": "bytes"
  344.            }
  345.     print(get_content_d_header(audio[0]))
  346.     if('download' in request.args):headers[ "Content-Disposition"] = get_content_d_header(audio[0])
  347.    
  348.     return Response(audio_downloaded,mimetype="audio/mpeg",headers=headers)
  349. @app.route("/playlist/<hash>")
  350. def playl(hash):
  351.     return Response(get_music_from_playlist_hash(hash,request.args),mimetype='text/html')
  352. @app.route("/artist/<artist_name>")
  353. def get_artist_music(artist_name):
  354.     audios = vks.load_artist(artist_hash=artist_name)
  355.     if(isinstance(audios,vk_audio.ArtistAudio)):
  356.         return Response(get_music_html(audios),mimetype='text/html')
  357.     else:#Такого артиста нет - выкидывает поиск
  358.         return Response(get_music_html(audios),mimetype='text/html')
  359. @app.route("/search")
  360. def search_req():
  361.     q = request.args.get("q")
  362.     if(not q):return HEAD+SEARCH_EL+"<br>Прости, но пустой посковой запрос недопускается."
  363.     resp = vks.search(q)
  364.     return Response(get_music_html(resp,"Поиск "+q),mimetype='text/html')
  365. @app.route("/")
  366. def main_page():
  367.     id= request.args.get("id")
  368.     if(id and id.lstrip("id").lstrip("-").isdigit()):
  369.         return redirect("/%i"%int(id),code=302)
  370.     return HEAD+MAIN_PAGE;
  371. app.run(debug=True)
  372.  
  373.  
  374.  
  375.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement