Home Page
  • April 28, 2024, 07:16:22 am *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Dakusan

Pages: 1 2 3 [4] 5 6 ... 36
46
Projects / Re: Plex Playlist Importer
« on: July 26, 2016, 08:12:09 pm »
You mean a separate Plex pass user, correct? One in which you would have had to of shared your libraries with via Libraries->...->Share ? (Or shares visible via plex.tv->launch->settings->users->friends)

47
Updates / Plex Playlist Importer v1.1
« on: July 14, 2016, 08:27:22 pm »
Original update for Plex Playlist Importer v1.1 can be found at https://www.castledragmire.com/Updates/Plex_Playlist_Importer_v1.1.
Originally posted on: 07/14/16
Regarding: Plex Playlist Importer

Plex Playlist Importer v1.1 (source). Current updates spanning 2017:
     
  • Fixed absolute path logic for Linux (partial credit to Matt Spitz)
  •  
  • Bypasses UTF8 BOM
  •  
  • Program now works off of argument flags.
         
    • Added parameters: Playlist encoding, override type, force list
    •    
    • Created special BulletHelpFormatter class for parameters
    •  
  •  
  • Playlist names can now conflict with other item/list names in Plex
  •  
  • Console column width passthrough in the .sh file
  •  
  • Updated READMEs regarding:
         
    • Unicode compliance
    •    
    • The “no such module : FTS4” error
    •    
    • Running the script from a computer external to the server running Plex
    •    
    • The “The program can’t start because MSVCR100.dll is missing” error
    •    
    • All updates
    •  
  •  
  • Added the ability to compile to a windows executable (via setup.py py2exe)
  •  
  • The Playlist Name is now an optional argument which can be entered after the program is ran. This allows directly dragging playlists onto the executable
  •  
  • Added shebang to main script
  •  
  • M3U files now ignore lines that are empty or have only whitespace

48
General Discussion / Re: how to enter the parameters?
« on: July 05, 2016, 04:42:39 pm »
Sure. If you needed the latest executable, it is available in this thread.

49
Projects / Re: Plex Playlist Importer
« on: July 05, 2016, 01:53:02 am »
Yikes. It feels like on a lot of this you are going to way more trouble than should be needed :-\

Quote
I've not found a good way to execute ListImporter from a folder not containing both the .exe and all its .dll files. This would be useful but is not essential. I do have to manage Acronis' insistence on restarting one of its supposedly unneeded services that uses a different sqlite3.dll. The sqlite3.dll used by the latest version of PMS no longer conflicts.
I think I might actually have been providing a bad sqlite3.dll with my previous releases, which could have been the problem. That is fixed in the new archive I had sent you. I don't really see an easier way to do distribute this without the dlls as separate files in the archive. I'm not big on installers.
Quote
The first of two small issues is that ListImporter is intolerant of blank lines in the m3u (e.g., at the end).
I have updated the code to ignore lines that are blank or only have whitespace. It is up on github and I will included it on my next executable install.
Quote
The second small issue is that any error in one track reference causes the entire import to abort with Errorlevel set to 1.  [...]
This is always something I haven't really been sure how to handle. Do you have any suggestions? I guess I could include a batch error mode that would be the default...
Quote
(a) execution message output appears to go to stderr vs. stdout, which can interfere with batch file output piping for logging/analysis purposes
I believe throwing errors to stderr is the proper behavior. Would it help if I included a parameter flag that instead pushed everything through stdout? In bash shell environments, it's as simple as adding "2>&1" after your command. Not sure about windows.
I think that covers everything you mentioned, minus track length. I just looked in the DB, and from a quick glance, I'm not actually sure where the track durations are stored for items on a playlist. I think I skipped that since I wanted to make a minimum number of modifications to the database and knew it would auto correct.

[Edit] P.S. The latest version (have not compiled into exe yet) allows dragging playlists onto the executable.

50
Posts / Painless migration from PHP MySQL to MySQLi
« on: July 02, 2016, 03:52:11 am »

The PHP MySQL extension is being deprecated in favor of the MySQLi extension in PHP 5.5, and removed as of PHP 7.0. MySQLi was first referenced in PHP v5.0.0 beta 4 on 2004-02-12, with the first stable release in PHP 5.0.0 on 2004-07-13[1]. Before that, the PHP MySQL extension was by far the most popular way of interacting with MySQL on PHP, and still was for a very long time after. This website was opened only 2 years after the first stable release!


With the deprecation, problems from some websites I help host have popped up, many of these sites being very, very old. I needed a quick and dirty solution to monkey-patch these websites to use MySQLi without rewriting all their code. The obvious answer is to overwrite the functions with wrappers for MySQLi. The generally known way of doing this is with the Advanced PHP Debugger (APD). However, using this extension has a lot of requirements that are not appropriate for a production web server. Fortunately, another extension I recently learned of offers the renaming functionality; runkit. It was a super simple install for me.

  1. From the command line, run “pecl install runkit”
  2. Add “extension=runkit.so” and “runkit.internal_override=On” to the php.ini

Besides the ability to override these functions with wrappers, I also needed a way to make sure this file was always loaded before all other PHP files. The simple solution for that is adding “auto_prepend_file=/PATH/TO/FILE” to the “.user.ini” in the user’s root web directory.

The code for this script is as follows. It only contains a limited set of the MySQL functions, including some very esoteric ones that the web site used. This is not a foolproof script, but it gets the job done.


//Override the MySQL functions
foreach(Array(
   'connect', 'error', 'fetch_array', 'fetch_row', 'insert_id', 'num_fields', 'num_rows',
   'query', 'select_db', 'field_len', 'field_name', 'field_type', 'list_dbs', 'list_fields',
   'list_tables', 'tablename'
) as $FuncName)
   runkit_function_redefine("mysql_$FuncName", '',
       'return call_user_func_array("mysql_'.$FuncName.'_OVERRIDE", func_get_args());');

//If a connection is not explicitely passed to a mysql_ function, use the last created connection
global $SQLLink; //The remembered SQL Link
function GetConn($PassedConn)
{
   if(isset($PassedConn))
       return $PassedConn;
   global $SQLLink;
   return $SQLLink;
}

//Override functions
function mysql_connect_OVERRIDE($Host, $Username, $Password) {
   global $SQLLink;
   return $SQLLink=mysqli_connect($Host, $Username, $Password);
}
function mysql_error_OVERRIDE($SQLConn=NULL) {
   return mysqli_error(GetConn($SQLConn));
}
function mysql_fetch_array_OVERRIDE($Result, $ResultType=MYSQL_BOTH) {
   return mysqli_fetch_array($Result, $ResultType);
}
function mysql_fetch_row_OVERRIDE($Result) {
   return mysqli_fetch_row($Result);
}
function mysql_insert_id_OVERRIDE($SQLConn=NULL) {
   return mysqli_insert_id(GetConn($SQLConn));
}
function mysql_num_fields_OVERRIDE($Result) {
   return mysqli_num_fields($Result);
}
function mysql_num_rows_OVERRIDE($Result) {
   return mysqli_num_rows($Result);
}
function mysql_query_OVERRIDE($Query, $SQLConn=NULL) {
   return mysqli_query(GetConn($SQLConn), $Query);
}
function mysql_select_db_OVERRIDE($DBName, $SQLConn=NULL) {
   return mysqli_select_db(GetConn($SQLConn), $DBName);
}
function mysql_field_len_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->length;
}
function mysql_field_name_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->name;
}
function mysql_field_type_OVERRIDE($Result, $Offset) {
   $Fields=$Result->fetch_fields();
   return $Fields[$Offset]->type;
}
function mysql_list_dbs_OVERRIDE($SQLConn=NULL) {
   $Result=mysql_query('SHOW DATABASES', GetConn($SQLConn));
   $Tables=Array();
   while($Row=mysqli_fetch_assoc($Result))
       $Tables[]=$Row['Database'];
   return $Tables;
}
function mysql_list_fields_OVERRIDE($DBName, $TableName, $SQLConn=NULL) {
   $SQLConn=GetConn($SQLConn);
   $CurDB=mysql_fetch_array(mysql_query('SELECT Database()', $SQLConn));
   $CurDB=$CurDB[0];
   mysql_select_db($DBName, $SQLConn);
   $Result=mysql_query("SHOW COLUMNS FROM $TableName", $SQLConn);
   mysql_select_db($CurDB, $SQLConn);
   if(!$Result) {
       print 'Could not run query: '.mysql_error($SQLConn);
       return Array();
   }
   $Fields=Array();
   while($Row=mysqli_fetch_assoc($Result))
       $Fields[]=$Row['Field'];
   return $Fields;
}
function mysql_list_tables_OVERRIDE($DBName, $SQLConn=NULL) {
   $SQLConn=GetConn($SQLConn);
   $CurDB=mysql_fetch_array(mysql_query('SELECT Database()', $SQLConn));
   $CurDB=$CurDB[0];
   mysql_select_db($DBName, $SQLConn);
   $Result=mysql_query("SHOW TABLES", $SQLConn);
   mysql_select_db($CurDB, $SQLConn);
   if(!$Result) {
       print 'Could not run query: '.mysql_error($SQLConn);
       return Array();
   }
   $Tables=Array();
   while($Row=mysql_fetch_row($Result))
       $Tables[]=$Row[0];
   return $Tables;
}
function mysql_tablename_OVERRIDE($Result) {
   $Fields=$Result->fetch_fields();
   return $Fields[0]->table;
}

And here is some test code to confirm functionality:
global $MyConn, $TEST_Table;
$TEST_Server='localhost';
$TEST_UserName='...';
$TEST_Password='...';
$TEST_DB='...';
$TEST_Table='...';
function GetResult() {
   global $MyConn, $TEST_Table;
   return mysql_query('SELECT * FROM '.$TEST_Table.' LIMIT 1', $MyConn);
}
var_dump($MyConn=mysql_connect($TEST_Server, $TEST_UserName, $TEST_Password));
//Set $MyConn to NULL here if you want to test global $SQLLink functionality
var_dump(mysql_select_db($TEST_DB, $MyConn));
var_dump(mysql_query('SELECT * FROM INVALIDTABLE LIMIT 1', $MyConn));
var_dump(mysql_error($MyConn));
var_dump($Result=GetResult());
var_dump(mysql_fetch_array($Result));
$Result=GetResult(); var_dump(mysql_fetch_row($Result));
$Result=GetResult(); var_dump(mysql_num_fields($Result));
var_dump(mysql_num_rows($Result));
var_dump(mysql_field_len($Result, 0));
var_dump(mysql_field_name($Result, 0));
var_dump(mysql_field_type($Result, 0));
var_dump(mysql_tablename($Result));
var_dump(mysql_list_dbs($MyConn));
var_dump(mysql_list_fields($TEST_DB, $TEST_Table, $MyConn));
var_dump(mysql_list_tables($TEST_DB, $MyConn));
mysql_query('CREATE TEMPORARY TABLE mysqltest (i int auto_increment, primary key (i))', $MyConn);
mysql_query('INSERT INTO mysqltest VALUES ()', $MyConn);
mysql_query('INSERT INTO mysqltest VALUES ()', $MyConn);
var_dump(mysql_insert_id($MyConn));
mysql_query('DROP TEMPORARY TABLE mysqltest', $MyConn);

51
Posts / Bullet Help Formatter for Python’s argparse
« on: July 02, 2016, 02:55:20 am »
Original post for Bullet Help Formatter for Python’s argparse can be found at https://www.castledragmire.com/Posts/Bullet_Help_Formatter_for_Python’s_argparse.
Originally posted on: 07/02/16

This is a HelpFormatter for Python’s argparse class which:
  • Takes raw input and wraps long lines to indent against the current line start.
  • When an indented/list line is encountered, which starts with spaces followed by a star "*", wrapped line’s indents will start 2 spaces after the star.
  • Lines attempt to split at words of 10 characters or less (see .MinCharsInSplitWord).
  • If a line needs to split along a word longer than this, a hyphen is inserted at the end of the line.

import argparse
import re
class BulletHelpFormatter(argparse.HelpFormatter):
   def __init__(self, *args, **kwargs):
       super(BulletHelpFormatter, self).__init__(*args, **kwargs)
       self.MinCharsInSplitWord=10

   def _split_lines(self, text, width):
       #Split lines around line breaks and then modify each line
       Lines=[]
       for Line in text.splitlines():
           #Get the number of spaces to put at subsequent lines
           #0 if not a list item, oherwise, 2+list item start
           ListEl=re.match(r'^ *\*', Line)
           NumBeginningSpace=(0 if ListEl==None else ListEl.end()+1)

           #Add extra spaces at the beginning of each line to match the start of the current line, and go to a maxium of $width
           IsFirstPass=True
           SpacesToAdd=''
           NumSpacesToAdd=0
           while(True):
               #Get the word break points before and after where the line would end
               MaxLineLen=max(min(width-NumSpacesToAdd, len(Line)), 1)
               PrevWordBreak=CurWordBreak=0
               for WordBreak in re.finditer(r'(?<=\W).|\W|$', Line):
                   PrevWordBreak=CurWordBreak
                   CurWordBreak=WordBreak.start()
                   if CurWordBreak>=MaxLineLen:
                       if CurWordBreak==MaxLineLen:
                           PrevWordBreak=CurWordBreak
                       break

               #If previous wordbreak is more than MinCharsInSplitWord away from MaxLineLen, then split at the end of the line
               IsSplit=(PrevWordBreak<1 or CurWordBreak-PrevWordBreak>self.MinCharsInSplitWord)
               SplitPos=(MaxLineLen if IsSplit else PrevWordBreak)

               #Append the new line to the list of lines
               Lines.append(SpacesToAdd+Line[0:SplitPos]+('-' if IsSplit else ''))
               Line=Line[SplitPos:]

               #If this is the end, nothing left to do
               if len(Line)==0:
                   break

               #If this is the first pass, update line creation variables
               if IsFirstPass:
                   IsFirstPass=False
                   NumSpacesToAdd=NumBeginningSpace
                   SpacesToAdd=(' ' * NumSpacesToAdd)

       return Lines

52
Projects / Re: Plex Playlist Importer
« on: July 01, 2016, 04:16:31 am »
I have made multiple updates to the software and recompiled it. I have attached it to this post if you want to check it out. I confirmed that it worked fine in command prompt with your m3u file. Update log is on github.

P.S. If possible, please let me know within the next few days if all is well now. Would like to get the confirmed updates and compilation up on my website.

53
General Discussion / Re: how to enter the parameters?
« on: June 29, 2016, 01:41:47 am »
Quote
I guess that french characters is the cause of that error:"List Importer  'Winamp playlist':'utf-8' codec can't decode byte 0xe9 in position  323:invalid continuarion byte
I have added a command line flag that lets you set the encoding of the file. You will want to set it to ISO-8859-1.
Quote
I chose an full English playlist. I have that:"Playlist name has already been taken by a non-playlist"
This has been fixed.
Quote
It seem that my plex playlist name can't be the same as the artist that  is already in my plex library, so I change the playlist name to  "paramorelist":DB Error: no such module fts4
I have added the following to the README file:
Quote
If running this mentions something about “no such module : FTS4”, you may need to replace the sqlite3.dll or sqlite3.so for your Python, which can be found at https://www.sqlite.org/download.html .
For a Python for Windows install, the DLL location will most likely be located at C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python%PYTHON_VERSION%\DLLs.

The new version is available on github. Will be uploading a new windows executable within the next few days.

54
Projects / Re: Plex Playlist Importer
« on: June 25, 2016, 03:24:48 am »
I'm working on updating the software this weekend.

55
General Discussion / Re: how to enter the parameters?
« on: June 25, 2016, 03:24:33 am »
I'm working on updating the software this weekend.

56
General Discussion / Re: how to enter the parameters?
« on: June 22, 2016, 09:08:00 pm »
You need to either be running on the computer that has the plex server installed, or be able to access plex's config directory directly. If it is not running on the same computer, let me know and I'll elaborate.

---

Go to your current directory with your playlist file.
Run: PlexPlaylistImporter YourPlayListFileName.m3u PlayListNameYouWantInPlex
E.x.: PlexPlaylistImporter Disc1.m3u "They Might Be Giants"

57
Projects / Re: Plex Playlist Importer
« on: June 18, 2016, 12:17:30 am »
OK, I merged in another authors branch to fix the linux absolute path problems. I fixed the UTF8 bom problem, so you don't have to worry about that anymore either. I also added cygwin compatibility.

I just tested with a utf8 m3u file and file names with Japanese characters and it imported fine (had to set up special test cases). Are you absolutely sure your file is utf8? Assuming your command line is in utf8, when the error is shown it should have the proper filename at the end of the error.

I also just tried to save a list from an older version of winamp and it just put question marks for any of the japanese characters ~.~

I also just did a massive import of all my music into plex (have been rebuilding my library). And interestingly enough, 0 of my 100+ files that had japanese characters even imported into plex!  >:( So are you also sure those files are actually in Plex?

There have been weird errors in the past regarding playlist and file lengths in plex. One example is that if your playlist has more than 150 entries, plex no longer recognizes it. The person on my forum that discovered it submitted a bug report to plex. Not sure if it was ever resolved.

But anywho, the playtimes are grabbed from what is already in the plex database, so it is possible it had not recorded them yet at the time you did your playlist import. Or perhaps they are storing additional information about the tracks elsewhere and not updating the main table. I didn't try very hard on that part, as I knew it would auto correct. Once the file is in the plex server playlist, my program no longer has any control over its values.

The error that you are showing regarding the charset looks like it might be b/c you are not in utf8 mode in your tty console. Also, the character you mentioned, c3, is "Ã", which is interesting.  I think I see that one a lot when there are encoding problems. If the board lets you, any chance you can post your playlist file with just that one song for me to inspect. And western european character set would definitely not work with the importer. UTF8 is essential.

Also, have you been running via the executable, or the python scripts? If the latter, I have the newest source up on github @ https://github.com/dakusan/PlexPlaylistImporter/ . If you are unable to run from source, I'll get an executable compiled for you (its a minor PITA). Not wanting to release a new version on the site until your problem is resolved

58
Projects / Re: Plex Playlist Importer
« on: June 17, 2016, 10:05:54 pm »
OK, my forum is acting super crazy right now and not showing your last post >.<; here it is again, and I am working on the stuff now.

Skipper42:
Quote
Well, I solved (kindasorta) the basic problem of BOM inclusion by  installing EditPad Lite (freeware, unlike the Pro version), which  permits me to create (Options menu) an M3U file type and specify UTF-8  and no BOM, and to replace the existing BOM with none if found. I can  then open an .m3u created in another app (e.g., MediaMonkey, mp3tag,  Notepad) and resave it with no BOM.
Unless there are character codes  beyond the basic alphabet (see below for a description of this newly  discovered problem), the .m3u will then import successfully...
...kindasorta.  After the first two successful playlist imports, PMS stopped displaying  the total duration (length) of the playlist, reporting only 'x Items'  where x is the track count. Further, when the playlist is opened in  Plex, all the track lengths are shown as 0:00. A quick check with mp3tag  showed the metadata for length as indeed being included in the .mp3  file, and when one browses to the album in Plex, it, too, has the track  length correctly shown. In both cases -- playlist or music browse --  Plex plays the track correctly. Interestingly, once a track has been  played from the playlist, suddenly PMS finds its brain and correctly  displays the track length on the Playlist page. There's no Refresh  opportunity in the Playlist dialogue to force this otherwise. After the  track lengths are displayed correctly once, they're displayed correctly  henceforth, along with the overall playlist length on the main Playlist  browse page. I noticed that it took a while for the data to propagate  there, however. Even after playing all tracks in a 1:46 duration  playlist (duration doesn't matter, simply starting each track is  sufficient to update the track length display after a few seconds), the  initial value shown for playlist length upon return to the main Playlist  page was 20 minutes. Returning to the track listing for the playlist  showed that indeed all the track lengths were still there, and on return  up to the main Playlist page, suddenly the duration was the correct  1:46 value.
I'm unable from where I sit to determine whether this is a  PMS bug or a PPI problem; perhaps there's a missing commit in the PPI  SQL update query for the track metadata records, and absent some refresh  mechanism, takes PMS a while to update itself?
Now on to the character set/codespace problem.
If  the path (artist, album) or track filename contain other than basic  alphanumeric characters thru ~ (code < 128 or 007F), then you run  into problems like the following, where PPI can't find the track .mp3 to  get its metadata:
Actual mp3 file record in m3u  playlist:<path>\Music Library\Saint-Saëns\Violin Concerto No. 3\02  Romance for violin & orchestra in C major, Op 48.mp3
PPI import  error:ListImporter 'Winamp playlist': Cannot find file listed in  playlist (must be relative to the playlist):<path>\Music  Library\Saint-Sa\xc3«ns\Violin Concerto No. 3\02 Romance for violin  & orchestra in C major, Op 48.mp3
In this case, the e-umlaut (ë) has a decimal character code of 235 (+00EB).
Doesn't  matter whether <path> in this example is relative ("dot  notation") or absolute (<drive letter>:<folder path>). Just  FYI - the error message always says "relative" even if absolute path  addressing is used (likely an artifact of your absolute addressing quick  fix).
Since PMS correctly renders the special characters and  correctly finds and plays the track, and since other apps (MediaMonkey,  mp3tag, Notepad, EditPad Lite) correctly find/render/play the .mp3 file,  this flaw appears to be inside PPI.
I checked and it also doesn't matter whether the character set used is UTF-8 or Western European.
This would seem thus that PPI's character set issues are larger than just ignoring the UTF-8 BOM in an .m3u file.
I  know that's not good news, but do hope there's enough info here for you  to diagnose and correct the bug; I've made enough progress with a  handful of successful playlist imports to be excited about the prospect  of overall success!

59
Projects / Re: Plex Playlist Importer
« on: June 17, 2016, 10:03:25 pm »
OK, my forum has been randomly deleting posts  >:( I just recovered this from the trashbin.

Pierre: it requires python3. I will be making a minor change soon to verify it uses that.

ulle: Playlists are not user based, they are library based. If you mean you want to use a non-admin user to import a playlist, it is possible as long as they have access to the plex sqllite3 file.

60
Projects / Re: Plex Playlist Importer
« on: June 16, 2016, 07:13:05 pm »
Sorry for taking so long on this, should be able to look into this and update the software tomorrow or the day after.

Pages: 1 2 3 [4] 5 6 ... 36