Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67af70569b | ||
|
|
68a62d8a7c | ||
|
|
55578f4de7 |
@@ -21,7 +21,7 @@ hopefully, quite reliable.
|
|||||||
# Latest container image
|
# Latest container image
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
ghcr.io/meeb/tubesync:v0.4
|
ghcr.io/meeb/tubesync:v0.5
|
||||||
```
|
```
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
@@ -98,7 +98,7 @@ Finally, download and run the container:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Pull a versioned image
|
# Pull a versioned image
|
||||||
$ docker pull ghcr.io/meeb/tubesync:v0.4
|
$ docker pull ghcr.io/meeb/tubesync:v0.5
|
||||||
# Start the container using your user ID and group ID
|
# Start the container using your user ID and group ID
|
||||||
$ docker run \
|
$ docker run \
|
||||||
-d \
|
-d \
|
||||||
@@ -109,7 +109,7 @@ $ docker run \
|
|||||||
-v /some/directory/tubesync-config:/config \
|
-v /some/directory/tubesync-config:/config \
|
||||||
-v /some/directory/tubesync-downloads:/downloads \
|
-v /some/directory/tubesync-downloads:/downloads \
|
||||||
-p 4848:4848 \
|
-p 4848:4848 \
|
||||||
ghcr.io/meeb/tubesync:v0.4
|
ghcr.io/meeb/tubesync:v0.5
|
||||||
```
|
```
|
||||||
|
|
||||||
Once running, open `http://localhost:4848` in your browser and you should see the
|
Once running, open `http://localhost:4848` in your browser and you should see the
|
||||||
@@ -121,7 +121,7 @@ Alternatively, for Docker Compose, you can use something like:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
tubesync:
|
tubesync:
|
||||||
image: ghcr.io/meeb/tubesync:v0.4
|
image: ghcr.io/meeb/tubesync:v0.5
|
||||||
container_name: tubesync
|
container_name: tubesync
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
0
tubesync/sync/management/__init__.py
Normal file
0
tubesync/sync/management/__init__.py
Normal file
0
tubesync/sync/management/commands/__init__.py
Normal file
0
tubesync/sync/management/commands/__init__.py
Normal file
18
tubesync/sync/management/commands/youtube-dl-info.py
Normal file
18
tubesync/sync/management/commands/youtube-dl-info.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import json
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from sync.youtube import get_media_info
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
help = 'Displays information obtained by youtube-dl in JSON to the console'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('url', type=str)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
url = options['url']
|
||||||
|
self.stdout.write(f'Showing information for URL: {url}')
|
||||||
|
info = get_media_info(url)
|
||||||
|
self.stdout.write(json.dumps(info, indent=4, sort_keys=True))
|
||||||
|
self.stdout.write('Done')
|
||||||
@@ -28,10 +28,13 @@ class Source(models.Model):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
SOURCE_TYPE_YOUTUBE_CHANNEL = 'c'
|
SOURCE_TYPE_YOUTUBE_CHANNEL = 'c'
|
||||||
|
SOURCE_TYPE_YOUTUBE_CHANNEL_ID = 'i'
|
||||||
SOURCE_TYPE_YOUTUBE_PLAYLIST = 'p'
|
SOURCE_TYPE_YOUTUBE_PLAYLIST = 'p'
|
||||||
SOURCE_TYPES = (SOURCE_TYPE_YOUTUBE_CHANNEL, SOURCE_TYPE_YOUTUBE_PLAYLIST)
|
SOURCE_TYPES = (SOURCE_TYPE_YOUTUBE_CHANNEL, SOURCE_TYPE_YOUTUBE_CHANNEL_ID,
|
||||||
|
SOURCE_TYPE_YOUTUBE_PLAYLIST)
|
||||||
SOURCE_TYPE_CHOICES = (
|
SOURCE_TYPE_CHOICES = (
|
||||||
(SOURCE_TYPE_YOUTUBE_CHANNEL, _('YouTube channel')),
|
(SOURCE_TYPE_YOUTUBE_CHANNEL, _('YouTube channel')),
|
||||||
|
(SOURCE_TYPE_YOUTUBE_CHANNEL_ID, _('YouTube channel by ID')),
|
||||||
(SOURCE_TYPE_YOUTUBE_PLAYLIST, _('YouTube playlist')),
|
(SOURCE_TYPE_YOUTUBE_PLAYLIST, _('YouTube playlist')),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -98,21 +101,25 @@ class Source(models.Model):
|
|||||||
# Fontawesome icons used for the source on the front end
|
# Fontawesome icons used for the source on the front end
|
||||||
ICONS = {
|
ICONS = {
|
||||||
SOURCE_TYPE_YOUTUBE_CHANNEL: '<i class="fab fa-youtube"></i>',
|
SOURCE_TYPE_YOUTUBE_CHANNEL: '<i class="fab fa-youtube"></i>',
|
||||||
|
SOURCE_TYPE_YOUTUBE_CHANNEL_ID: '<i class="fab fa-youtube"></i>',
|
||||||
SOURCE_TYPE_YOUTUBE_PLAYLIST: '<i class="fab fa-youtube"></i>',
|
SOURCE_TYPE_YOUTUBE_PLAYLIST: '<i class="fab fa-youtube"></i>',
|
||||||
}
|
}
|
||||||
# Format to use to display a URL for the source
|
# Format to use to display a URL for the source
|
||||||
URLS = {
|
URLS = {
|
||||||
SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/c/{key}',
|
SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/c/{key}',
|
||||||
|
SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'https://www.youtube.com/channel/{key}',
|
||||||
SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/playlist?list={key}',
|
SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/playlist?list={key}',
|
||||||
}
|
}
|
||||||
# Callback functions to get a list of media from the source
|
# Callback functions to get a list of media from the source
|
||||||
INDEXERS = {
|
INDEXERS = {
|
||||||
SOURCE_TYPE_YOUTUBE_CHANNEL: get_youtube_media_info,
|
SOURCE_TYPE_YOUTUBE_CHANNEL: get_youtube_media_info,
|
||||||
|
SOURCE_TYPE_YOUTUBE_CHANNEL_ID: get_youtube_media_info,
|
||||||
SOURCE_TYPE_YOUTUBE_PLAYLIST: get_youtube_media_info,
|
SOURCE_TYPE_YOUTUBE_PLAYLIST: get_youtube_media_info,
|
||||||
}
|
}
|
||||||
# Field names to find the media ID used as the key when storing media
|
# Field names to find the media ID used as the key when storing media
|
||||||
KEY_FIELD = {
|
KEY_FIELD = {
|
||||||
SOURCE_TYPE_YOUTUBE_CHANNEL: 'id',
|
SOURCE_TYPE_YOUTUBE_CHANNEL: 'id',
|
||||||
|
SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'id',
|
||||||
SOURCE_TYPE_YOUTUBE_PLAYLIST: 'id',
|
SOURCE_TYPE_YOUTUBE_PLAYLIST: 'id',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,32 +440,39 @@ class Media(models.Model):
|
|||||||
# Format to use to display a URL for the media
|
# Format to use to display a URL for the media
|
||||||
URLS = {
|
URLS = {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/watch?v={key}',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/watch?v={key}',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'https://www.youtube.com/watch?v={key}',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/watch?v={key}',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/watch?v={key}',
|
||||||
}
|
}
|
||||||
# Maps standardised names to names used in source metdata
|
# Maps standardised names to names used in source metdata
|
||||||
METADATA_FIELDS = {
|
METADATA_FIELDS = {
|
||||||
'upload_date': {
|
'upload_date': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'upload_date',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'upload_date',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'upload_date',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'upload_date',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'upload_date',
|
||||||
},
|
},
|
||||||
'title': {
|
'title': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'title',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'title',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'title',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'title',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'title',
|
||||||
},
|
},
|
||||||
'thumbnail': {
|
'thumbnail': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'thumbnail',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'thumbnail',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'thumbnail',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'thumbnail',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'thumbnail',
|
||||||
},
|
},
|
||||||
'description': {
|
'description': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'description',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'description',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'description',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'description',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'description',
|
||||||
},
|
},
|
||||||
'duration': {
|
'duration': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'duration',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'duration',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'duration',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'duration',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'duration',
|
||||||
},
|
},
|
||||||
'formats': {
|
'formats': {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'formats',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'formats',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: 'formats',
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'formats',
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'formats',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% include 'infobox.html' with message=message %}
|
{% include 'infobox.html' with message=message %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s12 l6 margin-bottom">
|
<div class="col m12 xl4 margin-bottom">
|
||||||
<a href="{% url 'sync:validate-source' source_type='youtube-channel' %}" class="btn">Add a YouTube channel <i class="fab fa-youtube"></i></a>
|
<a href="{% url 'sync:validate-source' source_type='youtube-channel' %}" class="btn">Add a YouTube channel <i class="fab fa-youtube"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s12 l6 margin-bottom">
|
<div class="col m12 xl4 margin-bottom">
|
||||||
|
<a href="{% url 'sync:validate-source' source_type='youtube-channel-id' %}" class="btn">Add a YouTube channel by ID <i class="fab fa-youtube"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="col m12 xl4 margin-bottom">
|
||||||
<a href="{% url 'sync:validate-source' source_type='youtube-playlist' %}" class="btn">Add a YouTube playlist <i class="fab fa-youtube"></i></a>
|
<a href="{% url 'sync:validate-source' source_type='youtube-playlist' %}" class="btn">Add a YouTube playlist <i class="fab fa-youtube"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class FrontEndTestCase(TestCase):
|
|||||||
def test_validate_source(self):
|
def test_validate_source(self):
|
||||||
test_source_types = {
|
test_source_types = {
|
||||||
'youtube-channel': Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
|
'youtube-channel': Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
|
||||||
|
'youtube-channel-id': Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID,
|
||||||
'youtube-playlist': Source.SOURCE_TYPE_YOUTUBE_PLAYLIST,
|
'youtube-playlist': Source.SOURCE_TYPE_YOUTUBE_PLAYLIST,
|
||||||
}
|
}
|
||||||
test_sources = {
|
test_sources = {
|
||||||
@@ -36,8 +37,6 @@ class FrontEndTestCase(TestCase):
|
|||||||
'https://www.youtube.com/testchannel',
|
'https://www.youtube.com/testchannel',
|
||||||
'https://www.youtube.com/c/testchannel',
|
'https://www.youtube.com/c/testchannel',
|
||||||
'https://www.youtube.com/c/testchannel/videos',
|
'https://www.youtube.com/c/testchannel/videos',
|
||||||
'https://www.youtube.com/channel/testchannel',
|
|
||||||
'https://www.youtube.com/channel/testchannel/videos',
|
|
||||||
),
|
),
|
||||||
'invalid_schema': (
|
'invalid_schema': (
|
||||||
'http://www.youtube.com/c/playlist',
|
'http://www.youtube.com/c/playlist',
|
||||||
@@ -53,13 +52,37 @@ class FrontEndTestCase(TestCase):
|
|||||||
),
|
),
|
||||||
'invalid_is_playlist': (
|
'invalid_is_playlist': (
|
||||||
'https://www.youtube.com/c/playlist',
|
'https://www.youtube.com/c/playlist',
|
||||||
'https://www.youtube.com/c/playlist',
|
),
|
||||||
|
'invalid_channel_with_id': (
|
||||||
|
'https://www.youtube.com/channel/channelid',
|
||||||
|
'https://www.youtube.com/channel/channelid/videos',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
'youtube-channel-id': {
|
||||||
|
'valid': (
|
||||||
|
'https://www.youtube.com/channel/channelid',
|
||||||
|
'https://www.youtube.com/channel/channelid/videos',
|
||||||
|
),
|
||||||
|
'invalid_schema': (
|
||||||
|
'http://www.youtube.com/channel/channelid',
|
||||||
|
'ftp://www.youtube.com/channel/channelid',
|
||||||
|
),
|
||||||
|
'invalid_domain': (
|
||||||
|
'https://www.test.com/channel/channelid',
|
||||||
|
'https://www.example.com/channel/channelid',
|
||||||
|
),
|
||||||
|
'invalid_path': (
|
||||||
|
'https://www.youtube.com/test/invalid',
|
||||||
|
'https://www.youtube.com/channel/test/invalid',
|
||||||
|
),
|
||||||
|
'invalid_is_named_channel': (
|
||||||
|
'https://www.youtube.com/c/testname',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
'youtube-playlist': {
|
'youtube-playlist': {
|
||||||
'valid': (
|
'valid': (
|
||||||
'https://www.youtube.com/playlist?list=testplaylist'
|
'https://www.youtube.com/playlist?list=testplaylist',
|
||||||
'https://www.youtube.com/watch?v=testvideo&list=testplaylist'
|
'https://www.youtube.com/watch?v=testvideo&list=testplaylist',
|
||||||
),
|
),
|
||||||
'invalid_schema': (
|
'invalid_schema': (
|
||||||
'http://www.youtube.com/playlist?list=testplaylist',
|
'http://www.youtube.com/playlist?list=testplaylist',
|
||||||
@@ -76,6 +99,7 @@ class FrontEndTestCase(TestCase):
|
|||||||
'invalid_is_channel': (
|
'invalid_is_channel': (
|
||||||
'https://www.youtube.com/testchannel',
|
'https://www.youtube.com/testchannel',
|
||||||
'https://www.youtube.com/c/testchannel',
|
'https://www.youtube.com/c/testchannel',
|
||||||
|
'https://www.youtube.com/channel/testchannel',
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,19 +110,21 @@ class FrontEndTestCase(TestCase):
|
|||||||
response = c.get('/source-validate/invalid')
|
response = c.get('/source-validate/invalid')
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
for (source_type, tests) in test_sources.items():
|
for (source_type, tests) in test_sources.items():
|
||||||
for test, field in tests.items():
|
for test, urls in tests.items():
|
||||||
source_type_char = test_source_types.get(source_type)
|
for url in urls:
|
||||||
data = {'source_url': field, 'source_type': source_type_char}
|
source_type_char = test_source_types.get(source_type)
|
||||||
response = c.post(f'/source-validate/{source_type}', data)
|
data = {'source_url': url, 'source_type': source_type_char}
|
||||||
if test == 'valid':
|
response = c.post(f'/source-validate/{source_type}', data)
|
||||||
# Valid source tests should bounce to /source-add
|
if test == 'valid':
|
||||||
self.assertEqual(response.status_code, 302)
|
# Valid source tests should bounce to /source-add
|
||||||
url_parts = urlsplit(response.url)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(url_parts.path, '/source-add')
|
url_parts = urlsplit(response.url)
|
||||||
else:
|
self.assertEqual(url_parts.path, '/source-add')
|
||||||
# Invalid source tests should reload the page with an error message
|
else:
|
||||||
self.assertEqual(response.status_code, 200)
|
# Invalid source tests should reload the page with an error
|
||||||
self.assertIn('<ul class="errorlist">', response.content.decode())
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('<ul class="errorlist">',
|
||||||
|
response.content.decode())
|
||||||
|
|
||||||
def test_add_source_prepopulation(self):
|
def test_add_source_prepopulation(self):
|
||||||
c = Client()
|
c = Client()
|
||||||
|
|||||||
@@ -128,10 +128,12 @@ class ValidateSourceView(FormView):
|
|||||||
}
|
}
|
||||||
source_types = {
|
source_types = {
|
||||||
'youtube-channel': Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
|
'youtube-channel': Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
|
||||||
|
'youtube-channel-id': Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID,
|
||||||
'youtube-playlist': Source.SOURCE_TYPE_YOUTUBE_PLAYLIST,
|
'youtube-playlist': Source.SOURCE_TYPE_YOUTUBE_PLAYLIST,
|
||||||
}
|
}
|
||||||
help_item = {
|
help_item = {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: _('YouTube channel'),
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: _('YouTube channel'),
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: _('YouTube channel ID'),
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: _('YouTube playlist'),
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: _('YouTube playlist'),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
@@ -141,6 +143,13 @@ class ValidateSourceView(FormView):
|
|||||||
'where <strong>CHANNELNAME</strong> is the name of the channel you want '
|
'where <strong>CHANNELNAME</strong> is the name of the channel you want '
|
||||||
'to add.'
|
'to add.'
|
||||||
),
|
),
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: _(
|
||||||
|
'Enter a YouTube channel URL by channel ID into the box below. A channel '
|
||||||
|
'URL by channel ID will be in the format of <strong>'
|
||||||
|
'https://www.youtube.com/channel/BiGLoNgUnIqUeId</strong> '
|
||||||
|
'where <strong>BiGLoNgUnIqUeId</strong> is the ID of the channel you want '
|
||||||
|
'to add.'
|
||||||
|
),
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: _(
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: _(
|
||||||
'Enter a YouTube playlist URL into the box below. A playlist URL will be '
|
'Enter a YouTube playlist URL into the box below. A playlist URL will be '
|
||||||
'in the format of <strong>https://www.youtube.com/playlist?list='
|
'in the format of <strong>https://www.youtube.com/playlist?list='
|
||||||
@@ -150,6 +159,8 @@ class ValidateSourceView(FormView):
|
|||||||
}
|
}
|
||||||
help_examples = {
|
help_examples = {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/google',
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/google',
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: ('https://www.youtube.com/channel/'
|
||||||
|
'UCK8sQmJBp8GCxrOtXWBpyEA'),
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: ('https://www.youtube.com/playlist?list='
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: ('https://www.youtube.com/playlist?list='
|
||||||
'PL590L5WQmH8dpP0RyH5pCfIaDEdt9nk7r')
|
'PL590L5WQmH8dpP0RyH5pCfIaDEdt9nk7r')
|
||||||
}
|
}
|
||||||
@@ -157,12 +168,21 @@ class ValidateSourceView(FormView):
|
|||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: {
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: {
|
||||||
'scheme': 'https',
|
'scheme': 'https',
|
||||||
'domain': 'www.youtube.com',
|
'domain': 'www.youtube.com',
|
||||||
'path_regex': '^\/(c\/|channel\/)?([^\/]+)(\/videos)?$',
|
'path_regex': '^\/(c\/)?([^\/]+)(\/videos)?$',
|
||||||
'path_must_not_match': ('/playlist', '/c/playlist'),
|
'path_must_not_match': ('/playlist', '/c/playlist'),
|
||||||
'qs_args': [],
|
'qs_args': [],
|
||||||
'extract_key': ('path_regex', 1),
|
'extract_key': ('path_regex', 1),
|
||||||
'example': 'https://www.youtube.com/SOMECHANNEL'
|
'example': 'https://www.youtube.com/SOMECHANNEL'
|
||||||
},
|
},
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: {
|
||||||
|
'scheme': 'https',
|
||||||
|
'domain': 'www.youtube.com',
|
||||||
|
'path_regex': '^\/channel\/([^\/]+)(\/videos)?$',
|
||||||
|
'path_must_not_match': ('/playlist', '/c/playlist'),
|
||||||
|
'qs_args': [],
|
||||||
|
'extract_key': ('path_regex', 0),
|
||||||
|
'example': 'https://www.youtube.com/channel/CHANNELID'
|
||||||
|
},
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: {
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: {
|
||||||
'scheme': 'https',
|
'scheme': 'https',
|
||||||
'domain': 'www.youtube.com',
|
'domain': 'www.youtube.com',
|
||||||
@@ -175,6 +195,7 @@ class ValidateSourceView(FormView):
|
|||||||
}
|
}
|
||||||
prepopulate_fields = {
|
prepopulate_fields = {
|
||||||
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: ('source_type', 'key', 'name', 'directory'),
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL: ('source_type', 'key', 'name', 'directory'),
|
||||||
|
Source.SOURCE_TYPE_YOUTUBE_CHANNEL_ID: ('source_type', 'key'),
|
||||||
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: ('source_type', 'key'),
|
Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: ('source_type', 'key'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ CONFIG_BASE_DIR = BASE_DIR
|
|||||||
DOWNLOADS_BASE_DIR = BASE_DIR
|
DOWNLOADS_BASE_DIR = BASE_DIR
|
||||||
|
|
||||||
|
|
||||||
VERSION = 0.4
|
VERSION = 0.5
|
||||||
SECRET_KEY = ''
|
SECRET_KEY = ''
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = []
|
||||||
|
|||||||
Reference in New Issue
Block a user