@@ -117,6 +117,10 @@ $(".ui.dashboard .content").on("click", ".download-success, .course-encrypted",
117117 $ ( this ) . parents ( ".course" ) . find ( ".download-status" ) . show ( ) ;
118118} ) ;
119119
120+ $ ( ".ui.dashboard .content" ) . on ( "click" , ".save_m3u.button" , function ( e ) {
121+ e . stopImmediatePropagation ( ) ;
122+ saveM3u ( $ ( this ) . parents ( ".course" ) ) ;
123+ } ) ;
120124$ ( ".ui.dashboard .content" ) . on ( "click" , ".download.button, .download-error" , function ( e ) {
121125 e . stopImmediatePropagation ( ) ;
122126 prepareDownloading ( $ ( this ) . parents ( ".course" ) ) ;
@@ -301,7 +305,7 @@ async function checkLogin(alertExpired = true) {
301305 ui . busyLogin ( false ) ;
302306 ui . showDashboard ( ) ;
303307
304- Settings . subscriber = utils . toBoolean ( userContext . header . user . enableLabsInPersonalPlan ) ;
308+ Settings . subscriber = utils . toBoolean ( userContext . header . user . enableLabsInPersonalPlan ) || utils . toBoolean ( userContext . header . user . consumer_subscription_active ) ;
305309 fetchCourses ( Settings . subscriber ) . then ( ( ) => {
306310 console . log ( "fetchCourses done" ) ;
307311 } ) ;
@@ -553,9 +557,10 @@ function renderCourses(response, isResearch = false) {
553557 $coursesItems . append ( courseElements ) ;
554558
555559 if ( response . next ) {
560+ const dataUrl = Array . isArray ( response . next ) ? response . next : [ response . next ] ;
556561 // added loadMore Button
557562 $coursesSection . append (
558- `<button class="ui basic blue fluid load-more button disposable" data-url=${ response . next } >
563+ `<button class="ui basic blue fluid load-more button disposable" data-url=${ JSON . stringify ( dataUrl ) } >
559564 ${ translate ( "Load More" ) }
560565 </button>`
561566 ) ;
@@ -707,6 +712,7 @@ async function fetchCourseContent(courseId, courseName, courseUrl) {
707712 } else {
708713
709714 switch ( ( lecture . quality || "" ) . toLowerCase ( ) ) {
715+ case "" :
710716 case "auto" :
711717 case "highest" :
712718 lecture . quality = streams . maxQuality ;
@@ -715,10 +721,10 @@ async function fetchCourseContent(courseId, courseName, courseUrl) {
715721 lecture . quality = streams . minQuality ;
716722 break ;
717723 default :
718- lecture . quality = utils . isNumber ( lecture . quality ) ? lecture . quality : lecture . quality . slice ( 0 , - 1 ) ;
724+ lecture . quality = utils . isNumber ( lecture . quality ) ? lecture . quality : lecture . quality . slice ( 0 , - 1 ) ;
719725 }
720726
721- if ( ! streams . sources [ lecture . quality ] ) {
727+ if ( lecture . quality && ! streams . sources [ lecture . quality ] ) {
722728 if ( utils . isNumber ( lecture . quality ) && streams . maxQuality != "auto" ) {
723729 const source = utils . getClosestValue ( streams . sources , lecture . quality ) ;
724730 lecture . quality = source ?. key || streams . maxQuality ;
@@ -801,18 +807,26 @@ async function fetchCourses(isSubscriber) {
801807function loadMore ( loadMoreButton ) {
802808 const $button = $ ( loadMoreButton ) ;
803809 const $courses = $button . prev ( ".courses.items" ) ;
804- const url = $button . data ( "url" ) ;
810+ const url = [ ... $button . data ( "url" ) ] ;
805811
806812 ui . busyLoadCourses ( true ) ;
807813 udemyService
808- . fetchLoadMore ( url )
814+ . fetchLoadMore ( url [ 0 ] )
809815 . then ( ( resp ) => {
810816 $courses . append ( ...resp . results . map ( ( course ) => createCourseElement ( course , false ) ) ) ;
811817 if ( ! resp . next ) {
812- $button . remove ( ) ;
818+ if ( url . length > 1 ) {
819+ $button . data ( "url" , [ url [ 1 ] ] ) ;
820+ } else {
821+ $button . remove ( ) ;
822+ }
813823 } else {
814- $button . data ( "url" , resp . next ) ;
815- }
824+ if ( url . length > 1 ) {
825+ $button . data ( "url" , [ resp . next , url [ 1 ] ] ) ;
826+ } else {
827+ $button . data ( "url" , [ resp . next ] ) ;
828+ }
829+ }
816830 } )
817831 . catch ( ( e ) => {
818832 const statusCode = ( e . response ?. status || 0 ) . toString ( ) + ( e . code ? ` :${ e . code } ` : "" ) ;
@@ -966,6 +980,68 @@ function removeCurseDownloads(courseId) {
966980 } ) ;
967981}
968982
983+ async function saveM3u ( $course ) {
984+ ui . prepareDownloading ( $course ) ;
985+
986+ const courseId = $course . attr ( "course-id" ) ;
987+ const courseName = $course . find ( ".coursename" ) . text ( ) ;
988+ const courseUrl = `https://${ Settings . subDomain } .udemy.com${ $course . attr ( "course-url" ) } ` ;
989+
990+ console . clear ( ) ;
991+
992+ let courseData = null ;
993+ try {
994+ courseData = await fetchCourseContent ( courseId , courseName , courseUrl ) ;
995+ if ( ! courseData ) {
996+ // ui.showProgress($course, false);
997+ return ;
998+ }
999+
1000+ console . log ( courseData ) ;
1001+ dialog
1002+ . showSaveDialog ( {
1003+ title : "Save M3U" ,
1004+ defaultPath : `${ courseName } .m3u` ,
1005+ filters : [ { name : "M3U File (*.m3u)" , fileExtension : [ "m3u" ] } ] ,
1006+ } )
1007+ . then ( ( result ) => {
1008+ if ( ! result . canceled ) {
1009+ let filePath = result . filePath ;
1010+ if ( ! filePath . endsWith ( ".m3u" ) ) filePath += ".m3u" ;
1011+
1012+ let content = "#EXTM3U" ;
1013+ let index = 0 ;
1014+ courseData . chapters . forEach ( ( chapter ) => {
1015+ chapter . lectures . forEach ( ( lecture , lec_index ) => {
1016+ index ++ ;
1017+ content += `\n#EXTINF:-1,${ lec_index + 1 } . ${ lecture . name } \n${ lecture . src } ` ;
1018+
1019+ if ( lecture . attachments && lecture . attachments . length > 0 )
1020+ lecture . attachments . forEach ( ( attachment , attach_index ) => {
1021+ content += `\n#EXTINF:-1,${ lec_index + 1 } .${ attach_index + 1 } ${ attachment . name } \n${ attachment . src } ` ;
1022+ } )
1023+ } )
1024+ } ) ;
1025+
1026+ fs . writeFile ( filePath , content , ( error ) => {
1027+ if ( error ) {
1028+ appendLog ( "saveM3u_Error" , error ) ;
1029+ return ;
1030+ }
1031+ console . log ( "File successfully create!" ) ;
1032+ } ) ;
1033+ }
1034+ } ) ;
1035+
1036+ } catch ( error ) {
1037+ handleApiError ( error , "ESAVE_M3U" , null , false ) ;
1038+ ui . busyOff ( ) ;
1039+ $course . find ( ".prepare-downloading" ) . hide ( ) ;
1040+ } finally {
1041+ ui . showProgress ( $course , false ) ;
1042+ }
1043+ }
1044+
9691045async function prepareDownloading ( $course , subtitle ) {
9701046 ui . prepareDownloading ( $course ) ;
9711047 // ui.showProgress($course, true);
0 commit comments