Stable release

This commit is contained in:
A S Lewis 2021-08-08 14:04:37 +01:00
parent 8e098f076f
commit 084b8def2c
32 changed files with 9025 additions and 8170 deletions

12
.github/ISSUE_TEMPLATE/ask_question.md vendored Normal file
View File

@ -0,0 +1,12 @@
---
name: Ask Question 💡
about: Ask a Tartube related question
labels: question
---
Thanks for taking the time to ask a question!
### Please read the README
Perhaps your question is answered there
### The authors are not experts in python, security, youtube-dl, FFmpeg, Debian/RPM packaging or Windows programming
You are welcome to ask a Tartube-related question, but you might get a better answer in forums where those kinds of expert can be found

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: Bug report 🐞
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
Thanks for taking the time to submit a bug report! Please include the following information:
### What operating system are you using?
If using MS Windows, are you using Windows 10, Windows 7, or something else?
### What version of Tartube are you using?
In Tartube's main window, click Help > About
### What happens when you run Tartube from a terminal window?
Many error messages are only visible in the terminal window. On MS Windows, this is how to do it:
- First, enable hidden folders on your system
- Then, run the application:
C:\Users\YOURNAME\AppData\Local\Tartube\msys64\mingw64.exe
- In this new window, type these commands to start Tartube:
cd /home/user/tartube
python3 tartube/tartube
###If your bug report is "I can't download this video", please provide a link to the video
This will save a lot of time!

View File

@ -0,0 +1,13 @@
---
name: Feature Request 💡
about: Suggest a new idea for the project.
labels: enhancement
---
Thanks for taking the time to submit a feature request!
### Make sure you are using the most recent version of Tartube
Perhaps your feature request has already been implemented. The most recent version can be downloaded from Github
### Please read the README
Perhaps your feature request is already possible

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# This file copied from
# https://python-packaging.readthedocs.io/en/latest/minimal.html?highlight=gitignore
# Compiled python modules.
*.pyc
# Setuptools distribution folder.
/dist/
# Python egg metadata, regenerated from source files by setuptools.
/*.egg-info

45
CHANGES
View File

@ -1,3 +1,48 @@
v2.3.332 (8 Jul 2021)
-------------------------------------------------------------------------------
MAJOR NEW FEATURES
- Tartube can extract a video's comments, and optionally store them in its own
database. (In either case, comments are stored in the video's .info.json
file). This feature is only available when using yt-dlp. To enable it,
click 'Edit > System preferences... > Operations > Comments', and select
'When checking/downloading videos, store comments in the metadata file',
(Note that the download option in 'Edit > General download options...' has
been removed). To view comments for a video, right-click the video and
select 'Show video > Properties > Comments'
MINOR NEW FEATURES
- In the preferences window (Edit > System preferences... > Windows > Main
window), the 'Reset' button now resets the position of various sldiers, as
well as the size of the main window
- Added a few more video/audio formats to the list selectable in the download
options window
- In the video slices dialogue window (right-click a video and select 'Special
> Remove video slices...') the user can now opt to remove a slice, or to
remove everything but a slice. The latter behaviour is slightly different
to downloading a video clip, because downloading a clip will create a new
entry in Tartube's database. The new button should clarify what the window
is actually supposed to do (Git #322)
- In the new-ish dialogue window that appears when nothing is downloaded, there
is a new section remnnding Classic Mode users that they can't download a
file that doesn't exist (and what to do about that) (Git #326)
- The same dialogue window appeared after checking a single video that had
previously been checked/downloaded. Fixed
- The setup dialogue window now explains to users what the Classic Mode tab is
for, and lets them specify that the main window should always open at that
tab, if they want
MAJOR FIXES
- The button to set the media file in a video's edit window did not work on
MS Windwos. Fixed (Git #320)
- In the Progress tab, the 'Maximum downloads' setting was broken. Fixed
- Fixed an error caused when a video's upload date (as returned by youtube-dl)
was None
MINOR FIXES
- .webp thumbnails from Odysee (and perhaps other websites) were not converted
into a displayable format; fixed
v2.3.306 (3 Jul 2021)
-------------------------------------------------------------------------------

View File

@ -59,14 +59,14 @@ For a full list of new features and fixes, see `recent changes <CHANGES>`__.
3 Downloads
===========
Latest version: **v2.3.306 (3 Aug 2021)**
Latest version: **v2.3.332 (8 Aug 2021)**
Official packages (also available from the `Github release page <https://github.com/axcore/tartube/releases>`__):
- `MS Windows (64-bit) installer <https://sourceforge.net/projects/tartube/files/v2.3.306/install-tartube-2.3.306-64bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.306/tartube-2.3.306-64bit-portable.zip/download>`__ from Sourceforge
- `MS Windows (32-bit) installer <https://sourceforge.net/projects/tartube/files/v2.3.306/install-tartube-2.3.306-32bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.306/tartube-2.3.306-32bit-portable/download>`__ from Sourceforge (but see `7.23 Doesn't work on 32-bit Windows`_)
- `DEB package (for Debian-based distros, e.g. Ubuntu, Linux Mint) <https://sourceforge.net/projects/tartube/files/v2.3.306/python3-tartube_2.3.306.deb/download>`__ from Sourceforge
- `RPM package (for RHEL-based distros, e.g. Fedora) <https://sourceforge.net/projects/tartube/files/v2.3.306/tartube-2.3.306.rpm/download>`__ from Sourceforge
- `MS Windows (64-bit) installer <https://sourceforge.net/projects/tartube/files/v2.3.332/install-tartube-2.3.332-64bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.332/tartube-2.3.332-64bit-portable.zip/download>`__ from Sourceforge
- `MS Windows (32-bit) installer <https://sourceforge.net/projects/tartube/files/v2.3.332/install-tartube-2.3.332-32bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.332/tartube-2.3.332-32bit-portable/download>`__ from Sourceforge (but see `7.23 Doesn't work on 32-bit Windows`_)
- `DEB package (for Debian-based distros, e.g. Ubuntu, Linux Mint) <https://sourceforge.net/projects/tartube/files/v2.3.332/python3-tartube_2.3.332.deb/download>`__ from Sourceforge
- `RPM package (for RHEL-based distros, e.g. Fedora) <https://sourceforge.net/projects/tartube/files/v2.3.332/tartube-2.3.332.rpm/download>`__ from Sourceforge
There are also some DEB/RPM packages marked STRICT. In these packages, updates to **youtube-dl** from within **Tartube** have been disabled. If **Tartube** is uploaded to a repository with lots of rules, such as the official Debian repository, then you should probably use the STRICT packages.

View File

@ -1 +1 @@
2.3.321
2.3.332

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# Tartube v2.3.321 installer script for MS Windows
# Tartube v2.3.332 installer script for MS Windows
#
# Copyright (C) 2019-2021 A S Lewis
#
@ -249,7 +249,7 @@
;Name and file
Name "Tartube"
OutFile "install-tartube-2.3.321-32bit.exe"
OutFile "install-tartube-2.3.332-32bit.exe"
;Default installation folder
InstallDir "$LOCALAPPDATA\Tartube"
@ -352,7 +352,7 @@ Section "Tartube" SecClient
# "Publisher" "A S Lewis"
# WriteRegStr HKLM \
# "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tartube" \
# "DisplayVersion" "2.3.321"
# "DisplayVersion" "2.3.332"
# Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"

View File

@ -1,4 +1,4 @@
# Tartube v2.3.321 installer script for MS Windows
# Tartube v2.3.332 installer script for MS Windows
#
# Copyright (C) 2019-2021 A S Lewis
#
@ -249,7 +249,7 @@
;Name and file
Name "Tartube"
OutFile "install-tartube-2.3.321-64bit.exe"
OutFile "install-tartube-2.3.332-64bit.exe"
;Default installation folder
InstallDir "$LOCALAPPDATA\Tartube"
@ -352,7 +352,7 @@ Section "Tartube" SecClient
# "Publisher" "A S Lewis"
# WriteRegStr HKLM \
# "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tartube" \
# "DisplayVersion" "2.3.321"
# "DisplayVersion" "2.3.332"
# Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"

View File

@ -42,8 +42,8 @@ import mainapp
# 'Global' variables
__packagename__ = 'tartube'
__version__ = '2.3.321'
__date__ = '5 Aug 2021'
__version__ = '2.3.332'
__date__ = '8 Aug 2021'
__copyright__ = 'Copyright \xa9 2019-2021 A S Lewis'
__license__ = """
Copyright \xa9 2019-2021 A S Lewis.

View File

@ -42,8 +42,8 @@ import mainapp
# 'Global' variables
__packagename__ = 'tartube'
__version__ = '2.3.321'
__date__ = '5 Aug 2021'
__version__ = '2.3.332'
__date__ = '8 Aug 2021'
__copyright__ = 'Copyright \xa9 2019-2021 A S Lewis'
__license__ = """
Copyright \xa9 2019-2021 A S Lewis.

View File

@ -42,8 +42,8 @@ import mainapp
# 'Global' variables
__packagename__ = 'tartube'
__version__ = '2.3.321'
__date__ = '5 Aug 2021'
__version__ = '2.3.332'
__date__ = '8 Aug 2021'
__copyright__ = 'Copyright \xa9 2019-2021 A S Lewis'
__license__ = """
Copyright \xa9 2019-2021 A S Lewis.

View File

@ -1,4 +1,4 @@
.TH man 1 "5 Aug 2021" "2.3.321" "tartube man page"
.TH man 1 "8 Aug 2021" "2.3.332" "tartube man page"
.SH NAME
tartube \- GUI front-end for youtube-dl
.SH SYNOPSIS

View File

@ -1,6 +1,6 @@
[Desktop Entry]
Name=Tartube
Version=2.3.321
Version=2.3.332
Exec=tartube
Icon=tartube
Type=Application

View File

@ -182,7 +182,7 @@ for path in glob.glob('sounds/*'):
# Setup
setuptools.setup(
name='tartube',
version='2.3.321',
version='2.3.332',
description='GUI front-end for youtube-dl',
long_description=long_description,
long_description_content_type='text/plain',

View File

@ -10111,7 +10111,7 @@ class FFmpegOptionsEditWin(GenericEditWin):
self.slice_start_entry.set_sensitive(False)
label4 = self.add_label(grid2,
_('Stop'),
_('Stop (optional)'),
2, 1, 1, 1,
)
label4.set_hexpand(False)
@ -10773,7 +10773,7 @@ class FFmpegOptionsEditWin(GenericEditWin):
self.simple_slice_start_entry.set_sensitive(False)
label4 = self.add_label(grid2,
_('Stop'),
_('Stop (optional)'),
2, 1, 1, 1,
)
label4.set_hexpand(False)
@ -10842,13 +10842,29 @@ class FFmpegOptionsEditWin(GenericEditWin):
# Add slice data to the treeview, one row at a time
for mini_dict in self.retrieve_val('slice_list'):
if 'category' in mini_dict:
category = mini_dict['category']
else:
category = 'n/a'
if 'action' in mini_dict:
action = mini_dict['action']
else:
action = 'n/a'
if 'start_time' in mini_dict:
start_time = mini_dict['start_time']
else:
start_time = 'n/a'
if 'stop_time' in mini_dict \
and mini_dict['stop_time'] is not None:
stop_time = mini_dict['stop_time']
else:
stop_time = 'n/a'
self.simple_slice_mode_liststore.append(
[
mini_dict['category'],
mini_dict['action'],
str(mini_dict['start_time']),
str(mini_dict['stop_time']),
],
[ category, action, str(start_time), str(stop_time) ],
)
@ -11161,13 +11177,17 @@ class FFmpegOptionsEditWin(GenericEditWin):
utils.timestamp_convert_to_seconds(self.app_obj, start_time),
)
stop_time = float(
utils.timestamp_convert_to_seconds(self.app_obj, stop_time),
)
if stop_time == '':
stop_time = None
else:
stop_time = float(
utils.timestamp_convert_to_seconds(self.app_obj, stop_time),
)
try:
ignore = float(start_time)
ignore = float(stop_time)
if stop_time is not None:
ignore = float(stop_time)
except:
return self.app_obj.dialogue_manager_obj.show_msg_dialogue(
@ -11177,7 +11197,7 @@ class FFmpegOptionsEditWin(GenericEditWin):
self, # Parent window is this window
)
if stop_time <= start_time:
if stop_time is not None and stop_time <= start_time:
return self.app_obj.dialogue_manager_obj.show_msg_dialogue(
_('Invalid start/stop times'),
'error',
@ -13335,7 +13355,7 @@ class VideoEditWin(GenericEditWin):
entry.set_hexpand(False)
label2 = self.add_label(grid,
_('Stop'),
_('Stop (optional)'),
2, 4, 1, 1,
)
label2.set_hexpand(False)
@ -13415,7 +13435,8 @@ class VideoEditWin(GenericEditWin):
else:
start_time = 'n/a'
if 'stop_time' in mini_dict:
if 'stop_time' in mini_dict \
and mini_dict['stop_time'] is not None:
stop_time = mini_dict['stop_time']
else:
stop_time = 'n/a'
@ -13958,25 +13979,25 @@ class VideoEditWin(GenericEditWin):
model2 = combo2.get_model()
action_type = model2[tree_iter2][0]
start_time = utils.strip_whitespace(entry.get_text())
stop_time = utils.strip_whitespace(entry2.get_text())
start_time = float(
utils.timestamp_convert_to_seconds(
self.app_obj,
utils.strip_whitespace(entry.get_text()),
)
utils.timestamp_convert_to_seconds(self.app_obj, start_time),
)
stop_time = float(
utils.timestamp_convert_to_seconds(
self.app_obj,
utils.strip_whitespace(entry2.get_text()),
if stop_time == '':
stop_time = None
else:
stop_time = float(
utils.timestamp_convert_to_seconds(self.app_obj, stop_time),
)
)
# Do nothing if specified timestamps aren't valid ('stop' is NOT
# optional)
# Do nothing if specified timestamps aren't valid
try:
ignore = float(start_time)
ignore = float(stop_time)
if stop_time is not None:
ignore = float(stop_time)
except:
return self.app_obj.dialogue_manager_obj.show_msg_dialogue(
@ -13986,7 +14007,7 @@ class VideoEditWin(GenericEditWin):
self, # Parent window is this window
)
if stop_time <= start_time:
if stop_time is not None and stop_time <= start_time:
return self.app_obj.dialogue_manager_obj.show_msg_dialogue(
_('Invalid start/stop times'),
'error',

View File

@ -225,6 +225,11 @@ class DownloadManager(threading.Thread):
self.total_clip_count = 0
self.total_slice_count = 0
self.total_size_count = 0
# Special count for media.Video objects which have already been
# checked/downloaded, and are being checked again (directly, for
# example after right-clicking the video)
# If non-zero, prevents mainwin.NewbieDialogue from opening
self.other_video_count = 0
# If mainapp.TartubeApp.operation_convert_mode is set to any value
# other than 'disable', then a media.Video object whose URL
@ -276,14 +281,10 @@ class DownloadManager(threading.Thread):
# Note that if a downloads.DownloadItem was created by a
# media.Scheduled object that specifies more (or fewer) workers,
# then self.change_worker_count() will be called
if self.alt_limits_flag \
and self.app_obj.alt_num_worker_apply_flag:
if self.alt_limits_flag:
worker_count = self.app_obj.alt_num_worker
elif (not self.alt_limits_flag) \
and self.app_obj.num_worker_apply_flag:
elif self.app_obj.num_worker_apply_flag:
worker_count = self.app_obj.num_worker_default
else:
worker_count = self.app_obj.num_worker_max
@ -401,8 +402,7 @@ class DownloadManager(threading.Thread):
# Change the number of workers. Bandwidth changes are
# applied by OptionsParser.build_limit_rate()
if self.app_obj.num_worker_default \
!= self.app_obj.alt_num_worker \
and self.app_obj.alt_num_worker_apply_flag:
!= self.app_obj.alt_num_worker:
if not new_flag:
@ -617,6 +617,9 @@ class DownloadManager(threading.Thread):
if DEBUG_FUNC_FLAG:
utils.debug_time('dld 475 check_alt_limits')
if not self.app_obj.alt_num_worker_apply_flag:
return False
# Get the current time and day of the week
local = utils.get_local_time()
current_hours = int(local.strftime('%H'))
@ -1068,23 +1071,29 @@ class DownloadManager(threading.Thread):
Args:
dl_type (str): 'new', 'sim', 'old' or 'clip', depending on the
calling function
dl_type (str): 'new', 'sim', 'old', 'clip' or 'other', depending on
the calling function
"""
if DEBUG_FUNC_FLAG:
utils.debug_time('dld 797 register_video')
self.total_video_count += 1
if dl_type == 'new':
self.total_dl_count += 1
elif dl_type == 'sim':
self.total_sim_count += 1
if dl_type == 'other':
# Special count for already checked/downloaded media.Videos, in
# order to prevent mainwin.NewbieDialogue opening
self.other_video_count += 1
if self.app_obj.autostop_videos_flag \
and self.total_video_count >= self.app_obj.autostop_videos_value:
self.stop_download_operation()
else:
self.total_video_count += 1
if dl_type == 'new':
self.total_dl_count += 1
elif dl_type == 'sim':
self.total_sim_count += 1
if self.app_obj.autostop_videos_flag \
and self.total_video_count >= self.app_obj.autostop_videos_value:
self.stop_download_operation()
def register_video_size(self, size=None):
@ -2445,7 +2454,7 @@ class DownloadList(object):
GObject.timeout_add(
0,
app_obj.system_error,
self.app_obj.system_error,
302,
'Invalid argument in Classic Mode tab download operation',
)
@ -2575,9 +2584,11 @@ class DownloadList(object):
if (
isinstance(media_data_obj, media.Video)
and custom_flag
and self.custom_dl_obj
and self.custom_dl_obj.dl_by_video_flag
and not media_data_obj.dl_flag
and (
(self.custom_dl_obj and self.custom_dl_obj.dl_by_video_flag) \
or self.app_obj.temp_stamp_list \
or self.app_obj.temp_slice_list
)
) or (
isinstance(media_data_obj, media.Video)
and (
@ -4173,7 +4184,9 @@ class VideoDownloader(object):
return
if 'upload_date' in json_dict:
# (Git #322, 'upload_date' might be None)
if 'upload_date' in json_dict \
and json_dict['upload_date'] is not None:
try:
# date_string in form YYYYMMDD
@ -4387,7 +4400,7 @@ class VideoDownloader(object):
and video_obj.name != app_obj.default_video_name:
# This video must not be displayed in the Results List, and
# does counts towards the limit (if any) specified by
# counts towards the limit (if any) specified by
# mainapp.TartubeApp.operation_check_limit
self.video_limit_count += 1
@ -4400,9 +4413,13 @@ class VideoDownloader(object):
and app_obj.operation_check_limit \
and self.video_limit_count >= app_obj.operation_check_limit:
# Limit reached. When we reach the end of this function,
# stop checking videos in this channel playlist
# stop checking videos in this channel/playlist
stop_flag = True
# The call to DownloadManager.register_video() below doesn't
# take account of this situation, so make our own call
self.download_manager_obj.register_video('other')
else:
# This video must be displayed in the Results List, and counts

View File

@ -621,8 +621,10 @@ while language_setup_list:
LANGUAGE_CODE_DICT[key] = value
DIALOGUE_ICON_DICT = {
'newbie_classic_icon': 'newbie_classic_icon.png',
'newbie_icon': 'newbie_icon_64.png',
'ready_icon': 'ready_icon_64.png',
'setup_classic_icon': 'setup_classic_icon.png',
'system_icon': 'system_icon_64.png',
'yt_remind_icon_en': 'yt_remind_icon_en.png',
'yt_remind_icon_kr': 'yt_remind_icon_kr.png',

View File

@ -9841,6 +9841,7 @@ class TartubeApp(Gtk.Application):
sim_count = self.download_manager_obj.total_sim_count
clip_count = self.download_manager_obj.total_clip_count
slice_count = self.download_manager_obj.total_slice_count
other_count = self.download_manager_obj.other_video_count
# For the 'custom_sim'/'classic_sim' operation, we need to use the same
# custom download manager
@ -9935,7 +9936,8 @@ class TartubeApp(Gtk.Application):
and dl_count == 0 \
and sim_count == 0 \
and clip_count == 0 \
and slice_count == 0:
and slice_count == 0 \
and other_count == 0:
show_newbie_dialogue_flag = True
@ -9946,11 +9948,11 @@ class TartubeApp(Gtk.Application):
else:
msg = _('Download operation halted')
if dl_count or sim_count:
if dl_count or sim_count or other_count:
msg += '\n\n' + _('Videos downloaded:') + ' ' \
+ str(dl_count) + '\n' + _('Videos checked:') \
+ ' ' + str(sim_count)
+ ' ' + str(sim_count + other_count)
if clip_count or slice_count:
msg += '\n'
@ -10073,7 +10075,10 @@ class TartubeApp(Gtk.Application):
and not self.debug_disable_newbie_flag \
and not manual_stop_flag:
dialogue_win = mainwin.NewbieDialogue(self.main_win_obj)
dialogue_win = mainwin.NewbieDialogue(
self.main_win_obj,
classic_mode_flag,
)
dialogue_win.run()
# Retrieve user choices from the dialogue window...
@ -12175,7 +12180,9 @@ class TartubeApp(Gtk.Application):
if 'id' in json_dict:
video_obj.set_vid(json_dict['id'])
if 'upload_date' in json_dict:
# (Git #322, 'upload_date' might be None)
if 'upload_date' in json_dict \
and json_dict['upload_date'] is not None:
try:
# date_string in form YYYYMMDD

View File

@ -15633,6 +15633,7 @@ class MainWin(Gtk.ApplicationWindow):
start_time = utils.strip_whitespace(dialogue_win.start_time)
stop_time = utils.strip_whitespace(dialogue_win.stop_time)
all_flag = dialogue_win.all_flag
all_but_flag = dialogue_win.all_but_flag
dialogue_win.destroy()
if response != Gtk.ResponseType.CANCEL \
@ -15649,12 +15650,13 @@ class MainWin(Gtk.ApplicationWindow):
)
)
stop_time = float(
utils.timestamp_convert_to_seconds(
self.app_obj,
stop_time,
if stop_time is not None:
stop_time = float(
utils.timestamp_convert_to_seconds(
self.app_obj,
stop_time,
)
)
)
except:
self.app_obj.dialogue_manager_obj.show_msg_dialogue(
@ -15665,7 +15667,7 @@ class MainWin(Gtk.ApplicationWindow):
return
if stop_time <= start_time:
if stop_time is not None and stop_time <= start_time:
self.app_obj.dialogue_manager_obj.show_msg_dialogue(
_('Invalid start/stop times'),
'error',
@ -15676,22 +15678,68 @@ class MainWin(Gtk.ApplicationWindow):
# Compile the mini-dictionary in the format described by
# media.Video.__init__()
mini_dict = {
'category': 'sponsor',
'action': 'skip',
'start_time': start_time,
'stop_time': stop_time,
'duration': 0,
}
# Then store the values in a temporary buffer, so that
# download/process operations can retrieve them
if not all_but_flag:
# Store the values in a temporary buffer, so that download/
# process operations can retrieve them
self.app_obj.set_temp_slice_list([ mini_dict ])
mini_dict = {
'category': 'sponsor',
'action': 'skip',
'start_time': start_time,
'stop_time': stop_time,
'duration': 0,
}
self.app_obj.set_temp_slice_list([ mini_dict ])
elif start_time > 0 and stop_time is not None:
mini_dict = {
'category': 'sponsor',
'action': 'skip',
'start_time': 0,
'stop_time': start_time,
'duration': 0,
}
mini_dict2 = {
'category': 'sponsor',
'action': 'skip',
'start_time': stop_time,
'stop_time': None,
'duration': 0,
}
self.app_obj.set_temp_slice_list([ mini_dict, mini_dict2 ])
elif start_time > 0 and stop_time is None:
mini_dict = {
'category': 'sponsor',
'action': 'skip',
'start_time': 0,
'stop_time': start_time,
'duration': 0,
}
self.app_obj.set_temp_slice_list([ mini_dict ])
else:
mini_dict = {
'category': 'sponsor',
'action': 'skip',
'start_time': stop_time,
'stop_time': None,
'duration': 0,
}
self.app_obj.set_temp_slice_list([ mini_dict ])
else:
# Remove all slices in the media.Video's .slice_list, ignoring
# any times the user just entered in the dialogue window
# Use all slices in the media.Video's .slice_list, ignoring any
# times the user just entered in the dialogue window
self.app_obj.set_temp_slice_list(media_data_obj.slice_list)
if not media_data_obj.dl_flag:
@ -27916,13 +27964,16 @@ class NewbieDialogue(Gtk.Dialog):
main_win_obj (mainwin.MainWin): The parent main window
classic_mode_flag (bool): True if the download operation was launched
from the Classic Mode tab, False otherwise
"""
# Standard class methods
def __init__(self, main_win_obj):
def __init__(self, main_win_obj, classic_mode_flag):
if DEBUG_FUNC_FLAG:
utils.debug_time('mwn 25247 __init__')
@ -27990,58 +28041,81 @@ class NewbieDialogue(Gtk.Dialog):
# Separator
grid.attach(Gtk.HSeparator(), 1, 1, grid_width, 1)
label2 = Gtk.Label(
if not classic_mode_flag:
extra_rows = 0
else:
extra_rows = 3
label2 = Gtk.Label(
_('Check the video/audio file actually exists'),
)
grid.attach(label2, 1, 2, grid_width, 1)
label3 = Gtk.Label(
_('(Try converting instead of a direct download)'),
)
grid.attach(label3, 1, 3, grid_width, 1)
frame = Gtk.Frame()
grid.attach(frame, 1, 4, grid_width, 1)
image2 = Gtk.Image.new_from_pixbuf(
main_win_obj.pixbuf_dict['newbie_classic_icon'],
)
frame.add(image2)
label4 = Gtk.Label(
' ' + _('Check the downloader is installed and updated') + ' ',
)
grid.attach(label2, 1, 2, grid_width, 1)
grid.attach(label4, 1, (extra_rows + 2), grid_width, 1)
button = Gtk.Button.new_with_label(
_('Update') + ' ' + self.main_win_obj.app_obj.get_downloader(),
)
grid.attach(button, 1, 3, grid_width, 1)
grid.attach(button, 1, (extra_rows + 3), grid_width, 1)
button.connect('clicked', self.on_update_button_clicked)
label3 = Gtk.Label(
label5 = Gtk.Label(
_('Tell Tartube where to find the downloader'),
)
grid.attach(label3, 1, 4, grid_width, 1)
grid.attach(label5, 1, (extra_rows + 4), grid_width, 1)
button2 = Gtk.Button.new_with_label(
_('Set the downloader\'s file path'),
)
grid.attach(button2, 1, 5, grid_width, 1)
grid.attach(button2, 1, (extra_rows + 5), grid_width, 1)
button2.connect('clicked', self.on_config_button_clicked)
button3 = Gtk.Button.new_with_label(
_('Try a different downloader'),
)
grid.attach(button3, 1, 6, grid_width, 1)
grid.attach(button3, 1, (extra_rows + 6), grid_width, 1)
button3.connect('clicked', self.on_change_button_clicked)
label4 = Gtk.Label(
label6 = Gtk.Label(
_('Find more help'),
)
grid.attach(label4, 1, 7, grid_width, 1)
grid.attach(label6, 1, (extra_rows + 7), grid_width, 1)
button4 = Gtk.Button.new_with_label(
_('Read the FAQ'),
)
grid.attach(button4, 1, 8, 1, 1)
grid.attach(button4, 1, (extra_rows + 8), 1, 1)
button4.connect('clicked', self.on_website_button_clicked)
button5 = Gtk.Button.new_with_label(
_('Ask for help'),
)
grid.attach(button5, 2, 8, 1, 1)
grid.attach(button5, 2, (extra_rows + 8), 1, 1)
button5.connect('clicked', self.on_issues_button_clicked)
# Separator
grid.attach(Gtk.HSeparator(), 1, 9, grid_width, 1)
grid.attach(Gtk.HSeparator(), 1, (extra_rows + 9), grid_width, 1)
label5 = Gtk.Label()
grid.attach(label5, 1, 10, grid_width, 1)
label5.set_markup(
label7 = Gtk.Label()
grid.attach(label7, 1, (extra_rows + 10), grid_width, 1)
label7.set_markup(
_(
'Don\'t forget to check the <b>Output</b> tab and the\n' \
'<b>Errors/Warnings</b> tab for error messages!',
@ -28049,10 +28123,10 @@ class NewbieDialogue(Gtk.Dialog):
)
# Separator
grid.attach(Gtk.HSeparator(), 1, 11, grid_width, 1)
grid.attach(Gtk.HSeparator(), 1, (extra_rows + 11), grid_width, 1)
checkbutton = Gtk.CheckButton()
grid.attach(checkbutton, 1, 12, grid_width, 1)
grid.attach(checkbutton, 1, (extra_rows + 12), grid_width, 1)
checkbutton.set_label(_('Always show this window'))
if self.show_flag:
checkbutton.set_active(True)
@ -28479,6 +28553,7 @@ class PrepareSliceDialogue(Gtk.Dialog):
self.start_time = None
self.stop_time = None
self.all_flag = False
self.all_but_flag = False
# Code
@ -28524,7 +28599,7 @@ class PrepareSliceDialogue(Gtk.Dialog):
label2 = Gtk.Label()
grid.attach(label2, 0, 2, 1, 1)
label2.set_markup(_('Stop'))
label2.set_markup(_('Stop (optional)'))
label2.set_alignment(0, 0.5)
entry2 = Gtk.Entry()
@ -28532,7 +28607,7 @@ class PrepareSliceDialogue(Gtk.Dialog):
entry2.connect('changed', self.on_stop_entry_changed)
if not video_obj.dl_flag:
msg = _('Download this sliced video')
msg = _('Download and remove this slice')
else:
msg = _('Create this sliced video')
@ -28542,6 +28617,20 @@ class PrepareSliceDialogue(Gtk.Dialog):
button.connect('clicked', self.on_one_button_clicked)
button.set_sensitive(False)
if video_obj.dl_flag:
extra_rows = 0
button = Gtk.Button()
else:
extra_rows = 1
button2 = Gtk.Button.new_with_label(
_('Download and remove everything but this slice'),
)
grid.attach(button2, 0, 5, 1, 1)
button2.set_hexpand(False)
button2.connect('clicked', self.on_all_but_button_clicked)
button2.set_sensitive(False)
if not video_obj.dl_flag:
msg = _('Download video with all slices removed')
else:
@ -28549,15 +28638,15 @@ class PrepareSliceDialogue(Gtk.Dialog):
msg += ' (' + str(len(video_obj.slice_list)) + ')'
button2 = Gtk.Button.new_with_label(msg)
grid.attach(button2, 0, 5, 1, 1)
button2.set_hexpand(False)
button2.connect('clicked', self.on_all_button_clicked)
button3 = Gtk.Button.new_with_label(msg)
grid.attach(button3, 0, (5 + extra_rows), 1, 1)
button3.set_hexpand(False)
button3.connect('clicked', self.on_all_button_clicked)
if not video_obj.slice_list:
button2.set_sensitive(False)
button3.set_sensitive(False)
# (Signal connect from above)
entry.connect('changed', self.on_start_entry_changed, button)
entry.connect('changed', self.on_start_entry_changed, button, button2)
# Display the dialogue window
self.show_all()
@ -28585,6 +28674,26 @@ class PrepareSliceDialogue(Gtk.Dialog):
self.destroy()
def on_all_but_button_clicked(self, button):
"""Called from a callback in self.__init__().
Marks everything but the specified slice to be removed, using the
specified times.
Args:
button (Gtk.Button): The widget clicked
"""
if DEBUG_FUNC_FLAG:
utils.debug_time('mwn 24914 on_all_but_button_clicked')
self.all_but_flag = True
self.destroy()
def on_one_button_clicked(self, button):
"""Called from a callback in self.__init__().
@ -28604,7 +28713,7 @@ class PrepareSliceDialogue(Gtk.Dialog):
self.destroy()
def on_start_entry_changed (self, entry, button):
def on_start_entry_changed (self, entry, button, button2):
"""Called from callback in self.__init__().
@ -28614,7 +28723,7 @@ class PrepareSliceDialogue(Gtk.Dialog):
entry (Gtk.Entry): The clicked widget
button (Gtk.Button): Another widget to be modified
button, button2 (Gtk.Button): Other widgets to be modified
"""
@ -28627,11 +28736,13 @@ class PrepareSliceDialogue(Gtk.Dialog):
self.start_time = None
button.set_sensitive(False)
button2.set_sensitive(False)
else:
self.start_time = value
button.set_sensitive(True)
button2.set_sensitive(True)
def on_stop_entry_changed (self, entry):

View File

@ -1824,7 +1824,8 @@ class Video(GenericMedia):
# formats.SPONSORBLOCK_ACTION_LIST (e.g. 'skip')
# mini_dict['start_time']
# mini_dict['stop_time'] = Floating point values in seconds,
# the beginning and end of the slice
# the beginning and end of the slice. If 'stop_time' is None,
# the end of the video is used
# mini_dict['duration'] = The video duration, as reported by
# SponsorBlock. This valus is not required by Tartube code,
# and its default value is 0

File diff suppressed because it is too large Load Diff

View File

@ -42,8 +42,8 @@ import mainapp
# 'Global' variables
__packagename__ = 'tartube'
__version__ = '2.3.321'
__date__ = '5 Aug 2021'
__version__ = '2.3.332'
__date__ = '8 Aug 2021'
__copyright__ = 'Copyright \xa9 2019-2021 A S Lewis'
__license__ = """
Copyright \xa9 2019-2021 A S Lewis.

View File

@ -929,7 +929,12 @@ def convert_slices_to_clips(app_obj, custom_dl_obj, slice_list, temp_flag):
])
# Next clip starts at the end of this slice
previous_time = mini_dict['stop_time']
if mini_dict['stop_time'] is not None:
previous_time = mini_dict['stop_time']
else:
# This clip ends at the end of the video; ignore any additional
# data in slice_list
return clip_list
if previous_time != 0 and previous_time != '0':

View File

@ -277,7 +277,7 @@ class GenericWizWin(Gtk.Window):
pass
def reset_changes(self):
def cancel_changes(self):
"""Called by self.on_button_cancel_clicked().
@ -480,7 +480,7 @@ class GenericWizWin(Gtk.Window):
"""
self.reset_changes()
self.cancel_changes()
self.destroy()
@ -573,6 +573,8 @@ class SetupWizWin(GenericWizWin):
self.ffmpeg_scrolled = None # Gtk.ScrolledWindow
self.ffmpeg_textview = None # Gtk.TextView
self.ffmpeg_textbuffer = None # Gtk.TextBuffer
self.auto_open_button = None # Gtk.Button
# IV list - other
# ---------------
@ -605,6 +607,9 @@ class SetupWizWin(GenericWizWin):
self.ytdl_fork_no_dependency_flag = False
# The new value of mainapp.TartubeApp.ytdl_update_current(), if any
self.ytdl_update_current = None
# The new value of
# mainapp.TartubeApp.show_classic_tab_on_startup_flag(), if any
self.show_classic_tab_on_startup_flag = None
# Flag set to True, once the 'More options' button has been clicked,
# so that it is never visible again
@ -628,13 +633,16 @@ class SetupWizWin(GenericWizWin):
if self.mswin_flag:
self.page_list.append('setup_fetch_downloader_page')
self.page_list.append('setup_fetch_ffmpeg_page')
self.page_list.append('setup_classic_mode_page')
self.page_list.append('setup_finish_page_mswin')
elif __main__.__pkg_strict_install_flag__:
self.page_list.append('setup_classic_mode_page')
self.page_list.append('setup_finish_page_strict')
else:
self.page_list.append('setup_fetch_downloader_page')
self.page_list.append('setup_classic_mode_page')
self.page_list.append('setup_finish_page_default')
# Set up the wizard window
@ -681,15 +689,20 @@ class SetupWizWin(GenericWizWin):
self.ytdl_fork_no_dependency_flag,
)
# (A None value, only if it hasn't been changed)
# (A None value, only if they haven't been changed)
if self.ytdl_update_current is not None:
self.app_obj.set_ytdl_update_current(self.ytdl_update_current)
if self.show_classic_tab_on_startup_flag is not None:
self.app_obj.set_show_classic_tab_on_startup_flag(
self.show_classic_tab_on_startup_flag,
)
# Continue with general initialisation
self.app_obj.open_wiz_win_continue()
def reset_changes(self):
def cancel_changes(self):
"""Called by self.on_button_cancel_clicked().
@ -1219,7 +1232,7 @@ class SetupWizWin(GenericWizWin):
+ ' YouTube.',
),
60,
) + '</span>',
) + '</span>',
0, 1, grid_width, 1,
)
@ -1258,6 +1271,56 @@ class SetupWizWin(GenericWizWin):
)
def setup_classic_mode_page(self):
"""Called by self.setup_page().
Invites the user to open Tartube at the Classic Mode tab.
"""
grid_width = 3
self.add_label(
'<span font_size="large" style="italic">' \
+ _('Tartube adds videos to a database.') \
+ '</span>',
0, 0, grid_width, 1,
)
self.add_label(
'<span font_size="large" style="italic">' \
+ _(
'If you don\'t need a database, you can use the Classic' \
+ ' Mode tab.',
) + '</span>',
0, 1, grid_width, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 2, grid_width, 1)
self.add_image(
self.app_obj.main_win_obj.icon_dict['setup_classic_icon'],
0, 3, grid_width, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 4, grid_width, 1)
if not self.show_classic_tab_on_startup_flag:
msg = _('Always open Tartube at this tab')
else:
msg = _('Don\'t open Tartube at this tab')
self.auto_open_button = Gtk.Button(msg)
self.inner_grid.attach(self.auto_open_button, 1, 5, 1, 1)
self.auto_open_button.set_hexpand(False)
self.auto_open_button.connect(
'clicked',
self.on_button_auto_open_clicked,
)
def setup_finish_page_mswin(self):
"""Called by self.setup_page().
@ -1345,27 +1408,30 @@ class SetupWizWin(GenericWizWin):
0, 5, 1, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 6, 1, 1)
self.add_label(
'<span font_size="large" style="italic">' \
+ utils.tidy_up_long_string(
_(
'Without FFmpeg, Tartube cannot download high-resolution' \
+ ' videos, and cannot display video thumbnails from' \
+ ' YouTube.',
'Without FFmpeg, Tartube cannot download video clips or' \
+ ' high-resolution videos, and cannot display many' \
+ ' video thumbnails.'
),
60,
) + '</span>',
0, 6, 1, 1,
0, 7, 1, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 7, 1, 1)
self.add_empty_label(0, 8, 1, 1)
self.add_label(
'<span font_size="large" style="italic">' \
+ _('Click the <b>OK</b> button to start Tartube!') \
+ '</span>',
0, 8, 1, 1,
0, 9, 1, 1,
)
@ -1397,27 +1463,30 @@ class SetupWizWin(GenericWizWin):
0, 3, 1, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 4, 1, 1)
self.add_label(
'<span font_size="large" style="italic">' \
+ utils.tidy_up_long_string(
_(
'Without FFmpeg, Tartube cannot download high-resolution' \
+ ' videos, and cannot display video thumbnails from' \
+ ' YouTube.',
'Without FFmpeg, Tartube cannot download video clips or' \
+ ' high-resolution videos, and cannot display many' \
+ ' video thumbnails.',
),
60,
) + '</span>',
0, 4, 1, 1,
0, 5, 1, 1,
)
# (Empty label for spacing)
self.add_empty_label(0, 5, 1, 1)
self.add_empty_label(0, 6, 1, 1)
self.add_label(
'<span font_size="large" style="italic">' \
+ _('Click the <b>OK</b> button to start Tartube!') \
+ '</span>',
0, 6, 1, 1,
0, 7, 1, 1,
)
@ -1552,6 +1621,27 @@ class SetupWizWin(GenericWizWin):
# (Callbacks)
def on_button_auto_open_clicked(self, button):
"""Called from a callback in self.setup_classic_mode_page().
Sets whether the main window should open at the Classic Mode tab, or
not.
Args:
button (Gtk.Button): The widget clicked
"""
if not self.show_classic_tab_on_startup_flag:
self.show_classic_tab_on_startup_flag = True
button.set_label(_('Don\'t open Tartube at this tab'))
else:
self.show_classic_tab_on_startup_flag = False
button.set_label(_('Always open Tartube at this tab'))
def on_button_cancel_clicked(self, button):
"""Modified version of the standard function, called from a callback in
@ -1566,7 +1656,7 @@ class SetupWizWin(GenericWizWin):
"""
self.reset_changes()
self.cancel_changes()
if not self.app_obj.update_manager_obj:
self.destroy()