Skip to content

Commit

Permalink
Rebase fix
Browse files Browse the repository at this point in the history
  • Loading branch information
INSANITY\Inrix authored and INSANITY\Inrix committed Jul 22, 2018
1 parent c15a4f2 commit 838fcc9
Show file tree
Hide file tree
Showing 18 changed files with 1,050 additions and 68 deletions.
10 changes: 1 addition & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1 @@
settings.json
videos.json
partial.json
node_modules/
videos/
/**/desktop.ini
releases/
videos
package-lock.json
./**/desktop.ini
47 changes: 47 additions & 0 deletions FloatplaneAPI.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
https://www.floatplane.com/api/user/info?id=5a9f3a8a58f4340e5111544b

&fetchAfter=0 -> 20Videos per page so ++ 20 for each new page of videos
https://www.floatplane.com/api/creator/videos?creatorGUID=59f94c0bdd241b70349eb72b&fetchAfter=0

https://cms.linustechtips.com/get/sprite/by_guid/Z81Xk5YZKY
https://www.floatplane.com/api/creator/info?creatorGUID=59f94c0bdd241b70349eb72b
https://www.floatplane.com/api/user/named?username=Inrix

https://www.floatplane.com/api/user/subscriptions

59f94c0bdd241b70349eb72b

info: "creator/info",
infoByName: "creator/named",
videos: "creator/videos",
playlists: "creator/playlists",
list: "creator/list",
subscription: "plan/info"

uploadVideo: "/video/upload",
submitVideo: "/video/submit",
postVideoChunk: "/video/chunk/upload",
checkVideoChunk: "/video/chunk/check",
updateVideoInfo: "/video/update",
uploadVideoThumbnail: "/video/upload/thumbnail",
transcodingList: "/video/transcode/list",
transcodeProgress: "/video/transcode/progress",
readyList: "/video/ready/list",
deleteVideos: "/video/delete",
updateLiveConfig: "/live/config/update",
uploadLiveThumbnail: "/live/thumbnail/upload"

info: "video/info",
comments: "video/comments",
commentReplies: "video/comment/replies",
addComment: "video/comment",
deleteComment: "video/comment/remove",
setInteraction: "video/comment/interaction/set",
clearInteraction: "video/comment/interaction/clear",
playlistVideos: "playlist/videos",
relatedVideos: "video/related",
getVideoUrl: "video/url",
getStreamingEdges: "edges"


https://www.floatplane.com/api/video/url?guid=YeM6cfNvIf&quality=1080
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Floatplane Club - PlexDownloader

[![https://gyazo.com/482af53e0a8cc281c9a60dd66d5ade56](https://i.gyazo.com/482af53e0a8cc281c9a60dd66d5ade56.jpg)](https://gyazo.com/482af53e0a8cc281c9a60dd66d5ade56)
[![https://gyazo.com/d496b2d946d2e96c88ff94a18952f403](https://i.gyazo.com/d496b2d946d2e96c88ff94a18952f403.jpg)](https://gyazo.com/d496b2d946d2e96c88ff94a18952f403)
[![Script](https://i.gyazo.com/3f9a5bd4651b298b07d49cf00fc67df6.png)](https://gyazo.com/3f9a5bd4651b298b07d49cf00fc67df6)

### Basic Info:

**We now have a discord! So head there if you need help... [Join Our Discord](https://discord.gg/aNTyMME)**

**You can download the latest stable version from here: https://github.com/Inrixia/Floatplane-PlexDownloader/releases**

This is a Node.js script to download the daily videos from the [LMG Floatplane](https://linustechtips.com/main/store/) and format them to be viewed in [Plex](https://www.plex.tv/). You can also view the raw files in the download folder.

This requires a **[Floatplane](http://floatplane.com)** subscription.

### **Install Guide**

* Make sure you have **[Node.js](https://nodejs.org/en/)** installed on your system to use this.
* If you want to use **[Plex](https://www.plex.tv/)** to browse the files installed you must have it installed.
* If you encounter any issues then feel free to create a issue here or just PM me on **[Discord](https://discordapp.com/) @Sir Inrix | <3#6950**.

#### Links:
* [Installing the Script & Downloading](https://github.com/Inrixia/Floatplane-PlexDownloader/blob/master/wiki/script.md)
* [Setting up Plex](https://github.com/Inrixia/Floatplane-PlexDownloader/blob/master/wiki/plex.md)
* [Settings Info](https://github.com/Inrixia/Floatplane-Downloader/blob/master/wiki/settings.md)

I will be maintaining this as I use it.

If you want to open Plex files in your own Media Player eg, VLC, MPC-BE, WindowsMediaPlayer. Go and install this tampermonkey script here: **https://github.com/Kayomani/PlexExternalPlayer** **Important Note** for chrome users: https://github.com/Kayomani/PlexExternalPlayer/issues/16

If you want plex to update after downloading new videos (fixing the issue with some video titles not updating after being downloaded until you refresh metadata) you can read about the plex specific settings in **[Settings Info](https://github.com/Inrixia/Floatplane-Downloader/blob/master/wiki/settings.md)**

**Note**: If anyone from LTT or Floatplane does not want me to have this publically avalible please just contact me and I will remove it.

---
## [More Screenshots](https://imgur.com/a/LdY1B)
5 changes: 0 additions & 5 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
v4.1.6
- Fixed issue with script failing on videos with no thumbnail
- Added videos.json to store downloaded videos
- Fixed subchannel Ignore not working

v4.0.5
- Fixed issue with script not handling site returning no videos
- Fixed issue with script not fetching subscriptions due to api update
Expand Down
84 changes: 35 additions & 49 deletions float.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ process.on('uncaughtException', function(err) { // "Nice" Error handling, will o
});

const settings = require('./settings.json'); // File containing user settings
const videos = require('./videos.json'); // Persistant storage of videos downloaded
const partial_data = require('./partial.json'); // File for saving details of partial downloads

if (!fs.existsSync(settings.videoFolder)){ // Check if the new path exists (plus season folder if enabled)
Expand Down Expand Up @@ -313,13 +312,6 @@ function saveSettings() { // Saves all the settings from the current settings ob
})
}

function saveVideoLog() { // Function for saving partial data, just writes out the variable to disk
fs.writeFile("./videos.json", JSON.stringify(videos), 'utf8', function (err) {
if (err) console.log(err)
});
}


function logEpisodeCount(){ // Print out the current number of "episodes" for each subchannel
return new Promise((resolve, reject) => {
console.log('\n\n=== \u001b[38;5;8mEpisode Count\u001b[0m ===')
Expand Down Expand Up @@ -450,8 +442,8 @@ function getVideos() {
video.subChannel = subChannel.title
}
});
if (subscription.ignore[video.subchannel]) {return false} // If this video is part of a subChannel we are ignoring then break
}
if (subscription.ignore[video.subChannel]) { return false } // If this video is part of a subChannel we are ignoring then break

// Manage paths for downloads
rawPath = settings.videoFolder+video.subChannel+'/' // Create the rawPath variable that stores the path to the file
Expand Down Expand Up @@ -493,46 +485,45 @@ function getVideos() {
// Check if video already exists
matchTitle = sanitize(matchTitle)
video.title = sanitize(video.title);
//files = glob.sync(rawPath+'*'+matchTitle.replace('(', '*').replace(')', '*')+".mp4") // Check if the video already exists based on the above match
//partialFiles = glob.sync(rawPath+'*'+video.title.replace('(', '*').replace(')', '*')+".mp4.part") // Check if the video is partially downloaded
files = glob.sync(rawPath+'*'+matchTitle.replace('(', '*').replace(')', '*')+".mp4") // Check if the video already exists based on the above match
partialFiles = glob.sync(rawPath+'*'+video.title.replace('(', '*').replace(')', '*')+".mp4.part") // Check if the video is partially downloaded
if (!colourList[video.subChannel]) { colourList[video.subChannel] = '\u001b[38;5;153m' }
if (i == Math.ceil(settings.maxVideos/20)) {
printLines()
}
//if (files.length > 0) { // If it already exists then format the title nicely, log that it exists in console and end for this video
if (videos[video.guid] == undefined){ videos[video.guid] = {title: video.title, partial: false, saved: false} }
if (!videos[video.guid].saved) {
if (files.length > 0) { // If it already exists then format the title nicely, log that it exists in console and end for this video
console.log(colourList[video.subChannel]+video.subChannel+'\u001b[0m> '+matchTitle, '== \u001b[32mEXISTS\u001b[0m');
} else {
updatePlex = true
episodeList[video.subChannel] += 1 // Increment the episode number for this subChannel
try{if(partial_data[video.title].failed){}}catch(err){partial_data[video.title] = {failed: true}} // Check if partialdata is corrupted and use a dirty fix if it is
if (!videos[video.guid].partial){ // If it dosnt exist then format the title with the proper incremented episode number and log that its downloading in console
if(settings.downloadArtwork && video.thumbnail) { floatRequest(video.thumbnail.path).pipe(fs.createWriteStream(rawPath+video.title+'.png'))} // Save the thumbnail with the same name as the video so plex will use it
loadCount += 1
if (liveCount < settings.maxParallelDownloads || settings.maxParallelDownloads == -1) { // If we havent hit the maxParallelDownloads or there isnt a limit then download
process.stdout.write(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[34mDOWNLOADING\u001b[0m');
download(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, video.title, video.subChannel, rawPath, video) // Download the video
} else { // Otherwise add to queue
console.log(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[35mQUEUED\u001b[0m');
queueDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, video.title, video.subChannel, rawPath, video) // Queue
}
} else { // The video is partially downloaded
if(settings.downloadArtwork && video.thumbnail) {floatRequest(video.thumbnail.path).pipe(fs.createWriteStream(rawPath+partial_data[video.title].title+'.png'))} // Save the thumbnail with the same name as the video so plex will use it
if(partialFiles.length > 0) { // If the video is partially downloaded
if(settings.downloadArtwork) { floatRequest(video.thumbnail.path).pipe(fs.createWriteStream(rawPath+partial_data[video.title].title+'.png'))} // Save the thumbnail with the same name as the video so plex will use it
loadCount += 1
if (partial_data[video.title].failed) { // If the download failed then start from download normally
//partialFiles.length = 1;
partialFiles.length = 1;
loadCount -= 1
} else {
if (liveCount < settings.maxParallelDownloads || settings.maxParallelDownloads == -1) { // If we havent hit the maxParallelDownloads or there isnt a limit then download
process.stdout.write(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[38;5;226mRESUMING DOWNLOAD\u001b[0m');
resumeDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, partial_data[video.title].title, video.subChannel, rawPath, video) // Download the video
resumeDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, partial_data[video.title].title, video.subChannel, rawPath) // Download the video
} else { // Otherwise add to queue
console.log(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[35mRESUME QUEUED\u001b[0m');
queueResumeDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, partial_data[video.title].title, video.subChannel, rawPath, video) // Queue
queueResumeDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, partial_data[video.title].title, video.subChannel, rawPath) // Queue
}
}
}
} else {
console.log(colourList[video.subChannel]+video.subChannel+'\u001b[0m> '+matchTitle, '== \u001b[32mEXISTS\u001b[0m');
if (partialFiles.length <= 0){ // If it dosnt exist then format the title with the proper incremented episode number and log that its downloading in console
if(settings.downloadArtwork) { floatRequest(video.thumbnail.path).pipe(fs.createWriteStream(rawPath+video.title+'.png'))} // Save the thumbnail with the same name as the video so plex will use it
loadCount += 1
if (liveCount < settings.maxParallelDownloads || settings.maxParallelDownloads == -1) { // If we havent hit the maxParallelDownloads or there isnt a limit then download
process.stdout.write(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[34mDOWNLOADING\u001b[0m');
download(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, video.title, video.subChannel, rawPath) // Download the video
} else { // Otherwise add to queue
console.log(colourList[video.subChannel]+'>-- '+'\u001b[0m'+matchTitle+' == \u001b[35mQUEUED\u001b[0m');
queueDownload(settings.floatplaneServer+'/Videos/'+video.guid+'/'+settings.video_res+'.mp4?wmsAuthSign='+settings.key, video.title, video.subChannel, rawPath) // Queue
}
}
}
})
}
Expand All @@ -542,29 +533,27 @@ function getVideos() {
})
}

function queueDownload(url, title, thisChannel, rawPath, video) { // Loop until current downloads is less than maxParallelDownloads and then download
function queueDownload(url, title, thisChannel, rawPath) { // Loop until current downloads is less than maxParallelDownloads and then download
setTimeout(function(){
if (liveCount < settings.maxParallelDownloads, video) {
download(url, title, thisChannel, rawPath, video)
if (liveCount < settings.maxParallelDownloads) {
download(url, title, thisChannel, rawPath)
} else {
queueDownload(url, title, thisChannel, rawPath, video) // Run this function again continuing the loop
queueDownload(url, title, thisChannel, rawPath) // Run this function again continuing the loop
}
}, 500)
}

function queueResumeDownload(url, title, thisChannel, rawPath, video) { // Loop until current downloads is less than maxParallelDownloads and then download
function queueResumeDownload(url, title, thisChannel, rawPath) { // Loop until current downloads is less than maxParallelDownloads and then download
setTimeout(function(){
if (liveCount < settings.maxParallelDownloads) {
resumeDownload(url, title, thisChannel, rawPath, video)
resumeDownload(url, title, thisChannel, rawPath)
} else {
queueResumeDownload(url, title, thisChannel, rawPath, video) // Run this function again continuing the loop
queueResumeDownload(url, title, thisChannel, rawPath) // Run this function again continuing the loop
}
}, 500)
}

function download(url, title, thisChannel, rawPath, video) { // The main download function, this is the guts of downloading stuff after the url is gotten from the form
videos[video.guid].partial = true
saveVideoLog()
function download(url, title, thisChannel, rawPath) { // The main download function, this is the guts of downloading stuff after the url is gotten from the form
partial_data[title] = {failed: true, title: title} // Set the download failed to true and the title incase a download starts but crashes before the first partial write
var bar = multi.newBar(':title [:bar] :percent :stats', { // Format with ffmpeg for titles/plex support
complete: '\u001b[42m \u001b[0m',
Expand Down Expand Up @@ -597,11 +586,11 @@ function download(url, title, thisChannel, rawPath, video) { // The main downloa
file = rawPath+title+'.mp4' // Specifies where the video is saved
name = title.replace(/^.*[0-9].- /, '').replace('- ', '') // Generate the name used for the title in metadata (This is for plex so "episodes" have actual names over Episode1...)
file2 = (rawPath+'TEMP_'+title+'.mp4') // Specify the temp file to write the metadata to
ffmpegFormat(file, name, file2, video) // Format with ffmpeg for titles/plex support
ffmpegFormat(file, name, file2, {url: url, title: title, thisChannel: thisChannel}) // Format with ffmpeg for titles/plex support
});
}

function resumeDownload(url, title, thisChannel, rawPath, video) { // This handles resuming downloads, its very similar to the download function with some changes
function resumeDownload(url, title, thisChannel, rawPath) { // This handles resuming downloads, its very similar to the download function with some changes
var total = partial_data[title].total // Set the total size to be equal to the stored value in the partial_data
var subTotal = partial_data[title].transferred // Set subTotal as the previous ammount transferred
var bar = multi.newBar(':title [:bar] :percent :stats', { // Create a new loading bar
Expand Down Expand Up @@ -639,11 +628,11 @@ function resumeDownload(url, title, thisChannel, rawPath, video) { // This handl
file = rawPath+title+'.mp4' // Specifies where the video is saved
name = title.replace(/^.*[0-9].- /, '').replace('- ', '') // Generate the name used for the title in metadata (This is for plex so "episodes" have actual names over Episode1...)
file2 = (rawPath+'TEMP_'+title+'.mp4') // Specify the temp file to write the metadata to
ffmpegFormat(file, name, file2, video) // Format with ffmpeg for titles/plex support
ffmpegFormat(file, name, file2, {url: url, title: title, thisChannel: thisChannel}) // Format with ffmpeg for titles/plex support
});
}

function ffmpegFormat(file, name, file2, video) { // This function adds titles to videos using ffmpeg for compatibility with plex
function ffmpegFormat(file, name, file2, recover) { // This function adds titles to videos using ffmpeg for compatibility with plex
ffmpeg(file).outputOptions("-metadata", "title="+name, "-map", "0", "-codec", "copy").saveToFile(file2).on('error', function(err, stdout, stderr) { // Add title metadata
setTimeout(function(){ // If the formatting fails, wait a second and try again
//console.log(name+' \u001b[41mFFMPEG Encountered a Error!\u001b[0m')
Expand All @@ -653,10 +642,7 @@ function ffmpegFormat(file, name, file2, video) { // This function adds titles t
if(loadCount == -1) { // If we are at the last video then run a plex collection update
updateLibrary();
}
fs.rename(file2, file, function(){
videos[video.id].saved = true
saveVideoLog();
})
fs.rename(file2, file, function(){})
})
}

Expand Down
1 change: 1 addition & 0 deletions latest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version": "4.0.5", "beta": "4.0.7"}
Loading

0 comments on commit 838fcc9

Please sign in to comment.