%\iffalse %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% ltx4yt.sty package, %% %% Copyright (C) 2020 %% %% dpstory@uakron.edu %% %% %% %% This program can redistributed and/or modified under %% %% the terms of the LaTeX Project Public License %% %% Distributed from CTAN archives in directory %% %% macros/latex/base/lppl.txt; either version 1 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e}[1997/12/01] %\ProvidesPackage{ltx4yt} % [2021/06/08 v1.0 ltx4yt: Play YouTube videos in the default browser (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex=false]{hyperref} \hypersetup{pdfpagemode=UseNone} \usepackage{fancyvrb} %\def\texorpdfstring#1#2{#1} %\pdfstringdefDisableCommands{\let\\\textbackslash} \OnlyDescription % comment out for implementation details \EnableCrossrefs \CodelineIndex \RecordChanges \InputIfFileExists{aebdocfmt.def}{\PackageInfo{ltx4yt}{Inputting aebdocfmt.def}} {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax \PackageInfo{ltx4yt}{aebdocfmt.def cannot be found}} \EnableCrossrefs \CodelineIndex \RecordChanges \makeatletter \renewcommand{\paragraph} {\@startsection{paragraph}{4}{0pt}{6pt}{-3pt} {\normalfont\normalsize\bfseries}} \renewenvironment{quote}[1][] {\def\@rgi{#1}\ifx\@rgi\@empty \let\rghtm\@empty\else\def\rghtm{\rightmargin\leftmargin}\fi \list{}{\rghtm} %{\rightmargin\leftmargin}% \item\relax} {\endlist} \makeatother \bgroup\ttfamily \gdef\brpr#1{\char123\relax#1\char125\relax}\egroup \let\darg\brpr \let\env\texttt \let\opt\texttt \let\app\textsf \let\tops\texorpdfstring \def\nmpsep#1{\hskip-\marginparsep\texttt{#1}} \def\visispace{\symbol{32}} \def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} \def\meta#1{\textsl{\texttt{#1}}} \def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}} \def\ltag{<}\def\rtag{>} \def\EXCL{!}\def\QMRK{?}\def\EQU{=} \let\app\textsf\let\pkg\textsf \begin{document} \GetFileInfo{ltx4yt.sty} \title{The \textsf{ltx4yt} Package} \author{D. P. Story\\ Email: \texttt{dpstory@acrotex.net}} \date{processed \today} \maketitle \tableofcontents \let\Email\texttt \DocInput{ltx4yt.dtx} \IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute \texttt{makeindex -s gind.ist -o ltx4yt.ind ltx4yt.idx} on the command line and recompile \texttt{ltx4yt.dtx}.} \IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute \texttt{makeindex -s gglo.ist -o ltx4yt.gls ltx4yt.glo} on the command line and recompile \texttt{ltx4yt.dtx}.} \end{document} % % \fi % \MakeShortVerb{|} % \InputIfFileExists{aebdonotindex.def}{\PackageInfo{ltx4yt}{Inputting aebdonotindex.def}} % {\PackageInfo{ltx4yt}{cannot find aebdonotindex.def}} % \DoNotIndex{\g@addto@macro,\divide,\box,\setbox,\x,\y,\z} % % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Introduction} % % It is July 2020 and Adobe's support for Flash will vanish in December. Google stopped % supporting Flash several years ago, so the package \pkg{yt4pdf} is no longer functional % and will be withdrawn from CTAN. If we cannot play videos within PDF anymore, the next best % course is to develop some basic commands for playing YouTube videos in the default browser, preferably % without any annoying advertisements. This can be done for some videos, but for others it cannot be done. % %\changes{v1.0}{2021/06/08}{Modify search-type macro to conform with new YouTube player parameters} %\changes{v0.1}{2020/07/17}{Begin new package \string\pkg{ltx4yt}} %\changes{v0.2}{2020/07/17}{Commands to pass arguments to urls} %\changes{v0.6}{2020/07/25}{Final version before first publication} %\changes{v0.7}{2020/07/30}{Corrected upload} %\changes{v0.8}{2020/08/01}{Added catcode protection} %\begin{macrocode} \RequirePackage{xkeyval} % \end{macrocode} % \leavevmode\IndexOpt{usepopup} When this option is taken, additional code to support % the use of popup menus is input. We also support \IndexOpt[\protect\EXCL]{!usepopup}\opt{!popup}, % which is a convenience option for not using \opt{usepopup}. % \begin{macrocode} \DeclareOption{usepopup}{\def\lo@dpu{\InputIfFileExists{ytpu.def} {\PackageInfo{ltx4yt}{Loading ytpu.def}} {\PackageInfo{ltx4yt}{Can't find ytpu.def}}}} \DeclareOption{!usepopup}{} \let\lo@dpu\relax \AtEndOfPackage{\lo@dpu} \ProcessOptions \edef\yt@restoreCats{% \catcode`\noexpand\"=\the\catcode`\"\relax \catcode`\noexpand\'=\the\catcode`\'\relax \catcode`\noexpand\,=\the\catcode`\,\relax \catcode`\noexpand\!=\the\catcode`\!\relax } \@makeother\"\@makeother\'\@makeother\,\@makeother\! \RequirePackage{xcolor} \RequirePackage{eforms} % \end{macrocode} % If the \opt{usepopup} option is taken, we load the \pkg{popupmenu} package. % \begin{macrocode} \ifx\lo@dpu\relax\else \def\YT@rpPU{\RequirePackage{popupmenu}[2020/07/26]}\expandafter \YT@rpPU\fi % \end{macrocode} % % \section{Implementation} % % The JavaScript method \texttt{app.launchURL\darg{\ameta{URL}}} is used to open the default browser % on the page determined by \ameta{URL}. The links created use \cs{URI} (\texttt{/S/URI/URI}), this action type % allows links to be functional in all PDF viewers, even on hand held devices. % % We have three implementations of this plan: (1)~links (\cs{ytvId} and \cs{ytLink}) for all devices; % (2)~dropdown menus (combo boxes) (\cs{ytComboList} (uses JavaScript); % and (3)~pop-up menus using the \env{popupmenu} environment of the \pkg{popupmenu} package (uses JavaScript). % The methods that use JavaScript will not function in the near future on hand held devices. % % \subsection{Playing a YouTube video from its Video ID} % % In this section, we create several ways of calling for a YouTube video to play % in the default browser. % % \subsubsection{Using a Link} % \begin{macro}{\ytvIdPresets}\nmpsep{\darg{\ameta{KV-pairs}}} % The options for the \cs{ytvId} link. The default is given below in the definition. % Initially, the preset is to produce \texttt{webbrown} colored links. % \begin{macrocode} \newcommand{\ytvIdPresets}[1]{\def\yt@vIdPresets{#1}} \definecolor{webbrown}{rgb}{.6,0,0} % from the web package \ytvIdPresets{\linktxtcolor{webbrown}} % \end{macrocode} % \end{macro} % Here is a convenience command. This definition has since been made % in \pkg{insdljs}. % \begin{macrocode} \providecommand{\URI}[1]{/S/URI/URI(#1)} % \end{macrocode} % Define \DescribeMacro\ytURL\cs{ytURL} to expand to the YouTube web site. % \begin{macrocode} \def\ytNF{false} \def\ytURL{https://www.youtube.com} % \end{macrocode} % \begin{macro}{\ytvId}\nmpsep{*[\ameta{opts}]\darg{\ameta{ytvID}}\darg{\ameta{text}}} % The \cs{ytvId} is link which when pressed plays the video whose Video Id is \ameta{ytvID}) % in the default browser. % \begin{quote} % \begin{itemize} % \item[\texttt*] If the \texttt*-option is taken, you have determined that this % video cannot be embedded (which is the ideal) and must be played normally on YouTube % with all advertisements and other extraneous information. % \item[{\ameta{opts}}:] link optional KV-pairs to modify the appearance of the link. % \item[{\ameta{ytvID}}:] The video Id for the YouTube video to play % \item[{\ameta{text}}:] The text that displays the link. %\end{itemize} %\end{quote} %\changes{v0.8}{2020/08/01}{added \string\cs{ytIdParams}} % \begin{macrocode} \def\ytvIdParams#1{\def\@rgi{#1}\ifx\@rgi\@empty \let\ytvIdP@rams\@empty\else\def\ytvIdP@rams{#1}\fi} \let\ytvIdP@rams\@empty \newcommand{\ytvId}{\@ifstar{\def\yt@ask{*}\yt@@vId} {\let\yt@ask\@empty\yt@@vId}} \newcommand{\yt@@vId}[3][]{\begingroup \ifx\ytvIdP@rams\@empty\let\ques\@empty\else \ifx\yt@ask\@empty\def\ques{?}\else\def\ques{&}\fi \fi \ifx\yt@ask\@empty \def\yt@lnk@hash{embed/#2\ques\ytvIdP@rams}\else \def\yt@lnk@hash{watch?v=#2\ques\ytvIdP@rams}\fi \setLink[\presets{\yt@vIdPresets}#1 \A{\URI{\ytURL/\yt@lnk@hash}}]{#3}\endgroup } % \end{macrocode} % \end{macro} % \begin{macro}{\ytvIdML}\nmpsep{*[\ameta{opts}]\darg{\ameta{ytvID}}\darg{\ameta{text}}} % The \cs{ytvId} is link which when pressed plays the video whose Video Id is \ameta{ytvID}) % in the default browser. This is a multi-line link, it requires the \pkg{aeb\_mlink} package % and the \app{dvips\,\texttt{->}\,distiller} workflow. % \begin{macrocode} \newcommand{\ytvIdML}{\@ifstar{\def\yt@ask{*}\yt@@vIdML} {\let\yt@ask\@empty\yt@@vIdML}} \newcommand{\yt@@vIdML}[3][]{\begingroup \ifx\ytvIdP@rams\@empty\let\ques\@empty\else \ifx\yt@ask\@empty\def\ques{?}\else\def\ques{&}\fi \fi \ifx\yt@ask\@empty \def\yt@lnk@hash{embed/#2\ques\ytvIdP@rams}\else \def\yt@lnk@hash{watch?v=#2\ques\ytvIdP@rams}\fi \mlsetLink[\presets{\yt@vIdPresets}#1 \A{\URI{\ytURL/\yt@lnk@hash}}]{#3}\endgroup } % \end{macrocode} % \end{macro} % \begin{macro}{\ytLink}\nmpsep{[\ameta{opts}]\darg{\ameta{spec}}\darg{\ameta{text}}} % We create a custom link for youtube videos. The \ameta{spec} (specification) argument has several % forms for maximum convenience and flexibility. % \begin{itemize} % \item |\ytLink{\embedId{|\ameta{ytvID}|}\params{|\ameta{parameters}|}}{|\ameta{text}|}|\\[3pt] This is the form % for playing a video with \ameta{ytvID} that \emph{can be embedded} (this best type of video). The \cs{params} % argument must follow the \cs{embedId}, its argument are any parameters you want to append to the URL. % The use of \cs{params} is optional; however, without the \cs{params} you may as well use % |\ytvId{|\ameta{ytvID}|}{|\ameta{text}|}|. % % \item |\ytLink{\watchId{|\ameta{ytvID}|}\params{|\ameta{parameters}|}}{|\ameta{text}|}|\\[3pt] This is the form % for playing a video with \ameta{ytvID} that \emph{cannot be embedded} (advertisements and other information % appears). The \cs{params} argument must follow the \cs{watchId}, its argument are any parameters you want to append to the URL. % The use of \cs{params} is optional; however, without the \cs{params} you may as well use % |\ytvId*{|\ameta{ytvID}|}{|\ameta{text}|}|. % % \item |\ytLink{\embed{|\ameta{spec}|}}{|\ameta{text}|}|\\[3pt] % A form that does not specify a video ID. It is useful for more general actions, such as % searches, for example, % \begin{flushleft} % \textcolor{red}{\textbf{Note:} \texttt{listType=search} is deprecated and will no longer be supported % as of 15 November, 2020.} % |\ytLink{\embed{listType=search&list=Adobe Acrobat DC}}|\\ % \qquad|{Search for Adobe Acrobat DC}| % \end{flushleft} % This form does not have a \cs{params} optional argument as all the parameters are built into the % argument of \cs{embed}. % % \item |\ytLink{|\ameta{spec}|}{|\ameta{text}|}|\\[3pt] The most general form. The action of this % link is |\URI{\ytURL/|\ameta{spec}|}|; for example, % \begin{flushleft} % \textcolor{red}{\textbf{Note:} \texttt{listType=search} is deprecated and will no longer be supported % as of 15 November, 2020.} % |\ytLink{embed?listType=search&list=Adobe Acrobat DC}|\\ % \qquad|{Search for Adobe Acrobat DC}| % \end{flushleft} % Here you are free to build whatever URL you can imagine. % % \item |\ytLink{\channel{|\ameta{name}|}}{|\ameta{text}|}|\\[3pt] % Such a link displays the channel \ameta{name}. For example, % \begin{flushleft} % |\ytLink{\channel{rocketjump}}{The RocketJump Channel}| % \end{flushleft} % This link opens the YouTube channel named \texttt{rocketjump}. % \end{itemize} % \paragraph*{Passing Player Parameters.} % As was illustrated above, the custom link \cs{ytLink} can pass various recognizable % parameters to YouTube. After reviewing, % \begin{flushleft} % \url{https://developers.google.com/youtube/player_parameters} % \end{flushleft} % the following parameters are recommended, some of them are illustrated in the % sample document \texttt{ltx4yt-1.tex}: % \begin{itemize} % \item \texttt{autoplay=\ameta{\upshape{0\string|1}}} (default \texttt{0}) % \item \texttt{controls=\ameta{\upshape{0\string|1}}} (default \texttt{1}) % \item \texttt{fs=\ameta{\upshape{0\string|1}}} (default \texttt{1}) % \item \texttt{modestbranding=\ameta{\upshape{0\string|0}}} % \item \texttt{playlist=\ameta{list}} % \item \texttt{listType=search\&list=\ameta{query}}\\ % \textcolor{red}{\textbf{Note:} \texttt{listType=search} is deprecated and will no longer be supported % as of 15 November, 2020.} % \end{itemize} % The specialized needs of the document author is most easily accommodated through the use % of the \cs{ytLink} command, for example, % \begin{flushleft}\obeylines % |\ytLink{\embedId{5y9-EVmreU4}\params{autoplay=1&modestbranding=1}}| % \qquad|{Lori's Corner: Episode \#1}| % \end{flushleft} % \begin{macrocode} \newif\ifytwatch \ytwatchfalse % \end{macrocode} % \paragraph*{The \cs{ytLink} command.} Before getting to \cs{ytLink} and \cs{ytLinkML}, % there is a long stream of commands to parse the \ameta{spec} argument of \cs{ytLink}. % It goes through looking for \cs{watchId}, \cs{embedId}, \cs{embed}, and \cs{params}. % As it progresses, it adds code to the macro \cs{ytspec}, which at the end of things % will hold the fully formed \ameta{spec} for insertion into the URL. % \begin{macrocode} \def\yt@@parse{\let\ytspec\@empty\yt@parse} \def\yt@parse{\@ifnextchar\@nil{\@gobble}{\yt@parsei}} \def\yt@parsei{\@ifnextchar\watchId{% check for \watchId \ytwatchtrue\yt@parse@watch}{\yt@parseii}} \def\yt@parse@watch\watchId#1{\g@addto@macro \ytspec{\watchId{#1}}\yt@parse} \def\yt@parseii{\@ifnextchar\embedId{% check for \embedId \yt@parse@embedId}{\yt@parseiii}} \def\yt@parse@embedId\embedId#1{\g@addto@macro \ytspec{\embedId{#1}}\yt@parse} \def\yt@parseiii{\@ifnextchar\embed{% check for \embed \yt@parse@embed}{\yt@parseiv}} \def\yt@parse@embed\embed#1{\g@addto@macro \ytspec{\embed{#1}}\yt@parse} \def\yt@parseiv{\@ifnextchar\params{% check for \params \yt@parse@params}{\yt@parsev}} \def\yt@parse@params\params#1{\ifytwatch \g@addto@macro\ytspec{}\else \g@addto@macro\ytspec{?#1}\fi \yt@parse} % \end{macrocode} % If we get this far, \ameta{spec} is raw, has none % of the helper commands. So we just insert the % entire argument into \cs{ytspec}. % \begin{macrocode} \def\yt@parsev#1\@nil{\g@addto@macro\ytspec{#1}} % \end{macrocode} % All preliminaries done, we define \cs{ytLink} % \begin{macrocode} \newcommand{\ytLink}[3][]{\begingroup \def\embedId##1{embed/##1}% \def\params##1{##1}\def\embed##1{embed?##1}% \def\watchId##1{watch?v=##1}\def\channel##1{c/##1}% \def\search##1{results?search_query=##1}% \def\user##1{user/##1}% \yt@@parse#2\@nil % returns arg in \ytspec \def\URLArg{\ytURL/\ytspec}% \setLink[\presets{\yt@vIdPresets}#1\A{\URI{\URLArg}} ]{#3}\endgroup } % \end{macrocode} % \end{macro} % \begin{macro}{\ytLinkML}\nmpsep{[\ameta{opts}]\darg{\ameta{spec}}\darg{\ameta{text}}} % is the multi-line version of \cs{ytLink}. It requires a \app{dvips\,\texttt{->}\,distiller} workflow % as well as the \pkg{aeb\_mlink} package. % \begin{macrocode} \newcommand{\ytLinkML}[3][]{\begingroup \def\embedId##1{embed/##1}% \def\params##1{##1}\def\embed##1{embed?##1}% \def\watchId##1{watch?v=##1}\def\channel##1{c/##1}% \def\search##1{results?search_query=##1}% \def\user##1{user/##1}% \yt@@parse#2\@nil % returns arg in \ytspec \def\URLArg{\ytURL/\ytspec}% \mlsetLink[\presets{\yt@vIdPresets}#1 \A{\URI{\URLArg}} ]{#3}\endgroup } % \end{macrocode} % \end{macro} % \subsubsection{Using a Combobox} % All commands associate with a combo box play list. % \begin{macro}{\ytComboList}\nmpsep{[\ameta{opts}]\darg{\ameta{name}}\darg{\ameta{wd}}\darg{\ameta{ht}}} % The \cs{ytComboList} command produces a combo box (dropdown menu) of video Ids and titles. The user selects a % video based on its title, then presses the PLAY button. The two commands % \cs{ytComboListPresets} and \cs{ytComboBtnPresets} are used to set the appearances % of the combo box and the PLAY button. %\begin{quote} %\begin{itemize} % \item[\ameta{opts}:] eforms key-value pairs % \item[\ameta{name}:] A unique name (ASCII letters and numbers) % \item[\ameta{wd}:] The width of the combo box % \item[\ameta{ht}:] The height of the combo box %\end{itemize} %\end{quote} % Now we have the code for \cs{ytComboList} % \begin{macrocode} \newcommand{\ytComboList}[4][]{% \comboBox[\Ff{\FfCommitOnSelChange}\DV{\yt@pl@def}\V{\yt@pl@def} \presets{\yt@ComboListPresets}#1]{ytSelect#2} {#3}{#4}{*\yt@pl@pl}% 2020/07/22 v0.4 } % \end{macrocode} % \end{macro} % \begin{macro}{\ytComboBtn}\nmpsep{[\ameta{opts}]\darg{\ameta{name}}\darg{\ameta{wd}}\darg{\ameta{ht}}} % A button to play the selection made in the combo box. The caption of the push button % is determined by the command \DescribeMacro\ytStrPLAY\cs{ytStrPlay}. % The parameters for \cs{ytComboBtn} are, % \begin{quote} %\begin{itemize} % \item[\ameta{opts}:] The KV-pairs to pass to the underlying push button. % \item[\ameta{name}:] A unique name (ASCII letters and numbers) % \item[\ameta{wd}:] The width of the combo box % \item[\ameta{ht}:] The height of the combo box %\end{itemize} %\end{quote} % \begin{macrocode} \newcommand{\ytStrPLAY}{PLAY} \newcommand{\ytComboBtn}[4][]{% \pushButton[\TU{Click to play}\CA{\ytStrPLAY} \presets{\yt@ComboBtnPresets}#1 \A{\JS{var f=this.getField("ytSelect#2");\r var ytID=f.value;\r var i=f.currentValueIndices;\r var ytFV=f.getItemAt(i,false);\r var i=ytFV.indexOf("*");\r if ( i == -1 )\r\t app.launchURL("\ytURL/embed/"+ytID,\ytNF);\r else\r\t app.launchURL("\ytURL/watch?v="+ytID,\ytNF); }}]{ytSelectBtn#2}{#3}{#4}% } % \end{macrocode} % \end{macro} % \begin{macro}{\ytPlayList}\nmpsep{\darg{\ameta{ytvID}}\darg{\ameta{\cs{cmd}}}} % This command is executed before \cs{ytComboList} to set the initial/default value (\ameta{ytvID}) of the % combo box and the play list (\ameta{\cs{cmd}}). Here \ameta{\cs{cmd}} is a command defined by the % \cs{declarePlayList} command. Use the \cs{ytPlayList} to pass the play list to the next combo box. % \begin{macrocode} \newcommand{\ytPlayList}{\begingroup\@makeother\_\@makeother\' \ytPlayList@i} \def\ytPlayList@i#1#2{\gdef\yt@pl@def{#1}\xdef\yt@pl@pl{#2}\endgroup} % \end{macrocode} % \end{macro} % \begin{macro}{\ytComboListPresets}\nmpsep{\darg{\ameta{opts}}} The KV-pairs % for \cs{ytComboList}. % \begin{macrocode} \newcommand{\ytComboListPresets}[1]{\def\yt@ComboListPresets{#1}} \let\yt@ComboListPresets\@empty % \end{macrocode} % \end{macro} % \begin{macro}{\ytComboBtnPresets}\nmpsep{\darg{\ameta{opts}}} The KV-pairs % for \cs{ytComboBtn}. % \begin{macrocode} \newcommand{\ytComboBtnPresets}[1]{\def\yt@ComboBtnPresets{#1}} \let\yt@ComboBtnPresets\@empty % \end{macrocode} % \end{macro} % \leavevmode\DescribeMacro{\ytIdTitle}\nmpsep{\darg{\ameta{text}}\darg{\ameta{VidID}}} % A convenience command to lay out the playlist. % \begin{macrocode} \newcommand{\ytIdTitle}[2]{[(#2)(#1)]} % \end{macrocode} % \begin{macro}{\declarePlayList} % A video ID may contain characters {\LaTeX} considers special, so we sanitize these % special characters before reading in the video ID. Near as I can determine, a video % id consists of 11 characters comprising combinations of letters (A-Z,a-z) numbers % (0-9) and special characters underscore and hyphen (\_ and -). We sanitize the last two. %\begin{Verbatim}[xleftmargin=\parindent,codes={\catcode`\%=9},commandchars={!()}] %\declarePlayList{!ameta(\cmd)}{ % \ytIdTitle{!ameta(text)}{!ameta(VidID)} % ... % \ytIdTitle{!ameta(text)}{!ameta(VidID)} % } %\end{Verbatim} %The entries may also be in raw form `|[(\ameta{VidID})(\ameta{text})]|'. Note that the two arguments are %enclosed in parentheses, there is a problem with parsing if \ameta{text} itself contains %parentheses. Within \ameta{text} enclose matching parentheses in braces, for example, %\begin{flushleft}|\ytIdTitle{Kung-Fu Fighting {(Bruce Lee version)}}{GZ9e3Dy7obA}|\end{flushleft} %\paragraph*{The role of \texttt* in the title.} If an \texttt{*} appears in the title, this means %that the video cannot be embedded. Viewing the video will come with advertisements and other information %that YouTube generates. %\begin{flushleft}|\ytIdTitle{Kung-Fu Fighting* {(Original version)}}{jhUkGIsKvn0}|\end{flushleft} %\changes{v0.4}{2020/07/22}{Changed parsing of \string\cs{declarePlayList} to accomodate %\string\cs{pdfstringdef}} % \begin{macrocode} \newcommand{\declarePlayList}[1]{\bgroup \Hy@unicodefalse \let\pl@yList\@empty \ifpdfmarkup \def\Esc{\eqbs}\else\def\Esc{}\fi \def\cs##1{\eqbs\eqbs##1}\relax \@makeother\_\@makeother\- \yt@declarePlayList{#1}% } \def\yt@declarePlayList#1#2{% \yt@declarePlayList@i#2\@nil\relax\relax \toks@=\expandafter{\pl@yList}\relax \xdef#1{\pl@yList}\egroup } \def\yt@declarePlayList@i{\@ifnextchar\@nil {\expandafter\@gobbletwo\@gobble} {\yt@declarePlayList@ii}% } \def\yt@declarePlayList@ii\ytIdTitle#1#2{% \pdfstringdef\yt@PLTitle{#1}% \edef\y{[(#2)(\yt@PLTitle)]}% \expandafter\g@addto@macro\expandafter \pl@yList\expandafter{\y}% \yt@declarePlayList@i } % \end{macrocode} % \end{macro} %An example of use of \cs{declarePlayList}: %\begin{Verbatim}[xleftmargin=\parindent,codes={\catcode`\%=9},commandchars={!()}] %\declarePlayList{\playListii}{% % \ytIdTitle{Elfego Baca}{gRwa0MdeqVs} % \ytIdTitle{Texas John Slaughter}{7yrk1BvtLE8} % \ytIdTitle{Swamp Fox}{-SBPnw5riLM&NR} % \ytIdTitle{Zorro Promo}{cKludhxEoJ0} %} %\end{Verbatim} % \begin{macrocode} % %<*pujs> % \end{macrocode} % \subsubsection{Using a popup menu} % These code lines (including the document JavaScript) are only included % when the \opt{usepopup} option is taken. % \begin{macro}{\ytUseMenus}\nmpsep{\darg{\ameta{menu-names}}} % A command used to list popupmenu data. It defines a command % \cs{ytPopupData} that is used in the JS support for popup menus. The argument % \ameta{menu-names} is a comma-delimited list of menu names defined by a \env{popupmenu} environment. The command % needs to be in the preamble. % \begin{macrocode} \def\ytPopupAllMenuData{// ltx4yt: Begin popup menu data^^J}% \let\ytMenuNames\@gobble \newcommand{\ytUseMenus}[1]{\bgroup \@for\yt@menu:=#1\do{% \edef\x{\noexpand\g@addto@macro\noexpand \ytMenuNames{,"\yt@menu"}}\x \edef\x{\expandafter\noexpand\@nameuse{\yt@menu}}% \toks@=\expandafter{\x^^J}% \expandafter\g@addto@macro\expandafter \ytPopupAllMenuData\expandafter{\the\toks@}% }\g@addto@macro\ytPopupAllMenuData {// ltx4yt: End of popup menu data}% \egroup } \@onlypreamble\ytUseMenus % \end{macrocode} % \end{macro} % \begin{macro}{\puIdTitle} % A convenience macro for entering popupmenu data for youtube videos. %\begin{Verbatim}[xleftmargin=\parindent,fontsize=\small,codes={\catcode`\%=9},commandchars={!()}] %\begin{popupmenu}{YTMenu} % \puIdTitle{Select a YouTube Video}{} % A title has no yt Id % \begin{submenu}{title=Music Videos} % \puIdTitle{Kung-Fu Fighting (Bruce Lee version)}{GZ9e3Dy7obA} % \puIdTitle{\string\"Sea Hunt\string\" TV serie}{MW-IZ67iADU} % ... % \end{submenu} %\end{popupmenu} %\end{Verbatim} % Note that we must protect the double quote. % \begin{macrocode} %\newcommand{\puIdTitle}[2]{\item{title={#1},% % return={[\itemindex,'#2']}}} \newcommand{\puIdTitle}[2]{\Hy@unicodefalse\pdfstringdef\x@YT{#1}% \edef\y@YT{\noexpand\item{title={\x@YT},% return={[\noexpand\itemindex,'#2']}}}\y@YT} % \end{macrocode} % \end{macro} % Some convenience commands for setting up a push button to display the popupmenu % on rollover. % \begin{macrocode} \def\ytpubtnCnt{0} \newcommand{\ytPopupBtn}[4][]{\bgroup \@tempcnta\ytpubtnCnt\relax \advance\@tempcnta\@ne \xdef\ytpubtnCnt{\the\@tempcnta}% \pushButton[\cmd{\pmpvCAOff}\CA{YT Menu} \textColor{0 0 1}\W1\BC{}\textSize{0} \H{N}\S{S}\presets{\yt@PopupPresets}#1 \AAmouseenter{ytPopupMenu("#2");} % dps ]{ytPopup\ytpubtnCnt}{#3}{#4}\egroup } \newcommand{\ytPopupPresets}[1]{\def\yt@PopupPresets{#1}} \let\yt@PopupPresets\@empty % \end{macrocode} % \begin{macrocode} % %<*package> % \end{macrocode} % \subsection{Search YouTube interactively} % \begin{macro}{\ytInputQuery}\nmpsep{[\ameta{opts}]\darg{\ameta{wd}}\darg{\ameta{ht}}} % Provides a text field to enter a query string. % \begin{macrocode} \newcommand{\ytInputQuery}[3][]{% \textField[\TU{Enter a query text string}#1]{ytSearchTxt}{#2}{#3}} % \end{macrocode} % \end{macro} % \begin{macro}{\ytSearch}\nmpsep{[\ameta{opts}]\darg{\ameta{wd}}\darg{\ameta{ht}}} % A push button what will search YouTube based on the query string. % \textcolor{red}{\textbf{Note:} \texttt{listType=search} is deprecated and will % no longer be supported as of 15 November, 2020.} % \changes{v1.0}{2021/06/08}{Replace \string\texttt{embed\string\QMRK} in search with % \string\texttt{results\string\QMRK\space search\string\_query\string\EQU}} % \begin{macrocode} \newcommand{\ytSearch}[3][]{% \pushButton[\CA{Search}#1\AAmouseup{% var f=this.getField("ytSearchTxt");\r var v=f.value;\r if ( (v=v.replace(/\string\\s/g,"+")) != "" )\r\t app.launchURL("\ytURL/results?search_query="+v); }]{ytSearchBtn}{#2}{#3}} % \end{macrocode} % \end{macro} % \begin{macro}{\ytClearQuery}\nmpsep{[\ameta{opts}]\darg{\ameta{wd}}\darg{\ameta{ht}}} % A button to clear the query string. % \begin{macrocode} \newcommand{\ytClearQuery}[3][]{% \pushButton[\CA{Clear}#1 \AAmouseup{this.resetForm("ytSearchTxt");} ]{ytSearchClr}{#2}{#3}% } % \end{macrocode} % \end{macro} % \begin{macrocode} % %<*pujs> % \end{macrocode} %\subsection{Document JavaScript} % Some JavaScript to process the user's choice and to launch the browser % to view the selected video. % \changes{v0.5}{2020/07/24}{Manage multiple menus} % \begin{macrocode} \begin{insDLJS*}{yt} \begin{newsegment}{ltx4yt: % Popup Menu Data and JavaScript support functions} var YTdebug=false; var aYTLastChoice=new Array; var bYTLastChoice=false; \ytPopupAllMenuData var aChoice; // make local function ytProcessMenu(cMenu) { // aMenu->cMenu now a string var aMenu=eval(cMenu); var cChoice = app.popUpMenuEx.apply( app, aMenu ); ytProcessMenu.cChoice=cChoice; if ( cChoice != null ) { aChoice=eval(cChoice); if (aChoice[1]=="") return null; var thisChoice=aChoice[0]; eval(cMenu+thisChoice).bMarked=true; if (!bYTLastChoice) { eval(cMenu+aChoice[0]).bMarked=true; } else { var structLoc=eval(aYTLastChoice[1])[0] eval(aYTLastChoice[0]+structLoc).bMarked=false; eval(cMenu+aChoice[0]).bMarked=true; } return aChoice; } else return null; } function ytPopupMenu(cMenu) { // cMenu now a string var aChoice=ytProcessMenu(cMenu); var cChoice=ytProcessMenu.cChoice; var aMenu=eval(cMenu); if (aChoice!=null) { var title=eval(cMenu+aChoice[0]).cName; var i=title.indexOf("*"); var _hash=(i == -1)?"embed/"+aChoice[1]:"watch?v="+aChoice[1]; if (!bYTLastChoice) { if(YTdebug) % console.println("launching url https://www.youtube.com/"+_hash); else app.launchURL("https://www.youtube.com/"+_hash,false); aYTLastChoice=[cMenu,cChoice]; bYTLastChoice=true; } else { var cLastMenu=eval(aYTLastChoice[1])[0] aYTLastChoice=[cMenu,cChoice]; if (cLastMenu!=aChoice[0]) { if (YTdebug) % console.println("will launch url: https://www.youtube.com/"+_hash); else app.launchURL("https://www.youtube.com/"+_hash,false); } else { if (YTdebug) console.println("will NOT launch url"); // choice is the same, uncheck this item eval(cMenu+aChoice[0]).bMarked=false; bYTLastChoice=false; } } } } \end{newsegment} \end{insDLJS*} % \end{macrocode} % \begin{macrocode} %<*pujs> %<*package> \yt@restoreCats % % \end{macrocode} % \Finale \endinput