git
This commit is contained in:
1 parent
7167ddceb1
commit
da8439daea
5 files changed
+154
No files matched your search
@@ -0,0 +1,50 @@
|
||||
from fastapi import FastAPI, Request, Form
|
||||
|
||||
description = """
|
||||
Oki.cx is a API for Converting Youtube Videos to MP4 & MP3. ▶️
|
||||
|
||||
## Requests
|
||||
|
||||
You can Requst a **MP4** File.
|
||||
You can Requst a **MP3** File.
|
||||
"""
|
||||
|
||||
from starlette.templating import Jinja2Templates
|
||||
|
||||
import models
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
app = FastAPI(
|
||||
title="Oki.cx - YouTube Converter",
|
||||
description=description,
|
||||
version="0.1",
|
||||
terms_of_service="http://oki.cx/youtube-converter/tos",
|
||||
contact={
|
||||
"name": "oki.cx",
|
||||
"email": "cody@oki.cx",
|
||||
},
|
||||
license_info={
|
||||
"name": "MIT License",
|
||||
"url": "https://gitlab.oki.cx/mrpvtdagger/oki.cx-youtube-converter/-/raw/main/LICENSE",
|
||||
},
|
||||
)
|
||||
|
||||
@app.get("/")
|
||||
def home(request: Request):
|
||||
return templates.TemplateResponse("base.html",{"request": request, "is_hidden": "is-hidden"})
|
||||
|
||||
@app.post("/")
|
||||
def download(request: Request, link: str = Form(...), media_format: str = Form(...)):
|
||||
response = models.convert_video(link, media_format)
|
||||
return templates.TemplateResponse("base.html",{"request": request, "is_hidden": "", "url": response["url"], "title": response["title"], "filename": response["filename"], "thumbnail": response["thumbnail"]})
|
||||
|
||||
@app.post("/json")
|
||||
def download(request: Request, link: str = Form(...), media_format: str = Form(...)):
|
||||
response = models.convert_video(link, media_format)
|
||||
return {"title": response["title"], "url": response["url"], "title": response["title"], "filename": response["filename"], "thumbnail": response["thumbnail"]}
|
||||
|
||||
@app.get("/delete/{filename}")
|
||||
def delete(request: Request, filename: str):
|
||||
models.delete_file(filename)
|
||||
return templates.TemplateResponse("base.html",{"request": request, "is_hidden": "is-hidden"})
|
||||
@@ -0,0 +1,32 @@
|
||||
from pytube import YouTube
|
||||
import random
|
||||
import string
|
||||
import os
|
||||
|
||||
def convert_video(link, media_format):
|
||||
def randmname(size=6, chars=string.ascii_lowercase + string.digits):
|
||||
return ''.join(random.choice(chars) for _ in range(size))
|
||||
rand_filename = f"{randmname(25)}.{media_format.lower()}"
|
||||
|
||||
stream_filter = ""
|
||||
if media_format == "mp4":
|
||||
stream_filter = "progressive=True, file_extension=mp4"
|
||||
elif media_format == "mp3":
|
||||
stream_filter = "only_audio=True"
|
||||
|
||||
|
||||
yt = YouTube(link)
|
||||
yt.streams.filter(stream_filter).order_by('resolution').desc().first().download(filename=rand_filename, output_path="files/ytdl")
|
||||
|
||||
cdn_url = {
|
||||
"url": f"https://cdn.oki.cx/files/{rand_filename}",
|
||||
"title": yt.title,
|
||||
"thumbnail": f"{yt.thumbnail_url}",
|
||||
"filename": rand_filename
|
||||
}
|
||||
|
||||
return cdn_url
|
||||
|
||||
def delete_file(filename):
|
||||
os.remove(f"files/ytdl/{filename}")
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Oki.cx - Youtube Converter</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous" defer></script>
|
||||
<script src="//code.iconify.design/1/1.0.6/iconify.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="padding p-4 has-text-centered">
|
||||
<p class="title is-1">Oki.cx Youtube Converter</p>
|
||||
<p class="subtitle is-4">Free and <a href="https://gitlab.oki.cx/mrpvtdagger/oki.cx-youtube-converter">Open Source <span class="iconify" data-icon="mdi-gitlab"></span> </a></br> With a <a href="/docs">API</a></br><strong>Personal use only!</strong></p>
|
||||
</div>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<form id="form" action="/" method="post">
|
||||
<div class="field has-addons has-addons-center pb pb-4">
|
||||
<p class="control">
|
||||
<span class="select">
|
||||
<select name="media_format">
|
||||
<option>MP4</option>
|
||||
<option>MP3</option>
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control is-expanded">
|
||||
<input name="link" class="input" type="text" placeholder="URL to Youtube Video">
|
||||
</p>
|
||||
<p class="control">
|
||||
<a id="convert" class="button is-link" onclick="document.getElementById('convert').classList.add('is-loading');document.getElementById('form').submit();">Convert</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-two-fifths">
|
||||
<div class="card {{is_hidden}}">
|
||||
<div class="card-image">
|
||||
<figure class="image is-4by3">
|
||||
<img src="{{thumbnail}}">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<div class="is-size-4">{{title}}</div>
|
||||
<br>
|
||||
<div class="is-size-7">{{filename}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a href="{{url}}" class="card-footer-item" target="_blank" download>Save</a>
|
||||
<a href="delete/{{filename}}" class="card-footer-item has-text-danger">Delete from Server</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="padding p-4 subtitle is-7 has-text-centered">By clicking <strong>"Convert"</strong> you agree to using this for personal use only</a>.</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var U={onLoad:t,process:ct,on:M,off:D,trigger:$,ajax:er,find:C,findAll:R,closest:H,values:function(e,t){var r=Mt(e,t||"post");return r.values},remove:O,addClass:L,removeClass:q,toggleClass:A,takeClass:T,defineExtension:or,removeExtension:ar,logAll:E,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])},version:"1.7.0"};var r={bodyContains:Y,filterValues:jt,hasAttribute:s,getAttributeValue:V,getClosestMatch:h,getExpressionVars:Gt,getHeaders:Xt,getInputValues:Mt,getInternalData:_,getSwapSpecification:Ut,getTriggerSpecs:ke,getTarget:ne,makeFragment:g,mergeObjects:Q,makeSettleInfo:zt,oobSwap:B,selectAndSwap:we,settleImmediately:Ct,shouldCancel:Pe,triggerEvent:$,triggerErrorEvent:J,withExtensions:gt};var n=["get","post","put","delete","patch"];var i=n.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}return parseFloat(e)||undefined}function f(e,t){return e.getAttribute&&e.getAttribute(t)}function s(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function V(e,t){return f(e,t)||f(e,"data-"+t)}function u(e){return e.parentElement}function z(){return document}function h(e,t){if(t(e)){return e}else if(u(e)){return h(u(e),t)}else{return null}}function o(e,t,r){var n=V(t,r);var i=V(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function G(t,r){var n=null;h(t,function(e){return n=o(t,e,r)});if(n!=="unset"){return n}}function d(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function a(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function l(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=z().createDocumentFragment()}return i}function g(e){if(U.config.useTemplateFragments){var t=l("<body><template>"+e+"</template></body>",0);return t.querySelector("template").content}else{var r=a(e);switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return l("<table>"+e+"</table>",1);case"col":return l("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return l("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return l("<table><tbody><tr>"+e+"</tr></tbody></table>",3);case"script":return l("<div>"+e+"</div>",1);default:return l(e,0)}}}function K(e){if(e){e()}}function p(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function m(e){return p(e,"Function")}function x(e){return p(e,"Object")}function _(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function y(e){var t=[];if(e){for(var r=0;r<e.length;r++){t.push(e[r])}}return t}function W(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function b(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function Y(e){if(e.getRootNode()instanceof ShadowRoot){return z().body.contains(e.getRootNode().host)}else{return z().body.contains(e)}}function w(e){return e.trim().split(/\s+/)}function Q(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function S(e){try{return JSON.parse(e)}catch(e){pt(e);return null}}function e(e){return Jt(z().body,function(){return eval(e)})}function t(t){var e=U.on("htmx:load",function(e){t(e.detail.elt)});return e}function E(){U.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function C(e,t){if(t){return e.querySelector(t)}else{return C(z(),e)}}function R(e,t){if(t){return e.querySelectorAll(t)}else{return R(z(),e)}}function O(e,t){e=k(e);if(t){setTimeout(function(){O(e)},t)}else{e.parentElement.removeChild(e)}}function L(e,t,r){e=k(e);if(r){setTimeout(function(){L(e,t)},r)}else{e.classList&&e.classList.add(t)}}function q(e,t,r){e=k(e);if(r){setTimeout(function(){q(e,t)},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")Line truncated
|
||||
Reference in new issue
Block a user