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" ;
import useRender from "./renderers" ;
2022-02-25 18:54:15 +00:00
2022-02-28 15:24:06 +00:00
//--- Logger Function ---//
2022-03-16 09:07:40 +00:00
function logger ( func , data , isError = false ) {
2022-03-21 23:47:11 +00:00
searchModule . logs . unshift ( {
name : func ,
time : Date . now ( ) ,
data : data ,
error : isError ,
} ) ;
2022-02-28 15:24:06 +00:00
}
2022-03-13 23:21:41 +00:00
//--- Youtube Base Parser ---//
function youtubeParse ( html , callback ) {
2022-03-21 23:47:11 +00:00
//--- Replace Encoded Characters ---///
html = html . replace ( /\\x([0-9A-F]{2})/gi , ( ... items ) => {
return String . fromCharCode ( parseInt ( items [ 1 ] , 16 ) ) ;
} ) ;
//--- Properly Format JSON ---//
html = html . replaceAll ( '\\\\"' , "" ) ;
//--- Parse JSON ---//
html = JSON . parse ( html ) ;
//--- Get Results ---// ( Thanks To appit-online On Github ) -> https://github.com/appit-online/youtube-search/blob/master/src/lib/search.ts
let results ;
if (
html &&
html . contents &&
html . contents . sectionListRenderer &&
html . contents . sectionListRenderer . contents &&
html . contents . sectionListRenderer . contents . length > 0 &&
html . contents . sectionListRenderer . contents [ 0 ] . itemSectionRenderer &&
html . contents . sectionListRenderer . contents [ 0 ] . itemSectionRenderer . contents
. length > 0
) {
results =
html . contents . sectionListRenderer . contents [ 0 ] . itemSectionRenderer
. contents ;
logger ( constants . LOGGER _NAMES . search , results ) ;
callback ( results ) ;
} else {
try {
results = JSON . parse (
html
. split ( '{"itemSectionRenderer":{"contents":' )
[ html . split ( '{"itemSectionRenderer":{"contents":' ) . length - 1 ] . split (
',"continuations":[{'
) [ 0 ]
) ;
logger ( constants . LOGGER _NAMES . search , results ) ;
callback ( results ) ;
} catch ( e ) { }
try {
results = JSON . parse (
html
. split ( '{"itemSectionRenderer":' )
[ html . split ( '{"itemSectionRenderer":' ) . length - 1 ] . split (
'},{"continuationItemRenderer":{'
) [ 0 ]
) . contents ;
logger ( constants . LOGGER _NAMES . search , results ) ;
callback ( results ) ;
} catch ( e ) { }
}
2022-03-13 23:21:41 +00:00
}
2022-03-04 02:07:53 +00:00
//--- Search Main Function ---//
function youtubeSearch ( text , callback ) {
2022-03-21 23:47:11 +00:00
Http . request ( {
method : "GET" ,
url : ` ${ constants . URLS . YT _URL } /results ` ,
params : { q : text , hl : "en" } ,
} )
. then ( ( res ) => {
//--- Get HTML Only ---//
let html = res . data ;
//--- Isolate The Script Containing Video Information ---//
html = html . split ( "var ytInitialData = '" ) [ 1 ] . split ( "';</script>" ) [ 0 ] ;
youtubeParse ( html , ( data ) => {
callback ( data ) ;
} ) ;
} )
. catch ( ( err ) => {
logger ( constants . LOGGER _NAMES . search , err , true ) ;
callback ( err ) ;
} ) ;
2022-03-04 02:07:53 +00:00
}
2022-03-16 09:07:40 +00:00
const searchModule = {
2022-03-21 23:47:11 +00:00
logs : new Array ( ) ,
2022-03-19 06:17:18 +00:00
2022-03-21 23:47:11 +00:00
//--- Get YouTube's Search Auto Complete ---//
autoComplete ( text , callback ) {
Http . request ( {
method : "GET" ,
url : ` ${ constants . URLS . YT _SUGGESTIONS } /search ` ,
params : { client : "youtube" , q : text } ,
} )
. then ( ( res ) => {
logger ( constants . LOGGER _NAMES . autoComplete , res ) ;
callback ( res . data ) ;
} )
. catch ( ( err ) => {
logger ( constants . LOGGER _NAMES . autoComplete , err , true ) ;
callback ( err ) ;
} ) ;
} ,
2022-02-25 18:54:15 +00:00
2022-03-23 13:07:03 +00:00
// search(text, callback) {
// let results = new Array();
// youtubeSearch(text, (videos) => {
// for (const i in videos) {
// const video = videos[i];
2022-03-21 23:47:11 +00:00
2022-03-23 13:07:03 +00:00
// if (video.compactVideoRenderer) {
// //--- If Entry Is A Video ---//
// results.push({
// id: video.compactVideoRenderer.videoId,
// title: video.compactVideoRenderer.title.runs[0].text,
// runtime: video.compactVideoRenderer.lengthText.runs[0].text,
// uploaded: video.compactVideoRenderer.publishedTimeText.runs[0].text,
// views: video.compactVideoRenderer.viewCountText.runs[0].text,
// thumbnails: video.compactVideoRenderer.thumbnail.thumbnails,
// });
// } else {
// //--- If Entry Is Not A Video ---//
// //logger(constants.LOGGER_NAMES.search, { type: "Error Caught Successfully", error: video }, true);
// }
// }
// });
// callback(results);
// },
2022-03-21 23:47:11 +00:00
getRemainingVideoInfo ( id , callback ) {
String . prototype . decodeEscapeSequence = function ( ) {
return this . replace ( /\\x([0-9A-Fa-f]{2})/g , function ( ) {
return String . fromCharCode ( parseInt ( arguments [ 1 ] , 16 ) ) ;
} ) ;
} ;
Http . request ( {
method : "GET" ,
url : ` ${ constants . URLS . YT _URL } /watch ` ,
params : { v : id } ,
} )
. then ( ( res ) => {
let dataUpdated = res . data . decodeEscapeSequence ( ) ;
let likes = dataUpdated
. split (
` "defaultIcon":{"iconType":"LIKE"},"defaultText":{"runs":[{"text":" `
) [ 1 ]
. split ( ` "}],"accessibility": ` ) [ 0 ] ;
let uploadDate = dataUpdated
. split ( ` "uploadDate":" ` ) [ 1 ]
. split ( ` }},"trackingParams":" ` ) [ 0 ]
. slice ( 0 , - 2 ) ;
let data = {
likes : likes ,
uploadDate : uploadDate ,
} ;
logger ( "vidData" , data ) ;
callback ( data ) ;
} )
. catch ( ( err ) => {
logger ( "codeRun" , err , true ) ;
callback ( err ) ;
} ) ;
} ,
getReturnYoutubeDislike ( id , callback ) {
Http . request ( {
method : "GET" ,
url : ` https://returnyoutubedislikeapi.com/votes ` ,
params : { videoId : id } ,
} )
. then ( ( res ) => {
logger ( "rydData" , res . data ) ;
callback ( res . data ) ;
} )
. catch ( ( err ) => {
logger ( "codeRun" , err , true ) ;
callback ( err ) ;
} ) ;
} ,
} ;
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 ) {
InnertubeAPI = await Innertube . createAsync ( ( message , isError ) => {
logger ( constants . LOGGER _NAMES . innertube , message , isError ) ;
} ) ;
}
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 ) ;
} catch ( error ) {
logger ( constants . LOGGER _NAMES . watch , error , true ) ;
}
} ,
2022-03-23 11:21:06 +00:00
getThumbnail ( id , resolution ) {
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 ;
} ;
}
return ` https://img.youtube.com/vi/ ${ id } /mqdefault.jpg ` ;
} ,
2022-03-21 23:47:11 +00:00
// It just works™
// Front page recommendation
async recommend ( ) {
const response = await InnertubeAPI . getRecommendationsAsync ( ) ;
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 ) => {
const video =
shelves . shelfRenderer ? . content ? . horizontalListRenderer ? . items ;
2022-03-23 11:21:06 +00:00
if ( video ) return video ;
2022-03-21 23:47:11 +00:00
} ) ;
console . log ( final ) ;
return final ;
} ,
2022-03-23 13:07:03 +00:00
async search ( query ) {
try {
const response = await InnertubeAPI . getSearchAsync ( query ) ;
return response . content . verticalListRenderer ;
} catch ( err ) {
logger ( constants . LOGGER _NAMES . search , err , true ) ;
}
} ,
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 } ) ;
inject ( "logger" , logger ) ;
} ;
2022-03-19 18:26:20 +00:00
logger ( constants . LOGGER _NAMES . init , "Program Started" ) ;