2022-02-28 15:24:06 +00:00
//--- Modules/Imports ---//
2022-03-21 23:47:11 +00:00
import { Http } from "@capacitor-community/http" ;
import Innertube from "./innertube" ;
import constants from "./constants" ;
2022-03-28 02:07:03 +00:00
import rendererUtils from "./renderers" ;
2022-03-26 08:24:40 +00:00
import { Buffer } from "buffer" ;
2022-03-29 07:02:52 +00:00
import iconv from "iconv-lite" ;
2022-04-09 03:06:35 +00:00
import { Toast } from "@capacitor/toast" ;
2022-02-25 18:54:15 +00:00
2022-03-27 09:15:09 +00:00
function getEncoding ( contentType ) {
const re = /charset=([^()<>@,;:\"/[\]?.=\s]*)/i ;
const content = re . exec ( contentType ) ;
console . log ( content ) ;
2022-03-29 07:02:52 +00:00
return content [ 1 ] . toLowerCase ( ) ;
2022-03-27 09:15:09 +00:00
}
2022-03-16 09:07:40 +00:00
const searchModule = {
2022-03-21 23:47:11 +00:00
logs : new Array ( ) ,
//--- Get YouTube's Search Auto Complete ---//
autoComplete ( text , callback ) {
2022-03-26 08:24:40 +00:00
Http . get ( {
url : ` ${ constants . URLS . YT _SUGGESTIONS } /search?q= ${ encodeURIComponent (
text
) } & client = youtube & ds = yt ` ,
responseType : "arraybuffer" ,
2022-03-21 23:47:11 +00:00
} )
. then ( ( res ) => {
2022-03-27 09:15:09 +00:00
const contentType = res . headers [ "Content-Type" ] ;
2022-03-26 08:24:40 +00:00
// make a new buffer object from res.data
const buffer = Buffer . from ( res . data , "base64" ) ;
// convert res.data from iso-8859-1 to utf-8
2022-03-29 07:02:52 +00:00
const data = iconv . decode ( buffer , getEncoding ( contentType ) ) ;
2022-03-26 08:24:40 +00:00
callback ( data ) ;
2022-03-21 23:47:11 +00:00
} )
. catch ( ( err ) => {
callback ( err ) ;
} ) ;
} ,
2022-02-25 18:54:15 +00:00
2022-03-21 23:47:11 +00:00
getReturnYoutubeDislike ( id , callback ) {
Http . request ( {
method : "GET" ,
url : ` https://returnyoutubedislikeapi.com/votes ` ,
params : { videoId : id } ,
} )
. then ( ( res ) => {
callback ( res . data ) ;
} )
. catch ( ( err ) => {
callback ( err ) ;
} ) ;
} ,
2022-06-01 02:50:55 +00:00
getSponsorBlock ( id , callback ) {
Http . request ( {
method : "GET" ,
url : ` https://sponsor.ajay.app/api/skipSegments ` ,
params : { videoID : id } ,
} )
. then ( ( res ) => {
callback ( res . data ) ;
} )
. catch ( ( err ) => {
callback ( err ) ;
} ) ;
2022-06-01 21:12:00 +00:00
} ,
showToast ( text ) {
Toast . show ( { text : text } ) ;
2022-06-22 05:24:06 +00:00
} ,
2022-03-21 23:47:11 +00:00
} ;
2022-03-13 23:45:04 +00:00
2022-03-20 09:02:52 +00:00
//--- Recommendations ---//
2022-03-17 13:17:32 +00:00
2022-03-18 06:15:19 +00:00
let InnertubeAPI ;
2022-03-20 09:02:52 +00:00
// Loads Innertube object. This will be the object used in all future Innertube API calls. getAPI Code provided by Lightfire228 (https://github.com/Lightfire228)
2022-03-17 13:17:32 +00:00
// These are just a way for the backend Javascript to communicate with the front end Vue scripts. Essentially a wrapper inside a wrapper
2022-03-20 09:50:13 +00:00
const innertubeModule = {
2022-03-21 23:47:11 +00:00
async getAPI ( ) {
if ( ! InnertubeAPI ) {
2022-04-09 03:06:35 +00:00
InnertubeAPI = await Innertube . createAsync (
( message , isError , shortMessage ) => {
if ( shortMessage ) {
Toast . show ( { text : shortMessage } ) ;
}
}
) ;
2022-03-21 23:47:11 +00:00
}
return InnertubeAPI ;
} ,
2022-03-18 06:15:19 +00:00
2022-03-21 23:47:11 +00:00
async getVid ( id ) {
try {
return await InnertubeAPI . VidInfoAsync ( id ) ;
2022-11-17 00:27:22 +00:00
} catch ( error ) {
}
} ,
getThumbnail ( id , resolution , backupThumbnail ) {
if ( resolution == "max" ) {
const url = ` https://img.youtube.com/vi/ ${ id } /maxresdefault.jpg ` ;
let img = new Image ( ) ;
img . src = url ;
img . onload = function ( ) {
if ( img . height !== 120 ) return url ;
} ;
}
if ( backupThumbnail [ backupThumbnail . length - 1 ] )
return backupThumbnail [ backupThumbnail . length - 1 ] . url ;
else return ` https://img.youtube.com/vi/ ${ id } /mqdefault.jpg ` ;
2022-03-23 11:21:06 +00:00
} ,
2022-05-04 05:21:14 +00:00
async getChannel ( url ) {
try {
const response = await InnertubeAPI . getChannelAsync ( url ) ;
return response . data ;
2022-11-17 00:27:22 +00:00
} catch ( error ) {
}
2022-05-04 05:21:14 +00:00
} ,
2022-03-21 23:47:11 +00:00
// It just works™
// Front page recommendation
async recommend ( ) {
const response = await InnertubeAPI . getRecommendationsAsync ( ) ;
2022-03-31 02:22:22 +00:00
2022-03-21 23:47:11 +00:00
if ( ! response . success )
throw new Error ( "An error occurred and innertube failed to respond" ) ;
const contents =
response . data . contents . singleColumnBrowseResultsRenderer . tabs [ 0 ]
. tabRenderer . content . sectionListRenderer . contents ;
const final = contents . map ( ( shelves ) => {
2022-03-24 11:47:13 +00:00
const video = shelves . shelfRenderer ? . content ? . horizontalListRenderer ;
2022-03-21 23:47:11 +00:00
2022-03-23 11:21:06 +00:00
if ( video ) return video ;
2022-03-21 23:47:11 +00:00
} ) ;
2022-04-01 01:02:08 +00:00
const continuations =
response . data . contents . singleColumnBrowseResultsRenderer . tabs [ 0 ]
. tabRenderer . content . sectionListRenderer . continuations ;
2022-03-31 02:22:22 +00:00
console . log ( { continuations : continuations , contents : final } ) ;
return { continuations : continuations , contents : final } ;
} ,
2022-04-01 01:02:08 +00:00
async recommendContinuation ( continuation , endpoint ) {
2022-04-19 14:03:46 +00:00
const response = await this . getContinuation ( continuation , endpoint ) ;
2022-04-01 01:02:08 +00:00
const contents =
response . data . continuationContents . sectionListContinuation . contents ;
2022-03-31 02:22:22 +00:00
const final = contents . map ( ( shelves ) => {
const video = shelves . shelfRenderer ? . content ? . horizontalListRenderer ;
if ( video ) return video ;
} ) ;
2022-04-01 01:02:08 +00:00
const continuations =
response . data . continuationContents . sectionListContinuation . continuations ;
2022-03-31 02:22:22 +00:00
return { continuations : continuations , contents : final } ;
} ,
2022-04-19 14:03:46 +00:00
async getContinuation ( continuation , endpoint , mode = "android" ) {
let contextAdditional = { } ;
if ( mode . toLowerCase ( ) == "web" ) {
contextAdditional = {
... contextAdditional ,
... {
client : {
2022-04-21 05:29:50 +00:00
clientName : constants . YT _API _VALUES . CLIENT _WEB _D ,
2022-04-19 14:03:46 +00:00
clientVersion : constants . YT _API _VALUES . VERSION _WEB ,
} ,
} ,
} ;
}
return await InnertubeAPI . getContinuationsAsync (
continuation ,
endpoint ,
contextAdditional
) ;
} ,
2022-03-23 13:07:03 +00:00
async search ( query ) {
try {
const response = await InnertubeAPI . getSearchAsync ( query ) ;
2022-03-24 11:47:13 +00:00
return response . contents . sectionListRenderer ;
2022-11-17 00:27:22 +00:00
} catch ( err ) {
}
2022-03-23 13:07:03 +00:00
} ,
2022-03-29 07:02:52 +00:00
2022-04-01 13:04:52 +00:00
async saveApiStats ( query , url ) {
await InnertubeAPI . apiStats ( query , url ) ;
2022-03-29 07:02:52 +00:00
} ,
2022-03-21 23:47:11 +00:00
} ;
2022-03-20 09:50:13 +00:00
2022-02-28 15:24:06 +00:00
//--- Start ---//
2022-02-25 18:39:17 +00:00
export default ( { app } , inject ) => {
2022-03-21 23:47:11 +00:00
inject ( "youtube" , { ... searchModule , ... innertubeModule } ) ;
2022-03-28 02:07:03 +00:00
inject ( "rendererUtils" , rendererUtils ) ;
2022-03-21 23:47:11 +00:00
} ;