Skip to content

Instantly share code, notes, and snippets.

@iluxonchik
Created December 14, 2017 08:38
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save iluxonchik/e6c9902cc67a13d128e0a8817b6f9069 to your computer and use it in GitHub Desktop.
Save iluxonchik/e6c9902cc67a13d128e0a8817b6f9069 to your computer and use it in GitHub Desktop.
Download JWPlayer .ts files, merge them into a single file and then convert the file to .mp4
"""
For my Neuroengineering course presentation my group wanted to download some videos,
the problem is that those videos were played by the JWPlayer, so obtaining the video
files was a little tricky. What I noticed from observing the network traffic is that
JWPlayer downloads the video files in chunks (each chunk was 4 seconds long) and
in .ts format. My goal was to combine all of those small video segments into a single
one and then convert the file to .mp4. To combine the multiple video chunks into one
I used the "cat" command and to convert resulting .ts file to .mp4 I used the "ffmpeg"
tool.
This tool is purpose-specific, so you'll need to adapt it for your own case. We were
in a hurry and this a script that I quickly put up so that we could proceed with work.
I'm leaving this here in case someone else encounters a similar task, you can use
this file as a guide.
Tested only on Linux, but should work just fine on OSX. Might need adaptations for Windows.
Requirements:
* Python 3.x
* "ffmpeg" command-line tool.
"""
import sys
import urllib.request
from os import system, remove
# used to generate the correct file names, so that they
# can be downloaded. This was purpuse-specific, so you might
# wanna change that.
index_begin = int(sys.argv[1])
index_end = int(sys.argv[2])
out_file_name = sys.argv[3]
url = 'http://videos-f.jwpsrv.com/content/conversions/24tOJIfp/videos/vWqXqYoa-29646386.mp4-{}.ts'
file_name = 'vWqXqYoa-29646386.mp4-{}.ts'
file_names = []
for i in range(index_begin, index_end + 1):
curr_file_name = file_name.format(i)
curr_url = url.format(i)
file_names += [curr_file_name]
print('Downloading {}'.format(curr_url))
urllib.request.urlretrieve(curr_url, curr_file_name)
print('All files downloaded')
print('Joining into a single .ts file...')
command = ''
for file_name in file_names:
command += '{} '.format(file_name)
command = 'cat ' + command + '> {}'.format(out_file_name + '.ts')
system(command)
system('ffmpeg -i {}.ts -acodec copy -vcodec copy {}.mp4'.format(out_file_name, out_file_name))
print('Clenaing up...')
for file_name in file_names:
remove(file_name)
remove('{}.ts'.format(out_file_name))
print('Done!')
@nikanar
Copy link

nikanar commented Sep 29, 2021

This worked when everything else failed, thank you.

Usage :
Change your specific url in the url / file_name variables
You need to find the count of ts files that cover the full length, in my case it was ~250 chunks for ~50 minutes (~5 chunks / minute)
python jwplayer_downloader.py 1 200 out will download it into out.mp4 from ts chunk 1 up to 200, adjust those numbers according to the video segment you are interested in.

@iluxonchik
Copy link
Author

This worked when everything else failed, thank you.

Usage : Change your specific url in the url / file_name variables You need to find the count of ts files that cover the full length, in my case it was ~250 chunks for ~50 minutes (~5 chunks / minute) python jwplayer_downloader.py 1 200 out will download it into out.mp4 from ts chunk 1 up to 200, adjust those numbers according to the video segment you are interested in.

no problem :) glad it helped out somebody else 😄

@droogie
Copy link

droogie commented Apr 7, 2022

Thanks for the script. To save some others some time, you can tweak the loop logic like this

i = 0
while True:
    curr_file_name = file_name.format(i)
    curr_url = url.format(i)
    file_names += [curr_file_name]
    print('Downloading {}'.format(curr_url))
    try:
        urllib.request.urlretrieve(curr_url, curr_file_name)
        i = i+1
    except:
        file_names.pop()
        break

then it will just start at part 0 and stop downloading the moment it hits the first 404, so you don't need to figure out what the last part number is

@rossnick
Copy link

Thanks for that ! Worked like a charm.

@burak-biyikli
Copy link

burak-biyikli commented Jun 25, 2022

In a similar vein, I had a video that was sparsely populated, so it would go 1, 5, 6, 10, 11, 12, 13, 15 etc. And sometimes the files were there but unplayable (They were less than 1kb), So I made this modification:

i = 0
failcount = 0
failmax = 10
fileminsizeb = 2048

while True:
    curr_file_name = file_name.format(i)
    curr_url = url.format(i)
    file_names += [curr_file_name]
    print('Downloading {}:'.format(curr_file_name), end="")

    try:
        urllib.request.urlretrieve(curr_url, curr_file_name)
    except:
        print(" error downloading.", end="")
        file_names.pop()
        i = i+1
        failcount = failcount + 1
        print("")
        if (failcount > failmax):
            break
        continue

    try:
        if( os.path.getsize(curr_file_name) < fileminsizeb ):
            print(f" File too small { os.path.getsize(curr_file_name) }", end = "")
            os.remove(curr_file_name)
            i = i+1
            failcount = failcount + 1
            print("")
            if (failcount > failmax):
                break
            continue
    except:
        print(f" Error resolving local path {curr_file_name}", end="")

    i = i+1
    failcount = 0
    print(" Success")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment