97
README.rst
|
@ -59,14 +59,14 @@ For a full list of new features and fixes, see `recent changes <CHANGES>`__.
|
|||
3 Downloads
|
||||
===========
|
||||
|
||||
Latest version: **v2.3.367 (12 Feb 2022)**
|
||||
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.367/install-tartube-2.3.367-64bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.367/tartube-2.3.367-64bit-portable.zip/download>`__ from Sourceforge
|
||||
- `MS Windows (32-bit) installer <https://sourceforge.net/projects/tartube/files/v2.3.367/install-tartube-2.3.367-32bit.exe/download>`__ and `portable edition <https://sourceforge.net/projects/tartube/files/v2.3.367/tartube-2.3.367-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.367/python3-tartube_2.3.367.deb/download>`__ from Sourceforge
|
||||
- `RPM package (for RHEL-based distros, e.g. Fedora) <https://sourceforge.net/projects/tartube/files/v2.3.367/tartube-2.3.367.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.
|
||||
|
||||
|
@ -170,7 +170,7 @@ If you want to perform a manual installation, you can follow this procedure, whi
|
|||
5.2 Installation - MacOS
|
||||
------------------------
|
||||
|
||||
**Several users have reported problems installing Tartube on MacOS. The authors do not use MacOS, so we don't know how to fix these problems. Apologies in advance!**
|
||||
**Several users have reported problems installing Tartube on MacOS. The authors do not use MacOS and don't know how to fix these problems. Apologies in advance.**
|
||||
|
||||
MacOS users should use the following procedure (with thanks to JeremyShih):
|
||||
|
||||
|
@ -377,7 +377,7 @@ Packages can be created in the standard way. For example, an RPM package would b
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The procedure used to create the MS Windows installers is described in full in the
|
||||
`installer scripts themselves <nsis/tatrube_install_64bit.nsi>`__.
|
||||
`installer scripts themselves <nsis/tartube_install_64bit.nsi>`__.
|
||||
|
||||
6 Using Tartube
|
||||
===============
|
||||
|
@ -416,10 +416,11 @@ The procedure used to create the MS Windows installers is described in full in t
|
|||
* `6.16.2 Favourite channels, playlists and folders`_
|
||||
* `6.17 Combining channels, playlists and folders`_
|
||||
* `6.17.1 Combining one channel and many playlists`_
|
||||
* `6.17.2 Combining channels from different websites`_
|
||||
* `6.17.3 Download all videos to a single folder`_
|
||||
* `6.17.4 Download all videos to an external folder`_
|
||||
* `6.17.5 External folders and yt-dlp`_
|
||||
* `6.17.2 Extracting playlists from a channel`_
|
||||
* `6.17.3 Combining channels from different websites`_
|
||||
* `6.17.4 Download all videos to a single folder`_
|
||||
* `6.17.5 Download all videos to an external folder`_
|
||||
* `6.17.6 External folders and yt-dlp`_
|
||||
* `6.18 Archiving videos`_
|
||||
* `6.19 Performance limits`_
|
||||
* `6.20 Managing databases`_
|
||||
|
@ -1021,7 +1022,35 @@ The solution is to tell **Tartube** to store all the videos from the channel and
|
|||
- Now, right-click on each playlist in turn, and then select **Playlist actions > Set download destination...**
|
||||
- In the dialogue window, click **Use a different location**, select the name of the channel, then click the **OK** button.
|
||||
|
||||
6.17.2 Combining channels from different websites
|
||||
6.17.2 Extracting playlists from a channel
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As described above, a creator might have a single channel, and several playlists. If there are a *lot* of playlists, it might take a long time to add them all to Tartube's database. However, there is a shortcut for YouTube channels.
|
||||
|
||||
- On the channel's webpage, click the **Playlists** tab
|
||||
- Add a new channel to Tartube's database, using this URL (which should end in **../playlists**)
|
||||
|
||||
YouTube does not always send us the list of playlists; that's why it's necessary to click the **Playlists** tab, rather than the **Videos** tab, as we normally would.
|
||||
|
||||
Now you have two choices. If you want to keep the original channel in your database, without downloading duplicate videos, do this:
|
||||
|
||||
- In Tartube's main window, right-click the channel, and select **Check channel**
|
||||
- When the operation has finished, right-click the channel and select **Show > Channel properties... > Associated Playlists**
|
||||
- Select the button **Set the channel as the download destination**
|
||||
- Click the **Add all playlists button**
|
||||
- Click **OK** to close the window
|
||||
- On the channel's webpage, click the **Videos** tab
|
||||
- In Tartube's main window, right-click the channel, and select **Channel actions > Set URL...**, and replace the URL with the one ending in **../videos**
|
||||
|
||||
Alternatively, if you don't want to keep the original channel, do this:
|
||||
|
||||
- In Tartube's main window, right-click the channel, and select **Check channel**
|
||||
- When the operation has finished, right-click the channel and select **Show > Channel properties... > Associated Playlists**
|
||||
- Click the **Add all playlists button**
|
||||
- Click **OK** to close the window
|
||||
- When you're ready, delete the channel
|
||||
|
||||
6.17.3 Combining channels from different websites
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A creator might release their videos on **YouTube**, but also on a site like **Odysee**. Sometimes they will only release a particular video on **Odysee**.
|
||||
|
@ -1037,7 +1066,7 @@ The solution is to tell **Tartube** to store videos from both channels in a sing
|
|||
|
||||
It doesn't matter which of the two channels you use as the download destination. There is also no limit to the number of parallel channels, so if a creator uploads videos to a dozen different websites, you can add them all.
|
||||
|
||||
6.17.3 Download all videos to a single folder
|
||||
6.17.4 Download all videos to a single folder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you don't care about keeping videos in separate directories/folders on your filesystem, you can download *all* videos into the **Unsorted videos** folder. Regardless of whether you have added one channel or a thousand, all the videos will be stored in that one location.
|
||||
|
@ -1048,7 +1077,7 @@ If you don't care about keeping videos in separate directories/folders on your f
|
|||
|
||||
Alternatively, you could select **Temporary Videos**. If you do, videos will be deleted when you restart **Tartube** (and will not be re-downloaded in the future).
|
||||
|
||||
6.17.4 Download all videos to an external folder
|
||||
6.17.5 Download all videos to an external folder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, all files are downloaded into Tartube's data folder. Users often request that **Tartube** should be able to download videos to other locations in the filesystem, *while retaining those videos in Tartube's database.*
|
||||
|
@ -1070,7 +1099,7 @@ If one of these reasons applies, then you can do this:
|
|||
- Click the **Set** button, and choose an external folder
|
||||
- When you're ready, click the **OK** button to apply your changes
|
||||
|
||||
6.17.5 External folders and yt-dlp
|
||||
6.17.6 External folders and yt-dlp
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Users of `yt-dlp <https://github.com/yt-dlp/yt-dlp/>`__ should be aware of the download option **--paths**, which may be more convenient in some situations. See the **yt-dlp** documentation for more information about how it works. In Tartube, it can be configured like this:
|
||||
|
@ -1755,14 +1784,10 @@ A: Tartube is known to fail on Windows 7 systems that have not been updated for
|
|||
A: New installers for MS Windows are not released frequently, but small updates and fixes *are* uploaded frequently to `Github <https://github.com/axcore/tartube/>`__. You can update your Tartube installation quite easily.
|
||||
|
||||
- Download the latest source code from `Github <https://github.com/axcore/tartube/>`__
|
||||
- On your MS Windows system, enable hidden folders. (Use a search engine if you're not sure how to do that)
|
||||
- Open the folder where Tartube's source code was installed. By default, that is
|
||||
|
||||
**C:\\Users\\YOURNAME\\AppData\\Local\\Tartube\\msys64\\home\\user\\tartube\\**
|
||||
|
||||
- Remove the folder (the one containing a file called **setup.py**)
|
||||
- Replace it with the folder you just downloaded
|
||||
- Check that the replacement folder contains a file called **setup.py**
|
||||
- In Tartube's main menu, select **System > Show Tartube script folder**
|
||||
- A folder opens containing files such as **setup.py** and **README.rst**
|
||||
- Copy the downloaded source code into this folder, replacing old files with new ones
|
||||
- Restart Tartube
|
||||
|
||||
A: On Linux, if the DEB or RPM package doesn't work, try installing via PyPI.
|
||||
|
||||
|
@ -1776,8 +1801,10 @@ It may be helpful to turn on debug messages (which are visible in a terminal win
|
|||
|
||||
On MS Windows, this is how to run **Tartube** from inside a terminal window:
|
||||
|
||||
- First, enable hidden folders on your system
|
||||
- Then, run the application: **C:\\Users\\YOURNAME\\AppData\\Local\\Tartube\\msys64\\mingw64.exe**
|
||||
- In Tartube's main menu, select **System > Show Tartube install folder**
|
||||
- After the folder window opens, shut down Tartube
|
||||
- In the folder window, click the **msys64** or **msys32** folder to open it
|
||||
- Open the terminal by double-clicking **mingw64.exe** or **mingw32.exe**
|
||||
- In this window, type these commands to start **Tartube** (paying attention to the *forward* slashes):
|
||||
|
||||
**cd /home/user/tartube**
|
||||
|
@ -2033,7 +2060,7 @@ This is a **youtube-dl** issue. A general solution is described in `this post <h
|
|||
|
||||
The solution describes how to create a cookies.txt file, which can be specified as a download option.
|
||||
|
||||
Having created the file, in the same edit window, click the **General** tab. In the box labelled **Extra command line options**, you can add:
|
||||
Having created the file, in the same edit window, click the **General** tab. In the box labelled **Additional download options**, you can add:
|
||||
|
||||
**--cookies=YT-cookies.txt**
|
||||
|
||||
|
@ -2070,19 +2097,20 @@ Unfortunately, it is not possible to switch between proxies while downloading a
|
|||
|
||||
A: **Tartube** is a Linux application. The installer for MS Windows contains not just **Tartube** itself, but a copy of Python and a whole bunch of essential graphics libraries, all of them ported to MS Windows.
|
||||
|
||||
Installing `FFmpeg <https://ffmpeg.org/>`__ will dramatically increase the size of the installed folder.
|
||||
|
||||
If you're at all suspicious that such a small application uses such a large installer, you are invited to examine the installed files for yourself:
|
||||
|
||||
**C:\\Users\\YOURNAME\\AppData\\Local\\Tartube**
|
||||
|
||||
(You might need to enable hidden folders; this can be done from the Control Panel.)
|
||||
- In Tartube's main menu, select **System > Show Tartube install folder**
|
||||
|
||||
Everything is copied into this single folder. The installer doesn't modify the Windows registry, nor does it install files anywhere else (other than to the desktop and the Start Menu).
|
||||
|
||||
The NSIS scripts used to create the installers can be found here:
|
||||
|
||||
**C:\\Users\\YOURNAME\\AppData\\Local\\Tartube\\msys64\\home\\user\\tartube\\nsis**
|
||||
- In Tartube's main menu, select **System > Show Tartube script folder**
|
||||
- Click the **nsis** folder to open it
|
||||
|
||||
The scripts contain full instructions, so you should be able to create your own installer, which can be compared with the official one.
|
||||
The scripts contain full instructions, so you should be able to create your own installer and then compare it to the official one.
|
||||
|
||||
7.23 Doesn't work on 32-bit Windows
|
||||
-----------------------------------
|
||||
|
@ -2165,7 +2193,12 @@ A: Tartube shows download statistics in a number of places, for example **Edit >
|
|||
|
||||
The graphs are created by `matplotlib <https://matplotlib.org/>`__, but none of the Tartube installers use it. If you want graphs, you have to install matplotlib yourself.
|
||||
|
||||
On Linux/BSD, use your system's software manager. On MS Windows, run the application **C:\Users\YOURNAME\AppData\Local\Tartube\msys64\mingw64.exe**, and in the new window type **pacman -S mingw-w64-x86_64-python-matplotlib**.
|
||||
On Linux/BSD, use your system's software manager.
|
||||
|
||||
On MS Windows, do this:
|
||||
|
||||
- In Tartube's main menu, select **System > Open MSYS2 terminal...**
|
||||
- In the terminal window, type **pacman -S mingw-w64-x86_64-python-matplotlib**.
|
||||
|
||||
7.31 Tartube is not visible in the system tray
|
||||
----------------------------------------------
|
||||
|
|
|
@ -7,7 +7,7 @@ You want to contribute a translation to this project? Well, that's just great!
|
|||
The simple way
|
||||
--------------
|
||||
|
||||
1. Get a copy of the file `../tartube/po/messages.pot <tartube/po/messages.pot>`__
|
||||
1. Get a copy of the file `../tartube/po/messages.pot <tartube/po/messages.pot>`__
|
||||
2. Open it in a text editor
|
||||
3. Read the notes below
|
||||
4. Translate everything
|
||||
|
@ -33,7 +33,7 @@ Header
|
|||
======
|
||||
|
||||
The lines at the top must be changed from this::
|
||||
|
||||
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
|
@ -41,7 +41,7 @@ The lines at the top must be changed from this::
|
|||
...to this::
|
||||
|
||||
# Tartube
|
||||
# Copyright (C) 2019-2022 A S Lewis
|
||||
# Copyright (C) 2019-2021 A S Lewis
|
||||
# This file is distributed under the same license as the Tartube package.
|
||||
|
||||
The Project-Id-Version must be changed from this::
|
||||
|
@ -106,7 +106,7 @@ Some pieces of text are spread across several lines, like this::
|
|||
|
||||
msgid ""
|
||||
"The video file is missing from Tartube's data folder (try downloading the "
|
||||
"video again!)"
|
||||
"video again!)"
|
||||
msgstr ""
|
||||
|
||||
The two strings are added to each other, producing a single string. You can do the same, if you want. (It doesn't matter how many strings you use).
|
||||
|
@ -120,7 +120,7 @@ Multiple strings are combined without extra space characters. You should add the
|
|||
"¡No puedo usar "
|
||||
"YouTube "
|
||||
"porque no hablo inglés!"
|
||||
|
||||
|
||||
Please preserve capitalisation and punctuation::
|
||||
|
||||
msgid "Help!"
|
||||
|
@ -128,10 +128,10 @@ Please preserve capitalisation and punctuation::
|
|||
|
||||
msgid "HELP!"
|
||||
msgstr "¡AYUDA!"
|
||||
|
||||
|
||||
msgid "help!"
|
||||
msgstr "¡ayuda!"
|
||||
|
||||
|
||||
One exception to this rule is underline/underscore characters. These denote keyboard shortcuts. Don't add the underline/underscore character to your translation::
|
||||
|
||||
msgid "_Channel"
|
||||
|
@ -164,7 +164,7 @@ Some strings contain {0}, {1}, {2} and so on. These are substituted for somethin
|
|||
Your translation must include the literal {0}, {1}, {2} and so on.
|
||||
|
||||
msgstr "blah blah blah {0} blah blah {1} blah blah"
|
||||
|
||||
|
||||
If your translation uses a different word order, then treat the substrings like a word.
|
||||
|
||||
msgstr "Give to the {1} the {0}, please"
|
||||
|
@ -177,7 +177,7 @@ Earlier version of Tartube used *directory* on Linux systems, and *folder* on MS
|
|||
Downloads
|
||||
=========
|
||||
|
||||
You have probably noticed two buttons in Tartube's main window: **Check all** and **Download all**.
|
||||
You have probably noticed two buttons in Tartube's main window: **Check all** and **Download all**.
|
||||
|
||||
The first one fetches a list of videos from websites, but doesn't download the videos. The second one fetches a list of videos from websites AND downloads the videos.
|
||||
|
||||
|
@ -186,7 +186,7 @@ Throughout **messages.pot**, the word *check* is used with this meaning. You can
|
|||
Operations
|
||||
==========
|
||||
|
||||
Throughout **messages.pot**, the word *operation* has a fixed meaning. When Tartube is busy doing something, many buttons don't work (are greyed out).
|
||||
Throughout **messages.pot**, the word *operation* has a fixed meaning. When Tartube is busy doing something, many buttons don't work (are greyed out).
|
||||
|
||||
For example, click the **Download all** button, and it is greyed out until the downloads are finished.
|
||||
|
||||
|
|
|
@ -4,18 +4,19 @@ All files in the ../dialogue sub-directory
|
|||
All files in the ../status sub-directory
|
||||
All files in the ../win sub-directory
|
||||
|
||||
Author: Vectorgraphit
|
||||
Author: Vectorgraphit
|
||||
Source: https://www.iconfinder.com/icons/199499/
|
||||
Author: bekeen studio
|
||||
Source: https://www.iconfinder.com/bekeenstudio
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 3.0 Unported
|
||||
License. To view a copy of this license, visit
|
||||
http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
|
||||
http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
|
||||
Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
||||
|
||||
All files in the ../large sub-directory
|
||||
All files in the ../msg sub-directory
|
||||
All files in the ../overlays sub-directory
|
||||
All files in the ../small sub-directory
|
||||
All files in the ../stock sub-directory
|
||||
All files in the ../toolbar sub-directory
|
||||
|
@ -25,7 +26,7 @@ Source: https://www.fatcow.com/free-icons
|
|||
|
||||
This work is licensed under the Creative Commons Attribution 3.0 Generic
|
||||
License. To view a copy of this license, visit
|
||||
http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
|
||||
http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
|
||||
Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
||||
|
||||
All files in the ../locale directory
|
||||
|
|
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 760 B |
After Width: | Height: | Size: 554 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 891 B |
After Width: | Height: | Size: 732 B |
After Width: | Height: | Size: 688 B |
|
@ -1,4 +1,4 @@
|
|||
# Tartube v2.3.367 installer script for MS Windows
|
||||
# Tartube v2.3.393 installer script for MS Windows
|
||||
#
|
||||
# Copyright (C) 2019-2022 A S Lewis
|
||||
#
|
||||
|
@ -249,7 +249,7 @@
|
|||
|
||||
;Name and file
|
||||
Name "Tartube"
|
||||
OutFile "install-tartube-2.3.367-32bit.exe"
|
||||
OutFile "install-tartube-2.3.393-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.367"
|
||||
# "DisplayVersion" "2.3.393"
|
||||
|
||||
# Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Tartube v2.3.367 installer script for MS Windows
|
||||
# Tartube v2.3.393 installer script for MS Windows
|
||||
#
|
||||
# Copyright (C) 2019-2022 A S Lewis
|
||||
#
|
||||
|
@ -249,7 +249,7 @@
|
|||
|
||||
;Name and file
|
||||
Name "Tartube"
|
||||
OutFile "install-tartube-2.3.367-64bit.exe"
|
||||
OutFile "install-tartube-2.3.393-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.367"
|
||||
# "DisplayVersion" "2.3.393"
|
||||
|
||||
# Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
|
|
@ -42,8 +42,8 @@ import mainapp
|
|||
|
||||
# 'Global' variables
|
||||
__packagename__ = 'tartube'
|
||||
__version__ = '2.3.367'
|
||||
__date__ = '12 Feb 2022'
|
||||
__version__ = '2.3.393'
|
||||
__date__ = '8 Mar 2022'
|
||||
__copyright__ = 'Copyright \xa9 2019-2022 A S Lewis'
|
||||
__license__ = """
|
||||
Copyright \xa9 2019-2022 A S Lewis.
|
||||
|
|
|
@ -42,8 +42,8 @@ import mainapp
|
|||
|
||||
# 'Global' variables
|
||||
__packagename__ = 'tartube'
|
||||
__version__ = '2.3.367'
|
||||
__date__ = '12 Feb 2022'
|
||||
__version__ = '2.3.393'
|
||||
__date__ = '8 Mar 2022'
|
||||
__copyright__ = 'Copyright \xa9 2019-2022 A S Lewis'
|
||||
__license__ = """
|
||||
Copyright \xa9 2019-2022 A S Lewis.
|
||||
|
|
|
@ -42,8 +42,8 @@ import mainapp
|
|||
|
||||
# 'Global' variables
|
||||
__packagename__ = 'tartube'
|
||||
__version__ = '2.3.367'
|
||||
__date__ = '12 Feb 2022'
|
||||
__version__ = '2.3.393'
|
||||
__date__ = '8 Mar 2022'
|
||||
__copyright__ = 'Copyright \xa9 2019-2022 A S Lewis'
|
||||
__license__ = """
|
||||
Copyright \xa9 2019-2022 A S Lewis.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH man 1 "12 Feb 2022" "2.3.367" "tartube man page"
|
||||
.TH man 1 "8 Mar 2022" "2.3.393" "tartube man page"
|
||||
.SH NAME
|
||||
tartube \- GUI front-end for youtube-dl
|
||||
.SH SYNOPSIS
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Name=Tartube
|
||||
Version=2.3.367
|
||||
Version=2.3.393
|
||||
Exec=tartube
|
||||
Icon=tartube
|
||||
Type=Application
|
||||
|
|
2
setup.py
|
@ -182,7 +182,7 @@ for path in glob.glob('sounds/*'):
|
|||
# Setup
|
||||
setuptools.setup(
|
||||
name='tartube',
|
||||
version='2.3.367',
|
||||
version='2.3.333',
|
||||
description='GUI front-end for youtube-dl',
|
||||
long_description=long_description,
|
||||
long_description_content_type='text/plain',
|
||||
|
|
1769
tartube/config.py
|
@ -112,6 +112,10 @@ class DialogueManager(threading.Thread):
|
|||
|
||||
"""
|
||||
|
||||
if self.app_obj.dialogue_disable_msg_flag:
|
||||
print(msg)
|
||||
return
|
||||
|
||||
if parent_win_obj is None:
|
||||
parent_win_obj = self.main_win_obj
|
||||
|
||||
|
@ -183,6 +187,10 @@ class DialogueManager(threading.Thread):
|
|||
|
||||
"""
|
||||
|
||||
if self.app_obj.dialogue_disable_msg_flag:
|
||||
print(msg)
|
||||
return
|
||||
|
||||
if parent_win_obj is None:
|
||||
parent_win_obj = self.main_win_obj
|
||||
|
||||
|
|
|
@ -4261,6 +4261,15 @@ class VideoDownloader(object):
|
|||
else:
|
||||
comment_list = []
|
||||
|
||||
if 'playlist_id' in json_dict:
|
||||
playlist_id = json_dict['playlist_id']
|
||||
if 'playlist_title' in json_dict:
|
||||
playlist_title = json_dict['playlist_title']
|
||||
else:
|
||||
playlist_title = None
|
||||
else:
|
||||
playlist_id = None
|
||||
|
||||
# Does an existing media.Video object match this video?
|
||||
media_data_obj = self.download_item_obj.media_data_obj
|
||||
video_obj = None
|
||||
|
@ -4365,6 +4374,14 @@ class VideoDownloader(object):
|
|||
if comment_list and app_obj.comment_store_flag:
|
||||
video_obj.set_comments(comment_list)
|
||||
|
||||
if app_obj.store_playlist_id_flag \
|
||||
and playlist_id is not None \
|
||||
and not isinstance(video_obj.parent_obj, media.Folder):
|
||||
video_obj.parent_obj.set_playlist_id(
|
||||
playlist_id,
|
||||
playlist_title,
|
||||
)
|
||||
|
||||
# If downloading from a channel/playlist, remember the video's
|
||||
# index. (The server supplies an index even for a channel, and
|
||||
# the user might want to convert a channel to a playlist)
|
||||
|
@ -4471,6 +4488,14 @@ class VideoDownloader(object):
|
|||
if not video_obj.comment_list and comment_list:
|
||||
video_obj.set_comments(comment_list)
|
||||
|
||||
if app_obj.store_playlist_id_flag \
|
||||
and playlist_id is not None \
|
||||
and not isinstance(video_obj.parent_obj, media.Folder):
|
||||
video_obj.parent_obj.set_playlist_id(
|
||||
playlist_id,
|
||||
playlist_title,
|
||||
)
|
||||
|
||||
# If downloading from a channel/playlist, remember the video's
|
||||
# index. (The server supplies an index even for a channel, and
|
||||
# the user might want to convert a channel to a playlist)
|
||||
|
|
|
@ -281,7 +281,7 @@ video_option_setup_list = [
|
|||
'400', 'mp4 [1440p] <400>', False,
|
||||
'401', 'mp4 [2160p] <401>', False,
|
||||
'402', 'mp4 [2880p] <402>', False,
|
||||
'571', 'mp4 [8k] <571', False,
|
||||
'571', 'mp4 [8k] <571>', False,
|
||||
'43', 'webm [360p] <43>', False,
|
||||
'44', 'webm [480p] <44>', False,
|
||||
'45', 'webm [720p] <45>', False,
|
||||
|
@ -703,55 +703,36 @@ TOOLBAR_ICON_DICT = {
|
|||
}
|
||||
|
||||
LARGE_ICON_DICT = {
|
||||
'video_both_large': 'video_both.png',
|
||||
'video_left_large': 'video_left.png',
|
||||
'video_none_large': 'video_none.png',
|
||||
'video_right_large': 'video_right.png',
|
||||
|
||||
'channel_both_large': 'channel_both.png',
|
||||
'channel_left_large': 'channel_left.png',
|
||||
'channel_none_large': 'channel_none.png',
|
||||
'channel_right_large': 'channel_right.png',
|
||||
|
||||
'playlist_both_large': 'playlist_both.png',
|
||||
'playlist_left_large': 'playlist_left.png',
|
||||
'playlist_none_large': 'playlist_none.png',
|
||||
'playlist_right_large': 'playlist_right.png',
|
||||
|
||||
'folder_both_large': 'folder_yellow_both.png',
|
||||
'folder_left_large': 'folder_yellow_left.png',
|
||||
'folder_none_large': 'folder_yellow_none.png',
|
||||
'folder_right_large': 'folder_yellow_right.png',
|
||||
|
||||
'folder_private_both_large': 'folder_red_both.png',
|
||||
'folder_private_left_large': 'folder_red_left.png',
|
||||
'folder_private_none_large': 'folder_red_none.png',
|
||||
'folder_private_right_large': 'folder_red_right.png',
|
||||
|
||||
'folder_fixed_both_large': 'folder_green_both.png',
|
||||
'folder_fixed_left_large': 'folder_green_left.png',
|
||||
'folder_fixed_none_large': 'folder_green_none.png',
|
||||
'folder_fixed_right_large': 'folder_green_right.png',
|
||||
|
||||
'folder_temp_both_large': 'folder_blue_both.png',
|
||||
'folder_temp_left_large': 'folder_blue_left.png',
|
||||
'folder_temp_none_large': 'folder_blue_none.png',
|
||||
'folder_temp_right_large': 'folder_blue_right.png',
|
||||
|
||||
'folder_no_parent_both_large': 'folder_black_both.png',
|
||||
'folder_no_parent_left_large': 'folder_black_left.png',
|
||||
'folder_no_parent_none_large': 'folder_black_none.png',
|
||||
'folder_no_parent_right_large': 'folder_black_right.png',
|
||||
|
||||
'attention_large': 'attention.png',
|
||||
'channel_large': 'channel.png',
|
||||
'copy_large': 'copy.png',
|
||||
'error_large': 'error.png',
|
||||
'folder_large': 'folder_yellow.png',
|
||||
'folder_fixed_large': 'folder_green.png',
|
||||
'folder_no_parent_large': 'folder_black.png',
|
||||
'folder_private_large': 'folder_red.png',
|
||||
'folder_temp_large': 'folder_blue.png',
|
||||
'hand_left_large': 'hand_left.png',
|
||||
'hand_right_large': 'hand_right.png',
|
||||
'limits_off_large': 'limits_off.png',
|
||||
'limits_on_large': 'limits_on.png',
|
||||
'playlist_large': 'playlist.png',
|
||||
'question_large': 'question.png',
|
||||
'video_large': 'video.png',
|
||||
'warning_large': 'warning.png',
|
||||
}
|
||||
|
||||
LARGE_ICON_COMPOSITE_LIST = [
|
||||
'channel_large',
|
||||
'folder_large',
|
||||
'folder_fixed_large',
|
||||
'folder_no_parent_large',
|
||||
'folder_private_large',
|
||||
'folder_temp_large',
|
||||
'playlist_large',
|
||||
'video_large',
|
||||
]
|
||||
|
||||
SMALL_ICON_DICT = {
|
||||
'video_small': 'video.png',
|
||||
'channel_small': 'channel.png',
|
||||
|
@ -761,6 +742,7 @@ SMALL_ICON_DICT = {
|
|||
'archived_small': 'archived.png',
|
||||
'arrow_up_small': 'arrow_up.png',
|
||||
'arrow_down_small': 'arrow_down.png',
|
||||
'attention_small': 'attention.png',
|
||||
'check_small': 'check.png',
|
||||
'comment_small': 'comment.png',
|
||||
'debut_now_small': 'debut_now.png',
|
||||
|
@ -775,6 +757,7 @@ SMALL_ICON_DICT = {
|
|||
'folder_blue_small': 'folder_blue.png',
|
||||
'folder_green_small': 'folder_green.png',
|
||||
'folder_red_small': 'folder_red.png',
|
||||
'keyboard_small': 'keyboard.png',
|
||||
'likes_small': 'likes.png',
|
||||
'have_file_small': 'have_file.png',
|
||||
'live_now_small': 'live_now.png',
|
||||
|
@ -823,7 +806,7 @@ THUMB_ICON_DICT = {
|
|||
}
|
||||
|
||||
EXTERNAL_ICON_DICT = {
|
||||
'ytdl-gui': 'youtube-dl-gui.png',
|
||||
'ytdl_gui': 'youtube-dl-gui.png',
|
||||
}
|
||||
|
||||
# (Replaces system stock icons, if not available)
|
||||
|
|
|
@ -293,7 +293,7 @@ class TartubeApp(Gtk.Application):
|
|||
|
||||
# Default window sizes (in pixels)
|
||||
self.main_win_width = 1000
|
||||
self.main_win_height = 750
|
||||
self.main_win_height = 700
|
||||
self.config_win_width = 650
|
||||
self.config_win_height = 450
|
||||
# Default slider position. This value applies to the sliders in the
|
||||
|
@ -776,7 +776,7 @@ class TartubeApp(Gtk.Application):
|
|||
self.classic_format_selection = None
|
||||
# Flag set to False, if videos should be downloaded in that format, or
|
||||
# True if they should be converted to the format using FFmpeg/AVConv
|
||||
self.classic_format_convert_flag = False
|
||||
self.classic_format_convert_flag = True
|
||||
# Flag set to True, if pending URLs (still visible in the top half of
|
||||
# the Classic Mode tab, or not yet downloaded in the bottom half)
|
||||
# should be saved when Tartube shuts down, and restored (to the top
|
||||
|
@ -1247,6 +1247,10 @@ class TartubeApp(Gtk.Application):
|
|||
# Flag set to True if the newbie dialogue should appear after a failed
|
||||
# download operation, explaining what to do
|
||||
self.show_newbie_dialogue_flag = True
|
||||
# Flag set to True if a dialogue should appear when the user opens the
|
||||
# MSYS2 terminal from the main menu (on MS Windows only; ignored on
|
||||
# other systems)
|
||||
self.show_msys2_dialogue_flag = True
|
||||
|
||||
# Media data classes are those specified in media.py. Those class
|
||||
# objects are media.Video (for individual videos), media.Channel,
|
||||
|
@ -1706,6 +1710,12 @@ class TartubeApp(Gtk.Application):
|
|||
# doesn't end with .../videos, the user should be prompted to add it
|
||||
self.dialogue_yt_remind_flag = True
|
||||
|
||||
# On Virtualbox MSWin installations, dialogue windows can freeze
|
||||
# Tartube, forcing a restart. Flag set to True if message dialogue
|
||||
# windows (only) should be disabled, their messages being displayed
|
||||
# in the terminal instead
|
||||
self.dialogue_disable_msg_flag = False
|
||||
|
||||
# Flag set to True if, when downloading videos, youtube-dl should be
|
||||
# passed, --download-archive, creating the file ytdl-archive.txt
|
||||
# If the file exists, youtube-dl won't re-download a video a user has
|
||||
|
@ -1743,6 +1753,11 @@ class TartubeApp(Gtk.Application):
|
|||
# are marked as missing. Ignored if self.track_missing_videos_flag or
|
||||
# self.track_missing_time_flag is False
|
||||
self.track_missing_time_days = 14
|
||||
# Flag set to True if Tartube should retrieve the playlist ID from each
|
||||
# checked/downloaded video, and store it in the parent channel/
|
||||
# playlist. (The user can use the collected IDs to get a list of
|
||||
# playlists associated with a channel)
|
||||
self.store_playlist_id_flag = True
|
||||
|
||||
# Flag set to True if a list of timestamps should be extracted from a
|
||||
# video's .info.json file, when it is received
|
||||
|
@ -2254,6 +2269,27 @@ class TartubeApp(Gtk.Application):
|
|||
gen_options_action.connect('activate', self.on_menu_general_options)
|
||||
self.add_action(gen_options_action)
|
||||
|
||||
# 'System' column
|
||||
if os.name == 'nt':
|
||||
|
||||
open_msys2_action = Gio.SimpleAction.new('open_msys2_menu', None)
|
||||
open_msys2_action.connect('activate', self.on_menu_open_msys2)
|
||||
self.add_action(open_msys2_action)
|
||||
|
||||
show_install_action = Gio.SimpleAction.new(
|
||||
'show_install_menu',
|
||||
None,
|
||||
)
|
||||
show_install_action.connect('activate', self.on_menu_show_install)
|
||||
self.add_action(show_install_action)
|
||||
|
||||
show_script_action = Gio.SimpleAction.new(
|
||||
'show_script_menu',
|
||||
None,
|
||||
)
|
||||
show_script_action.connect('activate', self.on_menu_show_script)
|
||||
self.add_action(show_script_action)
|
||||
|
||||
# 'Media' column
|
||||
add_video_menu_action = Gio.SimpleAction.new('add_video_menu', None)
|
||||
add_video_menu_action.connect('activate', self.on_menu_add_video)
|
||||
|
@ -2751,16 +2787,6 @@ class TartubeApp(Gtk.Application):
|
|||
)
|
||||
self.add_action(classic_add_urls_button_action)
|
||||
|
||||
classic_remove_button_action = Gio.SimpleAction.new(
|
||||
'classic_remove_button',
|
||||
None,
|
||||
)
|
||||
classic_remove_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_remove,
|
||||
)
|
||||
self.add_action(classic_remove_button_action)
|
||||
|
||||
classic_play_button_action = Gio.SimpleAction.new(
|
||||
'classic_play_button',
|
||||
None,
|
||||
|
@ -2771,25 +2797,15 @@ class TartubeApp(Gtk.Application):
|
|||
)
|
||||
self.add_action(classic_play_button_action)
|
||||
|
||||
classic_move_up_button_action = Gio.SimpleAction.new(
|
||||
'classic_move_up_button',
|
||||
classic_open_button_action = Gio.SimpleAction.new(
|
||||
'classic_open_button',
|
||||
None,
|
||||
)
|
||||
classic_move_up_button_action.connect(
|
||||
classic_open_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_move_up,
|
||||
self.on_button_classic_open,
|
||||
)
|
||||
self.add_action(classic_move_up_button_action)
|
||||
|
||||
classic_move_down_button_action = Gio.SimpleAction.new(
|
||||
'classic_move_down_button',
|
||||
None,
|
||||
)
|
||||
classic_move_down_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_move_down,
|
||||
)
|
||||
self.add_action(classic_move_down_button_action)
|
||||
self.add_action(classic_open_button_action)
|
||||
|
||||
classic_redownload_button_action = Gio.SimpleAction.new(
|
||||
'classic_redownload_button',
|
||||
|
@ -2821,6 +2837,36 @@ class TartubeApp(Gtk.Application):
|
|||
)
|
||||
self.add_action(classic_ffmpeg_button_action)
|
||||
|
||||
classic_move_up_button_action = Gio.SimpleAction.new(
|
||||
'classic_move_up_button',
|
||||
None,
|
||||
)
|
||||
classic_move_up_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_move_up,
|
||||
)
|
||||
self.add_action(classic_move_up_button_action)
|
||||
|
||||
classic_move_down_button_action = Gio.SimpleAction.new(
|
||||
'classic_move_down_button',
|
||||
None,
|
||||
)
|
||||
classic_move_down_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_move_down,
|
||||
)
|
||||
self.add_action(classic_move_down_button_action)
|
||||
|
||||
classic_remove_button_action = Gio.SimpleAction.new(
|
||||
'classic_remove_button',
|
||||
None,
|
||||
)
|
||||
classic_remove_button_action.connect(
|
||||
'activate',
|
||||
self.on_button_classic_remove,
|
||||
)
|
||||
self.add_action(classic_remove_button_action)
|
||||
|
||||
classic_clear_dl_button_action = Gio.SimpleAction.new(
|
||||
'classic_clear_dl_button',
|
||||
None,
|
||||
|
@ -3874,8 +3920,9 @@ class TartubeApp(Gtk.Application):
|
|||
self.classic_dir_list = json_dict['classic_dir_list']
|
||||
self.classic_dir_previous = json_dict['classic_dir_previous']
|
||||
if version >= 2003190: # v2.3.190
|
||||
# (Before v2.3.369, this values was stored with leading zeroes)
|
||||
self.classic_format_selection \
|
||||
= json_dict['classic_format_selection']
|
||||
= utils.strip_whitespace(json_dict['classic_format_selection'])
|
||||
self.classic_format_convert_flag \
|
||||
= json_dict['classic_format_convert_flag']
|
||||
if version >= 2002129: # v2.2.129
|
||||
|
@ -4034,6 +4081,9 @@ class TartubeApp(Gtk.Application):
|
|||
if version >= 2003114: # v2.3.114
|
||||
self.show_newbie_dialogue_flag \
|
||||
= json_dict['show_newbie_dialogue_flag']
|
||||
if version >= 2003376: # v2.3.376
|
||||
self.show_msys2_dialogue_flag \
|
||||
= json_dict['show_msys2_dialogue_flag']
|
||||
|
||||
if version >= 1003032: # v1.3.032
|
||||
self.auto_clone_options_flag = json_dict['auto_clone_options_flag']
|
||||
|
@ -4178,6 +4228,10 @@ class TartubeApp(Gtk.Application):
|
|||
if version >= 2003130: # v2.3.130
|
||||
self.dialogue_yt_remind_flag = json_dict['dialogue_yt_remind_flag']
|
||||
|
||||
if version >= 2003371: # v2.3.371
|
||||
self.dialogue_disable_msg_flag \
|
||||
= json_dict['dialogue_disable_msg_flag']
|
||||
|
||||
if version >= 1003018: # v1.3.018
|
||||
self.allow_ytdl_archive_flag \
|
||||
= json_dict['allow_ytdl_archive_flag']
|
||||
|
@ -4194,6 +4248,9 @@ class TartubeApp(Gtk.Application):
|
|||
= json_dict['track_missing_time_flag']
|
||||
self.track_missing_time_days \
|
||||
= json_dict['track_missing_time_days']
|
||||
if version >= 2003382: # v2.3.382
|
||||
self.store_playlist_id_flag \
|
||||
= json_dict['store_playlist_id_flag']
|
||||
|
||||
if version >= 2003181: # v2.3.181
|
||||
self.video_timestamps_extract_json_flag \
|
||||
|
@ -4566,8 +4623,8 @@ class TartubeApp(Gtk.Application):
|
|||
elif os.name == 'nt' and not 'PROGRAMFILES(X86)' in os.environ:
|
||||
|
||||
self.ytdl_update_dict['ytdl_update_win_64_no_dependencies'] = [
|
||||
'..\\..\\..\\mingw64\\bin\python3.exe',
|
||||
'..\\..\\..\\mingw64\\bin\pip3-script.py',
|
||||
'..\\..\\..\\mingw32\\bin\python3.exe',
|
||||
'..\\..\\..\\mingw32\\bin\pip3-script.py',
|
||||
'install',
|
||||
'-upgrade',
|
||||
'--no-dependencies',
|
||||
|
@ -4958,6 +5015,7 @@ class TartubeApp(Gtk.Application):
|
|||
'operation_download_limit': self.operation_download_limit,
|
||||
|
||||
'show_newbie_dialogue_flag': self.show_newbie_dialogue_flag,
|
||||
'show_msys2_dialogue_flag': self.show_msys2_dialogue_flag,
|
||||
|
||||
'auto_clone_options_flag': self.auto_clone_options_flag,
|
||||
'auto_delete_options_flag': self.auto_delete_options_flag,
|
||||
|
@ -5008,6 +5066,8 @@ class TartubeApp(Gtk.Application):
|
|||
'dialogue_keep_open_flag': self.dialogue_keep_open_flag,
|
||||
'dialogue_yt_remind_flag': self.dialogue_yt_remind_flag,
|
||||
|
||||
'dialogue_disable_msg_flag': self.dialogue_disable_msg_flag,
|
||||
|
||||
'allow_ytdl_archive_flag': self.allow_ytdl_archive_flag,
|
||||
'classic_ytdl_archive_flag': \
|
||||
self.classic_ytdl_archive_flag,
|
||||
|
@ -5015,6 +5075,7 @@ class TartubeApp(Gtk.Application):
|
|||
'track_missing_videos_flag': self.track_missing_videos_flag,
|
||||
'track_missing_time_flag': self.track_missing_time_flag,
|
||||
'track_missing_time_days': self.track_missing_time_days,
|
||||
'store_playlist_id_flag': self.store_playlist_id_flag,
|
||||
|
||||
'video_timestamps_extract_json_flag': \
|
||||
self.video_timestamps_extract_json_flag,
|
||||
|
@ -6625,7 +6686,7 @@ class TartubeApp(Gtk.Application):
|
|||
options_obj.options_dict['no_allow_dynamic_mpd'] = False
|
||||
options_obj.options_dict['hls_split_discontinuity'] = False
|
||||
|
||||
if version < 2003237: # v2.3.237
|
||||
if version < 2003237: # v2.3.237
|
||||
|
||||
# This version adds new IVs to media.Video objects
|
||||
for media_data_obj in self.media_reg_dict.values():
|
||||
|
@ -6633,7 +6694,7 @@ class TartubeApp(Gtk.Application):
|
|||
media_data_obj.vid = None
|
||||
media_data_obj.slice_list = []
|
||||
|
||||
if version < 2003251: # v2.3.251
|
||||
if version < 2003251: # v2.3.251
|
||||
|
||||
# This version adds new options to
|
||||
# ffmpeg_tartube.FFmpegOptionsManager
|
||||
|
@ -6641,7 +6702,7 @@ class TartubeApp(Gtk.Application):
|
|||
options_obj.options_dict['slice_mode'] = 'video'
|
||||
options_obj.options_dict['slice_list'] = []
|
||||
|
||||
if version < 2003291: # v2.3.291
|
||||
if version < 2003291: # v2.3.291
|
||||
|
||||
# This version adds a new IV to downloads.CustomDLManager objects
|
||||
for custom_dl_obj in self.custom_dl_reg_dict.values():
|
||||
|
@ -6653,7 +6714,7 @@ class TartubeApp(Gtk.Application):
|
|||
else:
|
||||
custom_dl_obj.dl_precede_flag = False
|
||||
|
||||
if version < 2003295: # v2.3.295
|
||||
if version < 2003295: # v2.3.295
|
||||
|
||||
# This version adds a new IV to media.Scheduled objects
|
||||
for scheduled_obj in self.scheduled_list:
|
||||
|
@ -6664,7 +6725,7 @@ class TartubeApp(Gtk.Application):
|
|||
else:
|
||||
scheduled_obj.custom_dl_uid = None
|
||||
|
||||
if version < 2003304: # v2.3.304
|
||||
if version < 2003304: # v2.3.304
|
||||
|
||||
# This version fixes an incorrect value for an IV in media.Folder
|
||||
# objects
|
||||
|
@ -6673,20 +6734,40 @@ class TartubeApp(Gtk.Application):
|
|||
and media_data_obj.restrict_mode == 'free':
|
||||
media_data_obj.restrict_mode = 'open'
|
||||
|
||||
if version < 2003314: # v2.3.314
|
||||
if version < 2003314: # v2.3.314
|
||||
|
||||
# This version adds a new IV to media.Video objects
|
||||
for media_data_obj in self.media_reg_dict.values():
|
||||
if isinstance(media_data_obj, media.Video):
|
||||
media_data_obj.comment_list = []
|
||||
|
||||
if version < 2003316: # v2.3.316
|
||||
if version < 2003316: # v2.3.316
|
||||
|
||||
# This version removes an option to options.OptionsManager
|
||||
for options_obj in options_obj_list:
|
||||
if 'write_comments' in options_obj.options_dict:
|
||||
del options_obj.options_dict['write_comments']
|
||||
|
||||
if version < 2003375: # v2.3.375
|
||||
|
||||
# This version adds new options to options.OptionsManager
|
||||
for options_obj in options_obj_list:
|
||||
|
||||
# (yt-dlp only)
|
||||
options_obj.options_dict['no_cookies'] = False
|
||||
options_obj.options_dict['cookies_from_browser'] = ''
|
||||
options_obj.options_dict['no_cookies_from_browser'] = True
|
||||
|
||||
if version < 2003382: # v2.3.382
|
||||
|
||||
# This version adds a new IV to media.Channel and media.Playlist
|
||||
# objects
|
||||
for media_data_obj in self.media_reg_dict.values():
|
||||
if isinstance(media_data_obj, media.Channel) \
|
||||
or isinstance(media_data_obj, media.Playlist):
|
||||
media_data_obj.playlist_id_dict = {}
|
||||
|
||||
|
||||
# --- Do this last, or call to .check_integrity_db() fails -----------
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
@ -8276,20 +8357,20 @@ class TartubeApp(Gtk.Application):
|
|||
self.ytdl_path_pypi,
|
||||
)
|
||||
|
||||
if os.path.isfile(self.ytdl_path_default):
|
||||
self.ytdl_path = self.ytdl_path_default
|
||||
elif os.path.isfile(pypi_path) \
|
||||
if os.path.isfile(pypi_path) \
|
||||
or __main__.__pkg_install_flag__:
|
||||
self.ytdl_path = self.ytdl_path_pypi
|
||||
elif os.path.isfile(self.ytdl_path_default):
|
||||
self.ytdl_path = self.ytdl_path_default
|
||||
else:
|
||||
self.ytdl_path = self.ytdl_bin
|
||||
|
||||
if not __main__.__pkg_strict_install_flag__:
|
||||
|
||||
if self.ytdl_path == self.ytdl_path_default:
|
||||
self.ytdl_update_current = 'ytdl_update_default_path'
|
||||
elif self.ytdl_path == self.ytdl_path_pypi:
|
||||
if self.ytdl_path == self.ytdl_path_pypi:
|
||||
self.ytdl_update_current = 'ytdl_update_pip3_recommend'
|
||||
elif self.ytdl_path == self.ytdl_path_default:
|
||||
self.ytdl_update_current = 'ytdl_update_default_path'
|
||||
else:
|
||||
self.ytdl_update_current = 'ytdl_update_local_path'
|
||||
|
||||
|
@ -10545,7 +10626,7 @@ class TartubeApp(Gtk.Application):
|
|||
msg = _('Update operation halted')
|
||||
else:
|
||||
msg = _('Update operation complete') \
|
||||
+ '\n\n' + self.get_downloader() + ' ' \
|
||||
+ '\n\n' + self.get_downloader(wiz_win_obj) + ' ' \
|
||||
+ _('version:') + ' '
|
||||
if ytdl_version is not None:
|
||||
msg += ytdl_version
|
||||
|
@ -11021,6 +11102,7 @@ class TartubeApp(Gtk.Application):
|
|||
utils.debug_time('app 8991 info_manager_finished')
|
||||
|
||||
# Import IVs from info.InfoManager, before it is destroyed
|
||||
video_obj = self.info_manager_obj.video_obj
|
||||
info_type = self.info_manager_obj.info_type
|
||||
success_flag = self.info_manager_obj.success_flag
|
||||
output_list = self.info_manager_obj.output_list.copy()
|
||||
|
@ -11055,9 +11137,26 @@ class TartubeApp(Gtk.Application):
|
|||
if url_string is not None and url_string != '':
|
||||
utils.open_file(self, self.temp_test_dir)
|
||||
|
||||
# Then show a dialogue window/desktop notification, if allowed
|
||||
if self.operation_dialogue_mode != 'default':
|
||||
# Show a confirmation, if allowed
|
||||
if self.operation_dialogue_mode == 'dialogue' \
|
||||
and (info_type == 'formats' or info_type == 'subs') \
|
||||
and success_flag:
|
||||
|
||||
# Show a custom dialogue window, that enables the user to modify or
|
||||
# apply download options directly
|
||||
dialogue_win = mainwin.FormatsSubsDialogue(
|
||||
self.main_win_obj,
|
||||
video_obj,
|
||||
info_type,
|
||||
)
|
||||
|
||||
response = dialogue_win.run()
|
||||
dialogue_win.destroy()
|
||||
|
||||
elif self.operation_dialogue_mode != 'default':
|
||||
|
||||
# Then show a message dialogue window/desktop notification, if
|
||||
# allowed
|
||||
if info_type != 'version' or not success_flag:
|
||||
|
||||
if not success_flag:
|
||||
|
@ -12438,6 +12537,21 @@ class TartubeApp(Gtk.Application):
|
|||
json_dict['chapters'],
|
||||
)
|
||||
|
||||
if self.store_playlist_id_flag \
|
||||
and 'playlist_id' in json_dict \
|
||||
and not isinstance(video_obj.parent_obj, media.Folder):
|
||||
|
||||
if 'playlist_title' in json_dict:
|
||||
video_obj.parent_obj.set_playlist_id(
|
||||
json_dict['playlist_id'],
|
||||
json_dict['playlist_title'],
|
||||
)
|
||||
else:
|
||||
video_obj.parent_obj.set_playlist_id(
|
||||
json_dict['playlist_id'],
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
def update_video_from_filesystem(self, video_obj, video_path,
|
||||
override_flag=False):
|
||||
|
@ -20970,6 +21084,58 @@ class TartubeApp(Gtk.Application):
|
|||
self.main_win_obj.classic_mode_tab_move_row(False)
|
||||
|
||||
|
||||
def on_button_classic_open(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
||||
Opens the destination(s) of any videos downloaded from the selected
|
||||
rows in the Classic Progress List.
|
||||
|
||||
Args:
|
||||
|
||||
action (Gio.SimpleAction): Object generated by Gio
|
||||
|
||||
par (None): Ignored
|
||||
|
||||
"""
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 16911 on_button_classic_open')
|
||||
|
||||
selection = self.main_win_obj.classic_progress_treeview.get_selection()
|
||||
(model, path_list) = selection.get_selected_rows()
|
||||
if not path_list:
|
||||
|
||||
# Nothing selected
|
||||
return
|
||||
|
||||
# Get the the dummy media.Video objects for each selected row, and
|
||||
# produce a list of destinations, ignoring duplicates
|
||||
dir_list = []
|
||||
for path in path_list:
|
||||
|
||||
this_iter = model.get_iter(path)
|
||||
dbid = model[this_iter][0]
|
||||
dummy_obj = self.main_win_obj.classic_media_dict[dbid]
|
||||
|
||||
if dummy_obj.dummy_dir \
|
||||
and not dummy_obj.dummy_dir in dir_list:
|
||||
dir_list.append(dummy_obj.dummy_dir)
|
||||
|
||||
if not dir_list:
|
||||
|
||||
self.dialogue_manager_obj.show_msg_dialogue(
|
||||
_('No destination(s) to show'),
|
||||
'error',
|
||||
'ok',
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
for this_dir in dir_list:
|
||||
utils.open_file(self, this_dir)
|
||||
|
||||
|
||||
def on_button_classic_play(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
@ -22728,6 +22894,35 @@ class TartubeApp(Gtk.Application):
|
|||
config.SystemPrefWin(self, 'live')
|
||||
|
||||
|
||||
def on_menu_open_msys2(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
||||
On MS Windows, opens the MINGW terminal for MSYS2.
|
||||
|
||||
Args:
|
||||
|
||||
action (Gio.SimpleAction): Object generated by Gio
|
||||
|
||||
par (None): Ignored
|
||||
|
||||
"""
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 18438 on_menu_open_msys2')
|
||||
|
||||
if 'PROGRAMFILES(X86)' in os.environ:
|
||||
utils.open_file(self, '..\\..\\..\\mingw64.exe')
|
||||
else:
|
||||
utils.open_file(self, '..\\..\\..\\mingw32.exe')
|
||||
|
||||
if self.show_msys2_dialogue_flag:
|
||||
|
||||
dialogue_win = mainwin.MSYS2Dialogue(self.main_win_obj)
|
||||
dialogue_win.run()
|
||||
dialogue_win.destroy()
|
||||
|
||||
|
||||
def on_menu_refresh_db(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
@ -22858,6 +23053,51 @@ class TartubeApp(Gtk.Application):
|
|||
self.mark_folder_hidden(media_data_obj, False)
|
||||
|
||||
|
||||
def on_menu_show_install(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
||||
On MS Windows (only), opens Tartube's installation folder.
|
||||
|
||||
Args:
|
||||
|
||||
action (Gio.SimpleAction): Object generated by Gio
|
||||
|
||||
par (None): Ignored
|
||||
|
||||
"""
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 18561 on_menu_show_install')
|
||||
|
||||
# (This path assumes that the standard NSIS installation script was
|
||||
# used to install Tartube)
|
||||
utils.open_file(
|
||||
self,
|
||||
self.script_parent_dir + '\\..\\..\\..\\..\\..',
|
||||
)
|
||||
|
||||
|
||||
def on_menu_show_script(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
||||
On MS Windows (only), opens Tartube's home folder.
|
||||
|
||||
Args:
|
||||
|
||||
action (Gio.SimpleAction): Object generated by Gio
|
||||
|
||||
par (None): Ignored
|
||||
|
||||
"""
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 18561 on_menu_show_install')
|
||||
|
||||
utils.open_file(self, self.script_parent_dir)
|
||||
|
||||
|
||||
def on_menu_stop_soon(self, action, par):
|
||||
|
||||
"""Called from a callback in self.do_startup().
|
||||
|
@ -23968,10 +24208,21 @@ class TartubeApp(Gtk.Application):
|
|||
self.dialogue_copy_clipboard_flag = True
|
||||
|
||||
|
||||
def set_dialogue_disable_msg_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 19519 set_dialogue_disable_msg_flag')
|
||||
|
||||
if not flag:
|
||||
self.dialogue_disable_msg_flag = False
|
||||
else:
|
||||
self.dialogue_disable_msg_flag = True
|
||||
|
||||
|
||||
def set_dialogue_keep_open_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 19518 set_dialogue_keep_open_flag')
|
||||
utils.debug_time('app 19520 set_dialogue_keep_open_flag')
|
||||
|
||||
if not flag:
|
||||
self.dialogue_keep_open_flag = False
|
||||
|
@ -25017,10 +25268,21 @@ class TartubeApp(Gtk.Application):
|
|||
self.show_custom_icons_flag = True
|
||||
|
||||
|
||||
def set_show_msys2_dialogue_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 20370 set_show_msys2_dialogue_flag')
|
||||
|
||||
if not flag:
|
||||
self.show_msys2_dialogue_flag = False
|
||||
else:
|
||||
self.show_msys2_dialogue_flag = True
|
||||
|
||||
|
||||
def set_show_newbie_dialogue_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 20370 set_show_newbie_dialogue_flag')
|
||||
utils.debug_time('app 20371 set_show_newbie_dialogue_flag')
|
||||
|
||||
if not flag:
|
||||
self.show_newbie_dialogue_flag = False
|
||||
|
@ -25214,10 +25476,21 @@ class TartubeApp(Gtk.Application):
|
|||
self.split_video_subdir_flag = True
|
||||
|
||||
|
||||
def set_store_playlist_id_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 20462 set_store_playlist_id_flag')
|
||||
|
||||
if not flag:
|
||||
self.store_playlist_id_flag = False
|
||||
else:
|
||||
self.store_playlist_id_flag = True
|
||||
|
||||
|
||||
def set_system_error_show_flag(self, flag):
|
||||
|
||||
if DEBUG_FUNC_FLAG:
|
||||
utils.debug_time('app 20462 set_system_error_show_flag')
|
||||
utils.debug_time('app 20463 set_system_error_show_flag')
|
||||
|
||||
if not flag:
|
||||
self.system_error_show_flag = False
|
||||
|
|
1289
tartube/mainwin.py
|
@ -1630,6 +1630,58 @@ class GenericRemoteContainer(GenericContainer):
|
|||
)
|
||||
|
||||
|
||||
def set_playlist_id(self, playlist_id, playlist_title):
|
||||
|
||||
# (Don't overwrite an existing entry unless the existing name is blank)
|
||||
if not playlist_id in self.playlist_id_dict \
|
||||
or self.playlist_id_dict[playlist_id] is None:
|
||||
self.playlist_id_dict[playlist_id] = playlist_title
|
||||
|
||||
|
||||
def reset_playlist_id(self):
|
||||
|
||||
self.playlist_id_dict = {}
|
||||
|
||||
|
||||
def extract_playlist_id(self, app_obj):
|
||||
|
||||
"""Can be called by anything, but mostly called by
|
||||
config.ChannelPlaylistEditWin.on_reset_assoc_playlist_button_clicked().
|
||||
|
||||
Reads the .info.json file for every child media.Video object, extracts
|
||||
the 'playlist_id' and 'playlist_title' fields, and uses them to update
|
||||
self.playlist_id_dict.
|
||||
|
||||
Does not check mainapp.TartubeApp.store_playlist_id_flag; the calling
|
||||
code should do that, if necessary.
|
||||
|
||||
Args:
|
||||
|
||||
app_obj (mainapp.TartubeApp): The main application
|
||||
|
||||
"""
|
||||
|
||||
self.playlist_id_dict = {}
|
||||
|
||||
for child_obj in self.child_list:
|
||||
|
||||
json_path = child_obj.check_actual_path_by_ext(
|
||||
app_obj,
|
||||
'.info.json',
|
||||
)
|
||||
if json_path is not None:
|
||||
|
||||
json_dict = app_obj.file_manager_obj.load_json(json_path)
|
||||
if 'playlist_id' in json_dict:
|
||||
|
||||
if 'playlist_title' in json_dict:
|
||||
self.playlist_id_dict[json_dict['playlist_id']] \
|
||||
= json_dict['playlist_title']
|
||||
|
||||
else:
|
||||
self.playlist_id_dict[json_dict['playlist_id']] = None
|
||||
|
||||
|
||||
def set_source(self, source):
|
||||
|
||||
self.source = source
|
||||
|
@ -3334,6 +3386,14 @@ class Channel(GenericRemoteContainer):
|
|||
self.new_count = 0
|
||||
self.waiting_count = 0
|
||||
|
||||
# Dictionary of playlist IDs extracted from every video in this channel
|
||||
# (can be used to compile a list of playlists associated with a
|
||||
# channel)
|
||||
# Dictionary in the form
|
||||
# playlist_id_dict[playlist_id] = playlist_title
|
||||
# ...where 'playlist_title' is None if the title is not known
|
||||
self.playlist_id_dict = {}
|
||||
|
||||
# List of error/warning messages generated the last time the channel
|
||||
# was checked or downloaded. Both set to empty lists if the channel
|
||||
# has never been checked or downloaded, or if there was no error/
|
||||
|
@ -3553,6 +3613,16 @@ class Playlist(GenericRemoteContainer):
|
|||
self.new_count = 0
|
||||
self.waiting_count = 0
|
||||
|
||||
# Dictionary of playlist IDs extracted from every video in this
|
||||
# playlist (will usually contain just one key-value pair; however, if
|
||||
# the URL self.source is actually a channel, not a playlist, it may
|
||||
# contain many key-value pairs; presumably the user will want to
|
||||
# convert the media.Playlist to a media.Channel at some point)
|
||||
# Dictionary in the form
|
||||
# playlist_id_dict[playlist_id] = playlist_title
|
||||
# ...where 'playlist_title' is None if the title is not known
|
||||
self.playlist_id_dict = {}
|
||||
|
||||
# List of error/warning messages generated the last time the channel
|
||||
# was checked or downloaded. Both set to empty lists if the channel
|
||||
# has never been checked or downloaded, or if there was no error/
|
||||
|
|
|
@ -380,6 +380,16 @@ class OptionsManager(object):
|
|||
no_clean_info_json (bool): If True, writes all fields to the infojson
|
||||
(default is to remove some private fields)
|
||||
|
||||
no_cookies (bool): If True, does not read/dump cookies from/to file
|
||||
(default)
|
||||
|
||||
cookies_from_browser (str): The name of the browser and (optionally)
|
||||
the name/path of the profile to load cookies from; a string in the
|
||||
from BROWSER[+KEYRING][:PROFILE]
|
||||
|
||||
no_cookies_from_browser (bool): If true, does not load cookies from the
|
||||
browser (default)
|
||||
|
||||
[Internet Shortcut Options]
|
||||
|
||||
write_link (bool): If True, writes an internet shortcut file, depending
|
||||
|
@ -804,6 +814,9 @@ class OptionsManager(object):
|
|||
'force_overwrites': False,
|
||||
'write_playlist_metafiles': False,
|
||||
'no_clean_info_json': False,
|
||||
'no_cookies': False,
|
||||
'cookies_from_browser': '',
|
||||
'no_cookies_from_browser': True,
|
||||
# (Internet Shortcut Options)
|
||||
'write_link': False,
|
||||
'write_url_link': False,
|
||||
|
@ -940,7 +953,7 @@ class OptionsParser(object):
|
|||
# -i, --ignore-errors
|
||||
OptionHolder('ignore_errors', '-i', False),
|
||||
# --abort-on-error
|
||||
OptionHolder('abort_on_error', '--abort-on-error ', False),
|
||||
OptionHolder('abort_on_error', '--abort-on-error', False),
|
||||
# NETWORK OPTIONS
|
||||
# --proxy URL
|
||||
OptionHolder('proxy', '--proxy', ''),
|
||||
|
@ -1043,7 +1056,7 @@ class OptionsParser(object):
|
|||
False,
|
||||
),
|
||||
# --prefer-insecure
|
||||
OptionHolder('prefer_insecure', '--prefer-insecure ', False),
|
||||
OptionHolder('prefer_insecure', '--prefer-insecure', False),
|
||||
# --user-agent UA
|
||||
OptionHolder('user_agent', '--user-agent', ''),
|
||||
# --referer URL
|
||||
|
@ -1172,6 +1185,16 @@ class OptionsParser(object):
|
|||
),
|
||||
# --no-clean-infojson
|
||||
OptionHolder('no_clean_info_json', '--no-clean-infojson', False),
|
||||
# --no-cookies
|
||||
OptionHolder('no_cookies', '--no-cookies', False),
|
||||
# --cookies-from-browser BROWSER[+KEYRING][:PROFILE]
|
||||
OptionHolder('cookies_from_browser', '--cookies-from-browser', ''),
|
||||
# --no-cookies-from-browser
|
||||
OptionHolder(
|
||||
'no_cookies_from_browser',
|
||||
'--no-cookies-from-browser',
|
||||
True,
|
||||
),
|
||||
# (Internet Shortcut Options)
|
||||
# --write-link
|
||||
OptionHolder('write_link', '--write-link', False),
|
||||
|
|
|
@ -42,8 +42,8 @@ import mainapp
|
|||
|
||||
# 'Global' variables
|
||||
__packagename__ = 'tartube'
|
||||
__version__ = '2.3.367'
|
||||
__date__ = '12 Feb 2022'
|
||||
__version__ = '2.3.393'
|
||||
__date__ = '8 Mar 2022'
|
||||
__copyright__ = 'Copyright \xa9 2019-2022 A S Lewis'
|
||||
__license__ = """
|
||||
Copyright \xa9 2019-2022 A S Lewis.
|
||||
|
|
|
@ -576,22 +576,18 @@ class UpdateManager(threading.Thread):
|
|||
|
||||
"""
|
||||
|
||||
substring = re.search(
|
||||
regex_list = [
|
||||
'Requirement already up\-to\-date.*\(([^\(\)]+)\)\s*$',
|
||||
stdout,
|
||||
)
|
||||
|
||||
if substring:
|
||||
self.ytdl_version = substring.group(1)
|
||||
|
||||
else:
|
||||
substring = re.search(
|
||||
'Successfully installed ' + downloader + '\-([^\(\)]+)\s*$',
|
||||
stdout,
|
||||
)
|
||||
'Requirement already satisfied.*\(([^\(\)]+)\)\s*$',
|
||||
'yt-dlp is up to date \(([^\(\)]+)\)\s*$',
|
||||
'Successfully installed ' + downloader + '\-([^\(\)]+)\s*$',
|
||||
]
|
||||
|
||||
for regex in regex_list:
|
||||
substring = re.search(regex, stdout)
|
||||
if substring:
|
||||
self.ytdl_version = substring.group(1)
|
||||
return
|
||||
|
||||
|
||||
def is_child_process_alive(self):
|
||||
|
|
|
@ -950,6 +950,25 @@ def convert_slices_to_clips(app_obj, custom_dl_obj, slice_list, temp_flag):
|
|||
return clip_list
|
||||
|
||||
|
||||
def convert_youtube_id_to_playlist(youtube_id):
|
||||
|
||||
"""Can be called by anything.
|
||||
|
||||
Converts an ID provided by YouTube into the full URL for a playlist.
|
||||
|
||||
Args:
|
||||
|
||||
youtube_id (str): The YouTube playlist ID
|
||||
|
||||
Returns:
|
||||
|
||||
The full URL for the playlist
|
||||
|
||||
"""
|
||||
|
||||
return 'https://www.youtube.com/playlist?list=' + youtube_id
|
||||
|
||||
|
||||
def convert_youtube_id_to_rss(media_type, youtube_id):
|
||||
|
||||
"""Can be called by anything; usually called by
|
||||
|
@ -974,6 +993,25 @@ def convert_youtube_id_to_rss(media_type, youtube_id):
|
|||
+ '_id=' + youtube_id
|
||||
|
||||
|
||||
def convert_youtube_id_to_video(youtube_id):
|
||||
|
||||
"""Can be called by anything.
|
||||
|
||||
Converts an ID provided by YouTube into the full URL for the video.
|
||||
|
||||
Args:
|
||||
|
||||
youtube_id (str): The YouTube video ID
|
||||
|
||||
Returns:
|
||||
|
||||
The full URL for the video
|
||||
|
||||
"""
|
||||
|
||||
return 'https://www.youtube.com/watch?v=' + youtube_id
|
||||
|
||||
|
||||
def convert_youtube_to_hooktube(url):
|
||||
|
||||
"""Can be called by anything.
|
||||
|
@ -1950,11 +1988,18 @@ custom_dl_obj=None, divert_mode=None):
|
|||
os.path.abspath(os.path.join(dl_path, 'ytdl-archive.txt')),
|
||||
)
|
||||
|
||||
# Fetch video comments, if required
|
||||
if app_obj.comment_fetch_flag \
|
||||
and app_obj.ytdl_fork is not None \
|
||||
and app_obj.ytdl_fork == 'yt-dlp':
|
||||
options_list.append('--write-comments')
|
||||
# yt-dlp options
|
||||
if app_obj.ytdl_fork is not None and app_obj.ytdl_fork == 'yt-dlp':
|
||||
|
||||
# Fetch video comments, if required
|
||||
if app_obj.comment_fetch_flag:
|
||||
options_list.append('--write-comments')
|
||||
|
||||
# On MS Windows, if --restrict-filenames is not specified, then insert
|
||||
# --windows-filenames. (I can't be sure that yt-dlp knows it is
|
||||
# running on MS Windows, when running inside MSYS2)
|
||||
if os.name == 'nt' and not '--restrict-filenames' in options_list:
|
||||
options_list.append('--windows-filenames')
|
||||
|
||||
# Show verbose output (youtube-dl debugging mode), if required
|
||||
if app_obj.ytdl_write_verbose_flag:
|
||||
|
@ -2160,6 +2205,15 @@ classic_flag):
|
|||
mod_options_list.append('-f')
|
||||
mod_options_list.append('(bestvideo+bestaudio/best)[protocol!*=dash]')
|
||||
|
||||
# On MS Windows and yt-dlp, if --restrict-filenames is not specified, then
|
||||
# insert --windows-filenames. (I can't be sure that yt-dlp knows it is
|
||||
# running on MS Windows, when running inside MSYS2)
|
||||
if app_obj.ytdl_fork is not None \
|
||||
and app_obj.ytdl_fork == 'yt-dlp' \
|
||||
and os.name == 'nt' \
|
||||
and not '--restrict-filenames' in mod_options_list:
|
||||
mod_options_list.append('--windows-filenames')
|
||||
|
||||
# Supply youtube-dl with the path to the ffmpeg binary, if the user has
|
||||
# provided one
|
||||
if app_obj.ffmpeg_path is not None:
|
||||
|
@ -2300,6 +2354,15 @@ clip_title, start_stamp, stop_stamp, custom_dl_obj, divert_mode, classic_flag):
|
|||
mod_options_list.append('-f')
|
||||
mod_options_list.append('(bestvideo+bestaudio/best)[protocol!*=dash]')
|
||||
|
||||
# On MS Windows and yt-dlp, if --restrict-filenames is not specified, then
|
||||
# insert --windows-filenames. (I can't be sure that yt-dlp knows it is
|
||||
# running on MS Windows, when running inside MSYS2)
|
||||
if app_obj.ytdl_fork is not None \
|
||||
and app_obj.ytdl_fork == 'yt-dlp' \
|
||||
and os.name == 'nt' \
|
||||
and not '--restrict-filenames' in mod_options_list:
|
||||
mod_options_list.append('--windows-filenames')
|
||||
|
||||
# Supply youtube-dl with the path to the ffmpeg binary, if the user has
|
||||
# provided one
|
||||
if app_obj.ffmpeg_path is not None:
|
||||
|
|
|
@ -598,7 +598,7 @@ class SetupWizWin(GenericWizWin):
|
|||
self.data_dir = None
|
||||
# The name of the youtube-dl fork to use, by default ('None' when
|
||||
# youtube-dl itself should be used)
|
||||
self.ytdl_fork = None
|
||||
self.ytdl_fork = 'yt-dlp'
|
||||
# Flag set to True if yt-dlp (only), when installed via pip, should be
|
||||
# installed without dependencies
|
||||
if os.name == 'nt':
|
||||
|
|